summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/forest/forest-index.dtx
blob: 1db075d33df2abd959c25619488d18fb9a3bb3fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
% \CheckSum{755}
% \iffalse meta-comment
% forest-index.dtx
%% `forest-index' is an indexing system for the documentation of package `forest', using the package itself.
%%
%% Copyright (c) 2016 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