From 18bbf166f13c7fc2b27723eab6a98003cffb9162 Mon Sep 17 00:00:00 2001 From: schwarze Date: Tue, 16 Aug 2022 17:44:53 +0000 Subject: [PATCH] When starting a new input line, even when continuing the same output line, use the current output position as the reference position for tabs on that input line. This brings mandoc in line with the behaviour of GNU, Heirloom, and Plan 9 roff. --- usr.bin/mandoc/man_term.c | 7 ++++-- usr.bin/mandoc/mdoc_term.c | 9 +++++--- usr.bin/mandoc/term.c | 45 +++++++++++++++++++++++++++++++------ usr.bin/mandoc/term.h | 5 +++-- usr.bin/mandoc/term_ascii.c | 4 ++-- 5 files changed, 54 insertions(+), 16 deletions(-) diff --git a/usr.bin/mandoc/man_term.c b/usr.bin/mandoc/man_term.c index 2ca2533dfa6..2ab9f780e5c 100644 --- a/usr.bin/mandoc/man_term.c +++ b/usr.bin/mandoc/man_term.c @@ -1,4 +1,4 @@ -/* $OpenBSD: man_term.c,v 1.192 2022/08/15 18:44:24 schwarze Exp $ */ +/* $OpenBSD: man_term.c,v 1.193 2022/08/16 17:44:53 schwarze Exp $ */ /* * Copyright (c) 2010-2015,2017-2020,2022 Ingo Schwarze * Copyright (c) 2008-2012 Kristaps Dzonsons @@ -908,8 +908,11 @@ print_man_node(DECL_ARGS) (p->flags & TERMP_NONEWLINE) == 0) term_newln(p); p->flags |= TERMP_BRNEVER; - } else + } else { + if (n->flags & NODE_LINE) + term_tab_ref(p); p->flags &= ~TERMP_BRNEVER; + } if (n->flags & NODE_ID) term_tag_write(n, p->line); diff --git a/usr.bin/mandoc/mdoc_term.c b/usr.bin/mandoc/mdoc_term.c index 6362a214a22..bbb1c565d49 100644 --- a/usr.bin/mandoc/mdoc_term.c +++ b/usr.bin/mandoc/mdoc_term.c @@ -1,6 +1,6 @@ -/* $OpenBSD: mdoc_term.c,v 1.279 2020/04/06 09:55:49 schwarze Exp $ */ +/* $OpenBSD: mdoc_term.c,v 1.280 2022/08/16 17:44:53 schwarze Exp $ */ /* - * Copyright (c) 2010, 2012-2020 Ingo Schwarze + * Copyright (c) 2010, 2012-2020, 2022 Ingo Schwarze * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2013 Franco Fichtner * @@ -318,8 +318,11 @@ print_mdoc_node(DECL_ARGS) (p->flags & TERMP_NONEWLINE) == 0) term_newln(p); p->flags |= TERMP_BRNEVER; - } else + } else { + if (n->flags & NODE_LINE) + term_tab_ref(p); p->flags &= ~TERMP_BRNEVER; + } if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT) return; diff --git a/usr.bin/mandoc/term.c b/usr.bin/mandoc/term.c index b300c53d108..db0ea3d7354 100644 --- a/usr.bin/mandoc/term.c +++ b/usr.bin/mandoc/term.c @@ -1,4 +1,4 @@ -/* $OpenBSD: term.c,v 1.149 2022/08/15 17:59:00 schwarze Exp $ */ +/* $OpenBSD: term.c,v 1.150 2022/08/16 17:44:53 schwarze Exp $ */ /* * Copyright (c) 2010-2022 Ingo Schwarze * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons @@ -155,7 +155,11 @@ term_flushln(struct termp *p) /* Finally, print the field content. */ term_field(p, vbl, nbr); - p->tcol->taboff += vbr + (*p->width)(p, ' '); + if (vbr < vtarget) + p->tcol->taboff += vbr; + else + p->tcol->taboff += vtarget; + p->tcol->taboff += (*p->width)(p, ' '); /* * If there is no text left in the field, exit the loop. @@ -175,7 +179,9 @@ term_flushln(struct termp *p) vbr += (*p->width)(p, ' '); continue; case '\n': + case ASCII_NBRZW: case ASCII_BREAK: + case ASCII_TABREF: continue; default: break; @@ -256,9 +262,11 @@ term_fill(struct termp *p, size_t *nbr, size_t *vbr, size_t vtarget) size_t vn; /* Visual position of the next character. */ int breakline; /* Break at the end of this word. */ int graph; /* Last character was non-blank. */ + int taboff; /* Temporary offset for literal tabs. */ *nbr = *vbr = vis = 0; breakline = graph = 0; + taboff = p->tcol->taboff; for (ic = p->tcol->col; ic < p->tcol->lastcol; ic++) { switch (p->tcol->buf[ic]) { case '\b': /* Escape \o (overstrike) or backspace markup. */ @@ -304,12 +312,19 @@ term_fill(struct termp *p, size_t *nbr, size_t *vbr, size_t vtarget) *vbr = vis; continue; + case ASCII_TABREF: + taboff = -vis - (*p->width)(p, ' '); + continue; + default: switch (p->tcol->buf[ic]) { case '\t': - vis += p->tcol->taboff; + if (taboff < 0 && (size_t)-taboff > vis) + vis = 0; + else + vis += taboff; vis = term_tab_next(vis); - vis -= p->tcol->taboff; + vis -= taboff; break; case ASCII_NBRZW: /* Non-breakable zero-width. */ break; @@ -352,8 +367,10 @@ term_field(struct termp *p, size_t vbl, size_t nbr) size_t vis; /* Visual position of the current character. */ size_t vt; /* Visual position including tab offset. */ size_t dv; /* Visual width of the current character. */ + int taboff; /* Temporary offset for literal tabs. */ vis = 0; + taboff = p->tcol->taboff; for (ic = p->tcol->col; ic < nbr; ic++) { /* @@ -366,11 +383,17 @@ term_field(struct termp *p, size_t vbl, size_t nbr) case ASCII_BREAK: case ASCII_NBRZW: continue; + case ASCII_TABREF: + taboff = -vis - (*p->width)(p, ' '); + continue; case '\t': case ' ': case ASCII_NBRSP: if (p->tcol->buf[ic] == '\t') { - vt = p->tcol->taboff + vis; + if (taboff < 0 && (size_t)-taboff > vis) + vt = 0; + else + vt = vis + taboff; dv = term_tab_next(vt) - vt; } else dv = (*p->width)(p, ' '); @@ -435,10 +458,10 @@ endline(struct termp *p) void term_newln(struct termp *p) { - p->tcol->taboff = 0; p->flags |= TERMP_NOSPACE; if (p->tcol->lastcol || p->viscol) term_flushln(p); + p->tcol->taboff = 0; } /* @@ -799,6 +822,14 @@ bufferc(struct termp *p, char c) p->tcol->lastcol = p->col; } +void +term_tab_ref(struct termp *p) +{ + if (p->tcol->lastcol && p->tcol->lastcol <= p->col && + (p->flags & TERMP_NOBUF) == 0) + bufferc(p, ASCII_TABREF); +} + /* * See encode(). * Do this for a single (probably unicode) value. @@ -944,7 +975,7 @@ term_strlen(const struct termp *p, const char *cp) const char *seq, *rhs; enum mandoc_esc esc; static const char rej[] = { '\\', ASCII_NBRSP, ASCII_NBRZW, - ASCII_BREAK, ASCII_HYPH, '\0' }; + ASCII_BREAK, ASCII_HYPH, ASCII_TABREF, '\0' }; /* * Account for escaped sequences within string length diff --git a/usr.bin/mandoc/term.h b/usr.bin/mandoc/term.h index afdc5591f57..20c6cac496c 100644 --- a/usr.bin/mandoc/term.h +++ b/usr.bin/mandoc/term.h @@ -1,7 +1,7 @@ -/* $OpenBSD: term.h,v 1.77 2022/08/15 13:01:40 schwarze Exp $ */ +/* $OpenBSD: term.h,v 1.78 2022/08/16 17:44:53 schwarze Exp $ */ /* + * Copyright (c) 2011-2015,2017,2019,2022 Ingo Schwarze * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2011-2015, 2017, 2019 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -150,6 +150,7 @@ size_t term_len(const struct termp *, size_t); void term_tab_set(const struct termp *, const char *); void term_tab_iset(size_t); +void term_tab_ref(struct termp *); size_t term_tab_next(size_t); void term_tab_free(void); diff --git a/usr.bin/mandoc/term_ascii.c b/usr.bin/mandoc/term_ascii.c index 19f4c261eb6..9aed8551fef 100644 --- a/usr.bin/mandoc/term_ascii.c +++ b/usr.bin/mandoc/term_ascii.c @@ -1,4 +1,4 @@ -/* $OpenBSD: term_ascii.c,v 1.53 2022/08/15 17:59:00 schwarze Exp $ */ +/* $OpenBSD: term_ascii.c,v 1.54 2022/08/16 17:44:53 schwarze Exp $ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons * Copyright (c) 2014,2015,2017,2018,2020 Ingo Schwarze @@ -186,7 +186,7 @@ terminal_sepline(void *arg) static size_t ascii_width(const struct termp *p, int c) { - return c != ASCII_BREAK && c != ASCII_NBRZW; + return c != ASCII_BREAK && c != ASCII_NBRZW && c != ASCII_TABREF; } void -- 2.20.1