* PATCH: Intra- and inter-document linking.
@ 2015-03-12 2:51 Kristaps Dzonsons
0 siblings, 0 replies; only message in thread
From: Kristaps Dzonsons @ 2015-03-12 2:51 UTC (permalink / raw)
To: discuss
[-- Attachment #1: Type: text/plain, Size: 3594 bytes --]
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Hi folks,
This wraps up an examplenimplementation of `Ix' for mdoc(7) by
extending `Xr' to handle indices made with `Ix'. In other words,
linking to sections in other manpages. Enclosed is the patch.
* BACKGROUND
`Ix' is a macro proposal that inserts an anchor at an arbitrary
location in an mdoc(7) document. There are already two implicit
anchors generated with `Sh' and `Ss'; `Ix' allows for the same.
As with `Sh' and `Ss', `Ix' anchors can be linked with the `Sx' macro.
In effect, this allows doing things like:
.Bl -tag -width Ds
.It Fl b Ar moo
.Ix -b flag
This is a flag...
...
.El
Then later:
The
.Sx -b flag
allows us to...
For completeness, I also add an `Lkx' macro that serves to link to
sections in the same document by a different name. Thus,
The
.Lkx "-b flag" "bee flag"
allows us to...
I actually don't like the `Lkx' and would prefer `Sxx' or something,
but bikeshed bikeshed bikeshed.
`Ix' is nice because it fits with the existing `Sx' model and can
simply be ignored in non-conformant tools like groff(1). Output modes
/not/ allowing for linkage, such as -Tascii, can simply discard `Ix'
and render the contents of `Sx' as-is. This is the existing behaviour
when using `Sx' to link to `Sh' and so on.
* INTER-PAGE LINKING
The remaining problem is inter-document linkage. This can be easily
accomodated by extending `Xr' to accept 1, 2, 3, or 4 arguments:
.Xr NAME [SECTION [LINK [LINKNAME]]]
So we can have
.Xr foo
.Xr foo 1
.Xr foo 1 NAME
.Xr foo 1 NAME "name section"
By default, links to other sections can be formatted as "foo(1)
section NAME", but this needs some more consideration because it might
not be a section that's linked.
* PROBLEMS
All of this works beautifully in -Thtml (and can be extended to -Tpdf
and friends). The problem is in -Tascii, which as it stands can't
support links. (That's beyond the scope of these patches.) While we
can get away with `Sx' doing nothing for sections, using `Sx' in
console mode to refer to `Ix' tags is confusing because, well, they
don't exist.
There is, however, a solution. I don't have a patch for this (yet),
but am working on it. Essentially, -Tascii knows the exact line and
column of its output. When we invoke an `Ix', we remember the output
line and column. Then when we use `Sx', we can refer to the line and
column of the origin.
For example,
Hello
.Ix world
world.
...
...
Link to
.Sx world .
Right now, this produces "Link to world". Why not make it do "Link to
world [line 23, column 45]"? This way, we can have arbitrary links in
- -Tascii and quickly jump to the locations in the manpager.
This doesn't do much for `Xr', unfortunately.
Best,
Kristaps
-----BEGIN PGP SIGNATURE-----
Comment: GPGTools - https://gpgtools.org
iQIcBAEBCgAGBQJVAP8VAAoJEMT2SUY9XBES7A8QAIbH4nUAzZwf05As7tKiOW+u
YV9kHedKZjgYWPX6MgUwGyl+MRwqdVcT+Xx/LPhJtXsnzBGwd+1CsKsAZFTfi7rr
dyB3ZupSf3ZF89X+aRn3MpY8A+7XiKUm/seXZFLtB/u7rMRnEP0TVJF1oWF6V5oW
fLAQvuq7Aw5HkPj1nscUSQO6pQx/xpYozgZ5R8E3aBSN7DRFj/6U6784C7AlIia8
IKrnvp4WJVYulDgwADxQE0SgxOfeIT+aDDIqGCy3gqfIeH1xsgiXHsB+IJQkgsLT
lxnw3blrPnDoEcYaUu0/u+i57z+Q+REbPYgkNENp7lZaHqopovY/lX2nZCmacyOE
yMONC9E7vLvnPVikyNfz2V6FXG3hb76m1HBxtPCcTZnn25uzbUI3Ha+N8pyMEL77
6tV+H7G8/ffkoS9UBXODyXETGqjCLG09L24k+iiIKuamEfaQcyHY46p8Nyo+TpH9
LES3RsquRUIdz96yK4kbLH964x8juU6fdCkZ8cR5iPYb+SdUz6RkmBAChlFHYPjB
3W/sEr+aw3AOsghaNwUznSCeNx9Ag492U0nIwPOeeUaWG9k68/Jd7mbcuy8avPLP
7F1O9j+g7mugmhHCcaIkPlsfbgwhtWmbmbPVGAqDgalzccxPA/0UyOsZ3/lGRy/t
hgOknxeuWPvk7B4vlC14
=cGAE
-----END PGP SIGNATURE-----
[-- Attachment #2: index.patch --]
[-- Type: text/plain, Size: 12791 bytes --]
? .DS_Store
? Makefile.local
? cgi.h
? config.h
? config.log
? configure.local
? foo.7
? foo.7.html
? foo.html
? index.patch
? linking.patch
? machine.diff
? tbl.patch
? tbl2.patch
Index: html.c
===================================================================
RCS file: /home/cvs/mdocml/mdocml/html.c,v
retrieving revision 1.185
diff -u -p -r1.185 html.c
--- html.c 21 Jan 2015 20:33:25 -0000 1.185
+++ html.c 12 Mar 2015 02:49:07 -0000
@@ -707,7 +707,8 @@ buffmt_includes(struct html *h, const ch
}
void
-buffmt_man(struct html *h, const char *name, const char *sec)
+buffmt_man(struct html *h, const char *name,
+ const char *sec, const char *index)
{
const char *p, *pp;
@@ -731,6 +732,10 @@ buffmt_man(struct html *h, const char *n
}
if (pp)
bufcat(h, pp);
+ if (NULL != index) {
+ bufcat(h, "#index-");
+ bufcat_id(h, index);
+ }
}
void
@@ -752,7 +757,12 @@ bufcat_id(struct html *h, const char *sr
{
/* Cf. <http://www.w3.org/TR/html4/types.html#h-6.2>. */
-
- while ('\0' != *src)
- bufcat_fmt(h, "%.2x", *src++);
+ for ( ; '\0' != *src; src++) {
+ if (isalnum((unsigned int)*src))
+ bufncat(h, src, 1);
+ else if (' ' == *src)
+ bufncat(h, "_", 1);
+ else
+ bufcat_fmt(h, "%.2x", *src);
+ }
}
Index: html.h
===================================================================
RCS file: /home/cvs/mdocml/mdocml/html.h,v
retrieving revision 1.70
diff -u -p -r1.70 html.h
--- html.h 2 Dec 2014 10:08:06 -0000 1.70
+++ html.h 12 Mar 2015 02:49:08 -0000
@@ -171,7 +171,7 @@ void bufcat_style(struct html *,
void bufcat_su(struct html *, const char *,
const struct roffsu *);
void bufinit(struct html *);
-void buffmt_man(struct html *,
+void buffmt_man(struct html *, const char *,
const char *, const char *);
void buffmt_includes(struct html *, const char *);
Index: mdoc.7
===================================================================
RCS file: /home/cvs/mdocml/mdocml/mdoc.7,v
retrieving revision 1.252
diff -u -p -r1.252 mdoc.7
--- mdoc.7 23 Feb 2015 13:31:04 -0000 1.252
+++ mdoc.7 12 Mar 2015 02:49:08 -0000
@@ -440,6 +440,8 @@ in the alphabetical
.El
.Ss Sections and cross references
.Bl -column "Brq, Bro, Brc" description
+.It Sx \&Ix Ta index anchor (one line)
+.It Sx \&Lkx Ta internal cross reference to an index
.It Sx \&Sh Ta section header (one line)
.It Sx \&Ss Ta subsection header (one line)
.It Sx \&Sx Ta internal cross reference to a section or subsection
@@ -510,6 +512,7 @@ in the alphabetical
.Bl -column "Brq, Bro, Brc" description
.It Sx \&An Ta author name (>0 arguments)
.It Sx \&Lk Ta hyperlink: Ar uri Op Ar name
+.It Sx \&Lkx Ta index: Ar index Op Ar name
.It Sx \&Mt Ta Do mailto Dc hyperlink: Ar address
.It Sx \&Cd Ta kernel configuration declaration (>0 arguments)
.It Sx \&Ad Ta memory address (>0 arguments)
@@ -1854,6 +1857,18 @@ will preserve the semicolon whitespace e
.Pp
See also
.Sx \&Bl .
+.Ss \&Ix
+Specify an index point with an arbitrary name.
+The argument is not printed.
+Its syntax is as follows:
+.Pp
+.Dl Pf \. Ix Ar index
+.Pp
+An index is an anchor within a document.
+It can be accessed with
+.Sx \&Lkx
+and
+.Sx \&Sx .
.Ss \&Lb
Specify a library.
The syntax is as follows:
@@ -1905,6 +1920,25 @@ Examples:
.Pp
See also
.Sx \&Mt .
+.Ss \&Lkx
+Formats an index link.
+If invoked without arguments, is the same as
+.Sx \&Sx .
+Its syntax is as follows:
+.Pp
+.Dl Pf \. Sx \&Lkx Ar index Op Ar name
+.Pp
+Examples:
+.Bd -literal -offset indent
+\&.Ix foobar
+Some text here.
+\&.Lkx foobar \(dqGo to the above link\(dq
+.Ed
+.Pp
+See also
+.Sx \&Ix
+and
+.Sx \&Sx .
.Ss \&Lp
Synonym for
.Sx \&Pp .
@@ -2705,18 +2739,31 @@ Link to another manual
.Pq Qq cross-reference .
Its syntax is as follows:
.Pp
-.D1 Pf \. Sx \&Xr Ar name Op section
+.D1 Pf \. Sx \&Xr Ar name Op section Op index Op index_name
.Pp
Cross reference the
.Ar name
and
.Ar section
-number of another man page;
-omitting the section number is rarely useful.
+number of another man page.
+.Pq Omitting the section number is rarely useful.
+If
+.Ar index
+is specified, the link is to a position specified with
+.Ss \&Ix ,
+.Ss \&Sh ,
+or
+.Ss \&Ss .
+If
+.Ar index_name
+is used as well, it is printed instead of
+.Ar index ,
+which is used purely as the index location.
.Pp
Examples:
.Dl \&.Xr mandoc 1
.Dl \&.Xr mandoc 1 \&;
+.Dl \&.Xr mandoc 1 "SEE ALSO"
.Dl \&.Xr mandoc 1 \&Ns s behaviour
.Ss \&br
Emits a line-break.
Index: mdoc.c
===================================================================
RCS file: /home/cvs/mdocml/mdocml/mdoc.c,v
retrieving revision 1.238
diff -u -p -r1.238 mdoc.c
--- mdoc.c 12 Feb 2015 13:00:52 -0000 1.238
+++ mdoc.c 12 Mar 2015 02:49:09 -0000
@@ -61,10 +61,12 @@ const char *const __mdoc_macronames[MDOC
"Fo", "Fc", "Oo", "Oc",
"Bk", "Ek", "Bt", "Hf",
"Fr", "Ud", "Lb", "Lp",
- "Lk", "Mt", "Brq", "Bro",
+ "Lk", "Lkx",
+ "Mt", "Brq", "Bro",
"Brc", "%C", "Es", "En",
"Dx", "%Q", "br", "sp",
- "%U", "Ta", "ll", "text",
+ "%U", "Ta", "ll", "Ix",
+ "text",
};
const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
Index: mdoc.h
===================================================================
RCS file: /home/cvs/mdocml/mdocml/mdoc.h,v
retrieving revision 1.136
diff -u -p -r1.136 mdoc.h
--- mdoc.h 12 Feb 2015 12:24:33 -0000 1.136
+++ mdoc.h 12 Mar 2015 02:49:09 -0000
@@ -126,6 +126,7 @@ enum mdoct {
MDOC_Lb,
MDOC_Lp,
MDOC_Lk,
+ MDOC_Lkx,
MDOC_Mt,
MDOC_Brq,
MDOC_Bro,
@@ -140,6 +141,7 @@ enum mdoct {
MDOC__U,
MDOC_Ta,
MDOC_ll,
+ MDOC_Ix,
MDOC_MAX
};
Index: mdoc_html.c
===================================================================
RCS file: /home/cvs/mdocml/mdocml/mdoc_html.c,v
retrieving revision 1.226
diff -u -p -r1.226 mdoc_html.c
--- mdoc_html.c 3 Mar 2015 21:11:34 -0000 1.226
+++ mdoc_html.c 12 Mar 2015 02:49:10 -0000
@@ -92,6 +92,7 @@ static int mdoc_ic_pre(MDOC_ARGS);
static int mdoc_igndelim_pre(MDOC_ARGS);
static int mdoc_in_pre(MDOC_ARGS);
static int mdoc_it_pre(MDOC_ARGS);
+static int mdoc_ix_pre(MDOC_ARGS);
static int mdoc_lb_pre(MDOC_ARGS);
static int mdoc_li_pre(MDOC_ARGS);
static int mdoc_lk_pre(MDOC_ARGS);
@@ -231,6 +232,7 @@ static const struct htmlmdoc mdocs[MDOC_
{mdoc_lb_pre, NULL}, /* Lb */
{mdoc_pp_pre, NULL}, /* Lp */
{mdoc_lk_pre, NULL}, /* Lk */
+ {mdoc_lk_pre, NULL}, /* Lkx */
{mdoc_mt_pre, NULL}, /* Mt */
{mdoc_quote_pre, mdoc_quote_post}, /* Brq */
{mdoc_quote_pre, mdoc_quote_post}, /* Bro */
@@ -245,6 +247,7 @@ static const struct htmlmdoc mdocs[MDOC_
{mdoc__x_pre, mdoc__x_post}, /* %U */
{NULL, NULL}, /* Ta */
{mdoc_skip_pre, NULL}, /* ll */
+ {mdoc_ix_pre, NULL}, /* Ix */
};
static const char * const lists[LIST_MAX] = {
@@ -538,6 +541,25 @@ mdoc_root_pre(MDOC_ARGS)
}
static int
+mdoc_ix_pre(MDOC_ARGS)
+{
+ struct htmlpair tag;
+
+ bufinit(h);
+ bufcat(h, "index-");
+
+ for (n = n->child; n && MDOC_TEXT == n->type; ) {
+ bufcat_id(h, n->string);
+ if (NULL != (n = n->next))
+ bufcat_id(h, " ");
+ }
+
+ PAIR_ID_INIT(&tag, h->buf);
+ print_otag(h, TAG_A, 1, &tag);
+ return(0);
+}
+
+static int
mdoc_sh_pre(MDOC_ARGS)
{
struct htmlpair tag;
@@ -556,7 +578,7 @@ mdoc_sh_pre(MDOC_ARGS)
}
bufinit(h);
- bufcat(h, "x");
+ bufcat(h, "index-");
for (n = n->child; n && MDOC_TEXT == n->type; ) {
bufcat_id(h, n->string);
@@ -586,7 +608,7 @@ mdoc_ss_pre(MDOC_ARGS)
return(1);
bufinit(h);
- bufcat(h, "x");
+ bufcat(h, "index-");
for (n = n->child; n && MDOC_TEXT == n->type; ) {
bufcat_id(h, n->string);
@@ -696,33 +718,56 @@ static int
mdoc_xr_pre(MDOC_ARGS)
{
struct htmlpair tag[2];
+ const char *name, *sec, *index, *desc;
+ struct tag *t;
- if (NULL == n->child)
+ if (NULL == (n = n->child))
return(0);
+ name = n->string;
+ sec = desc = index = NULL;
+ if (NULL != n->next) {
+ sec = n->next->string;
+ if (NULL != n->next->next) {
+ index = desc = n->next->next->string;
+ if (NULL != n->next->next->next)
+ desc = n->next->next->next->string;
+ }
+ }
+
PAIR_CLASS_INIT(&tag[0], "link-man");
if (h->base_man) {
- buffmt_man(h, n->child->string,
- n->child->next ?
- n->child->next->string : NULL);
+ buffmt_man(h, name, sec, NULL);
PAIR_HREF_INIT(&tag[1], h->buf);
- print_otag(h, TAG_A, 2, tag);
+ t = print_otag(h, TAG_A, 2, tag);
} else
- print_otag(h, TAG_A, 1, tag);
+ t = print_otag(h, TAG_A, 1, tag);
- n = n->child;
- print_text(h, n->string);
+ print_text(h, name);
- if (NULL == (n = n->next))
- return(0);
+ if (NULL != index) {
+ h->flags |= HTML_NOSPACE;
+ print_text(h, "(");
+ h->flags |= HTML_NOSPACE;
+ print_text(h, index);
+ h->flags |= HTML_NOSPACE;
+ print_text(h, ")");
+ }
+
+ if (NULL != desc) {
+ print_tagq(h, t);
+ h->flags |= HTML_NOSPACE;
+ print_text(h, ", section");
+ if (h->base_man) {
+ buffmt_man(h, name, sec, index);
+ PAIR_HREF_INIT(&tag[1], h->buf);
+ print_otag(h, TAG_A, 2, tag);
+ } else
+ print_otag(h, TAG_A, 1, tag);
+ print_text(h, desc);
+ }
- h->flags |= HTML_NOSPACE;
- print_text(h, "(");
- h->flags |= HTML_NOSPACE;
- print_text(h, n->string);
- h->flags |= HTML_NOSPACE;
- print_text(h, ")");
return(0);
}
@@ -1104,7 +1149,7 @@ mdoc_sx_pre(MDOC_ARGS)
struct htmlpair tag[2];
bufinit(h);
- bufcat(h, "#x");
+ bufcat(h, "#index-");
for (n = n->child; n; ) {
bufcat_id(h, n->string);
@@ -1592,14 +1637,23 @@ static int
mdoc_lk_pre(MDOC_ARGS)
{
struct htmlpair tag[2];
+ enum mdoct type = n->tok;
if (NULL == (n = n->child))
return(0);
assert(MDOC_TEXT == n->type);
- PAIR_CLASS_INIT(&tag[0], "link-ext");
- PAIR_HREF_INIT(&tag[1], n->string);
+ if (MDOC_Lkx == type) {
+ PAIR_CLASS_INIT(&tag[0], "link-int");
+ bufinit(h);
+ bufcat(h, "#index-");
+ bufcat_id(h, n->string);
+ PAIR_HREF_INIT(&tag[1], h->buf);
+ } else {
+ PAIR_CLASS_INIT(&tag[0], "link-ext");
+ PAIR_HREF_INIT(&tag[1], n->string);
+ }
print_otag(h, TAG_A, 2, tag);
Index: mdoc_macro.c
===================================================================
RCS file: /home/cvs/mdocml/mdocml/mdoc_macro.c,v
retrieving revision 1.183
diff -u -p -r1.183 mdoc_macro.c
--- mdoc_macro.c 12 Feb 2015 12:24:33 -0000 1.183
+++ mdoc_macro.c 12 Mar 2015 02:49:10 -0000
@@ -180,6 +180,7 @@ const struct mdoc_macro __mdoc_macros[MD
{ in_line, 0 }, /* Lb */
{ in_line_eoln, 0 }, /* Lp */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */
+ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lkx */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */
{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Brq */
{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
@@ -196,6 +197,7 @@ const struct mdoc_macro __mdoc_macros[MD
{ in_line_eoln, 0 }, /* %U */
{ phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */
{ in_line_eoln, MDOC_PROLOGUE }, /* ll */
+ { in_line_eoln, MDOC_JOIN }, /* Ix */
};
const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
@@ -1288,9 +1290,10 @@ in_line_argn(MACRO_PROT_ARGS)
case MDOC_Bx:
/* FALLTHROUGH */
case MDOC_Es:
- /* FALLTHROUGH */
- case MDOC_Xr:
maxargs = 2;
+ break;
+ case MDOC_Xr:
+ maxargs = 4;
break;
default:
maxargs = 1;
Index: mdoc_term.c
===================================================================
RCS file: /home/cvs/mdocml/mdocml/mdoc_term.c,v
retrieving revision 1.313
diff -u -p -r1.313 mdoc_term.c
--- mdoc_term.c 6 Mar 2015 15:48:52 -0000 1.313
+++ mdoc_term.c 12 Mar 2015 02:49:11 -0000
@@ -232,6 +232,7 @@ static const struct termact termacts[MDO
{ NULL, termp_lb_post }, /* Lb */
{ termp_sp_pre, NULL }, /* Lp */
{ termp_lk_pre, NULL }, /* Lk */
+ { termp_lk_pre, NULL }, /* Lkx */
{ termp_under_pre, NULL }, /* Mt */
{ termp_quote_pre, termp_quote_post }, /* Brq */
{ termp_quote_pre, termp_quote_post }, /* Bro */
@@ -246,6 +247,7 @@ static const struct termact termacts[MDO
{ NULL, termp____post }, /* %U */
{ NULL, NULL }, /* Ta */
{ termp_ll_pre, NULL }, /* ll */
+ { termp_skip_pre, NULL }, /* Ix */
};
@@ -1257,6 +1259,16 @@ termp_xr_pre(DECL_ARGS)
p->flags |= TERMP_NOSPACE;
term_word(p, ")");
+ if (NULL == (n = n->next))
+ return(0);
+
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, " section");
+ if (NULL != n->next)
+ term_word(p, n->next->string);
+ else
+ term_word(p, n->string);
+
return(0);
}
@@ -2174,6 +2186,9 @@ termp_lk_pre(DECL_ARGS)
if (NULL == (link = n->child))
return(0);
+ if (NULL != link->next)
+ link = link->next;
+
if (NULL != (descr = link->next)) {
term_fontpush(p, TERMFONT_UNDER);
while (NULL != descr) {
@@ -2188,7 +2203,6 @@ termp_lk_pre(DECL_ARGS)
term_fontpush(p, TERMFONT_BOLD);
term_word(p, link->string);
term_fontpop(p);
-
return(0);
}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2015-03-12 2:51 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-12 2:51 PATCH: Intra- and inter-document linking Kristaps Dzonsons
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).