When starting a new input line, even when continuing the same output
authorschwarze <schwarze@openbsd.org>
Tue, 16 Aug 2022 17:44:53 +0000 (17:44 +0000)
committerschwarze <schwarze@openbsd.org>
Tue, 16 Aug 2022 17:44:53 +0000 (17:44 +0000)
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
usr.bin/mandoc/mdoc_term.c
usr.bin/mandoc/term.c
usr.bin/mandoc/term.h
usr.bin/mandoc/term_ascii.c

index 2ca2533..2ab9f78 100644 (file)
@@ -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 <schwarze@openbsd.org>
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -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);
index 6362a21..bbb1c56 100644 (file)
@@ -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 <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2020, 2022 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
  *
@@ -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;
index b300c53..db0ea3d 100644 (file)
@@ -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 <schwarze@openbsd.org>
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -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
index afdc559..20c6cac 100644 (file)
@@ -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 <schwarze@openbsd.org>
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011-2015, 2017, 2019 Ingo Schwarze <schwarze@openbsd.org>
  *
  * 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);
 
index 19f4c26..9aed855 100644 (file)
@@ -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 <kristaps@bsd.lv>
  * Copyright (c) 2014,2015,2017,2018,2020 Ingo Schwarze <schwarze@openbsd.org>
@@ -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