=================================================================== RCS file: /cvs/mandoc/term.c,v retrieving revision 1.288 retrieving revision 1.290 diff -u -p -r1.288 -r1.290 --- mandoc/term.c 2022/08/15 13:04:43 1.288 +++ mandoc/term.c 2022/08/16 17:45:55 1.290 @@ -1,4 +1,4 @@ -/* $Id: term.c,v 1.288 2022/08/15 13:04:43 schwarze Exp $ */ +/* $Id: term.c,v 1.290 2022/08/16 17:45:55 schwarze Exp $ */ /* * Copyright (c) 2010-2022 Ingo Schwarze * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons @@ -157,7 +157,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. @@ -177,7 +181,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; @@ -208,7 +214,6 @@ term_flushln(struct termp *p) return; endline(p); - p->viscol = 0; /* * Normally, start the next line at the same indentation @@ -259,9 +264,11 @@ term_fill(struct termp *p, size_t *nbr, size_t *vbr, s 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. */ @@ -307,13 +314,22 @@ term_fill(struct termp *p, size_t *nbr, size_t *vbr, s *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; case ASCII_NBRSP: /* Non-breakable space. */ p->tcol->buf[ic] = ' '; /* FALLTHROUGH */ @@ -353,8 +369,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++) { /* @@ -365,12 +383,19 @@ term_field(struct termp *p, size_t vbl, size_t nbr) switch (p->tcol->buf[ic]) { case '\n': 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 +460,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; } /* @@ -571,18 +596,23 @@ term_word(struct termp *p, const char *word) break; case ESCAPE_NUMBERED: uc = mchars_num2char(seq, sz); - if (uc < 0) - continue; - break; + if (uc >= 0) + break; + bufferc(p, ASCII_NBRZW); + continue; case ESCAPE_SPECIAL: if (p->enc == TERMENC_ASCII) { cp = mchars_spec2str(seq, sz, &ssz); if (cp != NULL) encode(p, cp, ssz); + else + bufferc(p, ASCII_NBRZW); } else { uc = mchars_spec2cp(seq, sz); if (uc > 0) encode1(p, uc); + else + bufferc(p, ASCII_NBRZW); } continue; case ESCAPE_UNDEF: @@ -744,6 +774,9 @@ term_word(struct termp *p, const char *word) if (p->col > p->tcol->lastcol) p->col = p->tcol->lastcol; continue; + case ESCAPE_IGNORE: + bufferc(p, ASCII_NBRZW); + continue; default: continue; } @@ -791,6 +824,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. @@ -935,8 +976,8 @@ term_strlen(const struct termp *p, const char *cp) int ssz, skip, uc; const char *seq, *rhs; enum mandoc_esc esc; - static const char rej[] = { '\\', ASCII_NBRSP, ASCII_HYPH, - ASCII_BREAK, '\0' }; + static const char rej[] = { '\\', ASCII_NBRSP, ASCII_NBRZW, + ASCII_BREAK, ASCII_HYPH, ASCII_TABREF, '\0' }; /* * Account for escaped sequences within string length