texlive[74328] branches/branch2024.final/Master: indextra (branch)
commits+karl at tug.org
commits+karl at tug.org
Thu Feb 27 21:15:53 CET 2025
Revision: 74328
https://tug.org/svn/texlive?view=revision&revision=74328
Author: karl
Date: 2025-02-27 21:15:53 +0100 (Thu, 27 Feb 2025)
Log Message:
-----------
indextra (branch) (27feb25)
Modified Paths:
--------------
branches/branch2024.final/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
Added Paths:
-----------
branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/
branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/README.md
branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc-demo.tex
branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc.pdf
branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc.tex
branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra.xdy
branches/branch2024.final/Master/texmf-dist/makeindex/indextra/
branches/branch2024.final/Master/texmf-dist/makeindex/indextra/indextra.ist
branches/branch2024.final/Master/texmf-dist/source/latex/indextra/
branches/branch2024.final/Master/texmf-dist/source/latex/indextra/indextra.dtx
branches/branch2024.final/Master/texmf-dist/source/latex/indextra/indextra.ins
branches/branch2024.final/Master/texmf-dist/tex/latex/indextra/
branches/branch2024.final/Master/texmf-dist/tex/latex/indextra/indextra.sty
branches/branch2024.final/Master/tlpkg/tlpsrc/indextra.tlpsrc
Added: branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/README.md
===================================================================
--- branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/README.md (rev 0)
+++ branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/README.md 2025-02-27 20:15:53 UTC (rev 74328)
@@ -0,0 +1,15 @@
+# `indextra` - Enhanced index typesetting
+
+## Description
+
+This package provides some enhanced features for typesetting indexes, notably: (1) Continuation text when entries or
+sub-entries continue from one page or column to the next. (2) An interface for accessing marks created from index
+entries, so that (for example) a running head can include the range of index entries that appears on the page.
+
+## Author
+
+This package is by Alan J. Cain: a.j.cain (AT) gmail.com
+
+## Licence
+
+Released under the LaTeX Project Public License v1.3c or later: https://www.latex-project.org/lppl.txt
Property changes on: branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/README.md
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc-demo.tex
===================================================================
--- branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc-demo.tex (rev 0)
+++ branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc-demo.tex 2025-02-27 20:15:53 UTC (rev 74328)
@@ -0,0 +1,89 @@
+%%
+%% This is file `indextra-doc-demo.tex',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% indextra.dtx (with options: `demo')
+%%
+%% This is a generated file.
+%%
+%% Copyright (C) 2025 Alan J. Cain
+%%
+%% This file may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either
+%% version 1.3c of this license or (at your option) any later
+%% version. The latest version of this license is in:
+%%
+%% http://www.latex-project.org/lppl.txt
+%%
+%% and version 1.3c or later is part of all distributions of
+%% LaTeX version 2008-05-04 or later.
+%%
+\documentclass{article}
+
+\usepackage[
+paperwidth=105mm,
+paperheight=100mm,
+inner=5mm,
+width=90mm,
+height=90mm,
+top=5mm,
+nohead,
+nofoot,
+columnsep=5mm,
+twocolumn,
+]{geometry}
+
+\usepackage{xcolor}
+\definecolor{bg}{gray}{0.9}
+\pagecolor{bg}
+
+\parindent=1em
+
+\usepackage{indextra}
+
+\indextrasetup{
+ before code={},
+ after code={},
+}
+
+\newcommand\see[1]{\textit{see}~`#1'}
+\newcommand\seealso[1]{\textit{see also}~`#1'}
+
+\raggedright
+\pagestyle{empty}
+
+\begin{document}
+
+\begin{theindextra}
+ \indextrastyleversion{0.1}
+ \indextraprocessortype{ist}
+
+ \indextraentry{0}{neutron}{855, 862, 885--886}%
+ \indextraentry{0}{\textit{New Astronomy} (Kepler)}{\see{\textit{Astronomia Nova}}{}}%
+ \indextraentry{0}{Newtonian physics}{298, 376, 390, 589, 813, 830, 834, 842, 891, 894--895}%
+ \indextraentry{0}{\textit{Nicomachean Ethics} (Aristotle)}{85}%
+ \indextraentry{0}{Nim}{11}%
+ \indextraentry{0}{nine-point circle}{584, 641, 662--663}%
+ \indextraentry{0}{Nobel Prize}{}%
+ \indextraentry{1}{chemistry}{495, 566, 815, 865, 937}%
+ \indextraentry{1}{literature}{485}%
+ \indextraentry{1}{peace}{865}%
+ \indextraentry{1}{physics}{502, 598, 727, 834, 836, 838, 851, 853--854, 856, 865, 867, 877, 893, 903, 905, 918, 921}%
+ \indextraentry{0}{nobility}{188, 240, 250, 464}%
+ \indextraentry{0}{non-aesthetic property}{700, 715}%
+ \indextraentry{0}{non-associative algebra}{848}%
+ \indextraentry{0}{non-commutativity}{643}%
+ \indextraentry{0}{non-constructive proof}{787}%
+ \indextraentry{0}{non-determinism}{595}%
+ \indextraentry{0}{non-euclidean geometry}{380, 401, 404--408, 436, 628, 643, 880, 896}%
+ \indextraentry{0}{non-linearity}{882}%
+ \indextraentry{0}{non-measurable set}{672}%
+ \indextraentry{0}{non-sensory property}{695}%
+ \indextraentry{0}{non-visual thinking}{633}%
+ \indextraentry{0}{nonagon}{220}%
+
+\end{theindextra}
+
+\end{document}
Property changes on: branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc-demo.tex
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc.pdf
===================================================================
(Binary files differ)
Index: branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc.pdf
===================================================================
--- branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc.pdf 2025-02-27 20:15:24 UTC (rev 74327)
+++ branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc.pdf 2025-02-27 20:15:53 UTC (rev 74328)
Property changes on: branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Added: branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc.tex
===================================================================
--- branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc.tex (rev 0)
+++ branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc.tex 2025-02-27 20:15:53 UTC (rev 74328)
@@ -0,0 +1,23 @@
+%%
+%% This is file `indextra-doc.tex',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% indextra.dtx (with options: `metadriver')
+%%
+%% This is a generated file.
+%%
+%% Copyright (C) 2025 Alan J. Cain
+%%
+%% This file may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either
+%% version 1.3c of this license or (at your option) any later
+%% version. The latest version of this license is in:
+%%
+%% http://www.latex-project.org/lppl.txt
+%%
+%% and version 1.3c or later is part of all distributions of
+%% LaTeX version 2008-05-04 or later.
+%%
+\input{indextra.dtx}
Property changes on: branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra-doc.tex
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra.xdy
===================================================================
--- branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra.xdy (rev 0)
+++ branches/branch2024.final/Master/texmf-dist/doc/latex/indextra/indextra.xdy 2025-02-27 20:15:53 UTC (rev 74328)
@@ -0,0 +1,62 @@
+;;
+;; This is file `indextra.xdy',
+;; generated with the docstrip utility.
+;;
+;; The original source files were:
+;;
+;; indextra.dtx (with options: `xdy')
+;;
+;; This is a generated file.
+;;
+;; Copyright (C) 2025 Alan J. Cain
+;;
+;; This file may be distributed and/or modified under the
+;; conditions of the LaTeX Project Public License, either
+;; version 1.3c of this license or (at your option) any later
+;; version. The latest version of this license is in:
+;;
+;; http://www.latex-project.org/lppl.txt
+;;
+;; and version 1.3c or later is part of all distributions of
+;; LaTeX version 2008-05-04 or later.
+;;
+(define-attributes (("textit" "defterm")))
+
+(markup-index :open "\begin{theindextra}~n \indextrastyleversion{0.1}~n \indextraprocessortype{xdy}~n"
+ :close "~n~n\end{theindextra}~n"
+ :tree)
+
+(markup-letter-group-list :sep "~n \indextraspace~n")
+(markup-letter-group :open-head "~n % "
+ :close-head "~n"
+ :group "default")
+(markup-letter-group :open-head "~n \indextragroup{"
+ :close-head "}~n~n")
+
+(markup-indexentry :open " \indextraentry{0}{"
+ :close "}%~n"
+ :depth 0)
+(markup-indexentry :open "}%~n \indextraentry{1}{"
+ :close ""
+ :depth 1)
+(markup-indexentry :open "}%~n \indextraentry{2}{"
+ :close ""
+ :depth 2)
+
+(markup-keyword-list :open "" :close "}{" :sep ";")
+
+(markup-locclass-list :open "" :sep ", " :close "")
+(markup-locref-list :open "" :sep ", " :close "")
+
+(markup-range :sep "--")
+(markup-locref :open "\textit{" :close "}" :attr "textit")
+(markup-locref :open "\defterm{" :close "}" :attr "defterm")
+
+(markup-crossref-list :class "see"
+ :open "\see{"
+ :sep "}{}, \see{"
+ :close "}{}")
+(markup-crossref-list :class "seealso"
+ :open "\seealso{"
+ :sep "}{}, \seealso{"
+ :close "}{}")
Added: branches/branch2024.final/Master/texmf-dist/makeindex/indextra/indextra.ist
===================================================================
--- branches/branch2024.final/Master/texmf-dist/makeindex/indextra/indextra.ist (rev 0)
+++ branches/branch2024.final/Master/texmf-dist/makeindex/indextra/indextra.ist 2025-02-27 20:15:53 UTC (rev 74328)
@@ -0,0 +1,49 @@
+%%
+%% This is file `indextra.ist',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% indextra.dtx (with options: `ist')
+%%
+%% This is a generated file.
+%%
+%% Copyright (C) 2025 Alan J. Cain
+%%
+%% This file may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either
+%% version 1.3c of this license or (at your option) any later
+%% version. The latest version of this license is in:
+%%
+%% http://www.latex-project.org/lppl.txt
+%%
+%% and version 1.3c or later is part of all distributions of
+%% LaTeX version 2008-05-04 or later.
+%%
+page_precedence "ArRn"
+
+preamble "\\begin{theindextra}\n \\indextrastyleversion{0.1}\n \\indextraprocessortype{ist}\n"
+postamble "\n\n\n\\end{theindextra}\n"
+
+group_skip "\n\n\n \\indextraspace"
+
+heading_prefix "\n\n\n \\indextragroup{"
+heading_suffix "}\n"
+headings_flag 1
+
+item_0 "\n \\indextraentry{0}{"
+item_1 "\n \\indextraentry{1}{"
+item_01 "\n \\indextraentry{1}{"
+item_x1 "}{}\n \\indextraentry{1}{"
+item_2 "\n \\indextraentry{2}{"
+item_12 "\n \\indextraentry{2}{"
+item_x2 "}{}\n \\indextraentry{2}{"
+
+delim_0 "}{"
+delim_1 "}{"
+delim_2 "}{"
+delim_t "}"
+
+encap_prefix "\\"
+encap_infix "{"
+encap_suffix "}"
Property changes on: branches/branch2024.final/Master/texmf-dist/makeindex/indextra/indextra.ist
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: branches/branch2024.final/Master/texmf-dist/source/latex/indextra/indextra.dtx
===================================================================
--- branches/branch2024.final/Master/texmf-dist/source/latex/indextra/indextra.dtx (rev 0)
+++ branches/branch2024.final/Master/texmf-dist/source/latex/indextra/indextra.dtx 2025-02-27 20:15:53 UTC (rev 74328)
@@ -0,0 +1,1924 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2025 Alan J. Cain
+%
+% This file may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version
+% 1.3c of this license or (at your option) any later version. The latest version of this license is in:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% and version 1.3c or later is part of all distributions of LaTeX version 2008-05-04 or later.
+%
+% \fi
+%
+% \iffalse
+%<*driver>
+\PassOptionsToPackage{inline}{enumitem}
+\documentclass{l3doc}
+
+
+\makeatletter
+\ExplSyntaxOn
+
+\cs_gset:Npn \l at subsection { \@dottedtocline{2}{2.5em}{2.8em} } % #2 = 1.5em
+\cs_gset:Npn \l at subsubsection { \@dottedtocline{3}{5.3em}{3.2em} } % #2 = 1.5em
+
+\ExplSyntaxOff
+\makeatother
+
+
+\usepackage{xcolor}
+
+\definecolor{linkcolor}{rgb}{0.0,0.4,0.7}
+\colorlet{citecolor}{linkcolor}
+\colorlet{urlcolor}{linkcolor}
+
+\hypersetup{
+ linkcolor=linkcolor,%
+ citecolor=citecolor,%
+ urlcolor=urlcolor,%
+}
+
+
+\newcommand*\fullref[2]{%
+ \hyperref[#2]{#1\penalty 200\ \ref*{#2}}%
+}
+
+
+\numberwithin{figure}{section}
+\numberwithin{table}{section}
+
+
+
+\usepackage{mathtools}
+\DeclarePairedDelimiter{\abs}{\lvert}{\rvert}
+\DeclarePairedDelimiter{\set}{\lbrace}{\rbrace}
+
+
+
+\newcommand*\key[1]{\texttt{#1}}
+\newcommand*\val[1]{\texttt{#1}}
+\newcommand*\keyval[2]{\texttt{#1=#2}}
+\newcommand*\ttdashdash{\texttt{-}\texttt{-}\hskip 0pt\relax}
+
+
+\NewDocumentCommand{\default}{ m }{(\textit{Default:} #1)}
+
+
+\newcommand*\mcode[1]{\texttt{#1}}
+
+
+\newcommand*\param[1]{\texttt{\##1}}
+
+
+\newcommand*\MakeIndex{\textit{MakeIndex}}
+\newcommand*\upmendex{\texttt{upmendex}}
+\newcommand*\xindy{\texttt{xindy}}
+
+
+\usepackage{siunitx}
+\sisetup{
+ mode=match,
+}
+\DeclareSIUnit\point{pt}
+\DeclareSIUnit\spoint{sp}
+
+
+\newcommand*\purl[1]{\textsc{url:}~\url{#1}}
+
+
+\usepackage{listings}
+
+
+
+\usepackage{indextra}
+
+
+
+\begin{document}
+\DocInput{indextra.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+%
+%
+% \GetFileInfo{indextra.sty}
+%
+% \makeatletter
+% \lstset{
+% language=[LaTeX]TeX,
+% columns=fullflexible,
+% keepspaces=true,
+% commentstyle=\slshape,
+% basicstyle=\ttfamily\lst at ifdisplaystyle\small\fi,
+% }
+% \makeatother
+%
+%
+%
+% \title{^^A
+% \pkg{indextra} ^^A
+% --- Enhanced index typesetting^^A
+% \thanks{This file describes \fileversion, last revised \filedate.}^^A
+% }
+%
+% \author{^^A
+% Alan J. Cain^^A
+% }
+%
+% \date{Released \filedate}
+%
+% \maketitle
+%
+%
+%
+% \begin{abstract}
+% This package provides some enhanced features for typesetting indexes, notably: (1) Continuation text when entries or
+% sub-entries continue from one page or column to the next. (2) An interface for accessing marks created from index
+% entries, so that (for example) a running head can include the range of index entries that appears on the page.
+% \end{abstract}
+%
+%
+%
+% \tableofcontents
+%
+%
+%
+% \begin{documentation}
+%
+% \section{Introduction}
+%
+% By default, an index in a \LaTeX\ document is typeset in two columns and provides no indication if a page or column
+% break occurs inside an index entry or sub-entry. The package
+% \pkg{repeatindex}\footnote{\purl{https://ctan.org/pkg/repeatindex}} handles a page or column break that occurs between
+% sub-entries within the same entry by repeating the keyword of the main entry. But it does not repeat the keyword of a
+% sub-entry when a page or column break occurs within it. Nor does it repeat the keyword of an entry (at the top level)
+% % if the break occurs mid-way through a long list of pages or ranges for that entry directly.
+% In \emph{The \TeX book}, Knuth described a plain \TeX\ method to create continuation texts using the mark mechanism
+% \cite[pp.~261--3]{knuth_texbook}, which does not have these limitations. But there are still situations in which this
+% method can cause problems: for instance, if the keyword in the index entry spans two or more lines, it may break
+% across a page or column and the continuation text would appear in the middle of the keyword.
+%
+% The \pkg{indextra} package is intended to create suitable continuation texts for all of these possibilities. An
+% example is shown in \fullref{Figure}{fig:indextra-doc-demo}, where the list of locations within a sub-entry is too
+% long to fit in the left-hand column. At the top of the right-hand column, \pkg{indextra} has indicated that both the
+% main entry and the sub-entry have both been continued. If there had been a page break as well as a column break, the
+% same indicators would have been placed at the start of the left-hand column of the next page.
+%
+% \begin{figure}[t]
+% \centering
+% \includegraphics{indextra-doc-demo.pdf}
+% \caption{An example of how \pkg{indextra} continues an entry and a sub-entry after a column or page break.}
+% \label{fig:indextra-doc-demo}
+% \end{figure}
+%
+% \pkg{indextra} tries to break columns intelligently. If only one line of a multi-line index entry would fit in the
+% remaining space of the current column, the column break is inserted first, since there would be no saving in space
+% because the continutation text would occupy (at least) one line of the next column. Similarly, it will not break a
+% column before or during any cross-references in the index entry.
+%
+% \pkg{indextra} also supplies a system for retrieving index entry keywords as marks, for use in running heads to show
+% the range of index entries on the current page. The keywords of the first and last top-level entries on each page are
+% available as \cs{indextrafirstmark} and \cs{indextralastmark}.
+%
+% \medskip
+% \noindent\textit{Caveat:}~~Although \pkg{indextra} has been used successfully for the indexes of the author's
+% books,\footnote{Available on the Internet Archive under Creative Commons licences:\par
+% (1)~A.J. Cain, \textit{Form \& Number: A History of Mathematical Beauty}. Lisbon, 2024.
+% \purl{https://archive.org/details/cain_formandnumber_ebook_large}\par
+% (2)~G.H. Hardy, \textit{An Annotated Mathematician's Apology}. With annotations and commentary by A.J. Cain. Lisbon,
+% 2019. \purl{https://archive.org/details/hardy_annotated}} in its current state it should be regarded as
+% semi-experimental, requiring further development, and having many limitations and some incompatibilites (see
+% \fullref{Subsection}{subsec:limitations}).
+%
+%
+%
+% \section{Requirements}
+%
+% \pkg{indextra} does not depend on any other packages, but requires a recent \LaTeX\ kernel with \pkg{expl3} support.
+% (Any kernel version since 2020-02-02 should suffice.)
+%
+%
+%
+% \section{Installation}
+%
+% To install \pkg{indextra} manually, run \texttt{tex indextra.ins} and copy the file \texttt{indextra.sty} to somewhere
+% \LaTeX\ can find it, \texttt{indextra.ist} to somewhere \MakeIndex\ and/or \upmendex\ can find it, and
+% \texttt{indextra.xdy} to somewhere \xindy\ can find it. To build the documentation, first compile
+% \texttt{indextra-doc-demo.tex} to a PDF, then compile \texttt{indextra-doc.tex}.
+%
+%
+%
+% \section{Getting started}
+%
+% \subsection{\LaTeX}
+%
+% On the \LaTeX\ side, simply use the package with \lstinline!\usepackage{indextra}!. (There are no package options.)
+% Use \cs{makeindex} and \cs{index} as as usual. Note that \pkg{indextra} is incompatible with \pkg{imakeindex}.
+%
+% If the \pkg{hyperref} package is used, set \keyval{hyperindex}{false} in its package options or in \cs{hypersetup},
+% because \pkg{indextra} has its own mechanism to add index hyperlinks, activated by its own \key{hyperindex} key.
+%
+%
+%
+% \subsection{Index generation}
+%
+% The \file{.ind} file (generated by \MakeIndex, \upmendex, or \xindy) must be specially formatted for \pkg{indextra}.
+% The style file \file{indextra.ist} is supplied for use with \MakeIndex\ and \upmendex. It can be used with:\par
+% \texttt{makeindex -s indextra.ist \meta{filename}.idx}\par
+% \noindent or\par
+% \texttt{upmendex -s indextra.ist \meta{filename}.idx}\par
+% \noindent Also supplied is a barebones \xindy\ module \file{indextra.xdy} style file, which should be used with other
+% modules to set up sorting and attributes. The module \file{indextra.xdy} should be specified last when invoking
+% \xindy, to override any previous specification of how to write to the \file{.idx} file. For example, one might
+% use:\par
+% \texttt{xindy -M makeidx.xdy -M utf8.xdy -M indextra.xdy \meta{filename}.idx}
+%
+%
+%
+% \section{Configuration}
+%
+% \begin{function}{\indextrasetup}
+% \begin{syntax}
+% \cs{indextrasetup}\marg{options}
+% \end{syntax}
+% This command is used to specify options. The argument \meta{options} is a key--value list. The options are described
+% in the subsections below and are summarized in \fullref{Table}{tbl:keys-summary}.
+% \end{function}
+%
+% \begin{table}[t]
+% \addtolength{\leftskip}{-12mm}%
+% \addtolength{\textwidth}{12mm}%
+% \caption{Summary of keys that can be set using \cs{indextrasetup}.}
+% \label{tbl:keys-summary}
+% \begin{tabular*}{\textwidth}{lll@{\extracolsep{\fill}}}
+% \toprule
+% \textsf{Key name} & \textsf{Value} & \textsf{Default} \\
+% \midrule
+% \key{before code} & \LaTeX\ code & \val{\cs{begin}\{theindex\}} \\
+% \key{after code} & \LaTeX\ code & \val{\cs{end}\{theindex\}} \\
+% \key{level 0 style} & \LaTeX\ code & \val{\cs{parindent}=0em\cs{hangindent}=3.75em} \\
+% \key{level 1 style} & \LaTeX\ code & \val{\cs{parindent}=1.5em\cs{hangindent}=5.25em} \\
+% \key{level 2 style} & \LaTeX\ code & \val{\cs{parindent}=3em\cs{hangindent}=6.75em} \\
+% \key{separator keyword crossref} & \LaTeX\ code & \cs{break} \\
+% \key{separator keyword location} & \LaTeX\ code & \cs{space}\cs{space} \\
+% \key{separator crossref crossref} & \LaTeX\ code & \cs{break} \\
+% \key{separator crossref location} & \LaTeX\ code & \cs{break} \\
+% \key{separator location location} & \LaTeX\ code & \val{,\textvisiblespace} \\
+% \key{crossref macros} & List of macros & \cs{see}\cs{seealso} \\
+% \key{hyperindex} & \(\set{\val{true},\val{false}}\) & \val{true} \\
+% \key{bookmarks} & \(\set{\val{true},\val{false}}\) & \val{true} \\
+% \bottomrule
+% \end{tabular*}
+% \end{table}
+%
+%
+%
+% \subsection{Before and after code}
+%
+% \DescribeOption{before code}
+% This option specifies code that is executed at the start of the index (more specifically,
+% at the start of the \env{theindextra} environment in the generated \file{.ind} file). The code will be executed before
+% \pkg{indextra} sets various parameters and makes available the commands described in
+% \fullref{Section}{sec:ind-macros}. The user may wish to use this option to set up running heads using \pkg{indextra}'s
+% marks (see \fullref{Subsection}{subsec:example-marks} for an example). \default{\cs{begin}\mcode{\{theindex\}}}
+%
+% \DescribeOption{after code}
+% This option specifies code that is executed at end start of the index (more specifically,
+% at the end of the \env{theindextra} environment in the generated \file{.ind} file).
+% \default{\cs{begin}\mcode{\{theindex\}}}
+%
+%
+%
+% \subsection{Styles}
+%
+% \DescribeOption{level \(n\) style} The style applied to an index entry at level \(n = 0,1,2\) (that is, respectively
+% to an entry, a sub-entry, and a sub-sub-entry).
+%
+% \noindent
+% \begin{tabular}{@{}r@{~}l}
+% (\textit{Default:} & \keyval{level 0 style}{\cs{parindent}=0em\allowbreak\cs{hangindent}=3.75em}; \\
+% & \keyval{level 1 style}{\cs{parindent}=1.5em\cs{hangindent}=5.25em}; \\
+% & \keyval{level 2 style}{\cs{parindent}=3em\allowbreak\cs{hangindent}=6.75em})
+% \end{tabular}
+%
+%
+%
+% \subsection{Separators}
+%
+% \pkg{indextra} always typesets cross-references before locations in each index entry, sub-entry, or sub-sub-entry. The
+% following options specify the separators to be used.
+%
+% \DescribeOption{separator keyword crossref}
+% The separator to be placed between the keyword of an index entry and a cross-reference. \default{\cs{break}}
+%
+% \DescribeOption{separator keyword location}
+% The separator to be placed between the keyword of an index entry and a location (that is, a page or range of pages),
+% when the first location immediately follows the keyword (when there are no cross-references).
+% \default{\cs{space}\cs{space}}
+%
+% \DescribeOption{separator crossref crossref}
+% The separator to be placed between the two cross-references in an index entry. \default{\cs{break}}
+%
+% \DescribeOption{separator crossref location}
+% The separator to be placed between the last cross-reference in an entry and the first location. \default{\cs{break}}
+%
+% \DescribeOption{separator location location}
+% The separator to be placed between two locations in an index entry. \default{\texttt{,\textvisiblespace}}
+%
+%
+%
+% \subsection{Specification of cross-references}
+%
+% \DescribeOption{crossref macros}
+% A list of macros that signify cross-references. \default{\cs{see}\cs{seealso}}
+%
+%
+%
+% \subsection{Hyperlinks}
+%
+% \DescribeOption{hyperindex}
+% A boolean \val{true}/\val{false} that indicates whether index locations should be hyperlinked if the \cs{hyperpage}
+% macro from the \pkg{hyperref} package is available. Note that a user redefinition of \cs{indextrapage} or
+% \cs{indextrarange} (see \fullref{Subsection}{subsec:user-redefinable-page-range}) will override this setting. If
+% hyperlinks are required in this case, the user's redefinition should create them. \default{\val{true}}
+%
+%
+%
+% \subsection{Bookmarks}
+%
+% \DescribeOption{bookmarks}
+% A boolean \val{true}/\val{false} that indicates whether the beginning of each group of index entries (usually terms
+% beginning with a particular letter) should be bookmarked if the \cs{belowpdfbookmark} macro from the \pkg{hyperref}
+% package is available. \default{\val{true}}
+%
+%
+%
+% \subsection{Headings}
+%
+% \DescribeOption{headings} A boolean \val{true}/\val{false} that indicates whether there should be a heading at the
+% beginning of each group of index entries (usually terms beginning with a particular letter). This heading will be
+% created by the user-redefinable macro \cs{indextramakegroupheading} (see
+% \fullref{Subsection}{subsec:user-redefinable-heading}). \default{\val{true}}
+%
+%
+%
+% \section{Marks}
+%
+% \pkg{indextra} uses the keyword of each (top-level) index entry to insert a mark. The following macros make available
+% the first and last marks on the current page. They are intended for use in a running header to show the range of
+% entries on the current page.
+%
+% \begin{function}{\indextrafirstmark}
+% The first mark on the current page, with the macro \cs{indextramakemark} applied.
+% \end{function}
+%
+% \begin{function}{\indextralastmark}
+% The last mark on the current page, with the macro \cs{indextramakemark} applied.
+% \end{function}
+%
+%
+%
+% \section{User-redefinable macros}
+%
+% \subsection{Keywords}
+%
+% The following macros is used to typeset keywords of entries, sub-entries, and sub-sub-entries. It can be redefined by
+% the user.
+%
+% \begin{function}{\indextrakeyword}
+% \begin{syntax}
+% \cs{indextrakeyword}\marg{level}\marg{keyword}
+% \end{syntax}
+% This macro is used to typeset a keyword for an entry of level \meta{level}. The default definition simply yields
+% \meta{keyword}. Users may wish to use a redefinition to apply styling or for other purposes. The result will already
+% have the code specified in \key{level \meta{level} style} applied.
+% \end{function}
+%
+%
+%
+% \subsection{Page and range typesetting}
+% \label{subsec:user-redefinable-page-range}
+%
+% The following two macros are actually used to typeset locations. They can be redefined by the user.
+%
+% \begin{function}{\indextrapage}
+% \begin{syntax}
+% \cs{indextrapage}\marg{encapsulation}\marg{page}
+% \end{syntax}
+% This command is used to typeset a reference to a single page. The default definition is effectively
+% \meta{encapsulation}\texttt{\{}\meta{page}\texttt{\}}, but using the configuration option \keyval{hyperindex}{true}
+% will create a hyperlink to the actual page. Any redefinition of this command will override the effect of
+% \keyval{hyperindex}{true}, so if the user still wishes the reference to be a hyperlink to the actual page, the new
+% definition must create the hyperlink.
+% \end{function}
+%
+% \begin{function}{\indextrarange}
+% \begin{syntax}
+% \cs{indextrarange}\marg{encapsulation}\marg{start}\marg{end}
+% \end{syntax}
+% This command is used to typeset a reference to a range of pages. The default definition is effectively
+% \meta{encapsulation}\texttt{\{}\meta{page}\texttt{\}}\ttdashdash\meta{encapsulation}\texttt{\{}\meta{page}\texttt{\}},
+% but using the configuration option \keyval{hyperindex}{true} will create a hyperlink to the actual pages. Users may
+% wish to redefine \cs{indextrarange} to abbreviate ranges (so that, for instance, 1024--1025 is replaced by 1024--5).
+% Any redefinition of this command will override the effect of \keyval{hyperindex}{true}, so if the user still wishes
+% the references to be hyperlinks to the actual pages, the new definition must create the hyperlinks.
+% \end{function}
+%
+%
+%
+% \subsection{Continuation text}
+%
+% \pkg{indextra} inserts continuation text for each entry, sub-entry, and sub-sub-entry that has been interrupted by a
+% page or column break. The following macro creates the continuation text and can be redefined by the user.
+%
+% \begin{function}{\indextramakecontinuation}
+% \begin{syntax}
+% \cs{indextramakecontinuation}\marg{level}\marg{keyword}
+% \end{syntax}
+% This macro is used to generate a continuation text when the entry at \meta{level} with the supplied \meta{keyword}
+% contains a column break. The default definition simply yields \meta{keyword}\texttt{ (cont.)}. Users may wish to use
+% a redefinition to apply styling. The continuation text will already have the code specified in \key{level
+% \meta{level} style} applied.
+% \end{function}
+%
+%
+%
+% \subsection{Marks}
+%
+% \begin{function}{\indextramakemark}
+% \begin{syntax}
+% \cs{indextramakemark}\marg{text}
+% \end{syntax}
+% This command is applied to any mark retrieved via either \cs{indextrafirstmark} or \cs{indextralastmark}. The
+% default definition simply yields \meta{text}. A redefinition could be used to abbreviate or otherwise process
+% \meta{text}.
+% \end{function}
+%
+%
+%
+% \subsection{Headings}
+% \label{subsec:user-redefinable-heading}
+%
+% If the option \keyval{headings}{true} is set, the following macro generates the group heading and can be
+% redefined by the user.
+%
+% \begin{function}{\indextramakegroupheading}
+% \begin{syntax}
+% \cs{indextramakegroupheading}\marg{group}
+% \end{syntax}
+% This macro is used to generate a heading for \meta{group}. The default definition yields \cs{textbf}\marg{group}.
+% Users may wish to use a redefinition to apply a different style. Note that even if this command is redefined to
+% yield nothing, an extra vertical space will still be produced in the index where the heading would have been. To
+% disable headings and avoid this extra space, set \keyval{headings}{false} using \cs{indextrasetup}.
+% \end{function}
+%
+%
+%
+% \section{Macros used in the generated \texorpdfstring{\file{.ind}}{.ind} file}
+% \label{sec:ind-macros}
+%
+% For completeness, this section documents the commands and the enclosing environment used in the generated \file{.ind}
+% file. None of these is intended to be used or redefined by the user.
+%
+% \begin{environment}{theindextra}
+% Environment containing the generated index.
+% \end{environment}
+%
+% The commands below are only defined inside the \env{theindextra} environment.
+%
+% \begin{function}{\indextrastyleversion}
+% \begin{syntax}
+% \cs{indextrastyleversion}\marg{version}
+% \end{syntax}
+% Specify the \pkg{indextra} version of the style used to generate the \file{.ind} file. (This macro exists in case
+% future updates change the required format of the \file{.ind} file.)
+% \end{function}
+%
+% \begin{function}{\indextraprocessortype}
+% \begin{syntax}
+% \cs{indextraprocessortype}\marg{type}
+% \end{syntax}
+% Specify the type of the processor used to generate the \file{.ind} file. (Different encapsulations of ranges, which
+% must be handled differently, are generated by \MakeIndex/\upmendex\ and by \xindy.) \marg{type} is either
+% \mcode{ist}, indicating that \MakeIndex\ or \upmendex\ was used, or \mcode{xdy}, indicating that \xindy\ was used.
+% \end{function}
+%
+% \begin{function}{\indextraentry}
+% \begin{syntax}
+% \cs{indextraentry}\marg{level}\marg{keyword}\marg{crossrefs-and-locations}
+% \end{syntax}
+% This command typesets an index entry, sub-entry, or sub-sub-entry (if \meta{level} is respectively \mcode{0},
+% \mcode{1}, or \mcode{2}) with the given \meta{keyword}. The parameter \meta{crossrefs-and-locations} is a
+% comma-separated list of cross-references (using macros such as \cs{see} or \cs{seealso} as specified in the
+% \key{crossref macros} option) and locations (meaning pages or ranges).
+% \end{function}
+%
+% \begin{function}{\indextraspace}
+% \begin{syntax}
+% \cs{indextraspace}
+% \end{syntax}
+% This command produces a space of one line in the index.
+% \end{function}
+%
+% \begin{function}{\indextragroup}
+% \begin{syntax}
+% \cs{indextragroup}\marg{letter}
+% \end{syntax}
+% This command begins the new group \meta{letter}. Depending on configuration, it may produce a heading and/or a
+% bookmark.
+% \end{function}
+%
+%
+%
+% \section{Usage notes and caveats}
+% \label{sec:usage-notes}
+%
+% \subsection{Typesetting process}
+%
+% \pkg{indextra} works by tracking how much space is left in each column and intially typesetting each index entry into
+% a buffer and measuring it. If there is enough space left in the column, the buffer contents are added to the output
+% and the amount of space left is adjusted appropriately. Otherwise, enough of the buffer as will fit is split off and
+% output, then a column break is called, the continuation text is added to the top of the remaining content in the
+% buffer, and the process continues in a new column.
+%
+% This process relies on the fact that an index is a highly structured text with a restricted format. Any `exotic' index
+% entries may break the process.
+%
+%
+%
+% \subsection{Limitations and incompatibilies}
+% \label{subsec:limitations}
+%
+% \begin{itemize}
+%
+% \item When choosing where to break a column, \pkg{indextra} only considers the current entry at the current level.
+% It does not, for example, automatically decide to insert a column break before a one-line top-level entry
+% that contains a sub-entry, even though this would be a more desirable result.
+%
+% \item \pkg{indextra} cannot cope with \cs{verb} commands in index keywords. (But succeeding in generating such an
+% \file{.ind} via the usual \LaTeX\ indexing commands would be a challenge.)
+%
+% \item \pkg{indextra} is incompatible with \pkg{imakeidx}, which uses the \pkg{multicols} package to set the index
+% instead of the native \LaTeX\ two-column mode. In particular, \LaTeX\ marks cannot be set from within
+% the \env{multicols} environment.
+%
+% \item \pkg{indextra} should not be used with \pkg{repeatindex}, and in any case replaces its functionality.
+%
+% \item \pkg{indextra} cannot be used if the usual indexing system is heavily customized. For example, the
+% \cls{l3doc} class uses its own specialized implementation of indexing and so \pkg{indextra} cannot be used
+% alongside it.
+%
+% \end{itemize}
+%
+%
+%
+% \subsection{Example of using marks}
+% \label{subsec:example-marks}
+%
+% One could incorporate marks into the index running heads using by appending suitable code to the default value
+% (\cs{begin}\mcode{\{theindex\}}) of the \key{before code} key:
+% \iffalse
+%<*example>
+% \fi
+\begin{lstlisting}
+\indextrasetup{
+ before code={%
+ \begin{theindex}%
+ \markboth
+ {\MakeUppercase\indexname~%
+ \noexpand\indextrafirstmark--\noexpand\indextralastmark}
+ {\MakeUppercase\indexname~%
+ \noexpand\indextrafirstmark--\noexpand\indextralastmark}%
+ },
+}
+\end{lstlisting}
+% \iffalse
+%</example>
+% \fi
+% (The \cs{noexpand} macros ensure that \cs{indextrafirstmark} and \cs{indextralastmark} are expanded when
+% the page is shipped out, not when \cs{markboth} is used.)
+%
+%
+%
+% \begin{thebibliography}{1}
+%
+% \bibitem{knuth_texbook}
+% D.E.~Knuth.
+% \newblock \emph{{T}he {\TeX book}}.
+% \newblock Addison--Wesley, 2021.
+% \newblock \emph{{C}omputers {\&} {T}ypesetting}, vol.~A.
+%
+% \end{thebibliography}
+%
+%
+%
+% \end{documentation}
+%
+%
+%
+% \begin{implementation}
+%
+%
+%
+% \section{Implementation}
+%
+% \begin{macrocode}
+%<*package>
+%<@@=indextra>
+% \end{macrocode}
+%
+%
+%
+% \subsection{Initial set-up}
+%
+% Package identification/version information.
+% \begin{macrocode}
+\NeedsTeXFormat{LaTeX2e}[2020-02-02]
+\ProvidesExplPackage{indextra}{2025-02-26}{0.21.2}
+ {Enhanced index typesetting}
+% \end{macrocode}
+%
+%
+%
+% \subsection{User configuration}
+%
+% Set up the key--value options and the variables in which the settings will be stored.
+%
+% \begin{variable}{
+% \l_@@_before_code_tl,
+% \l_@@_after_code_tl,
+% }
+% Token list keys that store code to be executed before and after the index is typeset.
+% \begin{macrocode}
+\keys_define:nn { indextra }
+{
+ before~code .tl_set:N = \l_@@_before_code_tl,
+ after~code .tl_set:N = \l_@@_after_code_tl,
+ before~code .initial:n = {\begin{theindex}},
+ after~code .initial:n = {\end{theindex}},
+}
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \begin{variable}{
+% \l_@@_level_0_style_tl,
+% \l_@@_level_1_style_tl,
+% \l_@@_level_2_style_tl,
+% }
+% Token list keys that store the style to be applied to entries at each level.
+% \begin{macrocode}
+\keys_define:nn { indextra }
+{
+ level~0~style .tl_set:c = {l_@@_level_0_style_tl},
+ level~1~style .tl_set:c = {l_@@_level_1_style_tl},
+ level~2~style .tl_set:c = {l_@@_level_2_style_tl},
+ level~0~style .initial:n = {\parindent=0em\hangindent=3.75em},
+ level~1~style .initial:n = {\parindent=1.5em\hangindent=5.25em},
+ level~2~style .initial:n = {\parindent=3em\hangindent=6.75em},
+}
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \begin{variable}{
+% \l_@@_separator_kw_cr_tl,
+% \l_@@_separator_kw_loc_tl,
+% \l_@@_separator_cr_cr_tl,
+% \l_@@_separator_cr_loc_tl,
+% \l_@@_separator_loc_loc_tl,
+% }
+% Token list keys to store separators. Macros are abbreviated as follows \mcode{kw}: keyword; \mcode{cr}:
+% cross-reference; \mcode{loc}: location (page or range).
+% \begin{macrocode}
+\keys_define:nn { indextra }
+{
+ separator~keyword~crossref .tl_set:N = \l_@@_separator_kw_cr_tl,
+ separator~keyword~location .tl_set:N = \l_@@_separator_kw_loc_tl,
+ separator~crossref~crossref .tl_set:N = \l_@@_separator_cr_cr_tl,
+ separator~crossref~location .tl_set:N = \l_@@_separator_cr_loc_tl,
+ separator~location~location .tl_set:N = \l_@@_separator_loc_loc_tl,
+ separator~keyword~crossref .initial:n = {\break},
+ separator~keyword~location .initial:n = {\space\space},
+ separator~crossref~crossref .initial:n = {\break},
+ separator~crossref~location .initial:n = {\break},
+ separator~location~location .initial:n = {,~},
+}
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \begin{variable}{
+% \l_@@_crossref_macros_tl,
+% }
+% Token list key to store macros that should count as cross-references.
+% \begin{macrocode}
+\keys_define:nn { indextra }
+{
+ crossref~macros .tl_set:N = \l_@@_crossref_macros_tl,
+ crossref~macros .initial:n = {\see\seealso},
+}
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \begin{variable}{
+% \l_@@_hyperindex_bool,
+% }
+% Boolean indicating whether locations should be hyperlinked to pages, if \cs{hyperpage} is available and the user has
+% not redefined \cs{indextrapage} and \cs{indextrarange}.
+% \begin{macrocode}
+\keys_define:nn { indextra }
+{
+ hyperindex .bool_set:N = \l_@@_hyperindex_bool,
+ hyperindex .initial:n = {true},
+}
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \begin{variable}{
+% \l_@@_bookmarks_bool,
+% }
+% Boolean indicating whether groups should be bookmarked, if \cs{belowpdfbookmark} is available.
+% \begin{macrocode}
+\keys_define:nn { indextra }
+{
+ bookmarks .bool_set:N = \l_@@_bookmarks_bool,
+ bookmarks .initial:n = {true},
+}
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \begin{variable}{
+% \l_@@_headings_bool,
+% }
+% Boolean indicating whether group headings should appear.
+% \begin{macrocode}
+\keys_define:nn { indextra }
+{
+ headings .bool_set:N = \l_@@_headings_bool,
+ headings .initial:n = {true},
+}
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \begin{macro}{
+% \indextrasetup,
+% }
+% User command to set key--value configuration.
+% \begin{macrocode}
+\NewDocumentCommand{\indextrasetup}{ m }
+{
+ \keys_set:nn{ indextra }{ #1 }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Environment and commands for the \texorpdfstring{\file{.ind}}{.ind} file}
+%
+% Define the environment and commands used in the generated \file{.ind} file.
+%
+% \begin{macro}{
+% theindextra
+% }
+% This environment is the analogue of the \env{theindex} environment defined by basic \LaTeX.
+% \begin{macrocode}
+\NewDocumentEnvironment{theindextra}{}
+ { \@@_main_begin: }
+ { \@@_main_end: }
+%
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_main_begin:
+% }
+% This macro (locally) sets various \TeX\ dimensions and defines the commands that are actually used in the index,
+% namely \cs{indextrastyleversion}, \cs{indextraprocessortype}, \cs{indextraspace}, \cs{indextragroup}, and
+% \cs{indextraentry}.%
+% \begin{macrocode}
+\cs_new:Npn \@@_main_begin:
+{
+% \end{macrocode}
+% Open a group and execute code for before the index has been typeset.
+% \begin{macrocode}
+ \group_begin:
+ \tl_use:N\l_@@_before_code_tl
+% \end{macrocode}
+% Set \cs{splittopskip}, \cs{topskip}, and \cs{parskip} to the needed values, and set
+% \cs{g_@@_remaining_space_dim}, which tracks the space left in the current column, to the initial value of
+% \cs{@colht}, which will be the height of the column after any initial two-column text has been typeset.
+% \begin{macrocode}
+ \dim_gset:Nn\g_@@_remaining_space_dim{\@colht}
+ \dim_set:Nn\splittopskip{.7\baselineskip}
+ \dim_set:Nn\topskip{.7\baselineskip}
+ \dim_set:Nn\parskip{0pt}
+% \end{macrocode}
+% Make available the appropriate macros.
+% \begin{macrocode}
+ \cs_set_eq:NN\indextrastyleversion\@@_style_version:n
+ \cs_set_eq:NN\indextraprocessortype\@@_processor_type:n
+ \cs_set_eq:NN\indextraspace\@@_space:
+ \cs_set_eq:NN\indextragroup\@@_group:n
+ \cs_set_eq:NN\indextraentry\@@_entry:nnn
+% \end{macrocode}
+% If user settings require it, or \cs{belowpdfbookmark} is unavailable, disable group bookmarks and/or headings.
+% \begin{macrocode}
+ \bool_if:nF
+ { \l_@@_bookmarks_bool && \cs_if_exist_p:N\belowpdfbookmark }
+ {
+ \cs_set_eq:NN\@@_bookmark_stored_group:\prg_do_nothing:
+ }
+ \bool_if:NF\l_@@_headings_bool
+ {
+ \cs_set_eq:NN\@@_typeset_stored_group_heading:\prg_do_nothing:
+ }
+% \end{macrocode}
+% Depending on user configuration, if \cs{hyperpage} is available and \cs{indextrapage} or \cs{indextrapage} have not
+% been redefined, then change them to create hyperlinks.
+% \begin{macrocode}
+ \bool_if:nT{ \l_@@_hyperindex_bool && \cs_if_exist_p:N\hyperpage }
+ {
+ \cs_if_eq:NNT\indextrapage\@@_page_basic:nn
+ {
+ \cs_set_eq:NN\indextrapage\@@_page_hyperref:nn
+ }
+ \cs_if_eq:NNT\indextrarange\@@_range_basic:nnn
+ {
+ \cs_set_eq:NN\indextrarange\@@_range_hyperref:nnn
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_main_end:
+% }
+% Execute code for after the index has been typeset and close the group opened in \cs{@@_main_begin:}.
+% \begin{macrocode}
+\cs_new:Npn \@@_main_end:
+{
+ \tl_use:N\l_@@_after_code_tl
+ \group_end:
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+\msg_new:nnn{ indextra }{ incompatible_version }
+ { The~.ind~file~was~generated~using~a~style~from~a~different~version~of~indextra. }
+% \end{macrocode}%
+%
+% \begin{macro}{
+% \@@_style_version:n,
+% }
+% Specify the version of \pkg{indextra}'s index processor style file (\file{.ist} or \file{.xdy}) that was used to
+% generate the \file{.ind} file. If is incompatible with version of \pkg{indextra} in use, an error will result.
+% \begin{macrocode}
+\cs_new:Npn\@@_style_version:n #1
+{
+ \str_if_eq:nnF{#1}{0.1}
+ {
+ \msg_error:nn{ indextra }{ incompatible_version }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{
+% \@@_processor_type:n,
+% }
+% Set the type of the processor used to generate the \file{.ind} file. \MakeIndex\ and \upmendex\ produce ranges of
+% the form \cs{encapsulation}\texttt{\{}\meta{start}\ttdashdash\meta{end}\texttt{\}}, while \xindy\ produces ranges of
+% the form \cs{encapsulation}\texttt{\{}\texttt{\}}\ttdashdash\cs{encapsulation}\texttt{\{}\texttt{\}}. These kinds of
+% ranges must be parsed differently, and while the kind of range could be detected when typesetting each location,
+% there are efficiency savings from using a dedicated parser in each case. \param{1} should be either \mcode{ist},
+% indicating that the processor was either \MakeIndex\ or \upmendex, or \mcode{xdy}, that the processor was \xindy.
+% This macro will be set equal to \cs{indextrasetprocessortype} inside the \env{theindextra} environment.
+% \begin{macrocode}
+\cs_new:Npn\@@_processor_type:n #1
+{
+ \cs_set_eq:Nc\@@_typeset_aux_location:n
+ { @@_typeset_#1_location:n }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+%
+% \subsection{Column handling}
+%
+% \begin{variable}{
+% \g_@@_remaining_space_dim,
+% }
+% Dimension variable to hold the amount of space left in the current column.
+% \begin{macrocode}
+\dim_new:N\g_@@_remaining_space_dim
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{
+% \@@_new_column:
+% }
+% Fill any remaining space in the current column, start a new column, and set \cs{g_@@_remaining_space_dim} to
+% \cs{@colht} (which is the amount of space available in the new column).
+% \begin{macrocode}
+\cs_new:Npn\@@_new_column:
+ {
+ \vfill
+ \newpage
+ \dim_gset:Nn\g_@@_remaining_space_dim{\@colht}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Spaces}
+%
+% \begin{macro}{
+% \@@_space:,
+% }
+% Create a space in the index, which will usually signify the end of one letter group and the beginning of another.
+% This takes up space in the column, so the space (a \cs{strut}) is typeset via the same mechanism as index entries,
+% namely \cs{@@_typeset_buffer:}.
+% \begin{macrocode}
+\cs_new:Npn\@@_space:
+ {
+ \dim_compare:nNnT{\g_@@_remaining_space_dim}<{\baselineskip}{
+ \@@_new_column:
+ }
+ \vbox_set:Nn\l_@@_buffer_box{\leavevmode\strut\par}
+ \@@_typeset_buffer:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Groups}
+%
+% \begin{variable}{
+% \l_@@_group_tl
+% }
+% Token-list variable to store the current group.
+% \begin{macrocode}
+\tl_new:N\l_@@_group_tl
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \begin{macro}{
+% \@@_group:,
+% }
+% Begin a letter group in the index. The macro simply stores the group title; the bookmark and/or heading will be
+% created by the next index entry. This macro will be set equal to \cs{indextragroup} inside the \env{theindextra}
+% environment.
+% \begin{macrocode}
+\cs_new:Npn\@@_group:n #1
+ {
+ \tl_set:Nn\l_@@_group_tl{#1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{variable}{
+% \g_@@_group_bookmark_int
+% }
+% Integer variable to index groups; used in the creation of bookmarks in \cs{@@_bookmark_stored_group:}.
+% \begin{macrocode}
+\int_new:N\g_@@_group_bookmark_int
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \begin{macro}{
+% \@@_bookmark_stored_group:
+% }
+% If \cs{l_@@_group_tl} is non-empty, create a bookmark below the current level (i.e., using \cs{belowpdfbookmark}),
+% using \cs{l_@@_group_tl} for the bookmark text. The variable \cs{g_@@_group_bookmark_int} is incremented at each
+% call and used to create distinct bookmark names. (One cannot use the the content of \cs{l_@@_group_tl} for the
+% bookmark name, because (1) it might not be suitable as a name, and (2) there may be two indexes (e.g. names and
+% subjects) which contain the same groups.)
+% \begin{macrocode}
+\cs_new:Npn\@@_bookmark_stored_group:
+ {
+ \tl_if_empty:NF\l_@@_group_tl
+ {
+ \int_gincr:N\g_@@_group_bookmark_int
+ \belowpdfbookmark
+ {\tl_use:N\l_@@_group_tl}
+ {pdf:indextra:\int_value:w\g_@@_group_bookmark_int}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{
+% \@@_typeset_stored_group_heading:
+% }
+% If \cs{l_@@_group_tl} is non-empty, typeset its contents as a heading for the group.
+% \begin{macrocode}
+\cs_new:Npn\@@_typeset_stored_group_heading:
+ {
+ \tl_if_empty:NF\l_@@_group_tl
+ {
+ \group_begin:
+ \noindent\strut
+ \indextramakegroupheading{\tl_use:N\l_@@_group_tl}
+ \strut\par
+ \group_end:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{
+% \indextramakegroupheading
+% }
+% Typeset a heading for the letter group passed as \param{1}.
+% \begin{macrocode}
+\cs_new:Npn\indextramakegroupheading #1
+ {
+ \textbf{#1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+%
+%
+% \subsection{Entries}
+%
+% \begin{variable}{
+% \l_@@_level_int
+% }
+% Integer variable to hold the level of the current entry.
+% \begin{macrocode}
+\int_new:N\l_@@_level_int
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \begin{variable}{
+% \l_@@_saved_keyword_0,
+% \l_@@_saved_keyword_1,
+% \l_@@_saved_keyword_2,
+% }
+% Token list variables to save keywords at each level.
+% \begin{macrocode}
+\tl_new:c{l_@@_saved_keyword_0}
+\tl_new:c{l_@@_saved_keyword_1}
+\tl_new:c{l_@@_saved_keyword_2}
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \begin{variable}{
+% \l_@@_crossref_seq,
+% \l_@@_location_seq,
+% }
+% Comma-separated list variables to hold the cross-references and locations of the current entry. These will be
+% populated via a call to \cs{@@_filter_crossref_location_seqs:n}
+% \begin{macrocode}
+\seq_new:N\l_@@_crossref_seq
+\seq_new:N\l_@@_location_seq
+% \end{macrocode}
+% \end{variable}
+%
+%
+% \begin{macro}{
+% \@@_entry:nnn,
+% }
+% Typeset an index entry. The three parameters are the level (\param{1}), the keyword (\param{2}), and the rest of the
+% entry (\param{3}), which should be a comma-separated list of cross-references and/or locations.
+% \begin{macrocode}
+\cs_new:Npn\@@_entry:nnn #1#2#3
+ {
+% \end{macrocode}
+% First save the level and the keyword, and sort the rest of the entry into the cross-reference and location seqs.
+% \begin{macrocode}
+ \int_set:Nn\l_@@_level_int{#1}
+ \tl_set:cn{l_@@_saved_keyword_#1}{#2}
+ \@@_filter_crossref_location_seqs:n{#3}
+% \end{macrocode}
+% Typeset the entire entry (prefixed by any stored group heading) into \cs{l_@@_buffer_box}. The bookmarking command
+% is also executed here, since it is the contents of this box that will ultimately be shipped out.
+% \begin{macrocode}
+ \vbox_set:Nn\l_@@_buffer_box{
+ \@@_bookmark_stored_group:
+ \@@_typeset_stored_group_heading:
+ \group_begin:
+ \@@_set_style:n{#1}
+ \leavevmode
+ \strut
+ \indextrakeyword{#1}{#2}
+ \@@_typeset_between:
+ \@@_typeset_locations:
+ \strut
+ \par
+ \goodbreak
+ \group_end:
+ }
+% \end{macrocode}
+% Now typeset some material into \cs{l_tmpa_box} and \cs{l_tmpb_box}, the dimensions of which will be used in
+% computing the minimum acceptable portion of the entry to typeset into the current column. First, typeset the part of
+% the entry where a column break is unacceptable (prefixed by any stored group heading) into \cs{l_tmpa_box}.
+% \begin{macrocode}
+ \vbox_set:Nn\l_tmpa_box{
+ \@@_typeset_stored_group_heading:
+ \group_begin:
+ \@@_set_style:n{#1}
+ \leavevmode
+ \strut
+ \indextrakeyword{#1}{#2}
+ \@@_typeset_between:
+ \@@_typeset_first_location:
+ \strut
+ \par
+ \group_end:
+ }
+% \end{macrocode}
+% Typeset any stored group heading into \cs{l_tmpb_box}.
+% \begin{macrocode}
+ \vbox_set:Nn\l_tmpb_box{
+ \@@_typeset_stored_group_heading:
+ }
+% \end{macrocode}
+% Measuring \cs{l_tmpa_box}, \cs{l_tmpb_box}, and \cs{l_@@_buffer_box}, check whether there is enough space in the
+% current column to typeset any stored heading and the minimum acceptable portion of the entry. Basically, a split
+% should not occur within the part typeset into \cs{l_tmpa_box}, and if the entry as a whole is longer than one line,
+% then at least two lines should be typeset (because if only one line can fit into the current column, there is
+% probably no overall saving of space by putting it in the current column with a continuation in the next column).
+% Note that if there is no stored heading, the height and depth of \cs{l_tmpb_box} are both \qty{0}{\point}, so no
+% conditional is needed.
+% \begin{macrocode}
+ \dim_compare:nNnT
+ {\g_@@_remaining_space_dim}
+ <
+ {
+ \dim_min:nn{
+ \dim_max:nn{
+ \box_ht:N\l_tmpa_box
+ +\box_dp:N\l_tmpa_box
+ }{
+ \box_ht:N\l_tmpb_box
+ +\box_dp:N\l_tmpb_box
+ +2\baselineskip
+ }
+ }{
+ \box_ht:N\l_@@_buffer_box
+ +\box_dp:N\l_@@_buffer_box
+ }
+ }
+ {
+% \end{macrocode}
+% \textit{Case: not enough space in the current column.} Start a new column and, unless this is a top-level
+% entry, insert the appropriate continuation into the \cs{l_@@_buffer_box}.
+% \begin{macrocode}
+ \@@_new_column:
+ \int_compare:nNnT{#1}>{0}{
+ \@@_vbox_prepend:Nn\l_@@_buffer_box{
+ \@@_make_continuation:n{\l_@@_level_int-1}
+ }
+ }
+ }
+% \end{macrocode}
+% \cs{l_@@_buffer_box} now contains the material that should be typeset onto the page, and there is enough space in
+% the current column to typeset a minimal acceptable portion of it. Typesetting is handled by \cs{@@_set_buffer:},
+% which may use \tn{vsplit}, which produces a warning `\texttt{Underfull \tn{vbox} (badness 10000)}' with even a
+% \qty{1}{\spoint} mismatch between available breakpoints and desired height. For efficiency, \cs{@@_set_buffer:} uses
+% an approximation to the desired height, so set \tn{vbadness} to 10000 to suppress these warnings.
+% \begin{macrocode}
+ \group_begin:
+ \int_set:Nn\vbadness{10000}
+ \@@_typeset_buffer:
+ \group_end:
+% \end{macrocode}
+% Finally, clear any stored group.
+% \begin{macrocode}
+ \tl_clear:N\l_@@_group_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Filtering cross-references and locations}
+%
+% In each entry, cross-references and locations may be mixed up and need to be filtered into separate lists.
+%
+% \begin{macro}{
+% \@@_filter_crossref_location_seqs:n
+% }
+% Use the supplied list of cross-references and location (\param{1}), which is a clist, to populate
+% \cs{l_@@_crossref_seq} and \cs{l_@@_location_seq}. The list of macros that are the first tokens in
+% cross-references is contained in \cs{l_@@_crossref_macros_tl}. All that is required is to check whether the head
+% token in each item in the \param{1} is in \cs{l_@@_crossref_macros_tl}. and assign that item to the correct seq.
+% \begin{macrocode}
+\cs_new:Npn\@@_filter_crossref_location_seqs:n #1
+ {
+ \seq_clear:N\l_@@_crossref_seq
+ \seq_clear:N\l_@@_location_seq
+
+ \clist_map_inline:nn{#1}
+ {
+ \tl_if_in:NoTF
+ \l_@@_crossref_macros_tl{ \tl_head:w ##1 {} \q_stop }
+ {
+ \seq_put_right:Nn\l_@@_crossref_seq{##1}
+ }
+ {
+ \seq_put_right:Nn\l_@@_location_seq{##1}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Style}
+%
+% \begin{macro}{
+% \@@_set_style:n,
+% }
+% Set up the style for an index entry at the given level.
+% \begin{macrocode}
+\cs_new:Npn \@@_set_style:n #1
+ {
+ \tl_use:c{l_@@_level_#1_style_tl}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Typesetting keywords}
+%
+% \begin{macro}{
+% \indextrakeyword
+% }
+% Take a level (\param{1}) and a keyword (\param{2}) and return a (possibly styled) keyword.
+% \begin{macrocode}
+\cs_new:Npn\indextrakeyword #1#2
+ {
+ #2
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Typesetting cross-references}
+%
+% \begin{macro}{
+% \@@_typeset_between:
+% }
+% Typeset everything between the keyword and the locations. If there are no cross-references, this means typesetting
+% just the keyword--location separator; otherwise, it means typesetting the cross-references with the relevant
+% separators before, after, and between.
+% \begin{macrocode}
+\cs_new:Npn\@@_typeset_between:
+ {
+ \seq_if_empty:NTF\l_@@_crossref_seq
+ {
+ \tl_use:N\l_@@_separator_kw_loc_tl
+ }
+ {
+ \tl_use:N\l_@@_separator_kw_cr_tl
+ \seq_use:Nn
+ \l_@@_crossref_seq
+ { \tl_use:N\l_@@_separator_cr_cr_tl }
+ \seq_if_empty:NF\l_@@_location_seq
+ { \tl_use:N\l_@@_separator_cr_loc_tl }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Typesetting locations}
+%
+% \begin{variable}{
+% \l_@@_first_item_bool,
+% }
+% Boolean variable to track whether the current location is the first one in the entry, so that a separator can be
+% inserted before every non-first location.
+% \begin{macrocode}
+\bool_new:N\l_@@_first_item_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{
+% \@@_typeset_locations:
+% }
+% Typeset locations stored in \cs{l_@@_locations_seq}. Using \cs{seq_use:Nn} is not enough, because each entry must be
+% processed separately. Thus separators must be inserted `manually'.
+% \begin{macrocode}
+\cs_new:Npn\@@_typeset_locations:
+ {
+ \bool_set_true:N\l_@@_first_item_bool
+ \seq_map_inline:Nn\l_@@_location_seq
+ {
+ \bool_if:nF{\l_@@_first_item_bool}
+ { \tl_use:N\l_@@_separator_loc_loc_tl }
+ \@@_typeset_aux_location:n{##1}
+ \bool_set_false:N\l_@@_first_item_bool
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_typeset_first location:
+% }
+% Typeset the first location stored in \cs{l_@@_locations_seq}.
+% \begin{macrocode}
+\cs_new:Npn\@@_typeset_first_location:
+ {
+ \exp_args:Ne\@@_typeset_aux_location:n
+ {\seq_item:Nn\l_@@_location_seq{1}}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_is_nonrange_p:w
+% }
+% To be called in the form \cs{@@_is_nonrange_p:w}\meta{parameter}\ttdashdash\cs{q_stop}; uses \TeX\ parsing to check
+% whether \meta{parameter} does not contain a range marker \ttdashdash.
+% \begin{macrocode}
+\cs_new:Npn\@@_is_nonrange_p:w #1--#2\q_stop
+ {
+ \tl_if_empty_p:n{#2}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \cs_new:Npn\@@_typeset_ist_location:n
+% }
+% Typeset a \MakeIndex- or \upmendex-style location. The location might be a
+% \begin{itemize}
+% \item a single page;
+% \item an encapsulated single page \cs{encapsulation}\mcode{\{}\meta{page}\mcode{\}};
+% \item a range; or
+% \item an encapsulated range \cs{encapsulation}\mcode{\{}\meta{start}\ttdashdash\meta{end}\mcode{\}}.
+% \end{itemize}
+% \begin{macrocode}
+\cs_new:Npn\@@_typeset_ist_location:n #1
+ {
+% \end{macrocode}
+% Check for an encapsulation (a leading control sequence, comparing catcode with \cs{prg_do_nothing:} simply as a
+% convenience). Either call \cs{@@_typeset_ist_encap_page_or_range:Nn} with this encapsulation or with a `do-nothing'
+% encapsulation and the braced parameter.
+% \begin{macrocode}
+ \tl_if_head_eq_catcode:nNTF{#1}\prg_do_nothing:
+ {
+ \@@_typeset_ist_encap_page_or_range:Nn #1
+ }
+ {
+ \@@_typeset_ist_encap_page_or_range:Nn \prg_do_nothing:{#1}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_typeset_ist_encap_page_or_range:Nn
+% }
+% Take an encapsulation and a parameter and typeset the parameter as a page or range, as appropriate.
+% \begin{macrocode}
+\cs_new:Npn\@@_typeset_ist_encap_page_or_range:Nn #1#2
+ {
+ \bool_if:nTF{\@@_is_nonrange_p:w #2--\q_stop}
+ {
+% \end{macrocode}
+% \textit{Case: not a range.} Parameter \param{2} a single page.
+% \begin{macrocode}
+ \indextrapage{#1}{#2}
+ }
+ {
+% \end{macrocode}
+% \textit{Case: range.} Parameter \param{2} is a range. Call \cs{@@_typeset_ist_encap_range:w} to parse and
+% typeset it.
+% \begin{macrocode}
+ \@@_typeset_ist_encap_range:w#1\q_mark #2\q_stop
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_typeset_ist_encap_range:w
+% }
+% This is effectively just a helper macro so that \TeX\ parsing can be used to convert the parameters into the form
+% required by \cs{indextrarange}.
+% \begin{macrocode}
+\cs_new:Npn\@@_typeset_ist_encap_range:w #1\q_mark #2--#3\q_stop
+ {
+ \indextrarange{#1}{#2}{#3}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \cs_new:Npn\@@_typeset_xdy_location:n
+% }
+% Typeset a \xindy-style location. The location might be
+% \begin{itemize}
+% \item a single page;
+% \item an encapsulated single page \cs{encapsulation}\mcode{\{}\meta{page}\mcode{\}};
+% \item a range; or
+% \item an encapsulated range \cs{encapsulation}\mcode{\{}\meta{start}\mcode{\}}\ttdashdash\cs{encapsulation}\mcode{\{}\meta{end}\mcode{\}}.
+% \end{itemize}
+% \begin{macrocode}
+\cs_new:Npn\@@_typeset_xdy_location:n #1
+ {
+ \bool_if:nTF{\@@_is_nonrange_p:w #1--\q_stop}
+ {
+% \end{macrocode}
+% \textit{Case: not a range.} Check for an encapsulation (a leading control sequence, comparing catcode with
+% \cs{prg_do_nothing:} simply as a convenience). Either call \cs{@@_typeset_ist_encap_page_or_range:Nn} with this
+% encapsulation or with a `do-nothing' encapsulation and the braced parameter.
+% \begin{macrocode}
+ \tl_if_head_eq_catcode:nNTF{#1}\prg_do_nothing:
+ {
+ \indextrapage #1
+ }
+ {
+ \indextrapage \prg_do_nothing:{#1}
+ }
+ }
+ {
+% \end{macrocode}
+% \textit{Case: range.}
+% \begin{macrocode}
+ \@@_typeset_xdy_range:w #1\q_stop
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_typeset_xdy_range:w
+% }
+% To be called in the form \cs{@@_typeset_xdy_range:w}\meta{parameter}\cs{q_stop}, so that \param{1} and \param{2}
+% will be the start and end of the range, possibly with encapsulations. Check \param{1} for a leading control
+% sequence. If it exists, assume the same holds for \param{2}, and the parameters are of the form
+% \cs{encapsulation}\texttt{\{}\meta{start}\texttt{\}} and \cs{encapsulation}\texttt{\{}\meta{end}\texttt{\}} and can
+% be passed to \cs{@@_typeset_xdy_encap_range:w}. Otherwise, each parameter is a page, so call \cs{indextrarange} with
+% `do-nothing' encapsulations and braced parameters.
+% \begin{macrocode}
+\cs_new:Npn\@@_typeset_xdy_range:w #1--#2\q_stop
+ {
+ \tl_if_head_eq_catcode:nNTF{#1}\prg_do_nothing:
+ {
+ \@@_typeset_xdy_encap_range:NnNn #1#2
+ }
+ {
+ \indextrarange\prg_do_nothing:{#1}{#2}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_typeset_xdy_encap_range:NnNn
+% }
+% This is effectively just a helper macro so that \TeX\ parsing can be used to convert the parameters into the form
+% required by \cs{indextrarange}.
+% \begin{macrocode}
+\cs_new:Npn\@@_typeset_xdy_encap_range:NnNn #1#2#3#4
+ {
+ \indextrarange{#1}{#2}{#4}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{
+% \@@_page_basic:nn,
+% \@@_range_basic:nnn,
+% \@@_page_hyperref:nn,
+% \@@_range_hyperref:nnn,
+% }
+% Default macros for typesetting a page and a range, depending on whether \pkg{hyperref} is loaded.
+% \begin{macrocode}
+\cs_new:Npn\@@_page_basic:nn #1#2
+ {
+ #1{#2}
+ }
+\cs_new:Npn\@@_range_basic:nnn #1#2#3
+ {
+ #1{#2}--#1{#3}
+ }
+\cs_new:Npn\@@_page_hyperref:nn #1#2
+ {
+ #1{\hyperpage{#2}}
+ }
+\cs_new:Npn\@@_range_hyperref:nnn #1#2#3
+ {
+ #1{\hyperpage{#2}}--#1{\hyperpage{#3}}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% Set \cs{indextrapage} and \cs{indextrarange} to the `basic' versions of the above macros. They may be set to the
+% `hyperref' versions at the start of the \env{theindextra} environment depending on user settings.
+% \begin{macrocode}
+\cs_set_eq:NN\indextrapage\@@_page_basic:nn
+\cs_set_eq:NN\indextrarange\@@_range_basic:nnn
+% \end{macrocode}
+%
+%
+% \subsection{Continuations}
+%
+% \begin{macro}{
+% \@@_make_continuation:n
+% }
+% Return a continuation text for the level specified in \param{1}, indicating that this (and higher) levels are
+% continued from the previous column. The continuation text is created using the stored keywords with
+% \cs{indextramakecontinuation} applied to each.
+% \begin{macrocode}
+\cs_new:Npn\@@_make_continuation:n #1
+ {
+ \int_step_inline:nnn{0}{#1}{
+ \group_begin:
+ \@@_set_style:n{##1}
+ \leavevmode\strut
+ \indextramakecontinuation{##1}{\tl_use:c{l_@@_saved_keyword_##1}}
+ \strut\par
+ \group_end:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \indextramakecontinuation
+% }
+% Take a level (\param{1}) and a keyword (\param{2}) and return a continuation text.
+% \begin{macrocode}
+\cs_new:Npn\indextramakecontinuation #1#2
+ {
+ #2~(cont.)
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Marks}
+%
+% Define a new mark class for use by \pkg{indextra}.
+% \begin{macrocode}
+\mark_new_class:n{indextra}
+% \end{macrocode}
+%
+% \begin{macro}{
+% \@@_mark_insert:
+% }
+% Insert the top-level saved keyword as a mark.
+% \begin{macrocode}
+\cs_new:Npn\@@_mark_insert:
+ {
+ \mark_insert:nn{indextra}{\tl_use:c{l_@@_saved_keyword_0}}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \indextramakemark
+% }
+% Macro to process an \pkg{indextra} mark for use. Any mark retrieved by \cs{indextrafirstmark} or
+% \cs{indextralastmark} will have \cs{indextramakemark} applied.
+% \begin{macrocode}
+\cs_new:Npn\indextramakemark #1
+ {
+ #1
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \indextrafirstmark,
+% \indextralastmark,
+% }
+% Retrieve the first and last \pkg{indextra} marks on the page, where `first' and `last' have their standard \LaTeX\
+% meanings. The marks will be processed by \cs{indextramakemark}.
+% \begin{macrocode}
+\cs_new:Npn\indextrafirstmark
+ {
+ \indextramakemark{ \mark_use_first:nn{page}{indextra} }
+ }
+\cs_new:Npn\indextralastmark
+ {
+ \indextramakemark{ \mark_use_last:nn{page}{indextra} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Buffer}
+%
+% \begin{variable}{
+% \l_@@_buffer_box,
+% }
+% Box variable to hold remaining material to be typeset for the current index entry, sub-entry, or sub-sub-entry.
+% \begin{macrocode}
+\box_new:N\l_@@_buffer_box
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{
+% \@@_typeset_buffer:
+% }
+% Output material that has been typeset into \cs{l_@@_buffer_box} and update \cs{g_@@_remaining_space_dim} as
+% necessary. If necessary, split off as much material as will fit in the current column from \cs{l_@@_buffer_box},
+% typeset it, add continuation text to the top of \cs{l_@@_buffer_box}, then recursively call this macro. The
+% recursion ends when all material in \cs{l_@@_buffer_box} has been output.
+% \begin{macrocode}
+\cs_new:Npn\@@_typeset_buffer:
+ {
+% \end{macrocode}
+% Insert a mark. This is either on the first call, or a recursive call, in which case the current position is at the
+% top of the column. A mark should be inserted in any case.
+% \begin{macrocode}
+ \@@_mark_insert:
+% \end{macrocode}
+% Check whether it is necessary to split off some material for this column and start a new one. There is no need to
+% check about the minimum acceptable split: if necessary, a new column has already been started in \cs{@@_entry:nnn}.
+% \begin{macrocode}
+ \dim_compare:nNnT
+ {\g_@@_remaining_space_dim}
+ <
+ {\box_ht:N\l_@@_buffer_box+\box_dp:N\l_@@_buffer_box}
+ {
+% \end{macrocode}
+% \textit{Case: A split is necessary.} Compute an approximation (definitely too large, but acceptably so) to the
+% amount to be split off, then split and rebox.
+% \begin{macrocode}
+ \dim_set:Nn
+ \l_tmpa_dim{\g_@@_remaining_space_dim-.3\baselineskip}
+ \vbox_set_split_to_ht:NNn
+ \l_tmpa_box\l_@@_buffer_box{\l_tmpa_dim}
+ \vbox_set:Nn
+ \l_tmpa_box{\vbox_unpack_drop:N\l_tmpa_box}
+% \end{macrocode}
+% Update \cs{g_@@_remaining_space_dim} and output the split material.
+% \begin{macrocode}
+ \dim_gset:Nn\g_@@_remaining_space_dim
+ {
+ \g_@@_remaining_space_dim
+ -\box_ht:N\l_tmpa_box
+ -\box_dp:N\l_tmpa_box
+ }
+ \vbox_unpack_drop:N\l_tmpa_box
+% \end{macrocode}
+% Add a continuation text to the top of \cs{l_@@_buffer_box}, start a new column, and recurse.
+% \begin{macrocode}
+ \@@_vbox_prepend:Nn
+ \l_@@_buffer_box
+ {\@@_make_continuation:n{\l_@@_level_int}}
+ \@@_new_column:
+ \@@_typeset_buffer:
+ }
+ {
+% \end{macrocode}
+% \textit{Case: No split is necessary.} Update \cs{g_@@_remaining_space_dim} and output the buffer contents.
+% \begin{macrocode}
+ \dim_gset:Nn\g_@@_remaining_space_dim
+ {
+ \g_@@_remaining_space_dim
+ -\box_ht:N\l_@@_buffer_box
+ -\box_dp:N\l_@@_buffer_box
+ }
+ \vbox_unpack_drop:N\l_@@_buffer_box
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{
+% \@@_vbox_prepend
+% }
+% Takes a vertical box variable as \param{1} and typeset the material in \param{2} into it above the original content.
+% \begin{macrocode}
+\cs_new:Npn\@@_vbox_prepend:Nn #1#2
+{
+ \vbox_set:Nn #1{
+ \vbox{#2}
+ \vbox_unpack_drop:N #1
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+%
+%
+% \subsection{Style files}
+%
+% \subsubsection{\texorpdfstring{\file{.ist}}{ist} -- \MakeIndex, \upmendex}
+%
+% \begin{macrocode}
+%<*ist>
+% \end{macrocode}
+%
+% \begin{macrocode}
+page_precedence "ArRn"
+
+preamble "\\begin{theindextra}\n \\indextrastyleversion{0.1}\n \\indextraprocessortype{ist}\n"
+postamble "\n\n\n\\end{theindextra}\n"
+
+group_skip "\n\n\n \\indextraspace"
+
+heading_prefix "\n\n\n \\indextragroup{"
+heading_suffix "}\n"
+headings_flag 1
+
+item_0 "\n \\indextraentry{0}{"
+item_1 "\n \\indextraentry{1}{"
+item_01 "\n \\indextraentry{1}{"
+item_x1 "}{}\n \\indextraentry{1}{"
+item_2 "\n \\indextraentry{2}{"
+item_12 "\n \\indextraentry{2}{"
+item_x2 "}{}\n \\indextraentry{2}{"
+
+delim_0 "}{"
+delim_1 "}{"
+delim_2 "}{"
+delim_t "}"
+
+encap_prefix "\\"
+encap_infix "{"
+encap_suffix "}"
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</ist>
+% \end{macrocode}
+%
+%
+%
+% \subsubsection{\texorpdfstring{\file{.xdy}}{xdy} -- \xindy}
+%
+% \begin{macrocode}
+%<*xdy>
+% \end{macrocode}
+%
+% \begin{macrocode}
+(define-attributes (("textit" "defterm")))
+
+(markup-index :open "\begin{theindextra}~n \indextrastyleversion{0.1}~n \indextraprocessortype{xdy}~n"
+ :close "~n~n\end{theindextra}~n"
+ :tree)
+
+(markup-letter-group-list :sep "~n \indextraspace~n")
+(markup-letter-group :open-head "~n % "
+ :close-head "~n"
+ :group "default")
+(markup-letter-group :open-head "~n \indextragroup{"
+ :close-head "}~n~n")
+
+(markup-indexentry :open " \indextraentry{0}{"
+ :close "}%~n"
+ :depth 0)
+(markup-indexentry :open "}%~n \indextraentry{1}{"
+ :close ""
+ :depth 1)
+(markup-indexentry :open "}%~n \indextraentry{2}{"
+ :close ""
+ :depth 2)
+
+(markup-keyword-list :open "" :close "}{" :sep ";")
+
+(markup-locclass-list :open "" :sep ", " :close "")
+(markup-locref-list :open "" :sep ", " :close "")
+
+(markup-range :sep "--")
+(markup-locref :open "\textit{" :close "}" :attr "textit")
+(markup-locref :open "\defterm{" :close "}" :attr "defterm")
+
+(markup-crossref-list :class "see"
+ :open "\see{"
+ :sep "}{}, \see{"
+ :close "}{}")
+(markup-crossref-list :class "seealso"
+ :open "\seealso{"
+ :sep "}{}, \seealso{"
+ :close "}{}")
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</xdy>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
+%
+%
+%
+% \iffalse
+%<*metadriver>
+\input{indextra.dtx}
+%</metadriver>
+%
+%<*demo>
+\documentclass{article}
+
+\usepackage[
+paperwidth=105mm,
+paperheight=100mm,
+inner=5mm,
+width=90mm,
+height=90mm,
+top=5mm,
+nohead,
+nofoot,
+columnsep=5mm,
+twocolumn,
+]{geometry}
+
+\usepackage{xcolor}
+\definecolor{bg}{gray}{0.9}
+\pagecolor{bg}
+
+
+\parindent=1em
+
+\usepackage{indextra}
+
+\indextrasetup{
+ before code={},
+ after code={},
+}
+
+
+\newcommand\see[1]{\textit{see}~`#1'}
+\newcommand\seealso[1]{\textit{see also}~`#1'}
+
+
+\raggedright
+\pagestyle{empty}
+
+\begin{document}
+
+\begin{theindextra}
+ \indextrastyleversion{0.1}
+ \indextraprocessortype{ist}
+
+ \indextraentry{0}{neutron}{855, 862, 885--886}%
+ \indextraentry{0}{\textit{New Astronomy} (Kepler)}{\see{\textit{Astronomia Nova}}{}}%
+ \indextraentry{0}{Newtonian physics}{298, 376, 390, 589, 813, 830, 834, 842, 891, 894--895}%
+ \indextraentry{0}{\textit{Nicomachean Ethics} (Aristotle)}{85}%
+ \indextraentry{0}{Nim}{11}%
+ \indextraentry{0}{nine-point circle}{584, 641, 662--663}%
+ \indextraentry{0}{Nobel Prize}{}%
+ \indextraentry{1}{chemistry}{495, 566, 815, 865, 937}%
+ \indextraentry{1}{literature}{485}%
+ \indextraentry{1}{peace}{865}%
+ \indextraentry{1}{physics}{502, 598, 727, 834, 836, 838, 851, 853--854, 856, 865, 867, 877, 893, 903, 905, 918, 921}%
+ \indextraentry{0}{nobility}{188, 240, 250, 464}%
+ \indextraentry{0}{non-aesthetic property}{700, 715}%
+ \indextraentry{0}{non-associative algebra}{848}%
+ \indextraentry{0}{non-commutativity}{643}%
+ \indextraentry{0}{non-constructive proof}{787}%
+ \indextraentry{0}{non-determinism}{595}%
+ \indextraentry{0}{non-euclidean geometry}{380, 401, 404--408, 436, 628, 643, 880, 896}%
+ \indextraentry{0}{non-linearity}{882}%
+ \indextraentry{0}{non-measurable set}{672}%
+ \indextraentry{0}{non-sensory property}{695}%
+ \indextraentry{0}{non-visual thinking}{633}%
+ \indextraentry{0}{nonagon}{220}%
+
+\end{theindextra}
+
+\end{document}
+% </demo>
+% \fi
Property changes on: branches/branch2024.final/Master/texmf-dist/source/latex/indextra/indextra.dtx
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: branches/branch2024.final/Master/texmf-dist/source/latex/indextra/indextra.ins
===================================================================
--- branches/branch2024.final/Master/texmf-dist/source/latex/indextra/indextra.ins (rev 0)
+++ branches/branch2024.final/Master/texmf-dist/source/latex/indextra/indextra.ins 2025-02-27 20:15:53 UTC (rev 74328)
@@ -0,0 +1,65 @@
+%%
+%% Copyright (C) 2025 Alan J. Cain
+%%
+%% This file may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either
+%% version 1.3c of this license or (at your option) any later
+%% version. The latest version of this license is in:
+%%
+%% http://www.latex-project.org/lppl.txt
+%%
+%% and version 1.3c or later is part of all distributions of
+%% LaTeX version 2008-05-04 or later.
+%%
+\input l3docstrip.tex
+\askforoverwritefalse
+\nopostamble
+
+\preamble
+
+This is a generated file.
+
+Copyright (C) 2025 Alan J. Cain
+
+This file may be distributed and/or modified under the
+conditions of the LaTeX Project Public License, either
+version 1.3c of this license or (at your option) any later
+version. The latest version of this license is in:
+
+http://www.latex-project.org/lppl.txt
+
+and version 1.3c or later is part of all distributions of
+LaTeX version 2008-05-04 or later.
+
+\endpreamble
+
+\generate{\file{indextra.sty}{\from{indextra.dtx}{package}}}
+\generate{\file{indextra-doc.tex}{\from{indextra.dtx}{metadriver}}}
+\generate{\file{indextra-doc-demo.tex}{\from{indextra.dtx}{demo}}}
+\generate{\file{indextra.ist}{\from{indextra.dtx}{ist}}}
+
+
+\def\MetaPrefix{;;}
+
+\preamble
+
+This is a generated file.
+
+Copyright (C) 2025 Alan J. Cain
+
+This file may be distributed and/or modified under the
+conditions of the LaTeX Project Public License, either
+version 1.3c of this license or (at your option) any later
+version. The latest version of this license is in:
+
+http://www.latex-project.org/lppl.txt
+
+and version 1.3c or later is part of all distributions of
+LaTeX version 2008-05-04 or later.
+
+\endpreamble
+
+\generate{\file{indextra.xdy}{\from{indextra.dtx}{xdy}}}
+
+
+\endbatchfile
Added: branches/branch2024.final/Master/texmf-dist/tex/latex/indextra/indextra.sty
===================================================================
--- branches/branch2024.final/Master/texmf-dist/tex/latex/indextra/indextra.sty (rev 0)
+++ branches/branch2024.final/Master/texmf-dist/tex/latex/indextra/indextra.sty 2025-02-27 20:15:53 UTC (rev 74328)
@@ -0,0 +1,464 @@
+%%
+%% This is file `indextra.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% indextra.dtx (with options: `package')
+%%
+%% This is a generated file.
+%%
+%% Copyright (C) 2025 Alan J. Cain
+%%
+%% This file may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either
+%% version 1.3c of this license or (at your option) any later
+%% version. The latest version of this license is in:
+%%
+%% http://www.latex-project.org/lppl.txt
+%%
+%% and version 1.3c or later is part of all distributions of
+%% LaTeX version 2008-05-04 or later.
+%%
+\NeedsTeXFormat{LaTeX2e}[2020-02-02]
+\ProvidesExplPackage{indextra}{2025-02-26}{0.21.2}
+ {Enhanced index typesetting}
+\keys_define:nn { indextra }
+{
+ before~code .tl_set:N = \l__indextra_before_code_tl,
+ after~code .tl_set:N = \l__indextra_after_code_tl,
+ before~code .initial:n = {\begin{theindex}},
+ after~code .initial:n = {\end{theindex}},
+}
+\keys_define:nn { indextra }
+{
+ level~0~style .tl_set:c = {l__indextra_level_0_style_tl},
+ level~1~style .tl_set:c = {l__indextra_level_1_style_tl},
+ level~2~style .tl_set:c = {l__indextra_level_2_style_tl},
+ level~0~style .initial:n = {\parindent=0em\hangindent=3.75em},
+ level~1~style .initial:n = {\parindent=1.5em\hangindent=5.25em},
+ level~2~style .initial:n = {\parindent=3em\hangindent=6.75em},
+}
+\keys_define:nn { indextra }
+{
+ separator~keyword~crossref .tl_set:N = \l__indextra_separator_kw_cr_tl,
+ separator~keyword~location .tl_set:N = \l__indextra_separator_kw_loc_tl,
+ separator~crossref~crossref .tl_set:N = \l__indextra_separator_cr_cr_tl,
+ separator~crossref~location .tl_set:N = \l__indextra_separator_cr_loc_tl,
+ separator~location~location .tl_set:N = \l__indextra_separator_loc_loc_tl,
+ separator~keyword~crossref .initial:n = {\break},
+ separator~keyword~location .initial:n = {\space\space},
+ separator~crossref~crossref .initial:n = {\break},
+ separator~crossref~location .initial:n = {\break},
+ separator~location~location .initial:n = {,~},
+}
+\keys_define:nn { indextra }
+{
+ crossref~macros .tl_set:N = \l__indextra_crossref_macros_tl,
+ crossref~macros .initial:n = {\see\seealso},
+}
+\keys_define:nn { indextra }
+{
+ hyperindex .bool_set:N = \l__indextra_hyperindex_bool,
+ hyperindex .initial:n = {true},
+}
+\keys_define:nn { indextra }
+{
+ bookmarks .bool_set:N = \l__indextra_bookmarks_bool,
+ bookmarks .initial:n = {true},
+}
+\keys_define:nn { indextra }
+{
+ headings .bool_set:N = \l__indextra_headings_bool,
+ headings .initial:n = {true},
+}
+\NewDocumentCommand{\indextrasetup}{ m }
+{
+ \keys_set:nn{ indextra }{ #1 }
+}
+\NewDocumentEnvironment{theindextra}{}
+ { \__indextra_main_begin: }
+ { \__indextra_main_end: }
+\cs_new:Npn \__indextra_main_begin:
+{
+ \group_begin:
+ \tl_use:N\l__indextra_before_code_tl
+ \dim_gset:Nn\g__indextra_remaining_space_dim{\@colht}
+ \dim_set:Nn\splittopskip{.7\baselineskip}
+ \dim_set:Nn\topskip{.7\baselineskip}
+ \dim_set:Nn\parskip{0pt}
+ \cs_set_eq:NN\indextrastyleversion\__indextra_style_version:n
+ \cs_set_eq:NN\indextraprocessortype\__indextra_processor_type:n
+ \cs_set_eq:NN\indextraspace\__indextra_space:
+ \cs_set_eq:NN\indextragroup\__indextra_group:n
+ \cs_set_eq:NN\indextraentry\__indextra_entry:nnn
+ \bool_if:nF
+ { \l__indextra_bookmarks_bool && \cs_if_exist_p:N\belowpdfbookmark }
+ {
+ \cs_set_eq:NN\__indextra_bookmark_stored_group:\prg_do_nothing:
+ }
+ \bool_if:NF\l__indextra_headings_bool
+ {
+ \cs_set_eq:NN\__indextra_typeset_stored_group_heading:\prg_do_nothing:
+ }
+ \bool_if:nT{ \l__indextra_hyperindex_bool && \cs_if_exist_p:N\hyperpage }
+ {
+ \cs_if_eq:NNT\indextrapage\__indextra_page_basic:nn
+ {
+ \cs_set_eq:NN\indextrapage\__indextra_page_hyperref:nn
+ }
+ \cs_if_eq:NNT\indextrarange\__indextra_range_basic:nnn
+ {
+ \cs_set_eq:NN\indextrarange\__indextra_range_hyperref:nnn
+ }
+ }
+}
+\cs_new:Npn \__indextra_main_end:
+{
+ \tl_use:N\l__indextra_after_code_tl
+ \group_end:
+}
+\msg_new:nnn{ indextra }{ incompatible_version }
+ { The~.ind~file~was~generated~using~a~style~from~a~different~version~of~indextra. }
+\cs_new:Npn\__indextra_style_version:n #1
+{
+ \str_if_eq:nnF{#1}{0.1}
+ {
+ \msg_error:nn{ indextra }{ incompatible_version }
+ }
+}
+\cs_new:Npn\__indextra_processor_type:n #1
+{
+ \cs_set_eq:Nc\__indextra_typeset_aux_location:n
+ { __indextra_typeset_#1_location:n }
+}
+\dim_new:N\g__indextra_remaining_space_dim
+\cs_new:Npn\__indextra_new_column:
+ {
+ \vfill
+ \newpage
+ \dim_gset:Nn\g__indextra_remaining_space_dim{\@colht}
+ }
+\cs_new:Npn\__indextra_space:
+ {
+ \dim_compare:nNnT{\g__indextra_remaining_space_dim}<{\baselineskip}{
+ \__indextra_new_column:
+ }
+ \vbox_set:Nn\l__indextra_buffer_box{\leavevmode\strut\par}
+ \__indextra_typeset_buffer:
+ }
+\tl_new:N\l__indextra_group_tl
+\cs_new:Npn\__indextra_group:n #1
+ {
+ \tl_set:Nn\l__indextra_group_tl{#1}
+ }
+\int_new:N\g__indextra_group_bookmark_int
+\cs_new:Npn\__indextra_bookmark_stored_group:
+ {
+ \tl_if_empty:NF\l__indextra_group_tl
+ {
+ \int_gincr:N\g__indextra_group_bookmark_int
+ \belowpdfbookmark
+ {\tl_use:N\l__indextra_group_tl}
+ {pdf:indextra:\int_value:w\g__indextra_group_bookmark_int}
+ }
+ }
+\cs_new:Npn\__indextra_typeset_stored_group_heading:
+ {
+ \tl_if_empty:NF\l__indextra_group_tl
+ {
+ \group_begin:
+ \noindent\strut
+ \indextramakegroupheading{\tl_use:N\l__indextra_group_tl}
+ \strut\par
+ \group_end:
+ }
+ }
+\cs_new:Npn\indextramakegroupheading #1
+ {
+ \textbf{#1}
+ }
+\int_new:N\l__indextra_level_int
+\tl_new:c{l__indextra_saved_keyword_0}
+\tl_new:c{l__indextra_saved_keyword_1}
+\tl_new:c{l__indextra_saved_keyword_2}
+\seq_new:N\l__indextra_crossref_seq
+\seq_new:N\l__indextra_location_seq
+\cs_new:Npn\__indextra_entry:nnn #1#2#3
+ {
+ \int_set:Nn\l__indextra_level_int{#1}
+ \tl_set:cn{l__indextra_saved_keyword_#1}{#2}
+ \__indextra_filter_crossref_location_seqs:n{#3}
+ \vbox_set:Nn\l__indextra_buffer_box{
+ \__indextra_bookmark_stored_group:
+ \__indextra_typeset_stored_group_heading:
+ \group_begin:
+ \__indextra_set_style:n{#1}
+ \leavevmode
+ \strut
+ \indextrakeyword{#1}{#2}
+ \__indextra_typeset_between:
+ \__indextra_typeset_locations:
+ \strut
+ \par
+ \goodbreak
+ \group_end:
+ }
+ \vbox_set:Nn\l_tmpa_box{
+ \__indextra_typeset_stored_group_heading:
+ \group_begin:
+ \__indextra_set_style:n{#1}
+ \leavevmode
+ \strut
+ \indextrakeyword{#1}{#2}
+ \__indextra_typeset_between:
+ \__indextra_typeset_first_location:
+ \strut
+ \par
+ \group_end:
+ }
+ \vbox_set:Nn\l_tmpb_box{
+ \__indextra_typeset_stored_group_heading:
+ }
+ \dim_compare:nNnT
+ {\g__indextra_remaining_space_dim}
+ <
+ {
+ \dim_min:nn{
+ \dim_max:nn{
+ \box_ht:N\l_tmpa_box
+ +\box_dp:N\l_tmpa_box
+ }{
+ \box_ht:N\l_tmpb_box
+ +\box_dp:N\l_tmpb_box
+ +2\baselineskip
+ }
+ }{
+ \box_ht:N\l__indextra_buffer_box
+ +\box_dp:N\l__indextra_buffer_box
+ }
+ }
+ {
+ \__indextra_new_column:
+ \int_compare:nNnT{#1}>{0}{
+ \__indextra_vbox_prepend:Nn\l__indextra_buffer_box{
+ \__indextra_make_continuation:n{\l__indextra_level_int-1}
+ }
+ }
+ }
+ \group_begin:
+ \int_set:Nn\vbadness{10000}
+ \__indextra_typeset_buffer:
+ \group_end:
+ \tl_clear:N\l__indextra_group_tl
+ }
+\cs_new:Npn\__indextra_filter_crossref_location_seqs:n #1
+ {
+ \seq_clear:N\l__indextra_crossref_seq
+ \seq_clear:N\l__indextra_location_seq
+
+ \clist_map_inline:nn{#1}
+ {
+ \tl_if_in:NoTF
+ \l__indextra_crossref_macros_tl{ \tl_head:w ##1 {} \q_stop }
+ {
+ \seq_put_right:Nn\l__indextra_crossref_seq{##1}
+ }
+ {
+ \seq_put_right:Nn\l__indextra_location_seq{##1}
+ }
+ }
+ }
+\cs_new:Npn \__indextra_set_style:n #1
+ {
+ \tl_use:c{l__indextra_level_#1_style_tl}
+ }
+\cs_new:Npn\indextrakeyword #1#2
+ {
+ #2
+ }
+\cs_new:Npn\__indextra_typeset_between:
+ {
+ \seq_if_empty:NTF\l__indextra_crossref_seq
+ {
+ \tl_use:N\l__indextra_separator_kw_loc_tl
+ }
+ {
+ \tl_use:N\l__indextra_separator_kw_cr_tl
+ \seq_use:Nn
+ \l__indextra_crossref_seq
+ { \tl_use:N\l__indextra_separator_cr_cr_tl }
+ \seq_if_empty:NF\l__indextra_location_seq
+ { \tl_use:N\l__indextra_separator_cr_loc_tl }
+ }
+ }
+\bool_new:N\l__indextra_first_item_bool
+\cs_new:Npn\__indextra_typeset_locations:
+ {
+ \bool_set_true:N\l__indextra_first_item_bool
+ \seq_map_inline:Nn\l__indextra_location_seq
+ {
+ \bool_if:nF{\l__indextra_first_item_bool}
+ { \tl_use:N\l__indextra_separator_loc_loc_tl }
+ \__indextra_typeset_aux_location:n{##1}
+ \bool_set_false:N\l__indextra_first_item_bool
+ }
+ }
+\cs_new:Npn\__indextra_typeset_first_location:
+ {
+ \exp_args:Ne\__indextra_typeset_aux_location:n
+ {\seq_item:Nn\l__indextra_location_seq{1}}
+ }
+\cs_new:Npn\__indextra_is_nonrange_p:w #1--#2\q_stop
+ {
+ \tl_if_empty_p:n{#2}
+ }
+\cs_new:Npn\__indextra_typeset_ist_location:n #1
+ {
+ \tl_if_head_eq_catcode:nNTF{#1}\prg_do_nothing:
+ {
+ \__indextra_typeset_ist_encap_page_or_range:Nn #1
+ }
+ {
+ \__indextra_typeset_ist_encap_page_or_range:Nn \prg_do_nothing:{#1}
+ }
+ }
+\cs_new:Npn\__indextra_typeset_ist_encap_page_or_range:Nn #1#2
+ {
+ \bool_if:nTF{\__indextra_is_nonrange_p:w #2--\q_stop}
+ {
+ \indextrapage{#1}{#2}
+ }
+ {
+ \__indextra_typeset_ist_encap_range:w#1\q_mark #2\q_stop
+ }
+ }
+\cs_new:Npn\__indextra_typeset_ist_encap_range:w #1\q_mark #2--#3\q_stop
+ {
+ \indextrarange{#1}{#2}{#3}
+ }
+\cs_new:Npn\__indextra_typeset_xdy_location:n #1
+ {
+ \bool_if:nTF{\__indextra_is_nonrange_p:w #1--\q_stop}
+ {
+ \tl_if_head_eq_catcode:nNTF{#1}\prg_do_nothing:
+ {
+ \indextrapage #1
+ }
+ {
+ \indextrapage \prg_do_nothing:{#1}
+ }
+ }
+ {
+ \__indextra_typeset_xdy_range:w #1\q_stop
+ }
+ }
+\cs_new:Npn\__indextra_typeset_xdy_range:w #1--#2\q_stop
+ {
+ \tl_if_head_eq_catcode:nNTF{#1}\prg_do_nothing:
+ {
+ \__indextra_typeset_xdy_encap_range:NnNn #1#2
+ }
+ {
+ \indextrarange\prg_do_nothing:{#1}{#2}
+ }
+ }
+\cs_new:Npn\__indextra_typeset_xdy_encap_range:NnNn #1#2#3#4
+ {
+ \indextrarange{#1}{#2}{#4}
+ }
+\cs_new:Npn\__indextra_page_basic:nn #1#2
+ {
+ #1{#2}
+ }
+\cs_new:Npn\__indextra_range_basic:nnn #1#2#3
+ {
+ #1{#2}--#1{#3}
+ }
+\cs_new:Npn\__indextra_page_hyperref:nn #1#2
+ {
+ #1{\hyperpage{#2}}
+ }
+\cs_new:Npn\__indextra_range_hyperref:nnn #1#2#3
+ {
+ #1{\hyperpage{#2}}--#1{\hyperpage{#3}}
+ }
+\cs_set_eq:NN\indextrapage\__indextra_page_basic:nn
+\cs_set_eq:NN\indextrarange\__indextra_range_basic:nnn
+\cs_new:Npn\__indextra_make_continuation:n #1
+ {
+ \int_step_inline:nnn{0}{#1}{
+ \group_begin:
+ \__indextra_set_style:n{##1}
+ \leavevmode\strut
+ \indextramakecontinuation{##1}{\tl_use:c{l__indextra_saved_keyword_##1}}
+ \strut\par
+ \group_end:
+ }
+ }
+\cs_new:Npn\indextramakecontinuation #1#2
+ {
+ #2~(cont.)
+ }
+\mark_new_class:n{indextra}
+\cs_new:Npn\__indextra_mark_insert:
+ {
+ \mark_insert:nn{indextra}{\tl_use:c{l__indextra_saved_keyword_0}}
+ }
+\cs_new:Npn\indextramakemark #1
+ {
+ #1
+ }
+\cs_new:Npn\indextrafirstmark
+ {
+ \indextramakemark{ \mark_use_first:nn{page}{indextra} }
+ }
+\cs_new:Npn\indextralastmark
+ {
+ \indextramakemark{ \mark_use_last:nn{page}{indextra} }
+ }
+\box_new:N\l__indextra_buffer_box
+\cs_new:Npn\__indextra_typeset_buffer:
+ {
+ \__indextra_mark_insert:
+ \dim_compare:nNnT
+ {\g__indextra_remaining_space_dim}
+ <
+ {\box_ht:N\l__indextra_buffer_box+\box_dp:N\l__indextra_buffer_box}
+ {
+ \dim_set:Nn
+ \l_tmpa_dim{\g__indextra_remaining_space_dim-.3\baselineskip}
+ \vbox_set_split_to_ht:NNn
+ \l_tmpa_box\l__indextra_buffer_box{\l_tmpa_dim}
+ \vbox_set:Nn
+ \l_tmpa_box{\vbox_unpack_drop:N\l_tmpa_box}
+ \dim_gset:Nn\g__indextra_remaining_space_dim
+ {
+ \g__indextra_remaining_space_dim
+ -\box_ht:N\l_tmpa_box
+ -\box_dp:N\l_tmpa_box
+ }
+ \vbox_unpack_drop:N\l_tmpa_box
+ \__indextra_vbox_prepend:Nn
+ \l__indextra_buffer_box
+ {\__indextra_make_continuation:n{\l__indextra_level_int}}
+ \__indextra_new_column:
+ \__indextra_typeset_buffer:
+ }
+ {
+ \dim_gset:Nn\g__indextra_remaining_space_dim
+ {
+ \g__indextra_remaining_space_dim
+ -\box_ht:N\l__indextra_buffer_box
+ -\box_dp:N\l__indextra_buffer_box
+ }
+ \vbox_unpack_drop:N\l__indextra_buffer_box
+ }
+ }
+\cs_new:Npn\__indextra_vbox_prepend:Nn #1#2
+{
+ \vbox_set:Nn #1{
+ \vbox{#2}
+ \vbox_unpack_drop:N #1
+ }
+}
Property changes on: branches/branch2024.final/Master/texmf-dist/tex/latex/indextra/indextra.sty
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: branches/branch2024.final/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
===================================================================
--- branches/branch2024.final/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc 2025-02-27 20:15:24 UTC (rev 74327)
+++ branches/branch2024.final/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc 2025-02-27 20:15:53 UTC (rev 74328)
@@ -739,6 +739,7 @@
depend import
depend incgraph
depend indextools
+depend indextra
depend inline-images
depend inlinedef
depend inlinegraphicx
Added: branches/branch2024.final/Master/tlpkg/tlpsrc/indextra.tlpsrc
===================================================================
More information about the tex-live-commits
mailing list.