implement the roff(7) \p (break output line) escape sequence
authorschwarze <schwarze@openbsd.org>
Wed, 14 Jun 2017 01:31:19 +0000 (01:31 +0000)
committerschwarze <schwarze@openbsd.org>
Wed, 14 Jun 2017 01:31:19 +0000 (01:31 +0000)
regress/usr.bin/mandoc/roff/esc/Makefile
regress/usr.bin/mandoc/roff/esc/p.in [new file with mode: 0644]
regress/usr.bin/mandoc/roff/esc/p.out_ascii [new file with mode: 0644]
share/man/man7/roff.7
usr.bin/mandoc/html.c
usr.bin/mandoc/mandoc.c
usr.bin/mandoc/mandoc.h
usr.bin/mandoc/mdoc_markdown.c
usr.bin/mandoc/term.c

index f086036..6d81161 100644 (file)
@@ -1,6 +1,6 @@
-# $OpenBSD: Makefile,v 1.11 2015/04/29 18:32:57 schwarze Exp $
+# $OpenBSD: Makefile,v 1.12 2017/06/14 01:31:19 schwarze Exp $
 
-REGRESS_TARGETS = one two multi B c c_man e f h o w z ignore
+REGRESS_TARGETS = one two multi B c c_man e f h o w z ignore
 LINT_TARGETS   = B h w ignore
 
 .include <bsd.regress.mk>
diff --git a/regress/usr.bin/mandoc/roff/esc/p.in b/regress/usr.bin/mandoc/roff/esc/p.in
new file mode 100644 (file)
index 0000000..b94ab13
--- /dev/null
@@ -0,0 +1,15 @@
+.Dd June 14, 2017
+.Dt ESC-P 1
+.Os OpenBSD
+.Sh NAME
+.Nm esc-p
+.Nd line break escape sequence
+.Sh DESCRIPTION
+no blank: line one\pline two
+.Pp
+blank after esc: line one\p line two
+.Pp
+blank before esc: line one \pline two
+.Pp
+at eol: line one\p
+line two
diff --git a/regress/usr.bin/mandoc/roff/esc/p.out_ascii b/regress/usr.bin/mandoc/roff/esc/p.out_ascii
new file mode 100644 (file)
index 0000000..488e2c6
--- /dev/null
@@ -0,0 +1,19 @@
+ESC-P(1)                    General Commands Manual                   ESC-P(1)
+
+N\bNA\bAM\bME\bE
+     e\bes\bsc\bc-\b-p\bp - line break escape sequence
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+     no blank: line oneline
+     two
+
+     blank after esc: line one
+     line two
+
+     blank before esc: line one line
+     two
+
+     at eol: line one
+     line two
+
+OpenBSD                          June 14, 2017                         OpenBSD
index 9f152c0..b689e48 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: roff.7,v 1.67 2017/06/10 16:32:08 schwarze Exp $
+.\"    $OpenBSD: roff.7,v 1.68 2017/06/14 01:31:19 schwarze Exp $
 .\"
 .\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
 .\" Copyright (c) 2010,2011,2013-2015,2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: June 10 2017 $
+.Dd $Mdocdate: June 14 2017 $
 .Dt ROFF 7
 .Os
 .Sh NAME
@@ -1989,6 +1989,8 @@ Overstrike, writing all the characters contained in the
 to the same output position.
 In terminal and HTML output modes,
 only the last one of the characters is visible.
+.Ss \ep
+Break the output line at the end of the current word.
 .Ss \eR\(aq Ns Ar name Oo +|- Oc Ns Ar number Ns \(aq
 Set number register; ignored by
 .Xr mandoc 1 .
index f25c21d..5857624 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: html.c,v 1.83 2017/06/08 12:54:40 schwarze Exp $ */
+/*     $OpenBSD: html.c,v 1.84 2017/06/14 01:31:19 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -343,16 +343,18 @@ static int
 print_encode(struct html *h, const char *p, const char *pend, int norecurse)
 {
        char             numbuf[16];
-       size_t           sz;
-       int              c, len, nospace;
+       struct tag      *t;
        const char      *seq;
+       size_t           sz;
+       int              c, len, breakline, nospace;
        enum mandoc_esc  esc;
-       static const char rejs[9] = { '\\', '<', '>', '&', '"',
+       static const char rejs[10] = { ' ', '\\', '<', '>', '&', '"',
                ASCII_NBRSP, ASCII_HYPH, ASCII_BREAK, '\0' };
 
        if (pend == NULL)
                pend = strchr(p, '\0');
 
+       breakline = 0;
        nospace = 0;
 
        while (p < pend) {
@@ -363,14 +365,28 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
                }
 
                for (sz = strcspn(p, rejs); sz-- && p < pend; p++)
-                       if (*p == ' ')
-                               print_endword(h);
-                       else
-                               print_byte(h, *p);
+                       print_byte(h, *p);
+
+               if (breakline &&
+                   (p >= pend || *p == ' ' || *p == ASCII_NBRSP)) {
+                       t = print_otag(h, TAG_DIV, "");
+                       print_text(h, "\\~");
+                       print_tagq(h, t);
+                       breakline = 0;
+                       while (p < pend && (*p == ' ' || *p == ASCII_NBRSP))
+                               p++;
+                       continue;
+               }
 
                if (p >= pend)
                        break;
 
+               if (*p == ' ') {
+                       print_endword(h);
+                       p++;
+                       continue;
+               }
+
                if (print_escape(h, *p++))
                        continue;
 
@@ -415,6 +431,9 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
                        if (c <= 0)
                                continue;
                        break;
+               case ESCAPE_BREAK:
+                       breakline = 1;
+                       continue;
                case ESCAPE_NOSPACE:
                        if ('\0' == *p)
                                nospace = 1;
index 8000e4a..3aff3c5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mandoc.c,v 1.69 2017/06/11 19:36:31 schwarze Exp $ */
+/*     $OpenBSD: mandoc.c,v 1.70 2017/06/14 01:31:19 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -94,6 +94,8 @@ mandoc_escape(const char **end, const char **start, int *sz)
        case ',':
        case '/':
                return ESCAPE_IGNORE;
+       case 'p':
+               return ESCAPE_BREAK;
 
        /*
         * The \z escape is supposed to output the following
index 6f14e23..ed4d1d7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mandoc.h,v 1.171 2017/06/11 19:36:31 schwarze Exp $ */
+/*     $OpenBSD: mandoc.h,v 1.172 2017/06/14 01:31:19 schwarze Exp $ */
 /*
  * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -423,6 +423,7 @@ enum        mandoc_esc {
        ESCAPE_FONTPREV, /* previous font mode */
        ESCAPE_NUMBERED, /* a numbered glyph */
        ESCAPE_UNICODE, /* a unicode codepoint */
+       ESCAPE_BREAK, /* break the output line */
        ESCAPE_NOSPACE, /* suppress space if the last on a line */
        ESCAPE_HORIZ, /* horizontal movement */
        ESCAPE_HLINE, /* horizontal line drawing */
index 19d564a..1a8a70a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mdoc_markdown.c,v 1.22 2017/05/30 16:31:25 schwarze Exp $ */
+/*     $OpenBSD: mdoc_markdown.c,v 1.23 2017/06/14 01:31:19 schwarze Exp $ */
 /*
  * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
  *
@@ -493,7 +493,7 @@ md_word(const char *s)
 {
        const char      *seq, *prevfont, *currfont, *nextfont;
        char             c;
-       int              bs, sz, uc;
+       int              bs, sz, uc, breakline;
 
        /* No spacing before closing delimiters. */
        if (s[0] != '\0' && s[1] == '\0' &&
@@ -510,6 +510,7 @@ md_word(const char *s)
        if ((s[0] == '(' || s[0] == '[') && s[1] == '\0')
                outflags &= ~MD_spc;
 
+       breakline = 0;
        prevfont = currfont = "";
        while ((c = *s++) != '\0') {
                bs = 0;
@@ -595,6 +596,9 @@ md_word(const char *s)
                        case ESCAPE_FONTPREV:
                                nextfont = prevfont;
                                break;
+                       case ESCAPE_BREAK:
+                               breakline = 1;
+                               break;
                        case ESCAPE_NOSPACE:
                        case ESCAPE_SKIPCHAR:
                        case ESCAPE_OVERSTRIKE:
@@ -642,6 +646,13 @@ md_word(const char *s)
                if (bs)
                        putchar('\\');
                md_char(c);
+               if (breakline &&
+                   (*s == '\0' || *s == ' ' || *s == ASCII_NBRSP)) {
+                       printf("  \n");
+                       breakline = 0;
+                       while (*s == ' ' || *s == ASCII_NBRSP)
+                               s++;
+               }
        }
        if (*currfont != '\0') {
                outflags &= ~MD_spc;
index 07b7f57..e6aebdc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: term.c,v 1.129 2017/06/12 18:55:42 schwarze Exp $ */
+/*     $OpenBSD: term.c,v 1.130 2017/06/14 01:31:19 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -114,6 +114,7 @@ term_flushln(struct termp *p)
        size_t           jhy;   /* last hyph before overflow w/r/t j */
        size_t           maxvis; /* output position of visible boundary */
        int              ntab;  /* number of tabs to prepend */
+       int              breakline; /* after this word */
 
        vbl = (p->flags & TERMP_NOPAD) || p->tcol->offset < p->viscol ?
            0 : p->tcol->offset - p->viscol;
@@ -153,7 +154,13 @@ term_flushln(struct termp *p)
                 */
 
                jhy = 0;
+               breakline = 0;
                for (j = p->tcol->col; j < p->tcol->lastcol; j++) {
+                       if (p->tcol->buf[j] == '\n') {
+                               if ((p->flags & TERMP_BRIND) == 0)
+                                       breakline = 1;
+                               continue;
+                       }
                        if (p->tcol->buf[j] == ' ' || p->tcol->buf[j] == '\t')
                                break;
 
@@ -219,6 +226,8 @@ term_flushln(struct termp *p)
                for ( ; p->tcol->col < p->tcol->lastcol; p->tcol->col++) {
                        if (vend > bp && jhy > 0 && p->tcol->col > jhy)
                                break;
+                       if (p->tcol->buf[p->tcol->col] == '\n')
+                               continue;
                        if (p->tcol->buf[p->tcol->col] == '\t')
                                break;
                        if (p->tcol->buf[p->tcol->col] == ' ') {
@@ -258,6 +267,26 @@ term_flushln(struct termp *p)
                                    p->tcol->buf[p->tcol->col]);
                }
                vis = vend;
+
+               if (breakline == 0)
+                       continue;
+
+               /* Explicitly requested output line break. */
+
+               if (p->flags & TERMP_MULTICOL)
+                       return;
+
+               endline(p);
+               breakline = 0;
+               vis = vend = 0;
+
+               /* Re-establish indentation. */
+
+               vbl = p->tcol->offset;
+               maxvis = p->tcol->rmargin > vbl ?
+                   p->tcol->rmargin - vbl : 0;
+               bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
+                   p->maxrmargin > vbl ?  p->maxrmargin - vbl : 0;
        }
 
        /*
@@ -485,6 +514,9 @@ term_word(struct termp *p, const char *word)
                case ESCAPE_FONTPREV:
                        term_fontlast(p);
                        continue;
+               case ESCAPE_BREAK:
+                       bufferc(p, '\n');
+                       continue;
                case ESCAPE_NOSPACE:
                        if (p->flags & TERMP_BACKAFTER)
                                p->flags &= ~TERMP_BACKAFTER;