diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /graphics/pgf/contrib/forest/forest-index.dtx |
Initial commit
Diffstat (limited to 'graphics/pgf/contrib/forest/forest-index.dtx')
-rw-r--r-- | graphics/pgf/contrib/forest/forest-index.dtx | 911 |
1 files changed, 911 insertions, 0 deletions
diff --git a/graphics/pgf/contrib/forest/forest-index.dtx b/graphics/pgf/contrib/forest/forest-index.dtx new file mode 100644 index 0000000000..df2979690a --- /dev/null +++ b/graphics/pgf/contrib/forest/forest-index.dtx @@ -0,0 +1,911 @@ +% \CheckSum{755} +% \iffalse meta-comment +% forest-index.dtx +%% `forest-index' is an indexing system for the documentation of package +%% `forest', using the package itself. (The derived `forest-index.sty' is not +%% needed to use the package.) +%% +%% Copyright (c) 2012-2017 Saso Zivanovic +%% (Sa\v{s}o \v{Z}ivanovi\'{c}) +%% saso.zivanovic@guest.arnes.si +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3 +%% 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.3 or later is part of all distributions of LaTeX +%% version 2005/12/01 or later. +%% +%% This work has the LPPL maintenance status `author-maintained'. +%% +%% This file is a part of package `forest'. For the list of files +%% constituting the package see main source file of the package, +%% `forest.dtx', or the derived `forest.sty'. +%% +% \fi +% +% \newcommand\entry[1]{{``#1''}} +% +% \subsection{\protect{\texttt{forest-index}}} +% \label{sec:forest-index} +% +% The indexing system used to document the \foRest; package uses the +% package itself quite heavily. While this might be a bit surprising +% at first sight, as indexing draws no trees, the indexing package +% illustrates the usage of some of the more exotic features and +% usage-cases of the \foRest; package, which is why its source is +% included in this documentation.\footnote{Indexing with this package +% makes the compilation very slow, so I cannot whole-heartedly +% recommend it, but I still hope that it will make a useful example.} +% +% This package has three main functions: +% \begin{itemize} +% \item It is possible to index subentries using a \emph{short form} +% of their index key, i.e.\ without referring to their ancestor +% entries. For example, instead of writing |\index{option>content}| +% one can simply write |\index{content}|. (Obviously, the subentry +% must \entry{content} be defined as belonging to entry +% \entry{option} first. This is done using +% |\indexdef{option>content}|.) This works for all keys which are a +% subentry of a single entry. +% \item All subentries are automatically entered as main entries as +% well, with a qualificator of which entry they belong to. So, +% |\index{option>content}| produces two index entries: entry +% \entry{option} with subentry \entry{content} and entry +% \entry{content \scriptsize option}. This works for an arbitrary +% number of subentry levels. +% \item Entries can be given options that format the appearance of the +% entry and/or its descendants in both text and index. (Entries that +% format the appearance of their descendants are called categories +% below.) +% \item If |hyperref| package is loaded, the following hyperlinks are +% created besides the standard ones linking the page numbers in +% index to text: +% \begin{enumerate*}[(i)] +% \item entries in text link to the definition in text, +% \item definitions in the text link to the index entry, +% \item categories in index are cross-linked. +% \end{enumerate*} +% +% \end{itemize} +% +% The \foRest; package mainly enters the picture with respect to the +% entry formatting. A simple (narrow) tree is built containing an entry +% and all its ancestors. Formatting instructions are then processed +% using \foRest;'s option processing mechanisms. +% +% Finally, note that this package might change without retaining +% backwards compatibility, and that changes of this package will not +% be entered into the changelog. +% +% Identification. +% \begin{macrocode} +\ProvidesPackage{forest-index} +\RequirePackage{forest} +% \end{macrocode} +% Remember the original \LaTeX's |\index| command. +% \begin{macrocode} +\let\forestindex@LaTeX@index\index +% \end{macrocode} +% +% \subsubsection*{The user interface macros} +% +% \DescribeMacro{\index} is the general purpose macro. +% \DescribeMacro{\indexdef} and \DescribeMacro{\indexex} are +% shorthands for indexing definitions and +% examples. \DescribeMacro{\indexitem} is a combination of |\indexdef| +% and the |\item| of the |lstdoc| package. It automatically indexes +% the command being documented. \DescribeMacro{\indexset} neither +% typesets or indexes the entry, but only configures it; it is usually +% used to configure categories. All these macros parse their +% arguments using |xparse|. The arguments, listed in the reverse +% order: +% \begin{itemize} +% \item The final argument, which is the only mandatory argument, is a +% comma-separated list of index keys. +% \item The boolean switch |>| just before the mandatory argument +% signals that the keys are given in the full form. Otherwise, keys +% without a level separator are considered short. +% \item Indexing options are given by the |[|optional |]| argument. +% \item The first |(|optional|)| argument of: +% \begin{compactitem} +% \item |\indexitem|: specifies the default value of the command. +% \item |\index|: is used to +% provide ``early'' options. +% \end{compactitem} +% \end{itemize} +% +% Among the options of these commands, three keylists are of special +% importance: |index_key_format|, |index_form_format| and +% |print_format|. These hold instructions on how to format the index +% key, the form of the entry in the index and the form of the entry in +% the main text. They work by modifying the contents of an +% \indexex{autowrapped toks} register |result|. +% +% An example: how macros are indexed in this documentation. Style +% |macro| defined below does everything needed to format a macro name: +% it detokenizes the given name (in case the name contains some funny +% characters), prefixes the backslash, wraps in in the typewriter +% font, adds color and hyperlink (the final two styles are defined in +% below this package). Note the usage of |\protect|: it is needed +% because we want to use these styles to format entries not just in +% the main next, but also in the index. +% \lstinputregion{forest-doc.tex}{index_macro_style} Then, we +% configure the main level entry \entry{macro}: the child of this +% entry will be formatted (both in index and in the main text) using +% the previously defined style. +% \lstinputregion{forest-doc.tex}{index_macro_category} Usage is then +% simple: we write |\indexex{macro>forestoption}| (or simply +% |\indexex{forestoption}| to get \indexex{forestoption}. +% +% \begin{macrocode} +\DeclareDocumentCommand\indexdef{O{} t> m}{% + \IfBooleanTF{#2} + {\let\forestindex@resolvekey\forestindex@resolvekey@long} + {\let\forestindex@resolvekey\forestindex@resolvekey@shortorlong}% + \forestindex@index{definition}{#1}{#3}} +\DeclareDocumentCommand\indexex{O{} t> m}{% + \IfBooleanTF{#2} + {\let\forestindex@resolvekey\forestindex@resolvekey@long} + {\let\forestindex@resolvekey\forestindex@resolvekey@shortorlong}% + \forestindex@index{example}{#1}{#3}} +% \DeclareDocumentCommand\indexitem{D(){} O{} t> m}{% +% \IfBooleanTF{#3} +% {\let\forestindex@resolvekey\forestindex@resolvekey@long} +% {\let\forestindex@resolvekey\forestindex@resolvekey@shortorlong}% +% \forestindex@index{definition}{default={#1},print format=item,#2}{#4}} +\DeclareDocumentCommand\indexitem{D(){} O{} t> m}{% + \let\forestindex@resolvekey\forestindex@resolvekey@long + \forestindex@index{definition}{default={#1},#2,print format+=item}{#4}} +\DeclareDocumentCommand\indexset{O{} t> m}{% + \IfBooleanTF{#2} + {\let\forestindex@resolvekey\forestindex@resolvekey@long} + {\let\forestindex@resolvekey\forestindex@resolvekey@shortorlong}% + \forestindex@index{not print,not index,definition}{set={#1}}{#3}} +\DeclareDocumentCommand\index{D(){} O{} t> m}{% + \IfBooleanTF{#3} + {\let\forestindex@resolvekey\forestindex@resolvekey@long} + {\let\forestindex@resolvekey\forestindex@resolvekey@shortorlong}% + \forestindex@index{#1}{#2}{#4}% +} +% \end{macrocode} +% All UI macros call this macro. +% \begin{arguments} +% \item early option keylist +% \item late option keylist +% \item a comma-sep list of forest index key (full or short form). A +% key can be given an argument using |key=argument| syntax. How the +% argument is used is up to the user. For example, the +% \entry{environment} entry of the \foRest; documentation uses it to +% typeset the contents of the environment: +% \lstinputregion{forest-doc.tex}{forest_environment_doc} +% \end{arguments} +% \begin{macrocode} +\def\forestindex@index#1#2#3{% +% \end{macrocode} +% Partition the index keylist into single keys. And put it all in a group: the +% persistent stuff is saved globally. +% \begin{macrocode} + {\forcsvlist{\forestindex@forkey{#1}{#2}}{#3}}% +} +\def\forestindex@forkey#1#2#3{% +% \end{macrocode} +% Short-key resolution. The result is stored into |\forestindex@fullkey|. +% \begin{macrocode} + \forestindex@resolvekey{#3}% +% \end{macrocode} +% Manipulate arguments a bit, so that we can use our quick-and-dirty one-arg +% memoization. +% \begin{macrocode} + %\forestset{@index/.process={__o}{#1}{#2}{\forestindex@fullkey}} + \edef\forest@marshal{% + \noexpand\forestindex@index@{% + {\unexpanded{#1}}% + {\unexpanded{#2}}% + {\expandonce{\forestindex@fullkey}}% + }% + }\forest@marshal +} +% \end{macrocode} +% Call the central processing command, style |@index|. See how +% \indexex{handler>process} is used to expand (once) the last argument. +% \begin{macrocode} +\def\forestindex@index@#1{\forestset{@index/.process={__o}#1}} +\forestset{ +% \end{macrocode} +% \subsubsection*{Declarations} +% +% Should we print and/or index the entry? For example, +% |\index[not_print]{...}| will index silently (as \LaTeX's |\index| +% command does). +% \begin{macrocode} + declare boolean register=print, + declare boolean register=index, + declare boolean register=short, +% \end{macrocode} +% Options |name|, |content|, |key| and |argument| hold info about the +% current entry. We need to declare only the latter two, the former +% two we steal from \foRest;. +% \begin{macrocode} + declare toks={key}{}, + declare toks={argument}{}, +% \end{macrocode} +% These options will hold first the initial, and then the calculated +% values of the index key, index form and the form in text. When +% (late) options are executed, these options are initialized to the +% value of option |key|; it is safe to modify them at this point. +% Afterwards, they will be further processed by keylists +% |index_key_format|, |index_form_format| and |print_format|, +% respectively. +% \begin{macrocode} + declare toks={index key}{}, + declare toks={index form}{}, + declare toks={print form}{}, +% \end{macrocode} +% The customization of entries' appearance is done by specifying the +% following three keylists. The keylists work by modifying register +% |result|. +% \begin{macrocode} + declare keylist={index key format}{}, + declare keylist={index format}{}, + declare keylist={print format}{}, + declare autowrapped toks register=result, +% \end{macrocode} +% Some shorthands. +% \begin{macrocode} + format'/.style={print format'={#1}, index format'={#1}}, + format/.style={print format={#1}, index format={#1}}, + format+/.style={print format+={#1}, index format+={#1}}, + +format/.style={+print format={#1}, +index format={#1}}, + form/.style={print form={#1},index form={#1}}, + form+/.style={print form+={#1},index form+={#1}}, + +form/.style={+print form={#1},+index form={#1}}, +% \end{macrocode} +% Entry types are normal (default), definition, example. Only +% definitions are special, as their options are automatically saved. +% \begin{macrocode} + declare toks register=index entry type, + definition/.style={index entry type=definition}, + normal/.style={index entry type=normal}, + example/.style={index entry type=example}, + normal, +% \end{macrocode} +% This option is used internally to store the hyper ids. +% \begin{macrocode} + declare toks={index@hypertarget}{}, + every index begin/.style={}, + every index end/.style={}, +% \end{macrocode} +% Some formatting tools need to know whether we're typesetting text or +% index: this info is stored in the |stage| register.\indexex[margin]{declare toks register} +% \begin{macrocode} + declare toks register=stage, +% \end{macrocode} +% +% \subsubsection*{The central processing command} +% \begin{arguments} +% \item early option keylist (these are only used to define category +% ``@unknown'' at the end of this package) +% \item late option keylist +% \item index key (full form) +% \end{arguments} +% \begin{macrocode} + @index/.style n args={3}{ +% \end{macrocode} +% Set the defaults. +% \begin{macrocode} + print, index, index entry type=normal, set'={}, short, +% \end{macrocode} +% Create the tree structure: +% |[entry[subentry[subsubentry...]]]|. Three options of every node +% created: +% \begin{compactitem} +% \item |key| contains the key of the (sub)entry +% \item |name| contains the full path to the (sub)entry +% \item |arguments| contains the arguments given to the (sub)entry's key +% \item |content| contains the full key, with arguments for all but +% the most deeply embedded subentry +% \end{compactitem} +% \indexex{for step=\indexex{nodewalk}} is used because +% |create@subentry@node| walks down the created tree. At |if n=0| +% below, we're thus positioned at the lowest node.\indexex[margin]{step>nodewalk} +% \begin{macrocode} + for nodewalk={ +% \end{macrocode} +% The components of the full key are separated using \indexex{split}, +% with different keys being executed for the first component and the +% rest. +% \begin{macrocode} + split={#3}{>}{create@main@entry@node, create@subentry@node}, +% \end{macrocode} +% Remove the argument from the most deeply embedded subentry. +% \begin{macrocode} + if n=0{ + content/.option=key, + }{ + content/.process={OOw2} {!parent.content} {key} {##1>##2}, + } + }{}, + for root'={ +% \end{macrocode} +% Don't memoize if the key is of an unknown category. +% \begin{macrocode} + if strequal/.process={O}{!root.name}{@unknown}{TeX=\global\forest@memoizing@ok@false}{}, +% \end{macrocode} +% Option |print_form| is what will be typeset in the text. Option +% |index_key| is the key that will be used for sorting the +% index. Option |index_form| is what will be typeset in the index. All +% these are initialized to the |key|. See how +% \indexex{handler>option} is used to assign an option value to +% another option. +% \begin{macrocode} + for tree={ + print form/.option=key, + index key/.option=key, + index form/.option=key, + }, +% \end{macrocode} +% Below, \indexex{node key>on invalid} is set to \indexex{value of=on invalid>fake} at four points. +% This is so we won't get in trouble when |\indexset|ting the +% categories: when the category formatting code will try to step into +% the child, it will fail as the child does not exist when |\indexset| +% is called for the category; but we ignore the failure. +% +% Go to the the most deeply embedded subentry.\indexex[margin]{first leaf'} +% \begin{macrocode} + for first leaf'={ +% \end{macrocode} +% Execute every index options and the given early options. +% \begin{macrocode} + on invalid={fake}{ + every index begin, + #1, + }, +% \end{macrocode} +% Ancestors are walked in the \indexex{reverse} order (top down). At +% every node, the saved configuration is executed (if it exists). +% \begin{macrocode} + for reverse={current and ancestors}{on invalid={fake}{@@index/\forestoption{name}/.try}}, +% \end{macrocode} +% We don't execute the saved configuration for definitions, as +% definitions are where the configuration is set. +% \begin{macrocode} + if index entry type={definition}{}{% + on invalid={fake}{@@index/\forestoption{name}/.try}, + }, +% \end{macrocode} +% Execute late (well, normal) options. See the discussion about early +% options above. +% \begin{macrocode} + on invalid={fake}{ + #2, + every index end + }, +% \end{macrocode} +% Remember the given config for the rest of the document. +% \begin{macrocode} + if set={}{}{save@session}, +% \end{macrocode} +% If we're at a definition, save the config into the auxiliary file. +% \begin{macrocode} + if index entry type={definition}{save@foridx}{}, + }, + stage={}, +% \end{macrocode} +% Create hyperlink targets of the form |.entry.subentry.subsubentry...|. +% +% \FoRest; points: +% \begin{enumerate*}[(i)] +% \item the generic conditional \indexex{if}, +% \item handler \index{handler>process}, +% \end{enumerate*} +% \begin{macrocode} + if index={ + index@hypertarget/.process={OS_= ? l_ w2} + {index key} + {} + {}{.} + {##2##1}, + for descendants={ + index@hypertarget/.process={OO S _l1= ? w2 } + {!parent.index@hypertarget}{index key} + {} + {##1} % empty index key + {##1.##2} % otherwise + }, + }{}, +% \end{macrocode} +% Index. +% \begin{macrocode} + if index={ + begingroup, + stage=index, +% \end{macrocode} +% For each (sub)entry, format the |index_key| using the instructions +% in |index_key_format|. +% \begin{macrocode} + for tree={ + result/.option=index key, + process keylist'={index key format}{current}, + index key/.register=result, + }, +% \end{macrocode} +% For each (sub)entry, format the |index_form| using the instructions +% in |index_form_format|. +% \begin{macrocode} + for tree={ + result/.option=index form, + process keylist'={index format}{current}, + index form/.register=result, + }, +% \end{macrocode} +% Create an index entry for all nodes where |index_form| is non-empty. +% \begin{macrocode} + where index form={}{}{ +% \end{macrocode} +% All the ancestor nodes with an non-empty |index_form| will be +% appended (in script size, as a hyperlink) to the |index_form| of the +% current node. +% \begin{macrocode} + if n=0{ + temptoksb={}, + }{ + temptoksc={}, + for ancestors={ + if index form={}{}{ + temptoksb+/.expanded={\forestregister{temptoksc}% + \noexpand\protect\noexpand\hyperlinknocolor{% + \forestoption{index@hypertarget}}{\forestoption{index form}}}, + temptoksc={,\space}, + }, + }, + if temptoksb={}{}{ + +temptoksb={\protect\space\begingroup\protect\scriptsize}, + temptoksb+={\endgroup}, + }, + }, + temptoksa={}, + result'={}, + if n children=0{tempboola}{not tempboola}, + where index form={}{}{ +% \end{macrocode} +% Create the hypertarget that the definitions in text and other index entries +% will point to. +% \begin{macrocode} + temptoksd/.expanded={\noexpand\protect\noexpand\hypertarget{% + \forestoption{index@hypertarget}}{}}, +% \end{macrocode} +% Add the (inner) current node to the index entry of the (outer) current node. +% \begin{macrocode} + result+/.expanded={% + \forestregister{temptoksa}% + \forestoption{index key}% + =\forestoption{index form}% + \forestregister{temptoksd}% + \forestregister{temptoksb}% + }, + temptoksa={>}, + temptoksb={}, + }, +% \end{macrocode} +% Do the actual indexing. +% \begin{macrocode} + result+/.expanded={|indexpagenumber\forestregister{index entry type}}, + TeX and memoize/.expanded={\noexpand\forestindex@LaTeX@index{\forestregister{result}}}, + }, + endgroup + }{}, + if print={ + begingroup, + stage=print, +% \end{macrocode} +% For each (sub)entry, format the |print_form| using the instructions +% in |print_form_format|. +% \begin{macrocode} + for tree={ + result/.option=print form, + process keylist'={print format}{current}, + print form/.register=result, + }, +% \end{macrocode} +% Typeset the entry in the text. +% \begin{macrocode} + for first leaf'={TeX and memoize/.expanded={\forestoption{print form}}}, + endgroup, + }{}, + } + }, +% \end{macrocode} +% Create the main entry node and set to be the root. +% \begin{macrocode} + create@main@entry@node/.style={% #1 = subentry + set root={[]}, + do dynamics, for root'={process delayed=tree}, + root', + setup@entry@node={#1} + }, +% \end{macrocode} +% Create a subentry node and move into it. +% \begin{macrocode} + create@subentry@node/.style={ + append={[]}, + do dynamics, for root'={process delayed=tree}, + n=1, + setup@entry@node={#1} + }, +% \end{macrocode} +% Parse \#1 into |key| and |argument|, and assign |name| and |content|. +% \begin{macrocode} + setup@entry@node/.style={ + options={ + split={#1}{=}{key,argument}, + if n=0{ + name'/.option=key, + content={#1}, + }{ + name'/.process={OOw2} {!parent.name} {key} {##1>##2}, + content/.process={Ow1} {!parent.content} {##1>#1}, + }, + } + }, +} +% \end{macrocode} +% \subsubsection*{Saving and loading the options} +% \begin{macrocode} +\forestset{ +% \end{macrocode} +% This register holds whatever we need to remember. +% \begin{macrocode} + declare keylist register=set, +% \end{macrocode} +% Besides storing the keylist in the register, also immediately +% execute it.\indexex[margin]{Autoforward register}. +% \begin{macrocode} + Autoforward register={set}{##1}, +% \end{macrocode} +% Remember things by saving them in a global style. +% \begin{macrocode} + save@session/.style={@@index/\forestoption{name}/.global style/.register=set}, +% \end{macrocode} +% Save thinks to the auxiliary file. +% \begin{macrocode} + save@foridx/.style={ +% \end{macrocode} +% Don't save entries of unknown category. +% \begin{macrocode} + if strequal/.process={O}{!root.name}{@unknown}{}{ +% \end{macrocode} +% Don't save if nothing is set. +% \begin{macrocode} + if set={}{}{ + TeX and memoize/.expanded={% + \noexpand\immediate\noexpand\write\noexpand\forestindex@out{% + \noexpand\string\noexpand\indexloadsettings\noexpand\unexpanded{{\forestoption{name}}{\forestregister{set}}}% + }% + }, + }, + }, +% \end{macrocode} +% Save the full form of the key in the auxiliary file. Obviously, do +% it only for subentries. The full form contains whatever arguments +% were given to the non-last component. +% \begin{macrocode} + if key/.process={O}{content} {} {% + if short={ + TeX and memoize/.expanded={% + \noexpand\immediate\noexpand\write\noexpand\forestindex@out{% + \noexpand\string\noexpand\indexdefineshortkey\noexpand\unexpanded{{\forestoption{key}}{\forestoption{content}}}% + }% + }% + }{} + } + } +} +% \end{macrocode} +% Load settings from the auxiliary file into the global style. Warn +% if anything was configured more than once (e.g.\ by |\indexdef|ing +% the same key twice). +% \begin{macrocode} +\def\indexloadsettings#1#2{% + \pgfkeysifdefined{/forest/@@index/#1/.@cmd}{% + \forestindex@loadsettings@warning{#1}% + }{}% + % #s in #2 are doubled; the following \def removes one layer of doubling + \def\forest@temp{#2}% + \forestset{@@index/#1/.global style/.expand once=\forest@temp}% +} +\def\forestindex@loadsettings@warning#1{% + \PackageWarning{forest-index}{Forest index key "#1" was configured more than once! + I'm using the last configuration.}% +} +% \end{macrocode} +% Load the full form of a short key from the auxiliary file. Out of +% kindness for the end user, remember all the full keys corresponding +% to a short key: this will make a more informative warning below. +% \begin{macrocode} +\def\indexdefineshortkey#1#2{% + \def\forestindex@temp@short{#1}% + \def\forestindex@temp@long{#2}% + \ifx\forestindex@temp@short\forestindex@temp@long + \else + \ifcsdef{index@long@#1}{% + \global\cslet{index@long@#1}\relax + \csgappto{index@alllong@#1}{,#2}% + }{% + \global\csgdef{index@long@#1}{#2}% + \global\csgdef{index@alllong@#1}{#2}% + }% + \fi +} +% \end{macrocode} +% \subsubsection*{Short key resolution} +% +% Nothing to do for a long key. +% \begin{macrocode} +\def\forestindex@resolvekey@long#1{\def\forestindex@fullkey{#1}} +% \end{macrocode} +% Decide whether a key is short or long based on the absence or +% presence of the level separator |>|. +% \begin{macrocode} +\def\forestindex@resolvekey@shortorlong#1{% + \pgfutil@in@>{#1}% + \ifpgfutil@in@ + \expandafter\def\expandafter\forestindex@fullkey + \else + \expandafter\forestindex@resolvekey@short + \fi + {#1}% +} +% \end{macrocode} +% Before resolving the short key, we need to split the user input into +% the key and the argument. The latter is then appended to the full +% key (which can, in principle, contain arguments for other components +% as well). +% \begin{macrocode} +\def\forestindex@resolvekey@short#1{% + \forestset{split={#1}{=}{index@resolveshortkey@key,index@resolveshortkey@arg}}% +} +\forestset{ + index@resolveshortkey@key/.code={% + \ifcsvoid{index@long@#1}{% + \forestindex@resolveshortkey@warning{#1}% + \def\forestindex@fullkey{@unknown>#1}% + }{% + \letcs\forestindex@fullkey{index@long@#1}% + }% + }, + index@resolveshortkey@arg/.code={% + \appto\forestindex@fullkey{=#1}% + }, +} +\def\forestindex@resolveshortkey@warning#1{% + \PackageWarning{forest-index}{Cannot resolve short forest index key "#1". + These are the definitions I found (from the previous run): + "\csuse{index@alllong@#1}"}% +} +% \end{macrocode} +% \subsubsection*{Formatting styles} +% +% Define default colors for index entry types and provide a style that +% typesets the entry in text (but not index) in the desired color. +% \begin{macrocode} +\forestset{ + normal color/.initial=blue, + definition color/.initial=red, + example color/.initial=darkgreen, + print in color/.style={if stage={print}{result/.expanded=\noexpand\protect\noexpand\textcolor{% + \pgfkeysvalueof{/forest/#1 color}}{\unexpanded{##1}}}{}}, + print in color/.default=\forestregister{index entry type}, +% \end{macrocode} +% Use this style in |..._format| keylists if you want the index +% entries to be hyperlinks to the definition, and the definition to be +% a hyperlink to the index. +% \begin{macrocode} + hyper/.style={ + if stage={index}{}{ + if index entry type={definition}{ + result/.expanded={\noexpand\hypertarget{\forestoption{name}}% + {\noexpand\hyperlink{\forestoption{index@hypertarget}}{\forestregister{result}}}} + }{ + result/.expanded=\noexpand\hyperlink{\forestoption{name}}{\forestregister{result}} + } + } + }, +} +% \end{macrocode} +% Color page numbers in the index, with or without |hyperref| package. +% \begin{macrocode} +\ifdef\hyperpage{% + \newcommand\indexpagenumbernormal[1]{{% + \hypersetup{linkcolor=\pgfkeysvalueof{/forest/normal color}}\hyperpage{#1}}} + \newcommand\indexpagenumberdefinition[1]{{% + \hypersetup{linkcolor=\pgfkeysvalueof{/forest/definition color}}\hyperpage{#1}}} + \newcommand\indexpagenumberexample[1]{{% + \hypersetup{linkcolor=\pgfkeysvalueof{/forest/example color}}\hyperpage{#1}}} +}{ + \newcommand\indexpagenumbernormal[1]{% + \textcolor{\pgfkeysvalueof{/forest/normal color}}{#1}} + \newcommand\indexpagenumberdefinition[1]{% + \textcolor{\pgfkeysvalueof{/forest/definition color}}{#1}} + \newcommand\indexpagenumberexample[1]{% + \textcolor{\pgfkeysvalueof{/forest/example color}}{#1}} +} +% \end{macrocode} +% Provide dummy |\hyper...| commands if |hyperref| is not loaded. +% \begin{macrocode} +\providecommand\hyperlink[2]{#2} +\providecommand\hypertarget[2]{#2} +\providecommand\hypersetup[1]{} +% \end{macrocode} +% This is used by entry qualifiers: we want them to be hyperlinks, but black. +% \begin{macrocode} +\newcommand\hyperlinknocolor[2]{{\hypersetup{linkcolor=black}\hyperlink{#1}{#2}}} +% \end{macrocode} +% +% Use style |item| to have the index entry (in text) function as the +% |\item| of a |lstdoc|'s |syntax| environment. +% \begin{macrocode} +\forestset{ + declare toks register=default, + default={}, + item/.style={ + result/.process= {_RORw4} + {} {default} {!parent.print form} {result} + {\item[,##2,##3]{##4}}, + }, +} +% \end{macrocode} +% +% \subsubsection*{Utilities} +% +% We will need a global version of several |pgfkeys| commands. +% \begin{macrocode} +\pgfkeys{/handlers/.global style/.code=\pgfkeys{\pgfkeyscurrentpath/.global code=\pgfkeysalso{#1}}} +\pgfkeysdef{/handlers/.global code}{\pgfkeysglobaldef{\pgfkeyscurrentpath}{#1}} +\long\def\pgfkeysglobaldef#1#2{% + \long\def\pgfkeys@temp##1\pgfeov{#2}% + \pgfkeysgloballet{#1/.@cmd}{\pgfkeys@temp}% + \pgfkeysglobalsetvalue{#1/.@body}{#2}% +} +\def\pgfkeysgloballet#1#2{% + \expandafter\global\expandafter\let\csname pgfk@#1\endcsname#2% +} +\long\def\pgfkeysglobalsetvalue#1#2{% + \pgfkeys@temptoks{#2}\expandafter\xdef\csname pgfk@#1\endcsname{\the\pgfkeys@temptoks}% +} +\forestset{ + % unlike pgfmath function strequal, |if strequal| does not expand the compared args! + if strequal/.code n args={4}{\ifstrequal{#1}{#2}{\pgfkeysalso{#3}}{\pgfkeysalso{#4}}}, +} +% \end{macrocode} +% Begin and end group, \foRest;-style: +% \begin{macrocode} +\forestset{ + begingroup/.code={\begingroup}, + endgroup/.code={\endgroup}, +} +% \end{macrocode} +% +% \subsubsection{Memoize} +% +% Quick and dirty memoization. Single argument macros only. Does not support nesting. +% +% \begin{macrocode} +\newtoks\forest@memo@key +\newtoks\forest@memo +\newif\ifforest@memoizing@now@ +\newif\ifforest@memoizing@ok@ +\newif\ifforest@execandmemoize@ +\def\forest@memoize#1{% #1 = \cs + \cslet{forest@memo@orig@\string#1}#1% + \def#1##1{% + \ifforest@memoizing@now@ + \forest@globalsaveandrestoreifcs{forest@execandmemoize@}{% + \global\forest@execandmemoize@false + \csname forest@memo@orig@\string#1\endcsname{##1}% + }% + \else + \expandafter\global\expandafter\forest@memo@key\expandafter{\detokenize{forest@memo@#1{##1}}}% + \ifcsname\the\forest@memo@key\endcsname + \@escapeifif{\csname\the\forest@memo@key\endcsname}% + \else + \@escapeifif{% + \global\forest@memo{}% + \global\forest@memoizing@ok@true + \global\forest@memoizing@now@true + \global\forest@execandmemoize@true + \csname forest@memo@orig@\string#1\endcsname{##1}% + \global\forest@execandmemoize@false + \global\forest@memoizing@now@false + \ifforest@memoizing@ok@ + \csxdef{\the\forest@memo@key}{\the\forest@memo}% + \immediate\write\forest@memo@out{% + \noexpand\forest@memo@load{\the\forest@memo@key}{\the\forest@memo}% + }% + \fi + }% + \fi + \fi + }% +} +\def\forest@memo@load#1#2{% +% \end{macrocode} +% The following two |\def|s remove one level of hash-doubling from the +% arguments, introduced by |\write|. +% \begin{macrocode} + \def\forest@temp@key{#1}% + \def\forest@temp@value{#2}% + \csxdef{\detokenize\expandafter{\forest@temp@key}}{\expandonce\forest@temp@value}% + \immediate\write\forest@memo@out{% + \noexpand\forest@memo@load{\detokenize\expandafter{\forest@temp@key}}{\detokenize\expandafter{\forest@temp@value}}% + }% +} +\forestset{ + TeX and memoize/.code={\forest@execandmemoize{#1}}, +} +\def\forest@execandmemoize#1{% + \ifforest@execandmemoize@ + \let\forest@memo@next\forest@execandmemoize@ + \else + \let\forest@memo@next\@gobble + \fi + \forest@memo@next{#1}% + #1% +} +\def\forest@execandmemoize@#1{% + \gapptotoks\forest@memo{#1}% +} +\def\forest@memo@filename{\jobname.memo} +\newwrite\forest@memo@out +\immediate\openout\forest@memo@out=\forest@memo@filename.tmp +\IfFileExists{\forest@memo@filename}{% + \input\forest@memo@filename\relax +}{}% +\AtEndDocument{% + \immediate\closeout\forest@memo@out + \forest@file@copy{\forest@memo@filename.tmp}{\forest@memo@filename}% +} +% \end{macrocode} +% Commenting the following line turns off memoization. +% \begin{macrocode} +\forest@memoize\forestindex@index@ +% \end{macrocode} +% +% \subsubsection*{Initialize} +% +% Declare category ``@unknown''. +% \begin{macrocode} +\index(not print,not index)[% + set={ + index key=unknown, + form={\textbf{unknown!!}}, + for first={format={result/.expanded=\noexpand\textbf{\forestregister{result}??}}} + }, + ]>{@unknown} +% \end{macrocode} +% Load the auxiliary file made in the previous compilation, and open +% it for writing to save data from this compilation. +% \begin{macrocode} +\def\forestindex@filename{\jobname.foridx} +\IfFileExists{\forestindex@filename}{% + \input\forestindex@filename\relax +}{}% +\newwrite\forestindex@out +\immediate\openout\forestindex@out=\forestindex@filename.tmp +\AtEndDocument{% + \immediate\closeout\forestindex@out + \forest@file@copy{\forestindex@filename.tmp}{\forestindex@filename}% +} +\endinput +% \end{macrocode} +% +%%% \iffalse +%%% Local Variables: +%%% mode: doctex +%%% TeX-master: "forest-doc" +%%% TeX-command-default: "sty" +%%% End: +%%% \fi |