keithmarshall pushed a commit to branch master in repository groff. commit 2811e46d28b7a410a032298f11bd9d19c31e060c Author: Keith Marshall <keith.d.marsh...@ntlworld.com> AuthorDate: Mon Sep 13 21:18:00 2021 +0100
Factor document-specific bloat out of spdf.tmac * spdf.tmac: Reorganize; add many comments. (XN): Retained, but reimplemented, to serve as... (XH, XN): ...both of these; add callback hooks for... (XH-INIT, XN-INIT, XH-UPDATE-TOC): ...these; provide no-op stubs; factor out TOC collection code, delegating to XH-UPDATE-TOC. (opt*XN-N, opt*XN-S, opt*XN-X): Rename internal macros to... (de spdf:XH-N, de spdf:XH-S, de spdf:XH-X): ...these, respectively. (AN, @AN, IE, IS, LU, NN, PXREF, SAME-PAGE, XM): Delete; we do not require these; if users do, they should define their own. (pdf@toc): Delete internal macro; fold body into... (TC): ...this. * pdfmark.ms (XH-UPDATE-TOC): Implement callback; it is based on... (XN): ...original implementation of this, factored out of spdf.tmac, but with significant simplification, to remove unnecessary code. (XNVS1, XNVS2, XNVS3): Tighten vertical spacing. --- contrib/pdfmark/pdfmark.ms | 94 ++++++++--- contrib/pdfmark/spdf.tmac | 396 ++++++++++++++++++++++++++++----------------- 2 files changed, 321 insertions(+), 169 deletions(-) diff --git a/contrib/pdfmark/pdfmark.ms b/contrib/pdfmark/pdfmark.ms index 2abe022..58dd74d 100644 --- a/contrib/pdfmark/pdfmark.ms +++ b/contrib/pdfmark/pdfmark.ms @@ -103,31 +103,87 @@ Publishing with GNU Troff .ds = \f(CB\\$1\f(CR\\$4\f[CBI]\\$2\f(CR\\$3 . .NH 1 -.\" When we use numbered section headings, we might like to automatically -.\" insert a table of contents entry, using the text of the heading itself. -.\" The "ms" macros don't provide any standard mechanism for doing this, -.\" but "spdf.tmac" adds the "XN" macro, which will do it for us. +.\" Conventionally, in "ms", NH precedes text which is to be set as a +.\" numbered section heading, but it makes no provision for automatic +.\" reference to that heading in a table of contents, or (in the case +.\" of PDF document production) in a document outline. Both of these +.\" limitations may be mitigated, by using the XN macro, (provided by +.\" spdf.tmac), which sets its arguments, both as text to be included +.\" in the section heading, as printed, and as an assocated document +.\" outline reference; it will also make this same text available to +.\" the user-specified callback macro, XH-UPDATE-TOC, whereby it may +.\" be used, e.g. to construct a table of contents entry. .\" -.\" Here's a simple example of how we might use it. In this case, the word -.\" "Introduction" will appear both in the body of the document, as the text -.\" of the heading, and it will be added to the table of contents, which is -.\" subsequently "printed" using the "TC" macro; in both locations, it will -.\" be prefixed by the section number. +.\" Within the table of contents, structural layout will be achieved, +.\" under the direction of the following spacing control constants: .\" -.\" As an additional side effect, any use of "XN" will cause the table of -.\" contents entry to be automatically reproduced, with the exception of its -.\" page number reference, as a PDF document outline entry. Thus, the use -.\" of "XN" to specify numbered section headings results in the automatic -.\" creation of a numbered PDF document outline. This automatic creation -.\" of the outline is completely transparent, and will occur regardless -.\" of whether the "TC" macro is subsequently invoked, or not. +.ds XNVS1 0.50v \" leading for top level +.ds XNVS2 0.15v \" leading at nesting level increment +.ds XNVS3 0.30v \" leading following nested group .\" +.\" Note that one TOC related callback hook is shared by both XH and +.\" XN; its is called XH-UPDATE-TOC, regardless of whether called by +.\" XH or by XN; when called by XN, it is invoked with arguments: +.\" +.\" .XH-UPDATE-TOC <outline-level> <section-number> <text> ... +.\" +.de XH-UPDATE-TOC +.\" This implementation of XH-UPDATE-TOC utilizes the rudimentary ms +.\" mechanism for formatting a table of contents, using XS and XE to +.\" bracket individual entries. +. XS +. \" A local register, tc*hl, is used to track the outline level +. \" of each TOC entry, as it is added; it is not defined, until +. \" the first entry is recorded... +. \" +. if r tc*hl \{\ +. \" ...after which, we use it to establish indentation, +. \" to reflect changes in outline level. +. \" +. ie \\$1>1 \{\ +. \" When at any outline level greater than one, +. \" any level increment will be offset by XNVS2 +. \" units of vertical space... +. \" +. ie \\$1>\\n[tc*hl] .sp \\*[XNVS2] +. +. \" ...whereas any decrement will be offset by +. \" XNVS3 units. +. \" +. el .if \\n[tc*hl]>\\$1 .sp \\*[XNVS3] +. \} +. +. \" ...but every top-level entry, after the first, is +. \" offset by XNVS1 units. +. \" +. el .sp \\*[XNVS1] +. \} +. +. \" \$1 becomes the effective outline level for the current table +. \" of contents entry, but we must ensure that it is one or more. +. \" +. ie \\$1 .nr tc*hl \\$1 +. el .nr tc*hl 1 +. +. \" The current outline level determines the indentation at which +. \" we place the section number reference... +. \" +. nop \h'\\n[tc*hl]-1m'\\$2\c +. +. \" ...after which we discard \$1 and \$2, allowing us to append +. \" all remaining arguments, ensuring that there is at least 0.5n +. \" of following space, before the first leader dot. +. \" +. shift 2 +. nop \h'1.5n'\\$*\h'0.5n' +. XE +.. .XN Introduction .\" -.\" If using an old s.tmac, without the SN-NO-DOT extension, -.\" make sure we get SOMETHING in section number references. +.\" If using an old s.tmac, without the SN-NO-DOT extension, ensure +.\" that we get SOMETHING in section number references. .\" -.if !dSN-NO-DOT .als SN-NO-DOT SN +.if !d SN-NO-DOT .als SN-NO-DOT SN .LP It might appear that it is a fairly simple matter to produce documents in \*[Adobe]\~\(lqPortable\~Document\~Format\(rq, diff --git a/contrib/pdfmark/spdf.tmac b/contrib/pdfmark/spdf.tmac index d807faf..454802b 100644 --- a/contrib/pdfmark/spdf.tmac +++ b/contrib/pdfmark/spdf.tmac @@ -2,6 +2,9 @@ spdf.tmac +Binding macros for use of "-m pdfmark" in conjunction with "-ms". + + Copyright (C) 2004-2021 Free Software Foundation, Inc. Written by Keith Marshall (keith.d.marsh...@ntlworld.com) @@ -21,56 +24,144 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. .. +.\" Bindings +.\" ======== +.\" +.\" Generic output mode control flag; pdfmark.tmac will bind this to +.\" its own internal PDFOPMODE flag. .\" -.if !rOPMODE .nr OPMODE 1 +.if !r OPMODE .nr OPMODE 1 .\" .mso s.tmac .mso sanitize.tmac .mso pdfmark.tmac +. +.\" Establish a handler to clean up output context, at end of document. .\" +.de pdf@exit em +. if \\n[OPMODE] .pdfsync +. pg@end-text +.em pdf@exit +. +. .\" Omitted Sections .\" ================ .\" .\" Define section markers, for special document sections, .\" which are to be omitted from regular document processing. .\" +.\" .OMIT <name1> <name2> +.\" +.\" Defines a pair of macros, <name1> and <name2>, such that execution +.\" of .<name1> marks the start of a block of troff input which should +.\" be ignored; this block ends, on execution of .<name2> +.\" .de OMIT OMIT -.de \\$1 -.omit@begin \\$1 \\$2 -.. -.de \\$2 -.omit@end \\$1 \\$2 -.. +. de \\$1 +. omit@begin \\$1 \\$2 +. . +. de \\$2 +. omit@end \\$1 \\$2 +. . +.\" Definition of the OMIT macro itself, ends when it is first used, +.\" to identify an omitted section marker macro pair. +.\" .OMIT CS CE \" front cover text, processed independently .OMIT MS ME \" menu definitions, for info documents only +. +.\" Actual omission is initiated by recording the name of the block +.\" start macro, followed by injection of an "ig" request... .\" .de omit@begin -.ds omit@section \\$1 -.ig \\$2 +. ds omit@section \\$1 +\. ig \\$2 .. +.\" ...and terminates with verification that the end macro matches +.\" the start macro, and removal of the start macro record; (error +.\" reporting uses the "@error" macro, from s.tmac). +.\" .de omit@end -.if !'\\*[omit@section]'\\$1' .@error \\$2 without \\$1 -.rm omit@section +. if !'\\*[omit@section]'\\$1' .@error \\$2 without \\$1 +. rm omit@section .. -.de XM +.\" .XR <dest-name> [<affixed> [<prefix>]] .\" -.pdfhref M -X \\$@ -.. -.de XR +.\" A convenience shorthand macro, emulating the semantics of the "ms" +.\" font change macros, when invoked with one, two, or three arguments; +.\" it expands to the equivalent of: +.\" +.\" .pdfhref L -D <dest-name> [-A <affixed> [-P <prefix>]] +.\" +.\" to place a pdfhref reference link, to a named destination, within +.\" the same document, using the reference text which is predefined in +.\" the reference dictionary entry associated with the destination. +.\" +.de XR \" FIXME: suggest document-local implementation .if \\n(.$ \{\ . if \\n[OPMODE] \{\ -. ds spdf!opts -D "\\$1" -. if \\n(.$>1 .as spdf!opts " -A "\\$2" -. if \\n(.$>2 .as spdf!opts " -P "\\$3" -. pdfhref L \\*[spdf!opts] -. rm spdf!opts +. ds xr!argv -D "\\$1" +. if \\n(.$>1 .as xr!argv " -A "\\$2" +. if \\n(.$>2 .as xr!argv " -P "\\$3" +. pdfhref L \\*[xr!argv] +. rm xr!argv . \} . \} .. +. +.\" Document Outlines, and Section Headings +.\" ======================================= +.\" +.\" .XH [-N <name>] [-S] [-X] <outline-level> <heading-text> ... +.\" .XN [-N <name>] [-S] [-X] <heading-text> ... +.\" +.\" Use after SH, and XN <n> respectively, to define text to be set +.\" within the section heading, as a PDF document ouline entry, and +.\" optionally, as a table of contents entry. .\" -.\" Document Outlines, Section Headings and Table of Contents -.\" ========================================================= +.\" Options: +.\" -N <name> Assigns <name> as a pdfhref destination, +.\" and associates it with the heading. .\" +.\" -S Strip troff font-change escapes from the +.\" text copied to the document outline. +.\" +.\" -X Force pdfhref destination assignment; if +.\" -N <name> is unspecified, use first word +.\" of <heading-text> as <name>. +.\" +.\" Arguments: +.\" <outline-level> The nesting level of the heading, within +.\" the document outline, and TOC. Required +.\" for XH; inferred from NH <n>, for XN. +.\" +.\" <heading-text> Text (required) to appear within each of +.\" the section heading, document outline, +.\" and (optionally) TOC. +.\" +.\" Hooks: +.\" XH-INIT User-defined macro, called on entry to XH; +.\" used to specify initialization state which +.\" may be needed after using SH; e.g. specify +.\" a PDFHREF.INFO state without incorporation +.\" of any "section" references. +.\" +.\" XN-INIT User-defined macro, called on entry to XN; +.\" used to specify initialization state which +.\" may be needed after using NH; e.g. specify +.\" a PDFHREF.INFO state which may incorporate +.\" "section" references. +.\" +.\" XH-UPDATE-TOC User-defined macro, called by both XH, and +.\" XN; (there is no XN-UPDATE-TOC). Must be +.\" defined, if a TOC entry is to be generated +.\" by either XH, or XN; the format of such a +.\" TOC entry is determined by the definition +.\" of this macro. +.\" +.\" Both XH, and XN macros, share a common entry point. +.\" +.de XH als +.als XN XH .\" FIXME: within s.tmac, the heading level established by the most .\" recent prior invocation of the NH macro is tracked by the "nh*hl" .\" private register; perhaps s.tmac could expose this more publicly, @@ -85,93 +176,130 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. .\" .ie r nh*hl .nr spdf:nh*hl \n[nh*hl] .el .nr spdf:nh*hl 0 -.am @NH aln +.am @NH . nr spdf:nh*hl \\n[nh*hl] +.. .aln .NH spdf:nh*hl . -.de XN -.\" Use AFTER .NH n, to define the text of the numbered heading, -.\" automatically generating a matching formatted TOC entry, and -.\" a PDF document outline entry. -.\" -.\" String registers XNVS1, XNVS2 and XNVS3 establish additional leading, -.\" prior to top level headings, preceding each level of indented subheading, -.\" and following each nested level of subheading, respectively -.\" (strings are used, rather than numeric registers, so that these -.\" additional spacing parameters may be set relative to the current -.\" document line spacing, as set by \n[VS]). -.\" -.rm spdf:refname -.als spdf:bm.define spdf:bm.basic -.while dopt*XN\\$1 \{\ -. opt*XN\\$1 \\$* -. shift \\n[spdf:argc] -. \} -.rr spdf:argc -.if '\\$1'--' .shift -.if dspdf:refname .XM -N \\*[spdf:refname] -- \\$@ -.rm spdf:refname -.spdf:bm.define spdf:bm.text "\\$*" -.pdfhref O \\n[.NH] "\\*(SN \\*[spdf:bm.text]" -.XS -.if rtc*hl \{\ -. if !dXNVS1 .ds XNVS1 1.0v \" default leading for top level -. if !dXNVS2 .ds XNVS2 0.3v \" default leading at nesting increment -. if !dXNVS3 .ds XNVS3 0.6v \" default leading following nested group -. if \\n[.NH]=1 \{\ -. sp \\*[XNVS1] -. nr tc*hl-max 1 -. \} -. ie \\n[.NH]<\\n[tc*hl] .if \\n[.NH]>1 .sp \\*[XNVS3] -. el \{\ -. ie \\n[.NH]>\\n[tc*hl] .sp \\*[XNVS2] -. el \{\ -. if !r tc*hl-max .nr tc*hl-max 1 -. ie \\n[tc*hl-max]>\\n[.NH] .sp \\*[XNVS3] -. el .nr tc*hl-max \\n[.NH] -. \} +.\" The user is expected to furnish the XH-INIT, XH-UPDATE-TOC, and +.\" XN-INIT handlers. (Note that the XH-UPDATE-TOC hook serves both +.\" XH and XN; there is no separate XN-UPDATE-TOC). These stubs are +.\" provided to avoid possible "undefined macro" warnings; each is +.\" implemented as a no-op. +.\" +.de XH-INIT de +.de XH-UPDATE-TOC de +.de XN-INIT +.. +.\" The common entry point for both XH, and XN, handles initialization, +.\" and interpretation of any specified options, before handing over to +.\" one of two distinct formatting helper macros, which are specific to +.\" the XH, and XN implementations respectively. +.\" +.am XH \" and also XN +. \\$0-INIT +. rm spdf:refname +. als spdf:bm.define spdf:bm.basic +. while d spdf:XH\\$1 \{\ +. spdf:XH\\$1 \\$* +. shift \\n[spdf:argc] . \} -. \} -.nr tc*hl \\n[.NH] -\h'\\n[.NH]-1m'\c -\&\\*(SN\h'1n'\\$* -.\".pdfhref L -D \\*[PDFBOOKMARK.NAME] -- \&\\*(SN\h'1n'\\$* -.XE -\&\\$* +. rr spdf:argc +. if '\\$1'--' .shift +. spdf:\\$0.format \\$@ .. -.de opt*XN-N -.ds spdf:refname \\$2 -.nr spdf:argc 2 +.\" Interpret the "-N <name>" option... +.\" +.de spdf:XH-N +. ds spdf:refname \\$2 +. nr spdf:argc 2 .. -.de opt*XN-S -.als spdf:bm.define sanitize -.nr spdf:argc 1 +.\" ...the "-X" option, and... +.\" +.de spdf:XH-X +. if !d spdf:refname .ds spdf:refname \\\\$1 +. nr spdf:argc 1 .. -.de opt*XN-X -.if !dspdf:refname .ds spdf:refname \\\\$1 -.nr spdf:argc 1 +.\" ...the "-S" option. +.\" +.de spdf:XH-S +. als spdf:bm.define sanitize +. nr spdf:argc 1 .. +.\" By default, when the "-S" option is not specified, the text +.\" incorporated into the PDF document outline will be a simple +.\" verbatim copy of the arguments. +.\" .de spdf:bm.basic -.shift -.ds spdf:bm.text "\\$*\" +. shift \" ignore \$1; it should always be "spdf:bm.text" +. ds spdf:bm.text "\\$*\" .. -.de LU -.LP -The content for this section is not yet available. +.\" After initialization, and interpretation of options, the XH +.\" and XN implementations diverge, into this helper macro, which +.\" is specific to the XH implementation... +.\" +.de spdf:XH.format +. XH-UPDATE-TOC \\$@ +. ds spdf:bm.argv \\$1 +. shift \" finalization doesn't want the outline level in \$1 +. spdf:XH.finalize \\$@ .. -.de AN -.ie \\n(.$ .@AN \\$* -.el .@AN Note +.\" ...and this, which is specific to XN... +.\" +.de spdf:XN.format +. ds spdf:bm.argv \\n[.NH] \\*[SN] +. XH-UPDATE-TOC \\n[.NH] \\*[SN] \\$@ +. spdf:XH.finalize \\$@ .. -.de @AN -.SH -\\$* -.LP +.\" ...before ultimately converging back into this finalization +.\" macro, which is once again common to both XH and XN. +.\" +.de spdf:XH.finalize +. spdf:bm.define spdf:bm.text "\\$*" +. if d spdf:refname .pdfhref M -X -N \\*[spdf:refname] -- \\$@ +. pdfhref O \\*[spdf:bm.argv] \\*[spdf:bm.text] +. rm spdf:refname spdf:bm.argv spdf:bm.text +. nop \\$* .. +. +.\" Cross-Reference Marshalling +.\" =========================== +.\" +.\" s.tmac provides the "pg@bottom" macro, which has already +.\" been installed as a page transition trap. To ensure proper +.\" mapping of "pdfhref" links which overflow the bottom of any +.\" page, we need to install the "pdfhref" page transition hook, +.\" as an addendum to this macro. +. +.pdfhref I -PT pg@bottom +. +. +.\" Phased Output Control +.\" ===================== +.\" +.\" Segregate output of table of contents, and document body text, +.\" into two distinct output phases, to facilitate assembly of the +.\" aggregate document in the correct order, particularly when the +.\" TOC is generated at the end, by the default "ms" mechanism. +.\" .nr PDF-TOC-ONLY 1 .nr PDF-BODY-TEXT 2 +.\" +.\" .OP [<output-phase>] +.\" +.\" If the user-specified PHASE numeric register has been defined, +.\" and its value matches the <output-phase> argument value, (or if +.\" no <output-phase> argument is specified), then set the OPMODE +.\" control flag to one, and activate groff's "pen-down" mode. +.\" +.\" Otherwise, if <output-phase> is specified, but does NOT match +.\" PHASE, set OPMODE to zero, and select "pen-up" mode. +.\" +.\" Alternatively, if PHASE has not been defined, unconditionally +.\" set OPMODE to one, and leave groff's pen state unchanged. +.\" .de OP -.ie rPHASE \{\ +.ie r PHASE \{\ . ie \\n(.$ \{\ . nr op:request 0 . while \\n(.$ \{\ @@ -187,67 +315,35 @@ The content for this section is not yet available. . \} .el .nr OPMODE 1 .. -.nr SAME-PAGE 0 -.de NN -.if !\\n[SAME-PAGE] .bp -.nr SAME-PAGE 0 -.NH \\$1 -.nn*setname \\$2 -.shift 2 -.XN -N \\*[nn*name] -- \\$@ -.rm nn*name -.. -.de nn*setname -.ds nn*name \\$1 -.shift -.while \\n(.$ \{\ -. as nn*name -\\$1 -. shift -. \} -.. -.de PXREF -.nn*setname \\$2 -.XR \\*[nn*name] )\\$1 ( -.rm nn*name -.. -.de IS -.RS -.nr LL \\n(LL-\\n(PI -.. -.de IE -.RE -.nr LL \\n(LL+\\n(PI -.. -.\" Override the standard ms macro, -.\" to ensure the document outline cache is flushed -.\" BEFORE emitting the table of contents. +. +.\" Table of Contents Generation +.\" ============================ +.\" +.\" .TC [no] +.\" +.\" Replaces (and emulates) the TC macro, from s.tmac, to ensure +.\" that the pdfmark document outline cache is flushed, before TOC +.\" generation commences, that an outline reference is added for the +.\" TOC itself, and that pdfroff TOC relocation mode is enabled, for +.\" the TOC output phase of document production. +.\" .de TC -.pdfsync O -.P1 -.OP \n[PDF-TOC-ONLY] -.pg@begin 1 i -.if !\\n[PHASE] .tm pdfroff-option:set toc_relocation=enabled -.if \\n[OPMODE] .pdf@toc -.PX \\$1 -.. -.de pdf@toc -.pdfhref O -T T 1 "\\*[TOC]" -.pdfsync O -.. -.de pdf@exit -.if \\n[OPMODE] .pdfsync -.pg@end-text +. pdfsync O +. P1 +. OP \n[PDF-TOC-ONLY] +. pg@begin 1 i +. if !\\n[PHASE] .tm pdfroff-option:set toc_relocation=enabled +. if \\n[OPMODE] \{\ +. pdfhref O -T T 1 "\\*[TOC]" +. pdfsync O +. \} +. PX \\$1 .. -.em pdf@exit -.OP \n[PDF-BODY-TEXT] . -.\" groff "ms" provides the "pg@bottom" macro, which has already -.\" been installed as a page transition trap. To ensure proper -.\" mapping of "pdfhref" links which overflow the bottom of any -.\" page, we need to install the "pdfhref" page transition hook, -.\" as an addendum to this macro. +.\" Initialize the default output state, for production of "body-text". +.\" +.OP \n[PDF-BODY-TEXT] . -.pdfhref I -PT pg@bottom .\" Local Variables: .\" mode: nroff .\" End: _______________________________________________ Groff-commit mailing list Groff-commit@gnu.org https://lists.gnu.org/mailman/listinfo/groff-commit