diff options
-rw-r--r-- | main.c | 5 | ||||
-rw-r--r-- | mandoc.h | 5 | ||||
-rw-r--r-- | mdoc.7 | 60 | ||||
-rw-r--r-- | mdoc_macro.c | 29 | ||||
-rw-r--r-- | mdoc_term.c | 44 |
5 files changed, 127 insertions, 16 deletions
@@ -120,6 +120,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "unknown manual section", "section not in conventional manual section", "end of line whitespace", + "blocks badly nested", "scope open on exit", "generic error", @@ -143,7 +144,6 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "bad comment style", "unknown macro will be lost", "line scope broken", - "scope broken", "argument count wrong", "request scope close w/none open", "scope already open", @@ -162,7 +162,8 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "missing font type", "displays may not be nested", "unsupported display type", - "no scope to rewind: syntax violated", + "blocks badly nested", + "no such block is open", "scope broken, syntax violated", "line scope broken, syntax violated", "argument count wrong, violates syntax", @@ -47,6 +47,7 @@ enum mandocerr { MANDOCERR_BADMSEC, /* unknown manual section */ MANDOCERR_SECMSEC, /* section not in conventional manual section */ MANDOCERR_EOLNSPACE, /* end of line whitespace */ + MANDOCERR_SCOPENEST, /* blocks badly nested */ MANDOCERR_SCOPEEXIT, /* scope open on exit */ MANDOCERR_ERROR, /* ===== end of errors ===== */ @@ -70,9 +71,8 @@ enum mandocerr { MANDOCERR_BADCOMMENT, /* bad comment style */ MANDOCERR_MACRO, /* unknown macro will be lost */ MANDOCERR_LINESCOPE, /* line scope broken */ - MANDOCERR_SCOPE, /* scope broken */ MANDOCERR_ARGCOUNT, /* argument count wrong */ - MANDOCERR_NOSCOPE, /* request scope close w/none open */ + MANDOCERR_NOSCOPE, /* no such block is open */ MANDOCERR_SCOPEREP, /* scope already open */ /* FIXME: merge following with MANDOCERR_ARGCOUNT */ MANDOCERR_NOARGS, /* macro requires line argument(s) */ @@ -92,6 +92,7 @@ enum mandocerr { /* FIXME: this should be a MANDOCERR_ERROR */ MANDOCERR_NESTEDDISP, /* displays may not be nested */ MANDOCERR_BADDISP, /* unsupported display type */ + MANDOCERR_SCOPEFATAL, /* blocks badly nested */ MANDOCERR_SYNTNOSCOPE, /* no scope to rewind: syntax violated */ MANDOCERR_SYNTSCOPE, /* scope broken, syntax violated */ MANDOCERR_SYNTLINESCOPE, /* line scope broken, syntax violated */ @@ -478,6 +478,19 @@ they are separated by a vertical space, unless in the case of and .Sx \&Ft , which are always separated by vertical space. +.Pp +When text and macros following an +.Sx \&Nm +macro starting an input line span multiple output lines, +all output lines but the first will be indented to align +with the text immediately following the +.Sx \&Nm +macro, up to the next +.Sx \&Nm , +.Sx \&Sx , +or +.Sx \&Ss +macro or the end of an enclosing block, whichever comes first. .It Em DESCRIPTION This expands upon the brief, one-line description in .Em NAME . @@ -672,9 +685,20 @@ has multiple heads. .It Em Macro Ta Em Callable Ta Em Parsable Ta Em Scope .It Sx \&It Ta \&No Ta Yes Ta closed by Sx \&It , Sx \&El .It Sx \&Nd Ta \&No Ta \&No Ta closed by Sx \&Sh +.It Sx \&Nm Ta \&No Ta Yes Ta closed by Sx \&Nm , Sx \&Sh , Sx \&Ss .It Sx \&Sh Ta \&No Ta \&No Ta closed by Sx \&Sh .It Sx \&Ss Ta \&No Ta \&No Ta closed by Sx \&Sh , Sx \&Ss .El +.Pp +Note that the +.Sx \&Nm +macro is a +.Sx Block full-implicit +macro only when invoked as the first macro +in a +.Em SYNOPSIS +section line, else it is +.Sx In-line . .Ss Block partial-explicit Like block full-explicit, but also with single-line scope. Each has at least a body and, in limited circumstances, a head @@ -1958,6 +1982,42 @@ Examples: .D1 \&.Mt discuss@manpages.bsd.lv .Ss \&Nd .Ss \&Nm +The name of the manual page, or \(em in particular in section 1, 6, +and 8 pages \(em of an additional command or feature documented in +the manual page. +When first invoked, the +.Sx \&Nm +macro expects a single argument, the name of the manual page. +Usually, the first invocation happens in the +.Em NAME +section of the page. +The specified name will be remembered and used whenever the macro is +called again without arguments later in the page. +The +.Sx \&Nm +macro uses +.Sx Block full-implicit +semantics when invoked as the first macro on an input line in the +.Em SYNOPSIS +section; otherwise, it uses ordinary +.Sx In-line +semantics. +.Pp +Examples: +.Bd -literal -offset indent +\&.Sh SYNOPSIS +\&.Nm cat +\&.Op Fl benstuv +\&.Op Ar +.Ed +.Pp +In the +.Em SYNOPSIS +of section 2, 3 and 9 manual pages, use the +.Sx \&Fn +macro rather than +.Sx \&Nm +to mark up the name of the manual page. .Ss \&No .Ss \&Ns .Ss \&Nx diff --git a/mdoc_macro.c b/mdoc_macro.c index 82cca0c6..99730eee 100644 --- a/mdoc_macro.c +++ b/mdoc_macro.c @@ -97,7 +97,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */ { blk_full, 0 }, /* Nd */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */ + { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */ { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */ { obsolete, 0 }, /* Ot */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */ @@ -392,6 +392,8 @@ rew_dohalt(enum mdoct tok, enum mdoc_type type, if (MDOC_Op == p->tok) return(REWIND_MORE); break; + case (MDOC_Nm): + return(REWIND_NONE); case (MDOC_Nd): /* FALLTHROUGH */ case (MDOC_Ss): @@ -409,9 +411,11 @@ rew_dohalt(enum mdoct tok, enum mdoc_type type, /* * Default block rewinding rules. - * In particular, always skip block end markers. + * In particular, always skip block end markers, + * and let all blocks rewind Nm children. */ - if (ENDBODY_NOT != p->end || (MDOC_BLOCK == p->type && + if (ENDBODY_NOT != p->end || MDOC_Nm == p->tok || + (MDOC_BLOCK == p->type && ! (MDOC_EXPLICIT & mdoc_macros[tok].flags))) return(REWIND_MORE); @@ -507,8 +511,9 @@ make_pending(struct mdoc_node *broken, enum mdoct tok, taker->pending = broken->pending; } broken->pending = breaker; - mdoc_vmsg(m, MANDOCERR_SCOPE, line, ppos, "%s breaks %s", - mdoc_macronames[tok], mdoc_macronames[broken->tok]); + mdoc_vmsg(m, MANDOCERR_SCOPENEST, line, ppos, + "%s breaks %s", mdoc_macronames[tok], + mdoc_macronames[broken->tok]); return(1); } @@ -542,7 +547,9 @@ rew_sub(enum mdoc_type t, struct mdoc *m, return(make_pending(n, tok, m, line, ppos)); case (REWIND_ERROR): /* XXX Make this non-fatal. */ - mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTNOSCOPE); + mdoc_vmsg(m, MANDOCERR_SCOPEFATAL, line, ppos, + "%s cannot break %s", mdoc_macronames[tok], + mdoc_macronames[n->tok]); return 0; } break; @@ -653,7 +660,7 @@ blk_exp_close(MACRO_PROT_ARGS) continue; } - if (MDOC_BLOCK != n->type) + if (MDOC_BLOCK != n->type || MDOC_Nm == n->tok) continue; if (atok == n->tok) { assert(body); @@ -1290,8 +1297,8 @@ blk_part_imp(MACRO_PROT_ARGS) * is ugly behaviour nodding its head to OpenBSD's overwhelming * crufty use of `Op' breakage. */ - if (n != body && ! mdoc_vmsg(m, MANDOCERR_SCOPE, line, ppos, - "%s broken", mdoc_macronames[tok])) + if (n != body && ! mdoc_vmsg(m, MANDOCERR_SCOPENEST, + line, ppos, "%s broken", mdoc_macronames[tok])) return(0); if (n && ! rew_sub(MDOC_BODY, m, tok, line, ppos)) @@ -1647,7 +1654,9 @@ ctx_synopsis(MACRO_PROT_ARGS) * up formatting the block scope, then child nodes will inherit * the formatting. Be careful. */ - + if (MDOC_Nm == tok) + return(blk_full(m, tok, line, ppos, pos, buf)); + assert(MDOC_Vt == tok); return(blk_part_imp(m, tok, line, ppos, pos, buf)); } diff --git a/mdoc_term.c b/mdoc_term.c index 633394d1..5138a22d 100644 --- a/mdoc_term.c +++ b/mdoc_term.c @@ -85,6 +85,7 @@ static void termp_fo_post(DECL_ARGS); static void termp_in_post(DECL_ARGS); static void termp_it_post(DECL_ARGS); static void termp_lb_post(DECL_ARGS); +static void termp_nm_post(DECL_ARGS); static void termp_op_post(DECL_ARGS); static void termp_pf_post(DECL_ARGS); static void termp_pq_post(DECL_ARGS); @@ -170,7 +171,7 @@ static const struct termact termacts[MDOC_MAX] = { { termp_in_pre, termp_in_post }, /* In */ { termp_li_pre, NULL }, /* Li */ { termp_nd_pre, NULL }, /* Nd */ - { termp_nm_pre, NULL }, /* Nm */ + { termp_nm_pre, termp_nm_post }, /* Nm */ { termp_op_pre, termp_op_post }, /* Op */ { NULL, NULL }, /* Ot */ { termp_under_pre, NULL }, /* Pa */ @@ -1025,11 +1026,35 @@ static int termp_nm_pre(DECL_ARGS) { - if (NULL == n->child && NULL == m->name) + if (MDOC_BLOCK == n->type) + return(1); + + if (MDOC_BODY == n->type) { + if (NULL == n->child) + return(0); + p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; + p->offset += term_len(p, 1) + + (NULL == n->prev->child ? term_strlen(p, m->name) : + MDOC_TEXT == n->prev->child->type ? + term_strlen(p, n->prev->child->string) : + term_len(p, 5)); return(1); + } + + if (NULL == n->child && NULL == m->name) + return(0); synopsis_pre(p, n); + if (MDOC_HEAD == n->type && n->next->child) { + p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_HANG; + p->rmargin = p->offset + term_len(p, 1) + + (NULL == n->child ? term_strlen(p, m->name) : + MDOC_TEXT == n->child->type ? + term_strlen(p, n->child->string) : + term_len(p, 5)); + } + term_fontpush(p, TERMFONT_BOLD); if (NULL == n->child) term_word(p, m->name); @@ -1038,6 +1063,21 @@ termp_nm_pre(DECL_ARGS) /* ARGSUSED */ +static void +termp_nm_post(DECL_ARGS) +{ + + if (MDOC_HEAD == n->type && n->next->child) { + term_flushln(p); + p->flags &= ~(TERMP_NOBREAK | TERMP_HANG); + } else if (MDOC_BODY == n->type && n->child) { + term_flushln(p); + p->flags &= ~TERMP_NOLPAD; + } +} + + +/* ARGSUSED */ static int termp_fl_pre(DECL_ARGS) { |