aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2020-02-27 21:43:44 +0000
committerIngo Schwarze <schwarze@openbsd.org>2020-02-27 21:43:44 +0000
commitf170f4f7447172beaedf75482b2bfa599cadfb1d (patch)
tree15ae2b8147741c1e627be93a980ac12da520e96a
parent88750dda2da444fce307d20d33700d72e7c49c7f (diff)
downloadmandoc-f170f4f7447172beaedf75482b2bfa599cadfb1d.tar.gz
mandoc-f170f4f7447172beaedf75482b2bfa599cadfb1d.tar.zst
mandoc-f170f4f7447172beaedf75482b2bfa599cadfb1d.zip
Fully support explicit tagging of .Sh and .Ss.
This fixes the offset of two lines in terminal output and this improves HTML output by putting the id= attribute and <a> element into the respective <h1> or <h2> element rather than writing an additional <mark> element. To that end, introduce node flags NODE_ID (to make the node a link target, for example by writing an HTML id= attribute or by calling tag_put()) and NODE_HREF (to make the node a link source, used only in HTML output, used only to write an <a class="permalink"> element). In particular: * In the validator, generalize the concept of the "next node" such that it also works before .Sh and .Ss. * If the first argument of .Tg is empty, don't forget to complain if there are additional arguments, which will be ignored. * In the terminal formatter, support writing of explicit tags for all kinds of nodes, not just for .Tg. * In deroff(), allow nodes to have an explicit string representation even when they aren't text nodes. Use this for explicitly tagged section headers. Suprisingly, this is sufficient to make HTML output work, without explicit code changes in the HTML formatter. * In syntax tree output, display NODE_ID and NODE_HREF.
-rw-r--r--mdoc_term.c16
-rw-r--r--mdoc_validate.c51
-rw-r--r--regress/mdoc/Sh/Makefile6
-rw-r--r--regress/mdoc/Sh/tag.in21
-rw-r--r--regress/mdoc/Sh/tag.out_ascii22
-rw-r--r--regress/mdoc/Sh/tag.out_html9
-rw-r--r--regress/mdoc/Sh/tag.out_markdown27
-rw-r--r--roff.c4
-rw-r--r--roff.h4
-rw-r--r--tree.c9
10 files changed, 146 insertions, 23 deletions
diff --git a/mdoc_term.c b/mdoc_term.c
index 483db0ea..dc03b9aa 100644
--- a/mdoc_term.c
+++ b/mdoc_term.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc_term.c,v 1.377 2020/02/27 01:43:52 schwarze Exp $ */
+/* $Id: mdoc_term.c,v 1.378 2020/02/27 21:43:44 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012-2020 Ingo Schwarze <schwarze@openbsd.org>
@@ -117,7 +117,6 @@ static int termp_pp_pre(DECL_ARGS);
static int termp_ss_pre(DECL_ARGS);
static int termp_sy_pre(DECL_ARGS);
static int termp_tag_pre(DECL_ARGS);
-static int termp_tg_pre(DECL_ARGS);
static int termp_under_pre(DECL_ARGS);
static int termp_vt_pre(DECL_ARGS);
static int termp_xr_pre(DECL_ARGS);
@@ -244,7 +243,7 @@ static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = {
{ NULL, termp____post }, /* %Q */
{ NULL, termp____post }, /* %U */
{ NULL, NULL }, /* Ta */
- { termp_tg_pre, NULL }, /* Tg */
+ { termp_skip_pre, NULL }, /* Tg */
};
static int fn_prio = TAG_STRONG;
@@ -341,6 +340,10 @@ print_mdoc_node(DECL_ARGS)
memset(&npair, 0, sizeof(struct termpair));
npair.ppair = pair;
+ if (n->flags & NODE_ID)
+ tag_put(n->string == NULL ? n->child->string : n->string,
+ TAG_MANUAL, p->line);
+
/*
* Keeps only work until the end of a line. If a keep was
* invoked in a prior line, revert it to PREKEEP.
@@ -2066,13 +2069,6 @@ termp_tag_pre(DECL_ARGS)
}
static int
-termp_tg_pre(DECL_ARGS)
-{
- tag_put(n->child->string, TAG_MANUAL, p->line);
- return 0;
-}
-
-static int
termp_abort_pre(DECL_ARGS)
{
abort();
diff --git a/mdoc_validate.c b/mdoc_validate.c
index 0b90cf09..0ea41db1 100644
--- a/mdoc_validate.c
+++ b/mdoc_validate.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc_validate.c,v 1.378 2020/02/27 01:43:52 schwarze Exp $ */
+/* $Id: mdoc_validate.c,v 1.379 2020/02/27 21:43:44 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2020 Ingo Schwarze <schwarze@openbsd.org>
@@ -1094,21 +1094,32 @@ post_st(POST_ARGS)
static void
post_tg(POST_ARGS)
{
- struct roff_node *n, *nch;
+ struct roff_node *n, *nch, *nn;
size_t len;
+ /* Find the next node. */
n = mdoc->last;
+ for (nn = n; nn != NULL; nn = nn->parent) {
+ if (nn->next != NULL) {
+ nn = nn->next;
+ break;
+ }
+ }
+
+ /* Add the default argument, if needed. */
nch = n->child;
- if (nch == NULL && n->next != NULL &&
- n->next->child->type == ROFFT_TEXT) {
+ if (nch == NULL && nn != NULL && nn->child->type == ROFFT_TEXT) {
mdoc->next = ROFF_NEXT_CHILD;
roff_word_alloc(mdoc, n->line, n->pos, n->next->child->string);
nch = mdoc->last;
nch->flags |= NODE_NOSRC;
mdoc->last = n;
}
- if (nch == NULL || *nch->string == '\0') {
+
+ /* Validate the first argument. */
+ if (nch == NULL || *nch->string == '\0')
mandoc_msg(MANDOCERR_MACRO_EMPTY, n->line, n->pos, "Tg");
+ if (nch == NULL) {
roff_node_delete(mdoc, n);
return;
}
@@ -1116,14 +1127,42 @@ post_tg(POST_ARGS)
if (nch->string[len] != '\0')
mandoc_msg(MANDOCERR_TG_SPC, nch->line, nch->pos + len + 1,
"Tg %s", nch->string);
+
+ /* Keep only the first argument. */
if (nch->next != NULL) {
mandoc_msg(MANDOCERR_ARG_EXCESS, nch->next->line,
nch->next->pos, "Tg ... %s", nch->next->string);
while (nch->next != NULL)
roff_node_delete(mdoc, nch->next);
}
- if (nch->string[len] != '\0')
+
+ /* Drop the macro if the first argument is invalid. */
+ if (len == 0 || nch->string[len] != '\0') {
roff_node_delete(mdoc, n);
+ return;
+ }
+
+ /* By default, write a <mark> element. */
+ n->flags |= NODE_ID;
+ if (nn == NULL)
+ return;
+
+ /* Explicit tagging of specific macros. */
+ switch (nn->tok) {
+ case MDOC_Sh:
+ case MDOC_Ss:
+ if (nn->head->flags & NODE_ID || nn->head->child == NULL)
+ break;
+ n->flags |= NODE_NOPRT;
+ nn->head->flags |= NODE_ID | NODE_HREF;
+ assert(nn->head->string == NULL);
+ nn->head->string = mandoc_strdup(nch->string);
+ break;
+ default:
+ break;
+ }
+ if (n->flags & NODE_NOPRT)
+ n->flags &= ~NODE_ID;
}
static void
diff --git a/regress/mdoc/Sh/Makefile b/regress/mdoc/Sh/Makefile
index 213664ec..4b37bb2a 100644
--- a/regress/mdoc/Sh/Makefile
+++ b/regress/mdoc/Sh/Makefile
@@ -1,11 +1,11 @@
-# $OpenBSD: Makefile,v 1.12 2020/02/27 01:25:58 schwarze Exp $
+# $OpenBSD: Makefile,v 1.13 2020/02/27 21:38:27 schwarze Exp $
REGRESS_TARGETS = badNAME before empty emptyNAME first nohead order
REGRESS_TARGETS += orderNAME paragraph parbefore parborder punctNAME
-REGRESS_TARGETS += subbefore transp
+REGRESS_TARGETS += subbefore tag transp
LINT_TARGETS = badNAME before empty emptyNAME first nohead order
LINT_TARGETS += orderNAME parbefore parborder punctNAME subbefore
-HTML_TARGETS = paragraph
+HTML_TARGETS = paragraph tag
# groff-1.22.3 defects:
# - .Pp before .Sh NAME causes a blank line before the header line
diff --git a/regress/mdoc/Sh/tag.in b/regress/mdoc/Sh/tag.in
new file mode 100644
index 00000000..0e0e5fef
--- /dev/null
+++ b/regress/mdoc/Sh/tag.in
@@ -0,0 +1,21 @@
+.\" $OpenBSD: tag.in,v 1.1 2020/02/27 21:38:27 schwarze Exp $
+.Dd $Mdocdate: February 27 2020 $
+.Dt SH-TAG 1
+.Os
+.Sh NAME
+.Nm Sh-tag
+.Nd tagging section headers
+.Sh DESCRIPTION
+Text in the description.
+.Ss Subsection
+BEGINTEST
+.Pp
+Text in the subsection.
+.Tg examples
+.Sh EXAMPLES
+Text introducing examples.
+.Tg example
+.Ss Subsection
+Example text.
+.Pp
+ENDTEST
diff --git a/regress/mdoc/Sh/tag.out_ascii b/regress/mdoc/Sh/tag.out_ascii
new file mode 100644
index 00000000..df0ab050
--- /dev/null
+++ b/regress/mdoc/Sh/tag.out_ascii
@@ -0,0 +1,22 @@
+SH-TAG(1) General Commands Manual SH-TAG(1)
+
+NNAAMMEE
+ SShh--ttaagg - tagging section headers
+
+DDEESSCCRRIIPPTTIIOONN
+ Text in the description.
+
+ SSuubbsseeccttiioonn
+ BEGINTEST
+
+ Text in the subsection.
+
+EEXXAAMMPPLLEESS
+ Text introducing examples.
+
+ SSuubbsseeccttiioonn
+ Example text.
+
+ ENDTEST
+
+OpenBSD February 27, 2020 OpenBSD
diff --git a/regress/mdoc/Sh/tag.out_html b/regress/mdoc/Sh/tag.out_html
new file mode 100644
index 00000000..9722aa8c
--- /dev/null
+++ b/regress/mdoc/Sh/tag.out_html
@@ -0,0 +1,9 @@
+<p class="Pp">Text in the subsection.</p>
+</section>
+</section>
+<section class="Sh">
+<h1 class="Sh" id="examples"><a class="permalink" href="#examples">EXAMPLES</a></h1>
+<p class="Pp">Text introducing examples.</p>
+<section class="Ss">
+<h2 class="Ss" id="example"><a class="permalink" href="#example">Subsection</a></h2>
+<p class="Pp">Example text.</p>
diff --git a/regress/mdoc/Sh/tag.out_markdown b/regress/mdoc/Sh/tag.out_markdown
new file mode 100644
index 00000000..2813f8f0
--- /dev/null
+++ b/regress/mdoc/Sh/tag.out_markdown
@@ -0,0 +1,27 @@
+SH-TAG(1) - General Commands Manual
+
+# NAME
+
+**Sh-tag** - tagging section headers
+
+# DESCRIPTION
+
+Text in the description.
+
+## Subsection
+
+BEGINTEST
+
+Text in the subsection.
+
+# EXAMPLES
+
+Text introducing examples.
+
+## Subsection
+
+Example text.
+
+ENDTEST
+
+OpenBSD - February 27, 2020
diff --git a/roff.c b/roff.c
index 017f28f9..635bbc34 100644
--- a/roff.c
+++ b/roff.c
@@ -1,4 +1,4 @@
-/* $Id: roff.c,v 1.370 2020/02/27 01:43:52 schwarze Exp $ */
+/* $Id: roff.c,v 1.371 2020/02/27 21:43:44 schwarze Exp $ */
/*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
@@ -1173,7 +1173,7 @@ deroff(char **dest, const struct roff_node *n)
char *cp;
size_t sz;
- if (n->type != ROFFT_TEXT) {
+ if (n->string == NULL) {
for (n = n->child; n != NULL; n = n->next)
deroff(dest, n);
return;
diff --git a/roff.h b/roff.h
index 2cf8aeae..d1e05db5 100644
--- a/roff.h
+++ b/roff.h
@@ -1,4 +1,4 @@
-/* $Id: roff.h,v 1.71 2020/02/27 01:43:52 schwarze Exp $ */
+/* $Id: roff.h,v 1.72 2020/02/27 21:43:45 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
@@ -522,6 +522,8 @@ struct roff_node {
#define NODE_NOFILL (1 << 8) /* Fill mode switched off. */
#define NODE_NOSRC (1 << 9) /* Generated node, not in input file. */
#define NODE_NOPRT (1 << 10) /* Shall not print anything. */
+#define NODE_ID (1 << 11) /* Target for deep linking. */
+#define NODE_HREF (1 << 12) /* Link to another place in this page. */
int prev_font; /* Before entering this node. */
int aux; /* Decoded node data, type-dependent. */
enum roff_tok tok; /* Request or macro ID. */
diff --git a/tree.c b/tree.c
index 366673eb..c39e89b8 100644
--- a/tree.c
+++ b/tree.c
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.85 2020/01/11 16:03:42 schwarze Exp $ */
+/* $Id: tree.c,v 1.86 2020/02/27 21:43:45 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
@@ -199,6 +199,13 @@ print_mdoc(const struct roff_node *n, int indent)
putchar(')');
if (n->flags & NODE_EOS)
putchar('.');
+ if (n->flags & NODE_ID) {
+ printf(" ID");
+ if (n->string != NULL)
+ printf("=%s", n->string);
+ }
+ if (n->flags & NODE_HREF)
+ printf(" HREF");
if (n->flags & NODE_BROKEN)
printf(" BROKEN");
if (n->flags & NODE_NOFILL)