groff: ms TOC

 
 4.6.6.5 Creating a table of contents
 ....................................
 
 Because 'roff' formatters process their input in a single pass, material
 on page 50, for example, cannot influence what appears on page 1--this
 poses a challenge for a table of contents at its traditional location in
 front matter, if you wish to avoid manually maintaining it.  'ms'
 enables the collection of material to be presented in the table of
 contents as it appears, saving its page number along with it, and then
 emitting the collected contents on demand toward the end of the
 document.  The table of contents can then be resequenced to its desired
 location by physically rearranging the pages of a printed document, or
 as part of post-processing--with a 'sed(1)' script to reorder the pages
 in 'troff''s output, with 'pdfjam(1)', or with 'gropdf(1)''s
 '.pdfswitchtopage' feature, for example.
 
    Define an entry to appear in the table of contents by bracketing its
 text between calls to the 'XS' and 'XE' macros.  A typical application
 is to call them immediately after 'NH' or 'SH' and repeat the heading
 text within them.  The 'XA' macro, used within '.XS'/'.XE' pairs,
 supplements an entry--for instance, when it requires multiple output
 lines, whether because a heading is too long to fit or because style
 dictates that page numbers not be repeated.  You may wish to indent the
 text thus wrapped to correspond to its heading depth; this can be done
 in the entry text by prefixing it with tabs or horizontal motion escape
 sequences, or by providing a second argument to the 'XA' macro.  'XS'
 and 'XA' automatically associate the page number where they are called
 with the text following them, but they accept arguments to override this
 behavior.  At the end of the document, call 'TC' or 'PX' to emit the
 table of contents; 'TC' resets the page number to 'i' (Roman numeral
 one), and then calls 'PX'.  All of these macros are Berkeley extensions.
 
  -- Macro: .XS [page-number]
  -- Macro: .XA [page-number [indentation]]
  -- Macro: .XE
      Begin, supplement, and end a table of contents entry.  Each entry
      is associated with PAGE-NUMBER (otherwise the current page number);
      a PAGE-NUMBER of 'no' prevents a leader and page number from being
      emitted for that entry.  Use of 'XA' within 'XS'/'XE' is optional;
      it can be repeated.  If INDENTATION is present, a supplemental
      entry is indented by that amount; ens are assumed if no unit is
      indicated.  Text on input lines between 'XS' and 'XE' is stored for
      later recall by 'PX'.
 
  -- Macro: .PX [no]
      Switch to single-column layout.  Unless 'no' is specified, center
      and interpolate the 'TOC' string in bold and two points larger than
      the body text.  Emit the table of contents entries.
 
  -- Macro: .TC [no]
      Set the page number to 1, the page number format to lowercase Roman
      numerals, and call 'PX' (with a 'no' argument, if present).
 
    Here's an example of typical 'ms' table of contents preparation.  We
 employ horizontal escape sequences '\h' to indent the entries by
 sectioning depth.
 
      .NH 1
      Introduction
      .XS
      Introduction
      .XE
      ...
      .NH 2
      Methodology
      .XS
      \h'2n'Methodology
      .XA
      \h'4n'Fassbinder's Approach
      \h'4n'Kahiu's Approach
      .XE
      ...
      .NH 1
      Findings
      .XS
      Findings
      .XE
      ...
      .TC
 
    The remaining features in this subsubsection are GNU extensions.
 'groff' 'ms' obviates the need to repeat heading text after 'XS' calls.
 Call 'XN' and 'XH' after 'NH' and 'SH', respectively.
 
  -- Macro: .XN heading-text
  -- Macro: .XH depth heading-text
      Format HEADING-TEXT and create a corresponding table of contents
      entry.  'XN' computes the indentation from the depth of the
      preceding 'NH' call; 'XH' requires a DEPTH argument to do so.
 
    'groff' 'ms' encourages customization of table of contents entry
 production.
 
  -- Macro: .XN-REPLACEMENT heading-text
  -- Macro: .XH-REPLACEMENT depth heading-text
      These hook macros implement 'XN' and 'XH', respectively.  They call
      'XN-INIT' and pass their HEADING-TEXT arguments to 'XH-UPDATE-TOC'.
 
  -- Macro: .XN-INIT
  -- Macro: .XH-UPDATE-TOC depth heading-text
      The 'XN-INIT' hook macro does nothing by default.  'XH-UPDATE-TOC'
      brackets HEADING-TEXT with 'XS' and 'XE' calls, indenting it by 2
      ens per level of DEPTH beyond the first.
 
    We could therefore produce a table of contents similar to that in the
 previous example with fewer macro calls.  (The difference is that this
 input follows the "Approach" entries with leaders and page numbers.)
 
      .NH 1
      .XN Introduction
      ...
      .NH 2
      .XN Methodology
      .XH 3 "Fassbinder's Approach"
      .XH 3 "Kahiu's Approach"
      ...
      .NH 1
      .XN Findings
      ...
 
    To get the section number of the numbered headings into the table of
 contents entries, we might define 'XN-REPLACEMENT' as follows.  (We
 obtain the heading depth from 'groff' 'ms''s internal register 'nh*hl'.)
 
      .de XN-REPLACEMENT
      .XN-INIT
      .XH-UPDATE-TOC \\n[nh*hl] \\$@
      \&\\*[SN] \\$*
      ..
 
    You can change the style of the leader that bridges each table of
 contents entry with its page number; define the 'TC-LEADER' special
 character by using the 'char' request.  A typical leader combines the
 dot glyph '.' with a horizontal motion escape sequence to spread the
 dots.  The width of the page number field is stored in the 'TC-MARGIN'
 register.