# HG changeset patch
# Parent  e1db15f29257960d63e5fd7375a64550bbfc5c8c
[ms]: Provide global default XH and XN implementations.

cf. <https://savannah.gnu.org/bugs/?58946#comment12>

* tmac/s.tmac (XH-INIT, XN-INIT, XH-UPDATE-TOC)
(XH, XN, XH-REPLACEMENT, XN-REPLACEMENT): Implement them, and...
* tmac/groff_ms.7.man: ...document them.

diff --git a/tmac/groff_ms.7.man b/tmac/groff_ms.7.man
--- a/tmac/groff_ms.7.man
+++ b/tmac/groff_ms.7.man
@@ -1964,10 +1964,167 @@ with a horizontal space escape sequence 
 The width of the page number field is stored in the
 .B TC\-MARGIN
 register.
 .
 .
+.P
+When creating a table of contents,
+incorporating content derived from headings specified by
+.B .NH
+and
+.B .SH ,
+traditional
+.I ms
+implementations provide no convenient mechanism
+for duplication of the heading text into the table of contents;
+.I groff ms
+mitigates this limitation,
+by providing the following pair of macros,
+(for use after
+.B .NH
+and
+.B .SH
+respectively):
+.
+.TP
+.BI .XN\~ text\ ...
+.TQ
+.BI .XH\~ outline\-level\ text\ ...
+Duplicate
+.I text\~...
+added to the body ot the document,
+to create a table of contents entry,
+(which may be indented in accordance with
+.IR outline\-level ).
+.
+.P
+Either,
+or both of
+.B XN
+and
+.B XH
+may be redefined by the user,
+(preferably by definition of the replacement hook macros,
+.BR \%XN\-REPLACEMENT ,
+and
+.B \%XH\-REPLACEMENT
+respectively);
+in their default implementations,
+both emit their
+.I text
+arguments into the body of the document,
+as heading text;
+they also pass this same text to the callback macro:
+.
+.TP
+.BI \%.XH\-UPDATE\-TOC\~ \%outline\-level\ text\ ...
+Encapsulate
+.I text
+within
+.BR \%.XS ... XE ,
+to create a table of contents entry.
+This macro is called by both
+.B .XN
+and
+.B .XH
+(no complementary
+.B \%XN\-UPDATE\-TOC
+macro is required),
+and may be redefined by the user;
+in its default implementation,
+its
+.I \%outline\-level
+argument,
+(which is inferred from the last\[hy]specified
+.B .NH
+heading level,
+when called by
+.BR .XN ),
+is simply ignored,
+but may be used by any user\[hy]defined replacement,
+for example,
+to control indentation of the table of contents.
+.
+.IP
+When called by
+.BR .XN ,
+in addition to the inference of the
+.I \%outline\-level
+argument,
+the
+.I text
+arguments are augmented,
+by prefixing the current section number,
+(which is also deduced from the last preceding use of
+.BR .NH ).
+.
+.P
+In addition to
+.BR \%XH\-UPDATE\-TOC ,
+the default
+.B XN
+and
+.B XH
+implementations support the following pair of callback macros:
+.
+.TP
+.B \%.XN\-INIT
+.TQ
+.B \%.XH\-INIT
+Called by
+.BR .XN ,
+and by
+.B .XH
+respectively,
+.I before
+.B \%.XH\-UPDATE\-TOC
+is called;
+in their default implementations,
+neither does anything,
+but either,
+or both,
+may be redefined by the user.
+.
+.P
+If the user has chosen to redefine
+.BR \%XH\-UPDATE\-TOC ,
+in some fashion which requires descrimination
+between the cases of having been called by
+.BR .XN ,
+or by
+.BR .XH ,
+then it may also be appropriate to redefine
+.BR \%XN\-INIT ,
+or
+.BR \%XH\-INIT ,
+or both,
+to handle the required discriminatory effect.
+.
+.P
+It should be noted that,
+whereas
+.I groff ms
+will emit an error diagnostic,
+and will
+.I not
+create any table of contents entry,
+if
+.B .XN
+is used before the first use of
+.BR .NH ,
+no such restriction is imposed on the use of
+.BR .XH .
+Thus,
+while it is nominally intended for use after
+.BR .SH ,
+.B .XH
+may be used in any context,
+in which use of
+.BR \%.XS ... XE
+is permitted.
+.
+.
 .\" ====================================================================
 .SH "Differences from AT&T \f[I]ms\f[]"
 .\" ====================================================================
 .
 The
diff --git a/tmac/s.tmac b/tmac/s.tmac
--- a/tmac/s.tmac
+++ b/tmac/s.tmac
@@ -1699,11 +1699,11 @@ along with this program.  If not, see <h
 .\}
 .ds SN-DOT \\*[SN-NO-DOT].
 .nr sh*psincr (\\n[GROWPS]-\\n[nh*hl])*\\n[PSINCR]
 .SH-NO-TAG
 .DEVTAG-NH "\\$1"
-.  if '\*(.T'html' .nr s@devtag-needs-end-of-heading 1
+.if '\*(.T'html' .nr s@devtag-needs-end-of-heading 1
 \\*[SN-STYLE]
 ..
 .\" ****************************
 .\" ******** module toc ********
 .\" ****************************
@@ -1739,10 +1739,59 @@ along with this program.  If not, see <h
 .	ev
 .	di
 .\}
 .el .@error .XE without .XS
 ..
+.\" Rudimentary integration of TOC generation with SH and NH;
+.\" (called by XH and XN respectively, to capture heading text
+.\" for reuse as TOC entry); may be redefined, to achieve more
+.\" sophisticated TOC layout effects.
+.\"
+.\" No-op initializers are called by XH and XN respectively,
+.\" before XH-UPDATE-TOC is called; if XH-UPDATE-TOC has been
+.\" redefined, then it may also be necessary to redefine either,
+.\" or both of these, to perform any initialization specific
+.\" to use after SH and NH respectively.
+.de XH-INIT de
+.de XN-INIT
+..
+.de XH-UPDATE-TOC
+.\" .XH-UPDATE-TOC <outline-level> [<section-number>] <text>
+.\" (<section-number> present only when called by XN)
+.XS
+.shift\" don't use <outline-level> in rudimentary style
+\&\\$*\" capture <section-number> (if present) and <text>
+.XE
+..
+.\" Rudimentary integration hook, to be called (nominally)
+.\" after SH, but acceptable in any body-text context
+.de XH de
+.\" .XH <outline-level> <text>
+.rn XH-REPLACEMENT XH
+.XH \\$@
+.de XH-REPLACEMENT
+.XH-INIT
+.XH-UPDATE-TOC \\$@
+.shift
+\&\\$*
+..
+.\" Rudimentary integration hook, to be called after NH
+.de XN de
+.\" .XN <text>
+.ie \\n[nh*hl] .toc*xn-init \\$@
+.el \{ .@error .XN is not allowed before .NH
+.      nop \&\\$*
+.   \}
+.de toc*xn-init de
+.rn XN-REPLACEMENT XN
+.XN \\$@
+.rm \\$0
+.de XN-REPLACEMENT
+.XN-INIT
+.XH-UPDATE-TOC \\n[nh*hl] \\*[SN] \\$@
+\&\\$*
+..
 .de toc*end-entry
 \\a\\t\\*[toc*num]
 .br
 .rm toc*num
 ..
