% \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