├── .gitignore ├── LICENCE ├── Makefile ├── README ├── TeXSE-compile.sh ├── TeXSE-diff.sh ├── TeXSE-extract.py ├── TeXSE-test.sh ├── forest-compat.sty ├── forest-doc.ins ├── forest-doc.ist ├── forest-doc.sty ├── forest-doc.tex ├── forest-index.dtx ├── forest-libs.dtx ├── forest-test.tex ├── forest.dtx ├── forest.ins ├── readme.tex ├── tex.bib └── version.tex /.gitignore: -------------------------------------------------------------------------------- 1 | *.aux 2 | *.log 3 | *.dvi 4 | *.pdf 5 | *.ps 6 | *.glo 7 | *.idx 8 | *.toc 9 | *~ 10 | *.synctex.gz 11 | \#*\# 12 | auto 13 | forest.sty 14 | *.tmp 15 | *.out 16 | _region_* 17 | old-tests 18 | temp 19 | *.profiler.*.dat 20 | test* 21 | explore* 22 | *.ind 23 | *.ilg 24 | *.for 25 | *.auxlock 26 | *.for.dir 27 | *.aux.copy 28 | *.bbl 29 | *.blg 30 | forest.tex 31 | CHECKSUM 32 | VERSION 33 | versions 34 | forest-externalize.tex 35 | *.success 36 | *.foridx 37 | *.checksum 38 | tex.stackexchange.com/* -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | The LaTeX Project Public License 2 | =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 3 | 4 | LPPL Version 1.3c 2008-05-04 5 | 6 | Copyright 1999 2002-2008 LaTeX3 Project 7 | Everyone is allowed to distribute verbatim copies of this 8 | license document, but modification of it is not allowed. 9 | 10 | 11 | PREAMBLE 12 | ======== 13 | 14 | The LaTeX Project Public License (LPPL) is the primary license under 15 | which the LaTeX kernel and the base LaTeX packages are distributed. 16 | 17 | You may use this license for any work of which you hold the copyright 18 | and which you wish to distribute. This license may be particularly 19 | suitable if your work is TeX-related (such as a LaTeX package), but 20 | it is written in such a way that you can use it even if your work is 21 | unrelated to TeX. 22 | 23 | The section `WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE', 24 | below, gives instructions, examples, and recommendations for authors 25 | who are considering distributing their works under this license. 26 | 27 | This license gives conditions under which a work may be distributed 28 | and modified, as well as conditions under which modified versions of 29 | that work may be distributed. 30 | 31 | We, the LaTeX3 Project, believe that the conditions below give you 32 | the freedom to make and distribute modified versions of your work 33 | that conform with whatever technical specifications you wish while 34 | maintaining the availability, integrity, and reliability of 35 | that work. If you do not see how to achieve your goal while 36 | meeting these conditions, then read the document `cfgguide.tex' 37 | and `modguide.tex' in the base LaTeX distribution for suggestions. 38 | 39 | 40 | DEFINITIONS 41 | =========== 42 | 43 | In this license document the following terms are used: 44 | 45 | `Work' 46 | Any work being distributed under this License. 47 | 48 | `Derived Work' 49 | Any work that under any applicable law is derived from the Work. 50 | 51 | `Modification' 52 | Any procedure that produces a Derived Work under any applicable 53 | law -- for example, the production of a file containing an 54 | original file associated with the Work or a significant portion of 55 | such a file, either verbatim or with modifications and/or 56 | translated into another language. 57 | 58 | `Modify' 59 | To apply any procedure that produces a Derived Work under any 60 | applicable law. 61 | 62 | `Distribution' 63 | Making copies of the Work available from one person to another, in 64 | whole or in part. Distribution includes (but is not limited to) 65 | making any electronic components of the Work accessible by 66 | file transfer protocols such as FTP or HTTP or by shared file 67 | systems such as Sun's Network File System (NFS). 68 | 69 | `Compiled Work' 70 | A version of the Work that has been processed into a form where it 71 | is directly usable on a computer system. This processing may 72 | include using installation facilities provided by the Work, 73 | transformations of the Work, copying of components of the Work, or 74 | other activities. Note that modification of any installation 75 | facilities provided by the Work constitutes modification of the Work. 76 | 77 | `Current Maintainer' 78 | A person or persons nominated as such within the Work. If there is 79 | no such explicit nomination then it is the `Copyright Holder' under 80 | any applicable law. 81 | 82 | `Base Interpreter' 83 | A program or process that is normally needed for running or 84 | interpreting a part or the whole of the Work. 85 | 86 | A Base Interpreter may depend on external components but these 87 | are not considered part of the Base Interpreter provided that each 88 | external component clearly identifies itself whenever it is used 89 | interactively. Unless explicitly specified when applying the 90 | license to the Work, the only applicable Base Interpreter is a 91 | `LaTeX-Format' or in the case of files belonging to the 92 | `LaTeX-format' a program implementing the `TeX language'. 93 | 94 | 95 | 96 | CONDITIONS ON DISTRIBUTION AND MODIFICATION 97 | =========================================== 98 | 99 | 1. Activities other than distribution and/or modification of the Work 100 | are not covered by this license; they are outside its scope. In 101 | particular, the act of running the Work is not restricted and no 102 | requirements are made concerning any offers of support for the Work. 103 | 104 | 2. You may distribute a complete, unmodified copy of the Work as you 105 | received it. Distribution of only part of the Work is considered 106 | modification of the Work, and no right to distribute such a Derived 107 | Work may be assumed under the terms of this clause. 108 | 109 | 3. You may distribute a Compiled Work that has been generated from a 110 | complete, unmodified copy of the Work as distributed under Clause 2 111 | above, as long as that Compiled Work is distributed in such a way that 112 | the recipients may install the Compiled Work on their system exactly 113 | as it would have been installed if they generated a Compiled Work 114 | directly from the Work. 115 | 116 | 4. If you are the Current Maintainer of the Work, you may, without 117 | restriction, modify the Work, thus creating a Derived Work. You may 118 | also distribute the Derived Work without restriction, including 119 | Compiled Works generated from the Derived Work. Derived Works 120 | distributed in this manner by the Current Maintainer are considered to 121 | be updated versions of the Work. 122 | 123 | 5. If you are not the Current Maintainer of the Work, you may modify 124 | your copy of the Work, thus creating a Derived Work based on the Work, 125 | and compile this Derived Work, thus creating a Compiled Work based on 126 | the Derived Work. 127 | 128 | 6. If you are not the Current Maintainer of the Work, you may 129 | distribute a Derived Work provided the following conditions are met 130 | for every component of the Work unless that component clearly states 131 | in the copyright notice that it is exempt from that condition. Only 132 | the Current Maintainer is allowed to add such statements of exemption 133 | to a component of the Work. 134 | 135 | a. If a component of this Derived Work can be a direct replacement 136 | for a component of the Work when that component is used with the 137 | Base Interpreter, then, wherever this component of the Work 138 | identifies itself to the user when used interactively with that 139 | Base Interpreter, the replacement component of this Derived Work 140 | clearly and unambiguously identifies itself as a modified version 141 | of this component to the user when used interactively with that 142 | Base Interpreter. 143 | 144 | b. Every component of the Derived Work contains prominent notices 145 | detailing the nature of the changes to that component, or a 146 | prominent reference to another file that is distributed as part 147 | of the Derived Work and that contains a complete and accurate log 148 | of the changes. 149 | 150 | c. No information in the Derived Work implies that any persons, 151 | including (but not limited to) the authors of the original version 152 | of the Work, provide any support, including (but not limited to) 153 | the reporting and handling of errors, to recipients of the 154 | Derived Work unless those persons have stated explicitly that 155 | they do provide such support for the Derived Work. 156 | 157 | d. You distribute at least one of the following with the Derived Work: 158 | 159 | 1. A complete, unmodified copy of the Work; 160 | if your distribution of a modified component is made by 161 | offering access to copy the modified component from a 162 | designated place, then offering equivalent access to copy 163 | the Work from the same or some similar place meets this 164 | condition, even though third parties are not compelled to 165 | copy the Work along with the modified component; 166 | 167 | 2. Information that is sufficient to obtain a complete, 168 | unmodified copy of the Work. 169 | 170 | 7. If you are not the Current Maintainer of the Work, you may 171 | distribute a Compiled Work generated from a Derived Work, as long as 172 | the Derived Work is distributed to all recipients of the Compiled 173 | Work, and as long as the conditions of Clause 6, above, are met with 174 | regard to the Derived Work. 175 | 176 | 8. The conditions above are not intended to prohibit, and hence do not 177 | apply to, the modification, by any method, of any component so that it 178 | becomes identical to an updated version of that component of the Work as 179 | it is distributed by the Current Maintainer under Clause 4, above. 180 | 181 | 9. Distribution of the Work or any Derived Work in an alternative 182 | format, where the Work or that Derived Work (in whole or in part) is 183 | then produced by applying some process to that format, does not relax or 184 | nullify any sections of this license as they pertain to the results of 185 | applying that process. 186 | 187 | 10. a. A Derived Work may be distributed under a different license 188 | provided that license itself honors the conditions listed in 189 | Clause 6 above, in regard to the Work, though it does not have 190 | to honor the rest of the conditions in this license. 191 | 192 | b. If a Derived Work is distributed under a different license, that 193 | Derived Work must provide sufficient documentation as part of 194 | itself to allow each recipient of that Derived Work to honor the 195 | restrictions in Clause 6 above, concerning changes from the Work. 196 | 197 | 11. This license places no restrictions on works that are unrelated to 198 | the Work, nor does this license place any restrictions on aggregating 199 | such works with the Work by any means. 200 | 201 | 12. Nothing in this license is intended to, or may be used to, prevent 202 | complete compliance by all parties with all applicable laws. 203 | 204 | 205 | NO WARRANTY 206 | =========== 207 | 208 | There is no warranty for the Work. Except when otherwise stated in 209 | writing, the Copyright Holder provides the Work `as is', without 210 | warranty of any kind, either expressed or implied, including, but not 211 | limited to, the implied warranties of merchantability and fitness for a 212 | particular purpose. The entire risk as to the quality and performance 213 | of the Work is with you. Should the Work prove defective, you assume 214 | the cost of all necessary servicing, repair, or correction. 215 | 216 | In no event unless required by applicable law or agreed to in writing 217 | will The Copyright Holder, or any author named in the components of the 218 | Work, or any other party who may distribute and/or modify the Work as 219 | permitted above, be liable to you for damages, including any general, 220 | special, incidental or consequential damages arising out of any use of 221 | the Work or out of inability to use the Work (including, but not limited 222 | to, loss of data, data being rendered inaccurate, or losses sustained by 223 | anyone as a result of any failure of the Work to operate with any other 224 | programs), even if the Copyright Holder or said author or said other 225 | party has been advised of the possibility of such damages. 226 | 227 | 228 | MAINTENANCE OF THE WORK 229 | ======================= 230 | 231 | The Work has the status `author-maintained' if the Copyright Holder 232 | explicitly and prominently states near the primary copyright notice in 233 | the Work that the Work can only be maintained by the Copyright Holder 234 | or simply that it is `author-maintained'. 235 | 236 | The Work has the status `maintained' if there is a Current Maintainer 237 | who has indicated in the Work that they are willing to receive error 238 | reports for the Work (for example, by supplying a valid e-mail 239 | address). It is not required for the Current Maintainer to acknowledge 240 | or act upon these error reports. 241 | 242 | The Work changes from status `maintained' to `unmaintained' if there 243 | is no Current Maintainer, or the person stated to be Current 244 | Maintainer of the work cannot be reached through the indicated means 245 | of communication for a period of six months, and there are no other 246 | significant signs of active maintenance. 247 | 248 | You can become the Current Maintainer of the Work by agreement with 249 | any existing Current Maintainer to take over this role. 250 | 251 | If the Work is unmaintained, you can become the Current Maintainer of 252 | the Work through the following steps: 253 | 254 | 1. Make a reasonable attempt to trace the Current Maintainer (and 255 | the Copyright Holder, if the two differ) through the means of 256 | an Internet or similar search. 257 | 258 | 2. If this search is successful, then enquire whether the Work 259 | is still maintained. 260 | 261 | a. If it is being maintained, then ask the Current Maintainer 262 | to update their communication data within one month. 263 | 264 | b. If the search is unsuccessful or no action to resume active 265 | maintenance is taken by the Current Maintainer, then announce 266 | within the pertinent community your intention to take over 267 | maintenance. (If the Work is a LaTeX work, this could be 268 | done, for example, by posting to comp.text.tex.) 269 | 270 | 3a. If the Current Maintainer is reachable and agrees to pass 271 | maintenance of the Work to you, then this takes effect 272 | immediately upon announcement. 273 | 274 | b. If the Current Maintainer is not reachable and the Copyright 275 | Holder agrees that maintenance of the Work be passed to you, 276 | then this takes effect immediately upon announcement. 277 | 278 | 4. If you make an `intention announcement' as described in 2b. above 279 | and after three months your intention is challenged neither by 280 | the Current Maintainer nor by the Copyright Holder nor by other 281 | people, then you may arrange for the Work to be changed so as 282 | to name you as the (new) Current Maintainer. 283 | 284 | 5. If the previously unreachable Current Maintainer becomes 285 | reachable once more within three months of a change completed 286 | under the terms of 3b) or 4), then that Current Maintainer must 287 | become or remain the Current Maintainer upon request provided 288 | they then update their communication data within one month. 289 | 290 | A change in the Current Maintainer does not, of itself, alter the fact 291 | that the Work is distributed under the LPPL license. 292 | 293 | If you become the Current Maintainer of the Work, you should 294 | immediately provide, within the Work, a prominent and unambiguous 295 | statement of your status as Current Maintainer. You should also 296 | announce your new status to the same pertinent community as 297 | in 2b) above. 298 | 299 | 300 | WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE 301 | ====================================================== 302 | 303 | This section contains important instructions, examples, and 304 | recommendations for authors who are considering distributing their 305 | works under this license. These authors are addressed as `you' in 306 | this section. 307 | 308 | Choosing This License or Another License 309 | ---------------------------------------- 310 | 311 | If for any part of your work you want or need to use *distribution* 312 | conditions that differ significantly from those in this license, then 313 | do not refer to this license anywhere in your work but, instead, 314 | distribute your work under a different license. You may use the text 315 | of this license as a model for your own license, but your license 316 | should not refer to the LPPL or otherwise give the impression that 317 | your work is distributed under the LPPL. 318 | 319 | The document `modguide.tex' in the base LaTeX distribution explains 320 | the motivation behind the conditions of this license. It explains, 321 | for example, why distributing LaTeX under the GNU General Public 322 | License (GPL) was considered inappropriate. Even if your work is 323 | unrelated to LaTeX, the discussion in `modguide.tex' may still be 324 | relevant, and authors intending to distribute their works under any 325 | license are encouraged to read it. 326 | 327 | A Recommendation on Modification Without Distribution 328 | ----------------------------------------------------- 329 | 330 | It is wise never to modify a component of the Work, even for your own 331 | personal use, without also meeting the above conditions for 332 | distributing the modified component. While you might intend that such 333 | modifications will never be distributed, often this will happen by 334 | accident -- you may forget that you have modified that component; or 335 | it may not occur to you when allowing others to access the modified 336 | version that you are thus distributing it and violating the conditions 337 | of this license in ways that could have legal implications and, worse, 338 | cause problems for the community. It is therefore usually in your 339 | best interest to keep your copy of the Work identical with the public 340 | one. Many works provide ways to control the behavior of that work 341 | without altering any of its licensed components. 342 | 343 | How to Use This License 344 | ----------------------- 345 | 346 | To use this license, place in each of the components of your work both 347 | an explicit copyright notice including your name and the year the work 348 | was authored and/or last substantially modified. Include also a 349 | statement that the distribution and/or modification of that 350 | component is constrained by the conditions in this license. 351 | 352 | Here is an example of such a notice and statement: 353 | 354 | %% pig.dtx 355 | %% Copyright 2005 M. Y. Name 356 | % 357 | % This work may be distributed and/or modified under the 358 | % conditions of the LaTeX Project Public License, either version 1.3 359 | % of this license or (at your option) any later version. 360 | % The latest version of this license is in 361 | % http://www.latex-project.org/lppl.txt 362 | % and version 1.3 or later is part of all distributions of LaTeX 363 | % version 2005/12/01 or later. 364 | % 365 | % This work has the LPPL maintenance status `maintained'. 366 | % 367 | % The Current Maintainer of this work is M. Y. Name. 368 | % 369 | % This work consists of the files pig.dtx and pig.ins 370 | % and the derived file pig.sty. 371 | 372 | Given such a notice and statement in a file, the conditions 373 | given in this license document would apply, with the `Work' referring 374 | to the three files `pig.dtx', `pig.ins', and `pig.sty' (the last being 375 | generated from `pig.dtx' using `pig.ins'), the `Base Interpreter' 376 | referring to any `LaTeX-Format', and both `Copyright Holder' and 377 | `Current Maintainer' referring to the person `M. Y. Name'. 378 | 379 | If you do not want the Maintenance section of LPPL to apply to your 380 | Work, change `maintained' above into `author-maintained'. 381 | However, we recommend that you use `maintained', as the Maintenance 382 | section was added in order to ensure that your Work remains useful to 383 | the community even when you can no longer maintain and support it 384 | yourself. 385 | 386 | Derived Works That Are Not Replacements 387 | --------------------------------------- 388 | 389 | Several clauses of the LPPL specify means to provide reliability and 390 | stability for the user community. They therefore concern themselves 391 | with the case that a Derived Work is intended to be used as a 392 | (compatible or incompatible) replacement of the original Work. If 393 | this is not the case (e.g., if a few lines of code are reused for a 394 | completely different task), then clauses 6b and 6d shall not apply. 395 | 396 | 397 | Important Recommendations 398 | ------------------------- 399 | 400 | Defining What Constitutes the Work 401 | 402 | The LPPL requires that distributions of the Work contain all the 403 | files of the Work. It is therefore important that you provide a 404 | way for the licensee to determine which files constitute the Work. 405 | This could, for example, be achieved by explicitly listing all the 406 | files of the Work near the copyright notice of each file or by 407 | using a line such as: 408 | 409 | % This work consists of all files listed in manifest.txt. 410 | 411 | in that place. In the absence of an unequivocal list it might be 412 | impossible for the licensee to determine what is considered by you 413 | to comprise the Work and, in such a case, the licensee would be 414 | entitled to make reasonable conjectures as to which files comprise 415 | the Work. 416 | 417 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | INTERACTION = batchmode 2 | SINGLEPASS = no 3 | EXTERNALIZE = yes 4 | 5 | package-ins = forest.ins 6 | doc-ins = forest-doc.ins 7 | ins = ${package-ins} ${doc-ins} 8 | 9 | dtx = $(shell grep -Poh '\\from{(.*?)}' $(ins) | sed 's/\\from{\(.*\)}/\1/;' | sort | uniq) 10 | 11 | package-tex = 12 | package-nonderived-sty = forest-compat.sty 13 | package-derived-sty = $(shell grep -Poh '\\file{(.*?)}' $(package-ins) | sed 's/\\file{\(.*\)}/\1/;') 14 | package-sty = $(package-nonderived-sty) $(package-derived-sty) 15 | package-other = 16 | package-pdf = forest.pdf 17 | 18 | doc-tex = forest-doc.tex 19 | doc-nonderived-sty = forest-doc.sty 20 | doc-derived-sty = $(shell grep -Poh '\\file{(.*?)}' $(doc-ins) | sed 's/\\file{\(.*\)}/\1/;') 21 | doc-sty = $(doc-nonderived-sty) $(doc-derived-sty) 22 | doc-other = forest-doc.ist tex.bib 23 | doc-pdf = forest-doc.pdf 24 | 25 | tex = $(package-tex) $(doc-tex) 26 | sty = $(package-sty) $(doc-sty) 27 | other = $(package-other) $(doc-other) 28 | pdf = $(package-pdf) $(doc-pdf) 29 | 30 | %.success: % ; 31 | 32 | forest-doc.pdf: forest-doc.tex forest-doc.tex.success $(dtx) $(doc-sty) $(doc-other) forest-doc-test.tex 33 | $(call externalize, $(<:.success=)) 34 | @echo 35 | @echo Pass 1 ... 36 | $(call compile, $(<:.success=)) 37 | ifneq ($(SINGLEPASS),yes) 38 | @rm forest-doc.memo 39 | @echo 40 | @echo Pass 2 ... 41 | $(call compile, $(<:.success=)) 42 | @echo 43 | @echo Pass 3 ... 44 | $(call compile, $(<:.success=)) 45 | @echo 46 | @echo Pass 4 ... 47 | $(call compile, $(<:.success=)) 48 | endif 49 | @echo Compilation successful! 50 | @touch -r $< $<.success 51 | 52 | forest-doc-test.tex: 53 | [[ -a $@ ]] || touch $@ 54 | 55 | forest.pdf: forest.dtx.success forest.sty 56 | $(call externalize, $(<:.success=)) 57 | @echo Pass 1 ... 58 | $(call compile, $(<:.success=)) 59 | ifneq ($(SINGLEPASS),yes) 60 | @echo 61 | @echo Pass 2 ... 62 | $(call compile, $(<:.success=)) 63 | endif 64 | @echo Compilation successful! 65 | @touch -r $(<:.success=) $< 66 | 67 | externalize = if [[ "$(EXTERNALIZE)" == 'yes' ]] ; then \ 68 | echo Externalization is ON. ; echo "\\tikzexternalize" > $1-externalize.tex ; else \ 69 | echo Externalization is OFF. ; echo "" > $1-externalize.tex ; fi 70 | 71 | compile = time pdflatex -synctex=1 -interaction $(INTERACTION) $(1) && \ 72 | ( bibtex $(basename $1) || ( echo bibtex failed! && true ) ) && \ 73 | ( if [[ -f $(basename $1).idx ]] ; then makeindex -s forest-doc.ist $(basename $1) ; fi || ( echo makeindex failed! && true ) ) && \ 74 | if [[ `pdfinfo $(basename $1).pdf | sed -n '/^Pages:/s/^Pages: *//p'` > 10 ]] ; then cp $(basename $1).pdf $(basename $1).bak.pdf ; fi 75 | 76 | forest.sty: forest.dtx forest.ins 77 | tex forest.ins >/dev/null 78 | 79 | forest-lib-%.sty: forest-libs.dtx forest.ins 80 | tex forest.ins >/dev/null 81 | 82 | forest-index.sty: forest-index.dtx forest-doc.ins 83 | tex forest-doc.ins >/dev/null 84 | 85 | sty: 86 | @echo Generating .sty ... 87 | tex forest.ins >/dev/null 88 | tex forest-doc.ins >/dev/null 89 | 90 | README: readme.tex forest.sty 91 | @echo Generating README ... 92 | pdflatex -interaction batchmode readme >/dev/null 93 | mv README.txt README 94 | 95 | VERSION: version.tex forest.sty 96 | pdflatex -interaction batchmode version >/dev/null 97 | mv VERSION.txt VERSION 98 | @echo forest v`cat VERSION` 99 | 100 | versiondir: VERSION 101 | @echo Creating version directory ... 102 | mkdir -p versions 103 | mkdir versions/`cat VERSION` 104 | mkdir versions/`cat VERSION`/forest 105 | 106 | versiondirremove: VERSION 107 | @if [[ -d versions && -d versions/`cat VERSION` ]] ; then read -p "Remove forest v`cat VERSION` (y/n)? " jane ; if [ "$$jane" = "y" ] ; then rm -r versions/`cat VERSION` ; echo Removed it! ; else echo "Ok, I won't!" ; exit 1; fi ; fi 108 | 109 | %.dtx.checksum: %.dtx 110 | @cat $< | tr -cd '\\' |wc -m > $@ 111 | @sed -ne '1 s/^% *\\CheckSum{\([0-9\]*\)\} *$$/\1/p;' $< | \ 112 | if ! diff $@ - >/dev/null ; then \ 113 | checksum=`cat $@` ; \ 114 | echo Fixing checksum in $< to $$checksum ; \ 115 | sed -ie "1 s/\\CheckSum{\([0-9]*\)}/\\CheckSum{$$checksum}/;" $< ; \ 116 | fi 117 | 118 | 119 | nocheckexternalization : ; 120 | 121 | checkexternalization : 122 | @echo Checking if externalization is off ... 123 | @if grep '^[^%]\\tikzexternalize$$' forest-doc.tex >/dev/null || [[ "$(EXTERNALIZE)" == 'yes' ]] ; then echo ; echo Switch off externalization! ; echo; exit 1; fi 124 | 125 | checksums: $(patsubst %.dtx,%.dtx.checksum,$(dtx)) 126 | 127 | # Sometimes this will be too strict (e.g. when updating only one library). 128 | # In such a case, temporarily rename "checkreleasedate" to "nocheckreleasedate" in "zip:". 129 | checkreleasedate: $(ins) $(dtx) $(sty) $(tex) $(other) 130 | @echo Checking release dates ... 131 | @! grep "Copyright (c) 2012-.*Saso Zivanovic" $^ | grep -v `date +%Y` 132 | @touch checkreleasedate.temp ; for f in $^ ; do ! grep -H "\\Provides[a-zA-Z]*{.*}\[[0-9]" $$f | grep -v \\[`git log -1 --format=%cd --date=format:%Y/%m/%d $$f` || ( echo " Should be `git log -1 --format=%cd --date=format:%Y/%m/%d $$f`" && rm -f checkreleasedate.temp ) ; done ; ( test -e checkreleasedate.temp && rm checkreleasedate.temp ) 133 | 134 | nocheckreleasedate: 135 | 136 | zip: versiondir nocheckexternalization checksums checkreleasedate \ 137 | README LICENCE $(ins) $(dtx) $(sty) $(tex) $(other) $(pdf) 138 | @echo Copying files to the version `cat VERSION` directory ... 139 | @cp README LICENCE $(ins) $(dtx) $(doc-nonderived-sty) $(package-nonderived-sty) $(tex) $(pdf) $(other) versions/`cat VERSION`/forest 140 | @echo Zipping files 141 | @cd versions/`cat VERSION` && zip -r forest.zip forest 142 | @cd ../.. 143 | @echo ZIP file: versions/`cat VERSION`/forest.zip 144 | 145 | zipforce: versiondirremove zip 146 | 147 | runtime: VERSION $(package-sty) 148 | mkdir -p runtime 149 | mkdir runtime/`cat VERSION` 150 | cp $(package-sty) runtime/`cat VERSION` 151 | chmod -w runtime/`cat VERSION`/* 152 | zip runtime/forest-runtime_v`cat VERSION`.zip $(package-sty) 153 | 154 | runtimedirremove: 155 | @if [[ -d runtime && -d runtime/`cat VERSION` ]] ; then read -p "Remove runtime files for forest v`cat VERSION` (y/n)? " jane ; if [ "$$jane" = "y" ] ; then rm -r runtime/`cat VERSION` runtime/forest-runtime_v`cat VERSION`.zip ; echo Removed it! ; else echo "Ok, I won't!" ; exit 1; fi ; fi 156 | 157 | runtimeforce: runtimedirremove runtime 158 | 159 | currentruntime: 160 | @mkdir -p runtime/current 161 | @ln -sfr $(package-sty) runtime/current 162 | 163 | v=current 164 | use: currentruntime 165 | echo Trying to switch to forest v$(v) ... 166 | @if ! [[ -d runtime/$(v) && -f runtime/$(v)/forest.sty ]] ; then echo Runtimes files for forest v$(v) don\'t exist! Available versions: `ls runtime | grep -v zip`; false ; fi 167 | @if [[ ! -h $(HOME)/texmf/tex/latex/forest/latex ]] ; then echo Something is wrong with directory $(HOME)/texmf/tex/latex/forest/latex ... it should be a symlink to some version\'s runtime directory. ; false ; fi 168 | ln -sfT $(abspath runtime/$(v)) $(HOME)/texmf/tex/latex/forest/latex 169 | @texhash 2> /dev/null 170 | 171 | used: 172 | @ls -l $(HOME)/texmf/tex/latex/forest | sed -e 's/.*\///;' 173 | @echo Available versions: `ls runtime | grep -v zip` 174 | 175 | clean-aux: 176 | rm *.{aux,log,auxlock,bbl,blg,synctex.gz,idx,ilg,ind,out,toc,foridx,memo,memo.tmp} 177 | clean-test: 178 | rm test-*.{aux,log,auxlock,bbl,blg,synctex.gz,idx,ilg,ind,ins,out,toc} test-*~ 179 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | LaTeX package: forest [2017/07/14 v2.1.5 Drawing (linguistic) trees] 2 | 3 | Copyright (c) 2012-2017 Saso Zivanovic 4 | (Sa\v{s}o \v{Z}ivanovi\'{c}) 5 | saso.zivanovic@guest.arnes.si 6 | 7 | 8 | ABSTRACT 9 | 10 | `forest' is a pgf/tikz-based package for drawing linguistic (and other 11 | kinds of) trees. Its main features are: 12 | - a packing algorithm which can produce very compact trees; 13 | - a user-friendly interface consisting of the familiar bracket 14 | encoding of trees plus the key--value interface to option-setting; 15 | - many tree-formatting options, with control over option values of 16 | individual nodes and mechanisms for their manipulation; 17 | - a powerful mechanism for traversing the tree; 18 | - the possibility to decorate the tree using the full power of pgf/tikz; 19 | - an externalization mechanism sensitive to code-changes. 20 | 21 | 22 | LICENSE 23 | 24 | This work may be distributed and/or modified under the 25 | conditions of the LaTeX Project Public License, either version 1.3 26 | of this license or (at your option) any later version. 27 | The latest version of this license is in 28 | 29 | http://www.latex-project.org/lppl.txt 30 | 31 | and version 1.3 or later is part of all distributions of LaTeX 32 | version 2005/12/01 or later. 33 | 34 | 35 | For the list of files constituting the work see the main source file 36 | of the package, `forest.dtx', or the derived `forest.sty'. 37 | 38 | -------------------------------------------------------------------------------- /TeXSE-compile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | while [[ $1 ]] ; do 4 | if [[ $1 == "-v" ]] ; then 5 | verbose="1" 6 | elif [[ $1 == "-compat" || $1 == "-c" ]] ; then 7 | compat="$2" 8 | shift; 9 | else 10 | break 11 | fi 12 | shift; 13 | done 14 | 15 | function append_filevars () { 16 | echo " 17 | %%% Local Variables: 18 | %%% mode: latex 19 | %%% TeX-master: t" >> $1 20 | if [[ $2 != 'pdflatex' ]] ; then 21 | echo '%%% TeX-engine: ${2%latex}tex' >> $1 22 | fi 23 | echo "%%% End:" >> $1 24 | } 25 | 26 | # OK: compiles 27 | function test () { 28 | # $1=file, $2=engine 29 | if [[ ! ( -a $1.$2.ok || -a $1.$2.OK || -a $1.$2.bad || -a $1.$2.BAD || -a $1.$2.ignore ) ]] ; then 30 | dir=`pwd` 31 | echo -n "Testing ${dir##*/}/${1#./} $2 ..." 32 | mkdir $2-v1.0 2>/dev/null 33 | cd $2-v1.0 34 | ln -sf ../../../../versions/1.0.10/forest/forest.sty 35 | rm -rf ${1%tex}* 36 | cp ../$1 . 37 | append_filevars $1 $2 38 | if timeout -k 10s 5m $2 -interaction batchmode $1 >/dev/null ; then 39 | mkdir ../$2-v1.1 2>/dev/null 40 | cd ../$2-v1.1 41 | ln -sf ../../../../forest.sty ../../../../forest-lib-*.sty ../../../../forest-compat.sty . 42 | rm -rf ${1%tex}* 43 | cp ../$1 . 44 | append_filevars $1 $2 45 | if [[ $compat != "" ]] ; then 46 | # TODO: optional args to \usepackage 47 | sed -i -e "s/\\\\usepackage{forest}/\\\\usepackage[compat=$compat]{forest}/;" $1 48 | fi 49 | if $2 -interaction batchmode $1 >/dev/null ; then 50 | echo -n "v1.1 compiles, ok " 51 | if cmp ../$2-v1.0/${1%tex}pdf ${1%tex}pdf >/dev/null ; then 52 | echo -n "pdf are completely the same ... OK " ; 53 | touch ../$1.$2.OK 54 | else 55 | # from http://stackoverflow.com/questions/6469157/pdf-compare-on-linux-command-line 56 | gs -o ../$2-v1.0/${1%tex}ppm -sDEVICE=ppmraw -r300 ../$2-v1.0/${1%tex}pdf >/dev/null 57 | gs -o ${1%tex}ppm -sDEVICE=ppmraw -r300 ${1%tex}pdf >/dev/null 58 | if cmp ../$2-v1.0/${1%tex}ppm ${1%tex}ppm >/dev/null ; then 59 | echo -n "pdf are the same ... OK " ; 60 | touch ../$1.$2.OK 61 | else 62 | gs -o ../$2-v1.0/${1%tex}ppm -sDEVICE=ppmraw -r600 ../$2-v1.0/${1%tex}pdf >/dev/null 63 | gs -o ${1%tex}ppm -sDEVICE=ppmraw -r600 ${1%tex}pdf >/dev/null 64 | if cmp ../$2-v1.0/${1%tex}ppm ${1%tex}ppm >/dev/null ; then 65 | echo -n "pdf are the same ... OK " ; 66 | touch ../$1.$2.OK 67 | else 68 | echo -n "DIFFER! bad " 69 | touch ../$1.$2.bad 70 | fi 71 | fi 72 | rm ../$2-v1.0/${1%tex}ppm ${1%tex}ppm 73 | fi 74 | else 75 | echo -n "v1.1 DOES NOT COMPILE!, BAD" 76 | touch ../$1.$2.BAD 77 | fi 78 | else 79 | echo -n "v1.0 does not compile, ignore " 80 | touch ../$1.$2.ignore 81 | fi 82 | cd .. 83 | echo 84 | else 85 | if [[ $verbose ]] ; then echo -n "$info" ; fi 86 | fi 87 | } 88 | 89 | test $1 pdflatex 90 | #test $1 xelatex 91 | #test $1 lualatex 92 | -------------------------------------------------------------------------------- /TeXSE-diff.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | viewemacs='' 3 | viewfirst='' 4 | viewsecond='' 5 | viewdiff='' 6 | viewfolder='' 7 | viewall='1' 8 | while [[ ${1:0:1} == '-' ]] ; do 9 | viewall='' 10 | if [[ $1 == '-emacs' ]] ; then viewemacs='1' ; fi 11 | if [[ $1 == '-first' ]] ; then viewfirst='1' ; fi 12 | if [[ $1 == '-second' ]] ; then viewsecond='1' ; fi 13 | if [[ $1 == '-diff' ]] ; then viewdiff='1' ; fi 14 | if [[ $1 == '-folder' ]] ; then viewfolder='1' ; fi 15 | shift; 16 | done 17 | if [[ $viewall ]] ; then 18 | viewemacs='1' 19 | viewfirst='1' 20 | viewsecond='1' 21 | viewdiff='1' 22 | viewfolder='1' 23 | fi 24 | if [[ $1 == "Testing" ]] ; then 25 | dir="tex.stackexchange.com/questions/${2%/*}" 26 | fn=${2##*/} 27 | n=${fn%%.*} 28 | engine=$3 29 | else 30 | dir=${1%/*} 31 | fn=${1##*/} 32 | n=${fn%%.*} 33 | engine=${fn%.*} 34 | engine=${engine##*.} 35 | fi 36 | if [[ $viewfolder && -d $PWD/$dir ]] ; then thunar $PWD/$dir >/dev/null 2>/dev/null & fi 37 | #emacsclient -nce "(progn (find-file \"$PWD/$dir/$engine-v1.0/$n.tex\") (find-file \"$PWD/$dir/$engine-v1.1/$n.tex\"))" 38 | if [[ $viewemacs && -f $PWD/$dir/$engine-v1.1/$n.tex ]] ; then emacsclient -nc $PWD/$dir/$engine-v1.1/$n.tex $PWD/$dir/$engine-v1.0/$n.tex >/dev/null 2>/dev/null ; fi 39 | if [[ $viewfirst && -f $dir/$engine-v1.0/$n.pdf ]] ; then atril $dir/$engine-v1.0/$n.pdf >/dev/null 2>/dev/null & fi 40 | if [[ $viewsecond && -f $dir/$engine-v1.1/$n.pdf ]] ; then atril $dir/$engine-v1.1/$n.pdf >/dev/null 2>/dev/null & fi 41 | if [[ $viewdiff && -f $dir/$engine-v1.0/$n.pdf && -f $dir/$engine-v1.1/$n.pdf ]] ; then diffpdf -a $dir/$engine-v1.0/$n.pdf $dir/$engine-v1.1/$n.pdf >/dev/null 2>/dev/null & fi 42 | -------------------------------------------------------------------------------- /TeXSE-extract.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import fileinput 4 | incode=False 5 | n=0 6 | for line in fileinput.input(): 7 | if not incode: 8 | if line.startswith('
'):
9 | incode=True
10 | n+=1
11 | f=open('{}.tex'.format(n), 'w')
12 | line = line[11:]
13 | if incode:
14 | if line.startswith('
'):
15 | incode=False
16 | f.close()
17 | else:
18 | print(line, end='', file=f)
19 |
--------------------------------------------------------------------------------
/TeXSE-test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/bash
2 |
3 | verbose=""
4 | compat=""
5 | while [[ $1 ]] ; do
6 | if [[ $1 == "-v" ]] ; then
7 | verbose="-v"
8 | elif [[ $1 == "-compat" || $1 == "-c" ]] ; then
9 | compat="-compat $2"
10 | shift;
11 | fi
12 | shift;
13 | done
14 |
15 | # Clean
16 | #find tex.stackexchange.com -type f \( -iname '*.tex' \; -iname '*.log' \; -iname '*.aux' \) -execdir echo {} \;
17 |
18 | # Download questions
19 | # TODO: don't dl what we've already got?
20 | #wget -rE -l 1 -nc --accept-regex 'http://tex\.stackexchange\.com/questions/[0-9]*/[-a-z0-9]*' http://tex.stackexchange.com/questions/tagged/forest
21 | #wget -rE -l 1 -nc --accept-regex 'http://tex\.stackexchange\.com/questions/[0-9]*/[-a-z0-9]*' http://tex.stackexchange.com/questions/tagged/forest?page=2&sort=newest&pagesize=50
22 | #wget -rE -l 1 -nc --accept-regex 'http://tex\.stackexchange\.com/questions/[0-9]*/[-a-z0-9]*' http://tex.stackexchange.com/questions/tagged/forest?page=3&sort=newest&pagesize=50
23 | #wget -rE -l 1 -nc --accept-regex 'http://tex\.stackexchange\.com/questions/[0-9]*/[-a-z0-9]*' http://tex.stackexchange.com/questions/tagged/forest?page=4&sort=newest&pagesize=50
24 |
25 | # Extract code
26 | #find tex.stackexchange.com -type f -iname '*.html' -execdir ../../../TeXSE-extract.py {} \;
27 |
28 | # Test
29 | find tex.stackexchange.com -maxdepth 3 -type f -path '*.tex' -execdir ../../../TeXSE-compile.sh $verbose $compat {} \;
30 |
--------------------------------------------------------------------------------
/forest-compat.sty:
--------------------------------------------------------------------------------
1 | % \CheckSum{12884}
2 | % \iffalse meta-comment
3 | % forest-index.dtx
4 | %% `forest-compat' defines a compatibility layer of package `forest'.
5 | %%
6 | %% Copyright (c) 2012-2017 Saso Zivanovic
7 | %% (Sa\v{s}o \v{Z}ivanovi\'{c})
8 | %% saso.zivanovic@guest.arnes.si
9 | %%
10 | %% This work may be distributed and/or modified under the
11 | %% conditions of the LaTeX Project Public License, either version 1.3
12 | %% of this license or (at your option) any later version.
13 | %% The latest version of this license is in
14 | %%
15 | %% http://www.latex-project.org/lppl.txt
16 | %%
17 | %% and version 1.3 or later is part of all distributions of LaTeX
18 | %% version 2005/12/01 or later.
19 | %%
20 | %% This work has the LPPL maintenance status `author-maintained'.
21 | %%
22 | %% This file is a part of package `forest'. For the list of files
23 | %% constituting the package see main source file of the package,
24 | %% `forest.dtx', or the derived `forest.sty'.
25 |
26 | \ProvidesPackage{forest-compat}[2016/12/31]
27 |
28 | \def\forest@deprecated#1{%
29 | \PackageWarning{forest}{Compatibility mode for #1}%
30 | }
31 | \forestset{@@deprecated/.code={\forest@deprecated{#1}}}
32 | \def\forestcompat#1{\pgfqkeys{/forest/@compat}{#1}}
33 | \def\forestcompat@patchfailed{%
34 | \pgfkeys@split@path
35 | \PackageError{forest}{Patching in compat=\pgfkeyscurrentname\space failed}{}%
36 | }
37 | \forestcompat{
38 | silent/.code={\def\forest@deprecated##1{}},
39 | %%% begin listing region: compat_keys
40 | most/.style={1.0-most},
41 | all/.style={1.0-all},
42 | none/.style={},
43 | 1.0-harmless/.style={
44 | 1.0-triangle,1.0-linear,1.0-nodewalk,1.0-ancestors,
45 | 1.0-fittotree,1.0-for,1.0-forall,
46 | },
47 | 1.0-most/.style={1.0-harmless,2.0.2-most},
48 | 1.0-all/.style={1.0-harmless,
49 | 1.0-forstep,1.0-rotate,1.0-stages,1.0-name,
50 | 2.0.2-all,
51 | },
52 | 2.0.2-most/.style={2.0-most},
53 | 2.0.2-all/.style={
54 | 2.0.2-delayn,2.0.2-wrapnpgfmathargs,
55 | 2.0-all,
56 | },
57 | 2.0-edges/.style={2.0-anchors,2.0-forkededge,2.0-folder},
58 | 2.0-most/.style={2.1.1-most},
59 | 2.0-all/.style={
60 | 2.0-delayn,
61 | 2.0-edges,
62 | 2.1.1-all,
63 | },
64 | 2.1.1-most/.style={},
65 | 2.1.1-all/.style={2.1.1-loops},
66 | %%% end listing region: compat_keys
67 | 1.0-triangle/.style={
68 | /forest/triangle/.style={
69 | @@deprecated={key "triangle" from v1.0.x. Use key "roof" from library "linguistics" instead},
70 | edge path'={%
71 | (.north west)--(!u.south)--(.north east)--cycle
72 | }
73 | }
74 | },
75 | 1.0-linear/.style={
76 | /forest/define long step={linear next}{autostep}{%
77 | \forest@deprecated{nodewalk step "linear next" from v1.0. Use key "next node" instead.}%
78 | \edef\forest@cn{\forest@node@linearnextid}},
79 | /forest/define long step={linear previous}{autostep}{%
80 | \forest@deprecated{nodewalk step "linear previous" from v1.0. Use key "previous node" instead.}%
81 | \edef\forest@cn{\forest@node@linearpreviousid}},
82 | },
83 | 1.0-nodewalk/.style={
84 | /forest/node walk/before walk/.style={},
85 | /forest/node walk/every step/.style={},
86 | /forest/node walk/after walk/.style={},
87 | /forest/node walk/.style={
88 | @@deprecated={key "node walk" from v1.0. Use key "nodewalk" instead.},
89 | /forest/node walk/before walk,
90 | /forest/nodewalk/before walk/.style={/forest/node walk/before walk},
91 | /forest/nodewalk/every step/.style={/forest/node walk/every step},
92 | /forest/nodewalk/after walk/.style={/forest/node walk/after walk},
93 | /forest/nodewalk/node walk/.style={before walk,for nodewalk={####1,options={/forest/nodewalk/after walk}}{/forest/nodewalk/every step}},
94 | for nodewalk={##1,options={/forest/nodewalk/after walk}}{/forest/nodewalk/every step},
95 | },
96 | },
97 | 1.0-ancestors/.style={
98 | /forest/for ancestors'/.style={
99 | @@deprecated={key "for ancestors'" from v1.0.x. Use key "for current and ancestors" instead.},
100 | for current and ancestors={##1}},
101 | },
102 | 1.0-fittotree/.style={%
103 | /tikz/fit to tree/.style={
104 | /forest/@@deprecated={key "/tikz/fit to tree" from v1.0.x. Use "/tikz/fit to=tree" instead.},
105 | inner sep=0pt,fit to=tree
106 | }
107 | },
108 | 1.0-for/.style={
109 | /forest/for/.code 2 args={% #1 = nodewalk, #2 = after walk keylist
110 | \forest@deprecated{Key "for" from v1.0.x. Use key "for group" instead.}%
111 | \forest@forthis{\forest@nodewalk{##1,options={##2}}{}}%
112 | }
113 | },
114 | 1.0-forall/.style={
115 | /forest/for all next/.style={
116 | @@deprecated={Key "for all next" from v1.0.x. Use key "for following siblings" instead.},
117 | for following siblings={##1}},
118 | /forest/for all previous/.style={
119 | @@deprecated={Key "for all previous" from v1.0.x. Use key "for preceding siblings" instead.},
120 | for preceding siblings={##1}},
121 | },
122 | 1.0-forstep/.code={%
123 | \def\forest@forstepwrapper##1##2{%
124 | \forest@forthis{%
125 | \forest@configured@nodewalk{independent}{independent}{compatfake}{##1}{##2}%
126 | }%
127 | }%
128 | \def\forest@relatednode@option@compat@ignoreinvalidsteps##1{%
129 | \forest@saveandrestoremacro\forest@nodewalk@oninvalid{%
130 | \def\forest@nodewalk@oninvalid{compatfake}%
131 | ##1%
132 | }%
133 | }%
134 | },
135 | 1.0-rotate/.style={
136 | /forest/undef option=rotate,
137 | rotate/.style={
138 | @@deprecate={Using non-autoforwarded key "rotate". Some keys, like "forked edges" and "folder", might produce a wrong result.},
139 | node options={rotate={##1}},
140 | },
141 | },
142 | 1.0-stages/.style={
143 | /forest/@@deprecated={Using v1.0.x "stages" style},
144 | /forest/stages/.style={
145 | process keylist=before typesetting nodes,
146 | typeset nodes stage,
147 | process keylist=before packing,
148 | pack stage,
149 | process keylist=before computing xy,
150 | compute xy stage,
151 | process keylist=before drawing tree,
152 | draw tree stage,
153 | },
154 | /forest/TeX={%
155 | \def\forest@defstages##1{%
156 | \def\forest@stages{%
157 | begin forest,
158 | for root'={
159 | process keylist register=default preamble,
160 | process keylist register=preamble
161 | },
162 | process keylist=given options,
163 | ##1,
164 | end forest
165 | }%
166 | }%
167 | },
168 | },
169 | 1.0-name/.code={%
170 | \forest@deprecated{key "name": using key "name" from v1.0.x, which does not enforce uniqueness. If you really need this, you're doing something wrong.}%
171 | \def\forest@node@setname##1{%
172 | \ifstrempty{##1}{}{%
173 | \forestoeset{name}{##1}%
174 | \csedef{forest@id@of@##1}{\forest@cn}%
175 | }%
176 | }%
177 | \def\forest@node@setalias##1{%
178 | \ifstrempty{##1}{}{%
179 | \csedef{forest@id@of@##1}{\forest@cn}%
180 | }%
181 | }%
182 | },
183 | 2.0.2-delayn/.style={
184 | /forest/delay@n/.style 2 args={
185 | @@deprecated={propagator "delay n" (it introduces two levels of hash doubling reevaluates the first argument (the desired number of cycles) at every cycle)},
186 | if={##1==1}{delay={##2}}{delay={delay@n/.wrap pgfmath arg={{####1}{##2}}{##1-1}}}
187 | },
188 | 2.0-delayn/.style={}, % this key would patch the same thing!
189 | },
190 | 2.0.2-wrapnpgfmathargs/.code={%
191 | \def\forest@wrap@pgfmath@args@@@wrapandpasson{%
192 | \forest@deprecated{handler "wrap n pgfmath args" (it introduces two levels of hash doubling)}%
193 | \expandafter\expandafter\expandafter\def
194 | \expandafter\expandafter\expandafter\forest@wrapped
195 | \expandafter\expandafter\expandafter{%
196 | \expandafter\forest@wrap@code\forest@wrap@args}%
197 | \expandafter\pgfkeysalso\expandafter{\expandafter\pgfkeyscurrentpath\expandafter=\expandafter{\forest@wrapped}}%
198 | }%
199 | },
200 | 2.0-delayn/.style={
201 | /forest/delay n/.style 2 args={
202 | @@deprecated={propagator "delay n" (it reevaluates the first argument (the desired number of cycles) at every cycle)},
203 | if={##1==0}{##2}{delay@n={##1}{##2}}
204 | },
205 | /forest/delay@n/.style 2 args={
206 | if={##1==1}{delay={##2}}{delay={delay@n/.process={P}{##1-1}{##2}}}
207 | },
208 | },
209 | 2.0-anchors/.code={%
210 | \csdef{forest@anchor@@parent'}{%
211 | \forest@anchor@isbordertrue
212 | \edef\forest@temp@anchor{\number\numexpr\forestove{grow}-\forestove{rotate}+180}%
213 | }
214 | \csdef{forest@anchor@@parent first'}{%
215 | \forest@anchor@isbordertrue
216 | \edef\forest@temp@anchor@parent{\number\numexpr\forestove{grow}-\forestove{rotate}+180}%
217 | \edef\forest@temp@anchor@first{\number\numexpr\forestove{grow}-\forestove{rotate}\ifnum\forestove{reversed}=0 -\else+\fi90}%
218 | \forest@getaverageangle{\forest@temp@anchor@parent}{\forest@temp@anchor@first}\forest@temp@anchor
219 | }
220 | \csdef{forest@anchor@@parent last'}{%
221 | \forest@anchor@isbordertrue
222 | \edef\forest@temp@anchor@parent{\number\numexpr\forestove{grow}-\forestove{rotate}+180}%
223 | \edef\forest@temp@anchor@last{\number\numexpr\forestove{grow}-\forestove{rotate}\ifnum\forestove{reversed}=0 +\else-\fi90}%
224 | \forest@getaverageangle{\forest@temp@anchor@parent}{\forest@temp@anchor@last}\forest@temp@anchor
225 | }
226 | },
227 | 2.0-forkededge/.code={%
228 | \forest@iflibraryloaded{edges}{%
229 | \forestset{
230 | forked edge/.style={
231 | edge={rotate/.pgfmath=grow()},
232 | edge path'={(!u.parent anchor) -- ++(\forestoption{fork sep},0) |- (.child anchor)},
233 | },
234 | forked edges/.style={
235 | for tree={parent anchor=children},
236 | for descendants={child anchor=parent,forked edge}
237 | },
238 | }%
239 | }{%
240 | \appto\forest@compat@libraries@edges{\forestcompat{2.0-forkededge}}%
241 | }%
242 | },
243 | 2.0-folder/.code={%
244 | \forest@iflibraryloaded{edges}{%
245 | \expandafter\patchcmd\csname pgfk@/forest/folder/.@cmd\endcsname
246 | {parent anchor=-children last}
247 | {parent anchor=parent last}
248 | {}{\forestcompat@patchfailed}%
249 | \expandafter\patchcmd\csname pgfk@/forest/folder/.@cmd\endcsname
250 | {edge={rotate/.option=!parent.grow},}
251 | {edge={rotate/.pgfmath=grow()}}
252 | {}{\forestcompat@patchfailed}%
253 | }{%
254 | \appto\forest@compat@libraries@edges{\forestcompat{2.0-folder}}%
255 | }%
256 | },
257 | 2.1.1-loops/.code={%
258 | \patchcmd\newsafeRKloop % pre-{##1}
259 | {\forest@temp@toks}%
260 | {%
261 | \forest@deprecated{hash-doubling loops from pre-2.1.2}%
262 | \def\forest@temp
263 | }%
264 | {}{\forestcompat@patchfailed}%
265 | \patchcmd\newsafeRKloop % post-{##1}
266 | {\csedef}%
267 | {\forest@temp@toks\expandafter{\forest@temp}\csedef}%
268 | {}{\forestcompat@patchfailed}%
269 | },
270 | }
271 | \expandafter\forestcompat\expandafter{\forest@compat}
272 |
--------------------------------------------------------------------------------
/forest-doc.ins:
--------------------------------------------------------------------------------
1 | %% forest-doc.ins
2 | %%
3 | %% Copyright (c) 2015 Saso Zivanovic
4 | %% saso.zivanovic@guest.arnes.si
5 | %%
6 | %% This work may be distributed and/or modified under the
7 | %% conditions of the LaTeX Project Public License, either version 1.3
8 | %% of this license or (at your option) any later version.
9 | %% The latest version of this license is in
10 | %%
11 | %% http://www.latex-project.org/lppl.txt
12 | %%
13 | %% and version 1.3 or later is part of all distributions of LaTeX
14 | %% version 2005/12/01 or later.
15 | %%
16 | %% This file is a part of package `forest'. For the list of files
17 | %% constituting the package see main source file of the package,
18 | %% `forest.dtx', or the derived `forest.sty'.
19 | %%
20 | \input docstrip.tex
21 | \keepsilent
22 | \preamble
23 | \endpreamble
24 | \askforoverwritefalse
25 | \generate{\file{forest-index.sty}{\from{forest-index.dtx}{}}}
26 | \endbatchfile
27 |
--------------------------------------------------------------------------------
/forest-doc.ist:
--------------------------------------------------------------------------------
1 | %% This file is based on `gind.ist'.
2 |
3 | actual '='
4 | quote '&'
5 | level '>'
6 | preamble
7 | "\n \\begin{theindex} \n \\makeatletter\\scan@allowedfalse\n"
8 | postamble
9 | "\n\n \\end{theindex}\n"
10 | item_x1 "\\efill \n \\subitem "
11 | item_x2 "\\efill \n \\subsubitem "
12 | delim_0 "\\pfill "
13 | delim_1 "\\pfill "
14 | delim_2 "\\pfill "
15 | % The next lines will produce some warnings when
16 | % running Makeindex as they try to cover two different
17 | % versions of the program:
18 | lethead_prefix "{\\bfseries\\hfil\\indexlettertotoc "
19 | lethead_suffix "\\relax\\hfil}\\nopagebreak\n"
20 | lethead_flag 1
21 | heading_prefix "{\\bfseries\\hfil\\indexlettertotoc "
22 | heading_suffix "\\relax\\hfil}\\nopagebreak\n"
23 | % heading_prefix "{\\bfseries\\hfil "
24 | % heading_suffix "\\hfil}\\nopagebreak\n"
25 | headings_flag 1
26 |
--------------------------------------------------------------------------------
/forest-doc.sty:
--------------------------------------------------------------------------------
1 | %% forest-doc.sty
2 | %%
3 | %% `forest-doc.sty` is an auxiliary package needed to compile the documentation of package
4 | %% `forest`. (It is not needed to use the package.)
5 | %%
6 | %% Copyright (c) 2012-2017 Saso Zivanovic
7 | %% (Sa\v{s}o \v{Z}ivanovi\'{c})
8 | %% saso.zivanovic@guest.arnes.si
9 | %%
10 | %% This work may be distributed and/or modified under the
11 | %% conditions of the LaTeX Project Public License, either version 1.3
12 | %% of this license or (at your option) any later version.
13 | %% The latest version of this license is in
14 | %%
15 | %% http://www.latex-project.org/lppl.txt
16 | %%
17 | %% and version 1.3 or later is part of all distributions of LaTeX
18 | %% version 2005/12/01 or later.
19 | %%
20 | %% This work has the LPPL maintenance status `author-maintained'.
21 | %%
22 | %% This file is a part of package `forest'. For the list of files
23 | %% constituting the package see main source file of the package,
24 | %% `forest.dtx', or the derived `forest.sty'.
25 | %%
26 | \ProvidesPackage{forest-doc}
27 | \RequirePackage{lstdoc}
28 | \RequirePackage{pgfkeys}
29 | \RequirePackage{forest-index}
30 | % if you want index support, load package "forest-index", but later
31 |
32 | \lstset{language={[LaTeX]TeX},tabsize=4,gobble=2,%
33 | basicstyle=\small\ttfamily,basewidth=0.51em,boxpos=c,pointstyle=\pstyle,moredelim=[is][\pstyle]{~}{~}}
34 | %\lst@InstallKeywords{p}{point}{pointstyle}\relax{keywordstyle}{}ld
35 | \def\pstyle{\color{darkgreen}}
36 | \newcommand\itemnosep[1][0pt]{\vspace{\the\dimexpr-1.4ex+#1}}
37 | \lstset{
38 | rangebeginprefix=\ \ \%\%\%\ begin\ listing\ region:\ ,
39 | rangebeginsuffix=,
40 | rangeendprefix=\ \ \%\%\%\ end\ listing\ region:\ ,
41 | rangeendsuffix=,
42 | includerangemarker=false,
43 | keepspaces=true,
44 | }
45 | \newcommand\lstinputregion[3][]{\lstinputlisting[linerange=#3-#3,#1]{#2}}
46 | \def\lst@outputspace{{\ifx\lst@bkgcolor\empty\color{white}\else\lst@bkgcolor\fi\lst@visiblespace}}% this works for acroread, but not for atril :-(
47 |
48 | \lstnewenvironment{forestexample}[1][]{%
49 | \PackageWarning{forest-doc}{Compiling example}{}%
50 | \global\let\lst@intname\@empty
51 | \gdef\lst@sample{}%
52 | \def\forestexample@layout{tree on left}%
53 | \def\forestexample@treebin{box}%
54 | \pgfqkeys{/forestexample}{label format,#1}%
55 | \pgfkeysgetvalue{/forestexample/counter}\forestexample@temp
56 | \ifdefempty\forestexample@temp{}{\addtocounter{\forestexample@temp}{1}}%
57 | \setbox\lst@samplebox=\hbox\bgroup
58 | \pgfkeysvalueof{/forestexample/tree prefix}%
59 | \lst@BeginAlsoWriteFile{\jobname.tmp}%
60 | }{%
61 | \lst@EndWriteFile
62 | \pgfkeysvalueof{/forestexample/tree suffix}%
63 | \egroup
64 | \global\setbox\codebox=\box\lst@samplebox
65 | \global\setbox
66 | \treebox
67 | \csname forestexample@treebin@\forestexample@treebin\endcsname
68 | \pgfkeys{/forestexample/do layout/.expanded=\forestexample@layout}%
69 | }
70 | \pgfqkeys{/forestexample}{%
71 | .unknown/.code={\lstset{\pgfkeyscurrentname={#1}}},
72 | index/.code={\indexex[not print]{#1}},
73 | index>/.code={\indexex[not print]>{#1}},
74 | code prefix/.code={\gdef\lst@sample{#1}},
75 | tree prefix/.initial={},
76 | tree suffix/.initial={},
77 | counter/.initial=lstlisting,
78 | no label/.style={counter={}},
79 | label format/.store in=\@currentlabel,
80 | label format/.default={\arabic{\pgfkeysvalueof{/forestexample/counter}}},
81 | tree width/.initial={\dimexpr\linewidth-\wd\codebox-
82 | \glueexpr\pgfkeysvalueof{/forestexample/center skip}\relax\relax},
83 | layout/.store in=\forestexample@layout,
84 | tree bin/.store in=\forestexample@treebin,
85 | do layout/.is choice,
86 | do layout/export/.code={%
87 | \pgfkeysgetvalue{/forestexample/counter}\forestexample@temp
88 | \ifdefempty\forestexample@temp{}{\addtocounter{\forestexample@temp}{-1}}%
89 | },
90 | left skip/.initial={\glueexpr 0pt plus .4\linewidth minus \marginparsep + 0pt minus \@totalleftmargin + 0pt minus .75\marginparwidth},
91 | center skip/.initial={3em plus 0.1\linewidth minus 2em},
92 | right skip/.initial={0pt plus .4\linewidth},
93 | tree left skip/.initial=0pt,
94 | tree right skip/.initial=0pt,
95 | code left skip/.initial=0pt,
96 | code right skip/.initial=0pt,
97 | label y offset/.initial={\height-1ex}, % looks better to me this way
98 | do layout/tree on left/.code={%
99 | \begin{list}{}{\leftmargin 0pt}
100 | \item
101 | \@tempdima=\ifdim\totalht\treebox>\totalht\codebox
102 | \dimexpr0.5 \totalht\treebox\relax
103 | \else
104 | \dimexpr0.5 \totalht\codebox\relax
105 | \fi
106 | \mbox{%
107 | \mbox{\hbox to \linewidth{%
108 | \hskip\pgfkeysvalueof{/forestexample/left skip}\relax
109 | \textvcenter{\box\treebox}%
110 | \hskip\pgfkeysvalueof{/forestexample/center skip}\relax
111 | \hbox{\hskip-\@totalleftmargin\box\codebox\hskip\@totalleftmargin}%
112 | \hskip\pgfkeysvalueof{/forestexample/right skip}\relax
113 | }}%
114 | \forestexample@label
115 | }%
116 | \end{list}
117 | },
118 | v sep/.initial={1ex},
119 | align/.initial=center,
120 | do layout/tree on top/.code={%
121 | \begin{list}{}{\leftmargin 0pt \parsep 0pt \itemsep \pgfkeysvalueof{/forestexample/v sep}\relax}
122 | \item \forestexample@align{tree}\forestexample@label
123 | \item \forestexample@align{code}
124 | \end{list}
125 | },
126 | do layout/tree on bottom/.code={%
127 | \begin{list}{}{\leftmargin 0pt \parsep 0pt \itemsep \pgfkeysvalueof{/forestexample/v sep}\relax}
128 | \item \forestexample@align{code}\forestexample@label
129 | \item \forestexample@align{tree}
130 | \end{list}
131 | },
132 | do layout/only tree/.code={%
133 | \forestexample@align{tree}\forestexample@label
134 | },
135 | do layout/only code/.code={%
136 | \forestexample@align{code}\forestexample@label
137 | },
138 | }
139 | \newbox\treebox
140 | \newbox\codebox
141 | \def\forestexample@treebin@box{%
142 | \hbox{\lst@sampleInput}%
143 | }
144 | \def\forestexample@treebin@minipage{%
145 | \hbox{%
146 | \begin{minipage}{\pgfkeysvalueof{/forestexample/tree width}}%
147 | \lst@sampleInput
148 | \end{minipage}%
149 | }%
150 | }
151 | \def\forestexample@label{%
152 | \pgfkeysgetvalue{/forestexample/counter}\forestexample@temp
153 | \ifdefempty\forestexample@temp{}{%
154 | \makebox[0pt][l]{%
155 | \hskip-\linewidth
156 | \hskip-\@totalleftmargin
157 | \hskip\textwidth
158 | \hskip\marginparsep
159 | \raisebox
160 | {\dimexpr\@tempdima+\depth-\pgfkeysvalueof{/forestexample/label y offset}}%
161 | {\hbox to 0pt{\scriptsize(\@currentlabel)}}%
162 | }%
163 | }%
164 | }
165 | \def\forestexample@align#1{%
166 | \pgfkeysgetvalue{/forestexample/align}\forestexample@temp
167 | \mbox{\hbox to \linewidth{%
168 | \csname forestexample@align@left@\forestexample@temp\endcsname
169 | \hspace*{\pgfkeysvalueof{/forestexample/#1 left skip}}%
170 | \mbox{\expandafter\box\csname #1box\endcsname}%
171 | \hspace*{\pgfkeysvalueof{/forestexample/#1 right skip}}%
172 | \csname forestexample@align@right@\forestexample@temp\endcsname
173 | }}%
174 | }
175 | \def\forestexample@align@left@left{}
176 | \def\forestexample@align@right@left{}
177 | \def\forestexample@align@left@right{\hfill}
178 | \def\forestexample@align@right@right{}
179 | \def\forestexample@align@left@center{\hfill}
180 | \def\forestexample@align@right@center{\hfill}
181 | \newcommand\forestexampleimport[1][]{%
182 | \def\forestexample@layout{tree on left}%
183 | \pgfkeysgetvalue{/forestexample/counter}\forestexample@temp
184 | \ifdefempty\forestexample@temp{}{\addtocounter{\forestexample@temp}{1}}%
185 | \pgfqkeys{/forestexample}{%
186 | label format,
187 | do layout/.expanded=\forestexample@layout
188 | }%
189 | }
190 |
191 | \def\totalht#1{\dimexpr\ht#1 + \dp#1\relax}
192 | \def\textvcenter#1{\raisebox{\dimexpr .5\depth-.5\height}{#1}}
193 |
194 | % For some reason, lstdoc's version kills all spaces in defaults ...
195 | \def\lst@syntaxlabel@#1>#2\relax
196 | %{\edef\lst@temp{\zap@space#2 \@empty}}
197 | {\edef\lst@temp{#2}}
198 |
199 |
200 |
201 |
202 | \def\getforestversion#1/#2/#3 v#4 #5\getforestversion{v#4}
203 | \edef\forestversion{%
204 | \expandafter\expandafter\expandafter\getforestversion
205 | \csname ver@forest.sty\endcsname\getforestversion}
206 |
207 | \def\settodayfromforestdateA#1/#2/#3 v#4 #5\settodayfromforestdateA{\def\year{#1}\def\month{#2}\def\day{#3}}
208 | \def\settodayfromforestdate{\expandafter\expandafter\expandafter\settodayfromforestdateA\csname ver@forest.sty\endcsname\settodayfromforestdateA}
209 |
210 | \def\TikZ;{{\rm Ti\emph{k}Z}}
211 | \def\PGF;{\textsc{pgf}}
212 | \def\foRest;{\textsc{Forest}}
213 | \def\FoRest;{\textsc{Forest}}
214 |
215 | \let\keyname\texttt
216 | \newcommand\cmdname[1]{\texttt{\char\escapechar#1}}
217 |
218 | \gdef\greaterthan{>}
219 | \def\gobbleone#1{}
220 |
221 | \newcommand{\Repeat}[1]{% from tex.se http://tex.stackexchange.com/a/16194/16819
222 | \expandafter\@Repeat\expandafter{\the\numexpr #1\relax}%
223 | }
224 | \def\@Repeat#1{%
225 | \ifnum#1>0
226 | \expandafter\@@Repeat\expandafter{\the\numexpr #1-1\expandafter\relax\expandafter}%
227 | \else
228 | \expandafter\@gobble
229 | \fi
230 | }
231 | \def\@@Repeat#1#2{%
232 | \@Repeat{#1}{#2}#2%
233 | }
234 | \def\spaces#1{\Repeat{#1}\space}
235 |
236 | \RequirePackage{dingbat}
237 |
238 |
239 | %%% Local Variables:
240 | %%% mode: latex
241 | %%% fill-column: 100
242 | %%% TeX-command-default: "Make PDF"
243 | %%% TeX-master: "forest-doc"
244 | %%% End:
245 |
--------------------------------------------------------------------------------
/forest-index.dtx:
--------------------------------------------------------------------------------
1 | % \CheckSum{755}
2 | % \iffalse meta-comment
3 | % forest-index.dtx
4 | %% `forest-index' is an indexing system for the documentation of package
5 | %% `forest', using the package itself. (The derived `forest-index.sty' is not
6 | %% needed to use the package.)
7 | %%
8 | %% Copyright (c) 2012-2017 Saso Zivanovic
9 | %% (Sa\v{s}o \v{Z}ivanovi\'{c})
10 | %% saso.zivanovic@guest.arnes.si
11 | %%
12 | %% This work may be distributed and/or modified under the
13 | %% conditions of the LaTeX Project Public License, either version 1.3
14 | %% of this license or (at your option) any later version.
15 | %% The latest version of this license is in
16 | %%
17 | %% http://www.latex-project.org/lppl.txt
18 | %%
19 | %% and version 1.3 or later is part of all distributions of LaTeX
20 | %% version 2005/12/01 or later.
21 | %%
22 | %% This work has the LPPL maintenance status `author-maintained'.
23 | %%
24 | %% This file is a part of package `forest'. For the list of files
25 | %% constituting the package see main source file of the package,
26 | %% `forest.dtx', or the derived `forest.sty'.
27 | %%
28 | % \fi
29 | %
30 | % \newcommand\entry[1]{{``#1''}}
31 | %
32 | % \subsection{\protect{\texttt{forest-index}}}
33 | % \label{sec:forest-index}
34 | %
35 | % The indexing system used to document the \foRest; package uses the
36 | % package itself quite heavily. While this might be a bit surprising
37 | % at first sight, as indexing draws no trees, the indexing package
38 | % illustrates the usage of some of the more exotic features and
39 | % usage-cases of the \foRest; package, which is why its source is
40 | % included in this documentation.\footnote{Indexing with this package
41 | % makes the compilation very slow, so I cannot whole-heartedly
42 | % recommend it, but I still hope that it will make a useful example.}
43 | %
44 | % This package has three main functions:
45 | % \begin{itemize}
46 | % \item It is possible to index subentries using a \emph{short form}
47 | % of their index key, i.e.\ without referring to their ancestor
48 | % entries. For example, instead of writing |\index{option>content}|
49 | % one can simply write |\index{content}|. (Obviously, the subentry
50 | % must \entry{content} be defined as belonging to entry
51 | % \entry{option} first. This is done using
52 | % |\indexdef{option>content}|.) This works for all keys which are a
53 | % subentry of a single entry.
54 | % \item All subentries are automatically entered as main entries as
55 | % well, with a qualificator of which entry they belong to. So,
56 | % |\index{option>content}| produces two index entries: entry
57 | % \entry{option} with subentry \entry{content} and entry
58 | % \entry{content \scriptsize option}. This works for an arbitrary
59 | % number of subentry levels.
60 | % \item Entries can be given options that format the appearance of the
61 | % entry and/or its descendants in both text and index. (Entries that
62 | % format the appearance of their descendants are called categories
63 | % below.)
64 | % \item If |hyperref| package is loaded, the following hyperlinks are
65 | % created besides the standard ones linking the page numbers in
66 | % index to text:
67 | % \begin{enumerate*}[(i)]
68 | % \item entries in text link to the definition in text,
69 | % \item definitions in the text link to the index entry,
70 | % \item categories in index are cross-linked.
71 | % \end{enumerate*}
72 | %
73 | % \end{itemize}
74 | %
75 | % The \foRest; package mainly enters the picture with respect to the
76 | % entry formatting. A simple (narrow) tree is built containing an entry
77 | % and all its ancestors. Formatting instructions are then processed
78 | % using \foRest;'s option processing mechanisms.
79 | %
80 | % Finally, note that this package might change without retaining
81 | % backwards compatibility, and that changes of this package will not
82 | % be entered into the changelog.
83 | %
84 | % Identification.
85 | % \begin{macrocode}
86 | \ProvidesPackage{forest-index}
87 | \RequirePackage{forest}
88 | % \end{macrocode}
89 | % Remember the original \LaTeX's |\index| command.
90 | % \begin{macrocode}
91 | \let\forestindex@LaTeX@index\index
92 | % \end{macrocode}
93 | %
94 | % \subsubsection*{The user interface macros}
95 | %
96 | % \DescribeMacro{\index} is the general purpose macro.
97 | % \DescribeMacro{\indexdef} and \DescribeMacro{\indexex} are
98 | % shorthands for indexing definitions and
99 | % examples. \DescribeMacro{\indexitem} is a combination of |\indexdef|
100 | % and the |\item| of the |lstdoc| package. It automatically indexes
101 | % the command being documented. \DescribeMacro{\indexset} neither
102 | % typesets or indexes the entry, but only configures it; it is usually
103 | % used to configure categories. All these macros parse their
104 | % arguments using |xparse|. The arguments, listed in the reverse
105 | % order:
106 | % \begin{itemize}
107 | % \item The final argument, which is the only mandatory argument, is a
108 | % comma-separated list of index keys.
109 | % \item The boolean switch |>| just before the mandatory argument
110 | % signals that the keys are given in the full form. Otherwise, keys
111 | % without a level separator are considered short.
112 | % \item Indexing options are given by the |[|optional |]| argument.
113 | % \item The first |(|optional|)| argument of:
114 | % \begin{compactitem}
115 | % \item |\indexitem|: specifies the default value of the command.
116 | % \item |\index|: is used to
117 | % provide ``early'' options.
118 | % \end{compactitem}
119 | % \end{itemize}
120 | %
121 | % Among the options of these commands, three keylists are of special
122 | % importance: |index_key_format|, |index_form_format| and
123 | % |print_format|. These hold instructions on how to format the index
124 | % key, the form of the entry in the index and the form of the entry in
125 | % the main text. They work by modifying the contents of an
126 | % \indexex{autowrapped toks} register |result|.
127 | %
128 | % An example: how macros are indexed in this documentation. Style
129 | % |macro| defined below does everything needed to format a macro name:
130 | % it detokenizes the given name (in case the name contains some funny
131 | % characters), prefixes the backslash, wraps in in the typewriter
132 | % font, adds color and hyperlink (the final two styles are defined in
133 | % below this package). Note the usage of |\protect|: it is needed
134 | % because we want to use these styles to format entries not just in
135 | % the main next, but also in the index.
136 | % \lstinputregion{forest-doc.tex}{index_macro_style} Then, we
137 | % configure the main level entry \entry{macro}: the child of this
138 | % entry will be formatted (both in index and in the main text) using
139 | % the previously defined style.
140 | % \lstinputregion{forest-doc.tex}{index_macro_category} Usage is then
141 | % simple: we write |\indexex{macro>forestoption}| (or simply
142 | % |\indexex{forestoption}| to get \indexex{forestoption}.
143 | %
144 | % \begin{macrocode}
145 | \DeclareDocumentCommand\indexdef{O{} t> m}{%
146 | \IfBooleanTF{#2}
147 | {\let\forestindex@resolvekey\forestindex@resolvekey@long}
148 | {\let\forestindex@resolvekey\forestindex@resolvekey@shortorlong}%
149 | \forestindex@index{definition}{#1}{#3}}
150 | \DeclareDocumentCommand\indexex{O{} t> m}{%
151 | \IfBooleanTF{#2}
152 | {\let\forestindex@resolvekey\forestindex@resolvekey@long}
153 | {\let\forestindex@resolvekey\forestindex@resolvekey@shortorlong}%
154 | \forestindex@index{example}{#1}{#3}}
155 | % \DeclareDocumentCommand\indexitem{D(){} O{} t> m}{%
156 | % \IfBooleanTF{#3}
157 | % {\let\forestindex@resolvekey\forestindex@resolvekey@long}
158 | % {\let\forestindex@resolvekey\forestindex@resolvekey@shortorlong}%
159 | % \forestindex@index{definition}{default={#1},print format=item,#2}{#4}}
160 | \DeclareDocumentCommand\indexitem{D(){} O{} t> m}{%
161 | \let\forestindex@resolvekey\forestindex@resolvekey@long
162 | \forestindex@index{definition}{default={#1},#2,print format+=item}{#4}}
163 | \DeclareDocumentCommand\indexset{O{} t> m}{%
164 | \IfBooleanTF{#2}
165 | {\let\forestindex@resolvekey\forestindex@resolvekey@long}
166 | {\let\forestindex@resolvekey\forestindex@resolvekey@shortorlong}%
167 | \forestindex@index{not print,not index,definition}{set={#1}}{#3}}
168 | \DeclareDocumentCommand\index{D(){} O{} t> m}{%
169 | \IfBooleanTF{#3}
170 | {\let\forestindex@resolvekey\forestindex@resolvekey@long}
171 | {\let\forestindex@resolvekey\forestindex@resolvekey@shortorlong}%
172 | \forestindex@index{#1}{#2}{#4}%
173 | }
174 | % \end{macrocode}
175 | % All UI macros call this macro.
176 | % \begin{arguments}
177 | % \item early option keylist
178 | % \item late option keylist
179 | % \item a comma-sep list of forest index key (full or short form). A
180 | % key can be given an argument using |key=argument| syntax. How the
181 | % argument is used is up to the user. For example, the
182 | % \entry{environment} entry of the \foRest; documentation uses it to
183 | % typeset the contents of the environment:
184 | % \lstinputregion{forest-doc.tex}{forest_environment_doc}
185 | % \end{arguments}
186 | % \begin{macrocode}
187 | \def\forestindex@index#1#2#3{%
188 | % \end{macrocode}
189 | % Partition the index keylist into single keys. And put it all in a group: the
190 | % persistent stuff is saved globally.
191 | % \begin{macrocode}
192 | {\forcsvlist{\forestindex@forkey{#1}{#2}}{#3}}%
193 | }
194 | \def\forestindex@forkey#1#2#3{%
195 | % \end{macrocode}
196 | % Short-key resolution. The result is stored into |\forestindex@fullkey|.
197 | % \begin{macrocode}
198 | \forestindex@resolvekey{#3}%
199 | % \end{macrocode}
200 | % Manipulate arguments a bit, so that we can use our quick-and-dirty one-arg
201 | % memoization.
202 | % \begin{macrocode}
203 | %\forestset{@index/.process={__o}{#1}{#2}{\forestindex@fullkey}}
204 | \edef\forest@marshal{%
205 | \noexpand\forestindex@index@{%
206 | {\unexpanded{#1}}%
207 | {\unexpanded{#2}}%
208 | {\expandonce{\forestindex@fullkey}}%
209 | }%
210 | }\forest@marshal
211 | }
212 | % \end{macrocode}
213 | % Call the central processing command, style |@index|. See how
214 | % \indexex{handler>process} is used to expand (once) the last argument.
215 | % \begin{macrocode}
216 | \def\forestindex@index@#1{\forestset{@index/.process={__o}#1}}
217 | \forestset{
218 | % \end{macrocode}
219 | % \subsubsection*{Declarations}
220 | %
221 | % Should we print and/or index the entry? For example,
222 | % |\index[not_print]{...}| will index silently (as \LaTeX's |\index|
223 | % command does).
224 | % \begin{macrocode}
225 | declare boolean register=print,
226 | declare boolean register=index,
227 | declare boolean register=short,
228 | % \end{macrocode}
229 | % Options |name|, |content|, |key| and |argument| hold info about the
230 | % current entry. We need to declare only the latter two, the former
231 | % two we steal from \foRest;.
232 | % \begin{macrocode}
233 | declare toks={key}{},
234 | declare toks={argument}{},
235 | % \end{macrocode}
236 | % These options will hold first the initial, and then the calculated
237 | % values of the index key, index form and the form in text. When
238 | % (late) options are executed, these options are initialized to the
239 | % value of option |key|; it is safe to modify them at this point.
240 | % Afterwards, they will be further processed by keylists
241 | % |index_key_format|, |index_form_format| and |print_format|,
242 | % respectively.
243 | % \begin{macrocode}
244 | declare toks={index key}{},
245 | declare toks={index form}{},
246 | declare toks={print form}{},
247 | % \end{macrocode}
248 | % The customization of entries' appearance is done by specifying the
249 | % following three keylists. The keylists work by modifying register
250 | % |result|.
251 | % \begin{macrocode}
252 | declare keylist={index key format}{},
253 | declare keylist={index format}{},
254 | declare keylist={print format}{},
255 | declare autowrapped toks register=result,
256 | % \end{macrocode}
257 | % Some shorthands.
258 | % \begin{macrocode}
259 | format'/.style={print format'={#1}, index format'={#1}},
260 | format/.style={print format={#1}, index format={#1}},
261 | format+/.style={print format+={#1}, index format+={#1}},
262 | +format/.style={+print format={#1}, +index format={#1}},
263 | form/.style={print form={#1},index form={#1}},
264 | form+/.style={print form+={#1},index form+={#1}},
265 | +form/.style={+print form={#1},+index form={#1}},
266 | % \end{macrocode}
267 | % Entry types are normal (default), definition, example. Only
268 | % definitions are special, as their options are automatically saved.
269 | % \begin{macrocode}
270 | declare toks register=index entry type,
271 | definition/.style={index entry type=definition},
272 | normal/.style={index entry type=normal},
273 | example/.style={index entry type=example},
274 | normal,
275 | % \end{macrocode}
276 | % This option is used internally to store the hyper ids.
277 | % \begin{macrocode}
278 | declare toks={index@hypertarget}{},
279 | every index begin/.style={},
280 | every index end/.style={},
281 | % \end{macrocode}
282 | % Some formatting tools need to know whether we're typesetting text or
283 | % index: this info is stored in the |stage| register.\indexex[margin]{declare toks register}
284 | % \begin{macrocode}
285 | declare toks register=stage,
286 | % \end{macrocode}
287 | %
288 | % \subsubsection*{The central processing command}
289 | % \begin{arguments}
290 | % \item early option keylist (these are only used to define category
291 | % ``@unknown'' at the end of this package)
292 | % \item late option keylist
293 | % \item index key (full form)
294 | % \end{arguments}
295 | % \begin{macrocode}
296 | @index/.style n args={3}{
297 | % \end{macrocode}
298 | % Set the defaults.
299 | % \begin{macrocode}
300 | print, index, index entry type=normal, set'={}, short,
301 | % \end{macrocode}
302 | % Create the tree structure:
303 | % |[entry[subentry[subsubentry...]]]|. Three options of every node
304 | % created:
305 | % \begin{compactitem}
306 | % \item |key| contains the key of the (sub)entry
307 | % \item |name| contains the full path to the (sub)entry
308 | % \item |arguments| contains the arguments given to the (sub)entry's key
309 | % \item |content| contains the full key, with arguments for all but
310 | % the most deeply embedded subentry
311 | % \end{compactitem}
312 | % \indexex{for step=\indexex{nodewalk}} is used because
313 | % |create@subentry@node| walks down the created tree. At |if n=0|
314 | % below, we're thus positioned at the lowest node.\indexex[margin]{step>nodewalk}
315 | % \begin{macrocode}
316 | for nodewalk={
317 | % \end{macrocode}
318 | % The components of the full key are separated using \indexex{split},
319 | % with different keys being executed for the first component and the
320 | % rest.
321 | % \begin{macrocode}
322 | split={#3}{>}{create@main@entry@node, create@subentry@node},
323 | % \end{macrocode}
324 | % Remove the argument from the most deeply embedded subentry.
325 | % \begin{macrocode}
326 | if n=0{
327 | content/.option=key,
328 | }{
329 | content/.process={OOw2} {!parent.content} {key} {##1>##2},
330 | }
331 | }{},
332 | for root'={
333 | % \end{macrocode}
334 | % Don't memoize if the key is of an unknown category.
335 | % \begin{macrocode}
336 | if strequal/.process={O}{!root.name}{@unknown}{TeX=\global\forest@memoizing@ok@false}{},
337 | % \end{macrocode}
338 | % Option |print_form| is what will be typeset in the text. Option
339 | % |index_key| is the key that will be used for sorting the
340 | % index. Option |index_form| is what will be typeset in the index. All
341 | % these are initialized to the |key|. See how
342 | % \indexex{handler>option} is used to assign an option value to
343 | % another option.
344 | % \begin{macrocode}
345 | for tree={
346 | print form/.option=key,
347 | index key/.option=key,
348 | index form/.option=key,
349 | },
350 | % \end{macrocode}
351 | % Below, \indexex{node key>on invalid} is set to \indexex{value of=on invalid>fake} at four points.
352 | % This is so we won't get in trouble when |\indexset|ting the
353 | % categories: when the category formatting code will try to step into
354 | % the child, it will fail as the child does not exist when |\indexset|
355 | % is called for the category; but we ignore the failure.
356 | %
357 | % Go to the the most deeply embedded subentry.\indexex[margin]{first leaf'}
358 | % \begin{macrocode}
359 | for first leaf'={
360 | % \end{macrocode}
361 | % Execute every index options and the given early options.
362 | % \begin{macrocode}
363 | on invalid={fake}{
364 | every index begin,
365 | #1,
366 | },
367 | % \end{macrocode}
368 | % Ancestors are walked in the \indexex{reverse} order (top down). At
369 | % every node, the saved configuration is executed (if it exists).
370 | % \begin{macrocode}
371 | for reverse={current and ancestors}{on invalid={fake}{@@index/\forestoption{name}/.try}},
372 | % \end{macrocode}
373 | % We don't execute the saved configuration for definitions, as
374 | % definitions are where the configuration is set.
375 | % \begin{macrocode}
376 | if index entry type={definition}{}{%
377 | on invalid={fake}{@@index/\forestoption{name}/.try},
378 | },
379 | % \end{macrocode}
380 | % Execute late (well, normal) options. See the discussion about early
381 | % options above.
382 | % \begin{macrocode}
383 | on invalid={fake}{
384 | #2,
385 | every index end
386 | },
387 | % \end{macrocode}
388 | % Remember the given config for the rest of the document.
389 | % \begin{macrocode}
390 | if set={}{}{save@session},
391 | % \end{macrocode}
392 | % If we're at a definition, save the config into the auxiliary file.
393 | % \begin{macrocode}
394 | if index entry type={definition}{save@foridx}{},
395 | },
396 | stage={},
397 | % \end{macrocode}
398 | % Create hyperlink targets of the form |.entry.subentry.subsubentry...|.
399 | %
400 | % \FoRest; points:
401 | % \begin{enumerate*}[(i)]
402 | % \item the generic conditional \indexex{if},
403 | % \item handler \index{handler>process},
404 | % \end{enumerate*}
405 | % \begin{macrocode}
406 | if index={
407 | index@hypertarget/.process={OS_= ? l_ w2}
408 | {index key}
409 | {}
410 | {}{.}
411 | {##2##1},
412 | for descendants={
413 | index@hypertarget/.process={OO S _l1= ? w2 }
414 | {!parent.index@hypertarget}{index key}
415 | {}
416 | {##1} % empty index key
417 | {##1.##2} % otherwise
418 | },
419 | }{},
420 | % \end{macrocode}
421 | % Index.
422 | % \begin{macrocode}
423 | if index={
424 | begingroup,
425 | stage=index,
426 | % \end{macrocode}
427 | % For each (sub)entry, format the |index_key| using the instructions
428 | % in |index_key_format|.
429 | % \begin{macrocode}
430 | for tree={
431 | result/.option=index key,
432 | process keylist'={index key format}{current},
433 | index key/.register=result,
434 | },
435 | % \end{macrocode}
436 | % For each (sub)entry, format the |index_form| using the instructions
437 | % in |index_form_format|.
438 | % \begin{macrocode}
439 | for tree={
440 | result/.option=index form,
441 | process keylist'={index format}{current},
442 | index form/.register=result,
443 | },
444 | % \end{macrocode}
445 | % Create an index entry for all nodes where |index_form| is non-empty.
446 | % \begin{macrocode}
447 | where index form={}{}{
448 | % \end{macrocode}
449 | % All the ancestor nodes with an non-empty |index_form| will be
450 | % appended (in script size, as a hyperlink) to the |index_form| of the
451 | % current node.
452 | % \begin{macrocode}
453 | if n=0{
454 | temptoksb={},
455 | }{
456 | temptoksc={},
457 | for ancestors={
458 | if index form={}{}{
459 | temptoksb+/.expanded={\forestregister{temptoksc}%
460 | \noexpand\protect\noexpand\hyperlinknocolor{%
461 | \forestoption{index@hypertarget}}{\forestoption{index form}}},
462 | temptoksc={,\space},
463 | },
464 | },
465 | if temptoksb={}{}{
466 | +temptoksb={\protect\space\begingroup\protect\scriptsize},
467 | temptoksb+={\endgroup},
468 | },
469 | },
470 | temptoksa={},
471 | result'={},
472 | if n children=0{tempboola}{not tempboola},
473 | where index form={}{}{
474 | % \end{macrocode}
475 | % Create the hypertarget that the definitions in text and other index entries
476 | % will point to.
477 | % \begin{macrocode}
478 | temptoksd/.expanded={\noexpand\protect\noexpand\hypertarget{%
479 | \forestoption{index@hypertarget}}{}},
480 | % \end{macrocode}
481 | % Add the (inner) current node to the index entry of the (outer) current node.
482 | % \begin{macrocode}
483 | result+/.expanded={%
484 | \forestregister{temptoksa}%
485 | \forestoption{index key}%
486 | =\forestoption{index form}%
487 | \forestregister{temptoksd}%
488 | \forestregister{temptoksb}%
489 | },
490 | temptoksa={>},
491 | temptoksb={},
492 | },
493 | % \end{macrocode}
494 | % Do the actual indexing.
495 | % \begin{macrocode}
496 | result+/.expanded={|indexpagenumber\forestregister{index entry type}},
497 | TeX and memoize/.expanded={\noexpand\forestindex@LaTeX@index{\forestregister{result}}},
498 | },
499 | endgroup
500 | }{},
501 | if print={
502 | begingroup,
503 | stage=print,
504 | % \end{macrocode}
505 | % For each (sub)entry, format the |print_form| using the instructions
506 | % in |print_form_format|.
507 | % \begin{macrocode}
508 | for tree={
509 | result/.option=print form,
510 | process keylist'={print format}{current},
511 | print form/.register=result,
512 | },
513 | % \end{macrocode}
514 | % Typeset the entry in the text.
515 | % \begin{macrocode}
516 | for first leaf'={TeX and memoize/.expanded={\forestoption{print form}}},
517 | endgroup,
518 | }{},
519 | }
520 | },
521 | % \end{macrocode}
522 | % Create the main entry node and set to be the root.
523 | % \begin{macrocode}
524 | create@main@entry@node/.style={% #1 = subentry
525 | set root={[]},
526 | do dynamics, for root'={process delayed=tree},
527 | root',
528 | setup@entry@node={#1}
529 | },
530 | % \end{macrocode}
531 | % Create a subentry node and move into it.
532 | % \begin{macrocode}
533 | create@subentry@node/.style={
534 | append={[]},
535 | do dynamics, for root'={process delayed=tree},
536 | n=1,
537 | setup@entry@node={#1}
538 | },
539 | % \end{macrocode}
540 | % Parse \#1 into |key| and |argument|, and assign |name| and |content|.
541 | % \begin{macrocode}
542 | setup@entry@node/.style={
543 | options={
544 | split={#1}{=}{key,argument},
545 | if n=0{
546 | name'/.option=key,
547 | content={#1},
548 | }{
549 | name'/.process={OOw2} {!parent.name} {key} {##1>##2},
550 | content/.process={Ow1} {!parent.content} {##1>#1},
551 | },
552 | }
553 | },
554 | }
555 | % \end{macrocode}
556 | % \subsubsection*{Saving and loading the options}
557 | % \begin{macrocode}
558 | \forestset{
559 | % \end{macrocode}
560 | % This register holds whatever we need to remember.
561 | % \begin{macrocode}
562 | declare keylist register=set,
563 | % \end{macrocode}
564 | % Besides storing the keylist in the register, also immediately
565 | % execute it.\indexex[margin]{Autoforward register}.
566 | % \begin{macrocode}
567 | Autoforward register={set}{##1},
568 | % \end{macrocode}
569 | % Remember things by saving them in a global style.
570 | % \begin{macrocode}
571 | save@session/.style={@@index/\forestoption{name}/.global style/.register=set},
572 | % \end{macrocode}
573 | % Save thinks to the auxiliary file.
574 | % \begin{macrocode}
575 | save@foridx/.style={
576 | % \end{macrocode}
577 | % Don't save entries of unknown category.
578 | % \begin{macrocode}
579 | if strequal/.process={O}{!root.name}{@unknown}{}{
580 | % \end{macrocode}
581 | % Don't save if nothing is set.
582 | % \begin{macrocode}
583 | if set={}{}{
584 | TeX and memoize/.expanded={%
585 | \noexpand\immediate\noexpand\write\noexpand\forestindex@out{%
586 | \noexpand\string\noexpand\indexloadsettings\noexpand\unexpanded{{\forestoption{name}}{\forestregister{set}}}%
587 | }%
588 | },
589 | },
590 | },
591 | % \end{macrocode}
592 | % Save the full form of the key in the auxiliary file. Obviously, do
593 | % it only for subentries. The full form contains whatever arguments
594 | % were given to the non-last component.
595 | % \begin{macrocode}
596 | if key/.process={O}{content} {} {%
597 | if short={
598 | TeX and memoize/.expanded={%
599 | \noexpand\immediate\noexpand\write\noexpand\forestindex@out{%
600 | \noexpand\string\noexpand\indexdefineshortkey\noexpand\unexpanded{{\forestoption{key}}{\forestoption{content}}}%
601 | }%
602 | }%
603 | }{}
604 | }
605 | }
606 | }
607 | % \end{macrocode}
608 | % Load settings from the auxiliary file into the global style. Warn
609 | % if anything was configured more than once (e.g.\ by |\indexdef|ing
610 | % the same key twice).
611 | % \begin{macrocode}
612 | \def\indexloadsettings#1#2{%
613 | \pgfkeysifdefined{/forest/@@index/#1/.@cmd}{%
614 | \forestindex@loadsettings@warning{#1}%
615 | }{}%
616 | % #s in #2 are doubled; the following \def removes one layer of doubling
617 | \def\forest@temp{#2}%
618 | \forestset{@@index/#1/.global style/.expand once=\forest@temp}%
619 | }
620 | \def\forestindex@loadsettings@warning#1{%
621 | \PackageWarning{forest-index}{Forest index key "#1" was configured more than once!
622 | I'm using the last configuration.}%
623 | }
624 | % \end{macrocode}
625 | % Load the full form of a short key from the auxiliary file. Out of
626 | % kindness for the end user, remember all the full keys corresponding
627 | % to a short key: this will make a more informative warning below.
628 | % \begin{macrocode}
629 | \def\indexdefineshortkey#1#2{%
630 | \def\forestindex@temp@short{#1}%
631 | \def\forestindex@temp@long{#2}%
632 | \ifx\forestindex@temp@short\forestindex@temp@long
633 | \else
634 | \ifcsdef{index@long@#1}{%
635 | \global\cslet{index@long@#1}\relax
636 | \csgappto{index@alllong@#1}{,#2}%
637 | }{%
638 | \global\csgdef{index@long@#1}{#2}%
639 | \global\csgdef{index@alllong@#1}{#2}%
640 | }%
641 | \fi
642 | }
643 | % \end{macrocode}
644 | % \subsubsection*{Short key resolution}
645 | %
646 | % Nothing to do for a long key.
647 | % \begin{macrocode}
648 | \def\forestindex@resolvekey@long#1{\def\forestindex@fullkey{#1}}
649 | % \end{macrocode}
650 | % Decide whether a key is short or long based on the absence or
651 | % presence of the level separator |>|.
652 | % \begin{macrocode}
653 | \def\forestindex@resolvekey@shortorlong#1{%
654 | \pgfutil@in@>{#1}%
655 | \ifpgfutil@in@
656 | \expandafter\def\expandafter\forestindex@fullkey
657 | \else
658 | \expandafter\forestindex@resolvekey@short
659 | \fi
660 | {#1}%
661 | }
662 | % \end{macrocode}
663 | % Before resolving the short key, we need to split the user input into
664 | % the key and the argument. The latter is then appended to the full
665 | % key (which can, in principle, contain arguments for other components
666 | % as well).
667 | % \begin{macrocode}
668 | \def\forestindex@resolvekey@short#1{%
669 | \forestset{split={#1}{=}{index@resolveshortkey@key,index@resolveshortkey@arg}}%
670 | }
671 | \forestset{
672 | index@resolveshortkey@key/.code={%
673 | \ifcsvoid{index@long@#1}{%
674 | \forestindex@resolveshortkey@warning{#1}%
675 | \def\forestindex@fullkey{@unknown>#1}%
676 | }{%
677 | \letcs\forestindex@fullkey{index@long@#1}%
678 | }%
679 | },
680 | index@resolveshortkey@arg/.code={%
681 | \appto\forestindex@fullkey{=#1}%
682 | },
683 | }
684 | \def\forestindex@resolveshortkey@warning#1{%
685 | \PackageWarning{forest-index}{Cannot resolve short forest index key "#1".
686 | These are the definitions I found (from the previous run):
687 | "\csuse{index@alllong@#1}"}%
688 | }
689 | % \end{macrocode}
690 | % \subsubsection*{Formatting styles}
691 | %
692 | % Define default colors for index entry types and provide a style that
693 | % typesets the entry in text (but not index) in the desired color.
694 | % \begin{macrocode}
695 | \forestset{
696 | normal color/.initial=blue,
697 | definition color/.initial=red,
698 | example color/.initial=darkgreen,
699 | print in color/.style={if stage={print}{result/.expanded=\noexpand\protect\noexpand\textcolor{%
700 | \pgfkeysvalueof{/forest/#1 color}}{\unexpanded{##1}}}{}},
701 | print in color/.default=\forestregister{index entry type},
702 | % \end{macrocode}
703 | % Use this style in |..._format| keylists if you want the index
704 | % entries to be hyperlinks to the definition, and the definition to be
705 | % a hyperlink to the index.
706 | % \begin{macrocode}
707 | hyper/.style={
708 | if stage={index}{}{
709 | if index entry type={definition}{
710 | result/.expanded={\noexpand\hypertarget{\forestoption{name}}%
711 | {\noexpand\hyperlink{\forestoption{index@hypertarget}}{\forestregister{result}}}}
712 | }{
713 | result/.expanded=\noexpand\hyperlink{\forestoption{name}}{\forestregister{result}}
714 | }
715 | }
716 | },
717 | }
718 | % \end{macrocode}
719 | % Color page numbers in the index, with or without |hyperref| package.
720 | % \begin{macrocode}
721 | \ifdef\hyperpage{%
722 | \newcommand\indexpagenumbernormal[1]{{%
723 | \hypersetup{linkcolor=\pgfkeysvalueof{/forest/normal color}}\hyperpage{#1}}}
724 | \newcommand\indexpagenumberdefinition[1]{{%
725 | \hypersetup{linkcolor=\pgfkeysvalueof{/forest/definition color}}\hyperpage{#1}}}
726 | \newcommand\indexpagenumberexample[1]{{%
727 | \hypersetup{linkcolor=\pgfkeysvalueof{/forest/example color}}\hyperpage{#1}}}
728 | }{
729 | \newcommand\indexpagenumbernormal[1]{%
730 | \textcolor{\pgfkeysvalueof{/forest/normal color}}{#1}}
731 | \newcommand\indexpagenumberdefinition[1]{%
732 | \textcolor{\pgfkeysvalueof{/forest/definition color}}{#1}}
733 | \newcommand\indexpagenumberexample[1]{%
734 | \textcolor{\pgfkeysvalueof{/forest/example color}}{#1}}
735 | }
736 | % \end{macrocode}
737 | % Provide dummy |\hyper...| commands if |hyperref| is not loaded.
738 | % \begin{macrocode}
739 | \providecommand\hyperlink[2]{#2}
740 | \providecommand\hypertarget[2]{#2}
741 | \providecommand\hypersetup[1]{}
742 | % \end{macrocode}
743 | % This is used by entry qualifiers: we want them to be hyperlinks, but black.
744 | % \begin{macrocode}
745 | \newcommand\hyperlinknocolor[2]{{\hypersetup{linkcolor=black}\hyperlink{#1}{#2}}}
746 | % \end{macrocode}
747 | %
748 | % Use style |item| to have the index entry (in text) function as the
749 | % |\item| of a |lstdoc|'s |syntax| environment.
750 | % \begin{macrocode}
751 | \forestset{
752 | declare toks register=default,
753 | default={},
754 | item/.style={
755 | result/.process= {_RORw4}
756 | {} {default} {!parent.print form} {result}
757 | {\item[,##2,##3]{##4}},
758 | },
759 | }
760 | % \end{macrocode}
761 | %
762 | % \subsubsection*{Utilities}
763 | %
764 | % We will need a global version of several |pgfkeys| commands.
765 | % \begin{macrocode}
766 | \pgfkeys{/handlers/.global style/.code=\pgfkeys{\pgfkeyscurrentpath/.global code=\pgfkeysalso{#1}}}
767 | \pgfkeysdef{/handlers/.global code}{\pgfkeysglobaldef{\pgfkeyscurrentpath}{#1}}
768 | \long\def\pgfkeysglobaldef#1#2{%
769 | \long\def\pgfkeys@temp##1\pgfeov{#2}%
770 | \pgfkeysgloballet{#1/.@cmd}{\pgfkeys@temp}%
771 | \pgfkeysglobalsetvalue{#1/.@body}{#2}%
772 | }
773 | \def\pgfkeysgloballet#1#2{%
774 | \expandafter\global\expandafter\let\csname pgfk@#1\endcsname#2%
775 | }
776 | \long\def\pgfkeysglobalsetvalue#1#2{%
777 | \pgfkeys@temptoks{#2}\expandafter\xdef\csname pgfk@#1\endcsname{\the\pgfkeys@temptoks}%
778 | }
779 | \forestset{
780 | % unlike pgfmath function strequal, |if strequal| does not expand the compared args!
781 | if strequal/.code n args={4}{\ifstrequal{#1}{#2}{\pgfkeysalso{#3}}{\pgfkeysalso{#4}}},
782 | }
783 | % \end{macrocode}
784 | % Begin and end group, \foRest;-style:
785 | % \begin{macrocode}
786 | \forestset{
787 | begingroup/.code={\begingroup},
788 | endgroup/.code={\endgroup},
789 | }
790 | % \end{macrocode}
791 | %
792 | % \subsubsection{Memoize}
793 | %
794 | % Quick and dirty memoization. Single argument macros only. Does not support nesting.
795 | %
796 | % \begin{macrocode}
797 | \newtoks\forest@memo@key
798 | \newtoks\forest@memo
799 | \newif\ifforest@memoizing@now@
800 | \newif\ifforest@memoizing@ok@
801 | \newif\ifforest@execandmemoize@
802 | \def\forest@memoize#1{% #1 = \cs
803 | \cslet{forest@memo@orig@\string#1}#1%
804 | \def#1##1{%
805 | \ifforest@memoizing@now@
806 | \forest@globalsaveandrestoreifcs{forest@execandmemoize@}{%
807 | \global\forest@execandmemoize@false
808 | \csname forest@memo@orig@\string#1\endcsname{##1}%
809 | }%
810 | \else
811 | \expandafter\global\expandafter\forest@memo@key\expandafter{\detokenize{forest@memo@#1{##1}}}%
812 | \ifcsname\the\forest@memo@key\endcsname
813 | \@escapeifif{\csname\the\forest@memo@key\endcsname}%
814 | \else
815 | \@escapeifif{%
816 | \global\forest@memo{}%
817 | \global\forest@memoizing@ok@true
818 | \global\forest@memoizing@now@true
819 | \global\forest@execandmemoize@true
820 | \csname forest@memo@orig@\string#1\endcsname{##1}%
821 | \global\forest@execandmemoize@false
822 | \global\forest@memoizing@now@false
823 | \ifforest@memoizing@ok@
824 | \csxdef{\the\forest@memo@key}{\the\forest@memo}%
825 | \immediate\write\forest@memo@out{%
826 | \noexpand\forest@memo@load{\the\forest@memo@key}{\the\forest@memo}%
827 | }%
828 | \fi
829 | }%
830 | \fi
831 | \fi
832 | }%
833 | }
834 | \def\forest@memo@load#1#2{%
835 | % \end{macrocode}
836 | % The following two |\def|s remove one level of hash-doubling from the
837 | % arguments, introduced by |\write|.
838 | % \begin{macrocode}
839 | \def\forest@temp@key{#1}%
840 | \def\forest@temp@value{#2}%
841 | \csxdef{\detokenize\expandafter{\forest@temp@key}}{\expandonce\forest@temp@value}%
842 | \immediate\write\forest@memo@out{%
843 | \noexpand\forest@memo@load{\detokenize\expandafter{\forest@temp@key}}{\detokenize\expandafter{\forest@temp@value}}%
844 | }%
845 | }
846 | \forestset{
847 | TeX and memoize/.code={\forest@execandmemoize{#1}},
848 | }
849 | \def\forest@execandmemoize#1{%
850 | \ifforest@execandmemoize@
851 | \let\forest@memo@next\forest@execandmemoize@
852 | \else
853 | \let\forest@memo@next\@gobble
854 | \fi
855 | \forest@memo@next{#1}%
856 | #1%
857 | }
858 | \def\forest@execandmemoize@#1{%
859 | \gapptotoks\forest@memo{#1}%
860 | }
861 | \def\forest@memo@filename{\jobname.memo}
862 | \newwrite\forest@memo@out
863 | \immediate\openout\forest@memo@out=\forest@memo@filename.tmp
864 | \IfFileExists{\forest@memo@filename}{%
865 | \input\forest@memo@filename\relax
866 | }{}%
867 | \AtEndDocument{%
868 | \immediate\closeout\forest@memo@out
869 | \forest@file@copy{\forest@memo@filename.tmp}{\forest@memo@filename}%
870 | }
871 | % \end{macrocode}
872 | % Commenting the following line turns off memoization.
873 | % \begin{macrocode}
874 | \forest@memoize\forestindex@index@
875 | % \end{macrocode}
876 | %
877 | % \subsubsection*{Initialize}
878 | %
879 | % Declare category ``@unknown''.
880 | % \begin{macrocode}
881 | \index(not print,not index)[%
882 | set={
883 | index key=unknown,
884 | form={\textbf{unknown!!}},
885 | for first={format={result/.expanded=\noexpand\textbf{\forestregister{result}??}}}
886 | },
887 | ]>{@unknown}
888 | % \end{macrocode}
889 | % Load the auxiliary file made in the previous compilation, and open
890 | % it for writing to save data from this compilation.
891 | % \begin{macrocode}
892 | \def\forestindex@filename{\jobname.foridx}
893 | \IfFileExists{\forestindex@filename}{%
894 | \input\forestindex@filename\relax
895 | }{}%
896 | \newwrite\forestindex@out
897 | \immediate\openout\forestindex@out=\forestindex@filename.tmp
898 | \AtEndDocument{%
899 | \immediate\closeout\forestindex@out
900 | \forest@file@copy{\forestindex@filename.tmp}{\forestindex@filename}%
901 | }
902 | \endinput
903 | % \end{macrocode}
904 | %
905 | %%% \iffalse
906 | %%% Local Variables:
907 | %%% mode: doctex
908 | %%% TeX-master: "forest-doc"
909 | %%% TeX-command-default: "sty"
910 | %%% End:
911 | %%% \fi
912 |
--------------------------------------------------------------------------------
/forest-libs.dtx:
--------------------------------------------------------------------------------
1 | % \CheckSum{236}
2 | % \iffalse meta-comment
3 | % forest-libs.dtx
4 | %% `forest-libs' is a collection of libraries for package `forest'.
5 | %%
6 | %% Copyright (c) 2012-2017 Saso Zivanovic
7 | %% (Sa\v{s}o \v{Z}ivanovi\'{c})
8 | %% saso.zivanovic@guest.arnes.si
9 | %%
10 | %% This work may be distributed and/or modified under the
11 | %% conditions of the LaTeX Project Public License, either version 1.3
12 | %% of this license or (at your option) any later version.
13 | %% The latest version of this license is in
14 | %%
15 | %% http://www.latex-project.org/lppl.txt
16 | %%
17 | %% and version 1.3 or later is part of all distributions of LaTeX
18 | %% version 2005/12/01 or later.
19 | %%
20 | %% This work has the LPPL maintenance status `author-maintained'.
21 | %%
22 | %% This file is a part of package `forest'. For the list of files
23 | %% constituting the package see main source file of the package,
24 | %% `forest.dtx', or the derived `forest.sty'.
25 | %%
26 | % \fi
27 | %
28 | % \section{Libraries}
29 | %
30 | % This chapter contains not only the reference of commands found in libraries and some examples of
31 | % their usage, but also their definitions. This is done in the hope that these definitions, being
32 | % mostly styles, will be useful as examples of the core features of the package. I even managed to
33 | % comment them a bit \dots
34 | %
35 | % \paragraph{Disclaimer.} At least in the initial stages of a library's development, the function
36 | % and interface of macros and keys defined in a library might change without backwards compatibility
37 | % support! Though I'll try to keep this from happening \dots
38 | %
39 | % \begin{macrocode}
40 | \RequirePackage{forest}
41 | % \end{macrocode}
42 | %
43 | %\iffalse
44 | %<*linguistics>
45 | %\fi
46 | % \librarysection{linguistics}
47 | % \begin{macrocode}
48 | \ProvidesForestLibrary{linguistics}[2017/07/14 v0.1.2]
49 | % \end{macrocode}
50 | %
51 | % Defaults:
52 | % \begin{macrocode}
53 | \forestset{
54 | linguistics@set@baseline/.style={
55 | if phantom={for next node=linguistics@set@baseline}{baseline}
56 | },
57 | libraries/linguistics/defaults/.style={
58 | default preamble={
59 | % \end{macrocode}
60 | % Edges of the children will ``meet'' under the node:
61 | % \begin{macrocode}
62 | sn edges,
63 | % \end{macrocode}
64 | % The root of the tree will be aligned with the text \dots\ or, more commonly, the example number.
65 | % More precisely, we actually align the first (in linear order) non-phantom node. This covers the
66 | % common case of side-by-side trees joined with a phantom root.
67 | % \begin{macrocode}
68 | before drawing tree={
69 | if nodewalk valid={name=forest@baseline@node}{}{linguistics@set@baseline},
70 | },
71 | % \end{macrocode}
72 | % Enable (centered) multi-line nodes.
73 | % \begin{macrocode}
74 | for tree={align=center},
75 | },
76 | },
77 | }
78 | % \end{macrocode}
79 | %
80 | % There's no linguistics without c-command\footnote{The definition of c-command is as follows: a node c-commands its siblings and their descendants.} \dots
81 | % \begin{syntax}
82 | % \indexitem{step>c-commanded} Visit all the nodes c-commanded by the current node.
83 | % \indexitem{step>c-commanders} Visit all the c-commanders of the current node, starting from the closest.
84 | %
85 | % \begin{forestexample}[tree bin=minipage,index={branch',c-commanded}]
86 | % \begin{forest}
87 | % [VP
88 | % [DP[John]]
89 | % [V'
90 | % [V, draw, for c-commanded={draw,circle}
91 | % [sent]
92 | % ]
93 | % [DP[Mary]]
94 | % [DP[D[a]][NP[letter]]]
95 | % ]
96 | % ]
97 | % \end{forest}
98 | % \end{forestexample}
99 | %
100 | % See how \indexex{branch'} is used to define |c-commanded|, and how \indexex{while nodewalk valid} and \indexex{nodewalk key>fake} are combined in the definition of |c-commanders|.
101 | % \begin{macrocode}
102 | \forestset{
103 | define long step={c-commanded}{style}{branch'={siblings,descendants}},
104 | define long step={c-commanders}{style}{while nodewalk valid={parent}{siblings,fake=parent}},
105 | }
106 | % \end{macrocode}
107 | %
108 | % |c-commanders| could also be defined using \indexex{branch}:
109 | % \begin{lstlisting}
110 | % branch={current and ancestors, siblings}
111 | % \end{lstlisting}
112 | %
113 | % \indexitem{node key>sn edges}
114 | %
115 | % In linguistics, most people want the parent-child edge to go from the \emph{s}outh of the parent
116 | % to the \emph{n}orth of the child. This is achieved by this (badly named) style, which makes the
117 | % entire (sub)tree have such edges.
118 | %
119 | % \begin{forestexample}
120 | % \begin{forest}
121 | % sn edges
122 | % [VP
123 | % [DP]
124 | % [V'
125 | % [V]
126 | % [DP]
127 | % ]
128 | % ]
129 | % \end{forest}
130 | % \end{forestexample}
131 | %
132 | % \begin{macrocode}
133 | \forestset{
134 | sn edges/.style={
135 | for tree={
136 | parent anchor=children, child anchor=parent
137 | }
138 | },
139 | }
140 | % \end{macrocode}
141 | %
142 | % A note on implementation. Despite its name, this style does not refer to the |south| and |north|
143 | % anchor of the parent and the child node directly. If it did so, it would only work for trees with
144 | % standard linguistic \index{grow}|=-90|. So we rather use \FoRest;'s growth direction based
145 | % anchors: \index{anchor>children} always faces the children and \index{anchor>parent} always faces
146 | % the parent, so the edge will always be between them, and the normal, upward growing trees will
147 | % look good as well.
148 | %
149 | % \begin{forestexample}[index={anchor>south,anchor>north,option>parent anchor,option>child anchor}]
150 | % \begin{forest}
151 | % [bad![VP,no edge, for tree={grow=90, edge=red},
152 | % for tree={parent anchor=south, child anchor=north} % bad
153 | % [DP][V'[V][DP]]]]
154 | % \end{forest}
155 | % \begin{forest}
156 | % [good![VP, no edge, for tree={grow=90, edge=green},
157 | % ~sn edges~ % good!
158 | % [DP][V'[V][DP]]]]
159 | % \end{forest}
160 | % \end{forestexample}
161 | %
162 | % \indexitem{node key>roof} Makes the edge to parent a triangular roof.
163 | % \begin{macrocode}
164 | \forestset{
165 | roof/.style={edge path'={%
166 | (.parent first)--(!u.children)--(.parent last)--cycle
167 | }
168 | },
169 | }
170 | % \end{macrocode}
171 | %
172 | % \indexitem{node key>nice empty nodes}
173 | %
174 | % We often need empty nodes: tree (\ref{ex:niceemptynodes}a) shows how they look like by default:
175 | % ugly.
176 | %
177 | % First, we don't want the gaps: we change the shape of empty nodes to coordinate. We get tree
178 | % (\ref{ex:niceemptynodes}b).
179 | %
180 | % Second, the empty nodes seem too close
181 | % to the other (especially empty) nodes (this is a result of a small
182 | % default |s_sep|). We could use a greater \index{s sep}, but a better solution seems
183 | % to be to use |calign=fixed_angles|. The result is shown in (\ref{ex:niceemptynodes}c).
184 | %
185 | % However, at the transitions from empty to non-empty nodes, tree (\ref{ex:niceemptynodes}c)
186 | % seems to zigzag (although the base points of the spine nodes
187 | % are perfectly in line), and the edge to the empty node left to VP
188 | % seems too long (it reaches to the level of VP's base, while we'd
189 | % prefer it to stop at the same level as the edge to VP itself). The
190 | % first problem is solved by substituting |fixed_angles| for
191 | % |fixed_edge_angles|; the second one, by anchoring siblings of
192 | % empty nodes at north. Voilà, (\ref{ex:niceemptynodes}d)!
193 | %
194 | % \begin{forestexample}[label=ex:niceemptynodes,layout=tree on bottom,index={fixed angles,fixed edge angles,calign,tree,delay,where option,content,for step,step>parent,step>children,option>anchor}]
195 | % \forestset{
196 | % xlist/.style={
197 | % phantom,
198 | % for children={no edge,replace by={[,append,
199 | % delay={content/.wrap pgfmath arg={\csname @alph\endcsname{##1}.}{n()+#1}}
200 | % ]}}
201 | % },
202 | % xlist/.default=0
203 | % }
204 | % \begin{forest}
205 | % [,~xlist~,
206 | % for tree={after packing node={s+=0.1pt}}, % hack!!!
207 | % [CP, %(a)
208 | % [][[][[][VP[DP[John]][V'[V[loves]][DP[Mary]]]]]]]
209 | % [CP, delay={where content={}{shape=coordinate}{}} %(b)
210 | % [][[][[][VP[DP[John]][V'[V[loves]][DP[Mary]]]]]]]
211 | % [CP, for tree={calign=fixed angles}, %(c)
212 | % delay={where content={}{shape=coordinate}{}}
213 | % [][[][[][VP[DP[John]][V'[V[loves]][DP[Mary]]]]]]]
214 | % [CP, ~nice empty nodes~ %(d)
215 | % [][[][[][VP[DP[John]][V'[V[loves]][DP[Mary]]]]]]]
216 | % ]
217 | % \end{forest}
218 | % \end{forestexample}
219 | %
220 | % \begin{macrocode}
221 | \forestset{
222 | nice empty nodes/.style={
223 | for tree={calign=fixed edge angles},
224 | delay={where content={}{shape=coordinate,
225 | for current and siblings={anchor=north}}{}}
226 | },
227 | }
228 | % \end{macrocode}
229 | %
230 | % \indexitem{node key>draw brackets} Outputs the bracket representation of the tree.
231 | % \indexitem{node key>draw brackets compact}
232 | % \itemnosep
233 | % \indexitem{node key>draw brackets wide} These keys control whether the brackets have extra
234 | % spaces around them (|wide|) or not (|compact|).
235 | % \begin{macrocode}
236 | \providecommand\text[1]{\mbox{\scriptsize#1}}
237 | \forestset{
238 | draw brackets compact/.code={\let\drawbracketsspace\relax},
239 | draw brackets wide/.code={\let\drawbracketsspace\space},
240 | draw brackets/.style={
241 | % \end{macrocode}
242 | % There's stuff to do both before (output the opening bracket and the content) and after (output the
243 | % closing bracket) processing the children, so we use \indexex{for tree'}.
244 | % \begin{macrocode}
245 | for tree'={
246 | TeX={[%
247 | % \end{macrocode}
248 | % Complication: \index{content format} must be expanded in advance, to correctly process tabular environments implicitely loaded by \index{align}|=|\index{value of=align>center}, which is the default in this library. (Not that one would want a multiline output in the bracket representation, but it's better than crashing.)
249 | % \begin{macrocode}
250 | \edef\forestdrawbracketscontentformat{\foresteoption{content format}}%
251 | },
252 | if n children=0{
253 | TeX={\drawbracketsspace\forestdrawbracketscontentformat\drawbracketsspace}
254 | }{
255 | TeX={\textsubscript{\text{\forestdrawbracketscontentformat}}\drawbracketsspace}
256 | },
257 | }{
258 | TeX={]\drawbracketsspace},
259 | }
260 | },
261 | draw brackets wide
262 | }
263 | % \end{macrocode}
264 | % \end{syntax}
265 | %
266 | % \subsubsection{GP1}
267 | %
268 | % \begin{syntax}
269 | % \indexitem{node key>GP1}
270 | %
271 | % For Government Phonology (v1) representations. Here, the big trick
272 | % is to evenly space $\times$s by having a large enough |outer_xsep|
273 | % (adjustable), and then, before drawing (timing control option
274 | % |before_drawing_tree|), setting |outer_xsep| back to 0pt. The last step
275 | % is important, otherwise the arrows between $\times$s won't draw!
276 | %
277 | % An example of an ``embedded'' |GP1| style:
278 | % \begin{forestexample}[layout=tree on bottom,index={where option,tier,for step,step>children,content,tikz,option>l,dimen+,no edge},index>={!}]
279 | % \begin{forest}
280 | % myGP1/.style={
281 | % ~GP1~,
282 | % delay={where tier={x}{
283 | % for children={content=\textipa{##1}}}{}},
284 | % tikz={\draw[dotted](.south)--
285 | % (!1.north west)--(!l.north east)--cycle;},
286 | % for children={l+=5mm,no edge}
287 | % }
288 | % [VP[DP[John,tier=word,myGP1
289 | % [O[x[dZ]]]
290 | % [R[N[x[6]]]]
291 | % [O[x[n]]]
292 | % [R[N[x]]]
293 | % ]][V'[V[loves,tier=word,myGP1
294 | % [O[x[l]]]
295 | % [R[N[x[a]]]]
296 | % [O[x[v]]]
297 | % [R[N[x]]]
298 | % [O[x[z]]]
299 | % [R[N[x]]]
300 | % ]][DP[Mary,tier=word,myGP1
301 | % [O[x[m]]]
302 | % [R[N[x[e]]]]
303 | % [O[x[r]]]
304 | % [R[N[x[i]]]]
305 | % ]]]]
306 | % \end{forest}%
307 | % \end{forestexample}
308 | %
309 | % And an example of annotations.
310 | % \begin{forestexample}
311 | % \begin{forest}[,phantom,s sep=1cm
312 | % [{[ei]}, GP1
313 | % [R[N[x[A,~el~[I,~head~,~associate=N~]]][x]]]
314 | % ]
315 | % [{[mars]}, GP1
316 | % [O[x[m]]]
317 | % [R[N[x[a]]][x,~encircle~,densely dotted[r]]]
318 | % [O[x,~encircle~,~govern=<~[s]]]
319 | % [R,~fen~[N[x]]]
320 | % ]
321 | % ]\end{forest}
322 | % \end{forestexample}
323 | %
324 | % \begin{macrocode}
325 | \newbox\standardnodestrutbox
326 | \setbox\standardnodestrutbox=\hbox to 0pt{\phantom{\forestOve{standard node}{content}}}
327 | \def\standardnodestrut{\copy\standardnodestrutbox}
328 | \forestset{
329 | GP1/.style 2 args={
330 | for n={1}{baseline},
331 | s sep=0pt, l sep=0pt,
332 | for descendants={
333 | l sep=0pt, l={#1},
334 | anchor=base,calign=first,child anchor=north,
335 | inner xsep=1pt,inner ysep=2pt,outer sep=0pt,s sep=0pt,
336 | },
337 | delay={
338 | if content={}{phantom}{for children={no edge}},
339 | for tree={
340 | if content={O}{tier=OR}{},
341 | if content={R}{tier=OR}{},
342 | if content={N}{tier=N}{},
343 | if content={x}{
344 | tier=x,content={$\times$},outer xsep={#2},
345 | for tree={calign=center},
346 | for descendants={content format={\noexpand\standardnodestrut\forestoption{content}}},
347 | before drawing tree={outer xsep=0pt,delay={typeset node}},
348 | s sep=4pt
349 | }{},
350 | },
351 | },
352 | before drawing tree={where content={}{parent anchor=center,child anchor=center}{}},
353 | },
354 | GP1/.default={5ex}{8.0pt},
355 | associate/.style={%
356 | tikz+={\draw[densely dotted](!)--(!#1);}},
357 | spread/.style={
358 | before drawing tree={tikz+={\draw[dotted](!)--(!#1);}}},
359 | govern/.style={
360 | before drawing tree={tikz+={\draw[->](!)--(!#1);}}},
361 | p-govern/.style={
362 | before drawing tree={tikz+={\draw[->](.north) to[out=150,in=30] (!#1.north);}}},
363 | no p-govern/.style={
364 | before drawing tree={tikz+={\draw[->,loosely dashed](.north) to[out=150,in=30] (!#1.north);}}},
365 | encircle/.style={before drawing tree={circle,draw,inner sep=0pt}},
366 | fen/.style={pin={[font=\footnotesize,inner sep=1pt,pin edge=<-]10:\textsc{Fen}}},
367 | el/.style={content=\textsc{\textbf{##1}}},
368 | head/.style={content=\textsc{\textbf{\underline{##1}}}}
369 | }
370 | % \end{macrocode}
371 | % \end{syntax}
372 | %\iffalse
373 | %
374 | %\fi
375 | %
376 | %
377 | %
378 | %\iffalse
379 | %<*edges>
380 | %\fi
381 | % \librarysection{edges}
382 | % \begin{macrocode}
383 | \ProvidesForestLibrary{edges}[2016/12/05 v0.1.1]
384 | % \end{macrocode}
385 | %
386 | % \begin{syntax}
387 | %
388 | % \indexitem{node key>forked edge'}
389 | %
390 | % Sets a forked edge to the current node. Arbitrary growth direction and node rotation are
391 | % supported.
392 | %
393 | % \indexitem{node key>forked edge}
394 | %
395 | % Like \index{forked edge'}, but it also sets \index{option>parent anchor} and \index{option>child
396 | % anchor} to the likely values of \index{anchor>children} and \index{anchor>parent}, respectively.
397 | %
398 | % \indexitem(tree){node key>forked edges}|=|\meta{nodewalk}
399 | %
400 | % Invokes \index{forked edge} for all nodes in the \meta{nodewalk}, by default the entire (sub)tree
401 | % rooted in the current node.
402 | %
403 | % \indexitem{option>fork sep} The \index{forest cs>l}-distance between the parent anchor and the
404 | % fork.
405 | %
406 | % \end{syntax}
407 | %
408 | % \begin{forestexample}[index={for step,tree,grow',forked edges}]
409 | % \begin{forest}
410 | % for tree={grow'=0,draw},
411 | % forked edges,
412 | % [/
413 | % [home
414 | % [saso
415 | % [Download]
416 | % [TeX]
417 | % ]
418 | % [alja]
419 | % [joe]
420 | % ]
421 | % [usr
422 | % [bin]
423 | % [share]
424 | % ]
425 | % ]
426 | % \end{forest}
427 | % \end{forestexample}
428 | %
429 | % See how growth direction based anchors \indexex{anchor>children} and \indexex{anchor>parent} are
430 | % used in the definition below to easily take care of arbitrary \index{grow} and
431 | % \index{rotate}.
432 | % \begin{macrocode}
433 | \forestset{
434 | declare dimen={fork sep}{0.5em},
435 | forked edge'/.style={
436 | edge={rotate/.option=!parent.grow},
437 | edge path'={(!u.parent anchor) -- ++(\forestoption{fork sep},0) |- (.child anchor)},
438 | },
439 | forked edge/.style={
440 | on invalid={fake}{!parent.parent anchor=children},
441 | child anchor=parent,
442 | forked edge',
443 | },
444 | forked edges/.style={for nodewalk={#1}{forked edge}},
445 | forked edges/.default=tree,
446 | }
447 | % \end{macrocode}
448 | %
449 | % \begin{syntax}
450 | % \indexitem{node key>folder} The children of the node are drawn like folders.
451 | %
452 | % All growth directions are supported (well, cardinal directions work perfectly; the others await
453 | % the sensitivity of packing to \index{edge path}), as well as node rotation and \index{reversed}
454 | % order of children.
455 | %
456 | % The outlook of the folder can be influenced by setting standard \foRest;'s options \index{l sep}
457 | % and \index{s sep} any time before packing, or \index{option>l} and \index{option>s} after
458 | % packing. Setting \index{option>l} and \index{option>s} before packing will have no influence on
459 | % the layout of the tree.
460 | %
461 | % \begin{syntax}
462 | % \indexitem(.45em){register>folder indent}|=|\meta{dimen}
463 | %
464 | % Specifies the shift of the parent's side of the edge in the \index{forest cs>l}-direction.
465 | % \end{syntax}
466 | %
467 | % \end{syntax}
468 | %
469 | % \begin{forestexample}[index={for step,tree,grow',folder}]
470 | % \begin{forest}
471 | % for tree={grow'=0,~folder~,draw}
472 | % [/
473 | % [home
474 | % [saso
475 | % [Download]
476 | % [TeX]
477 | % ]
478 | % [alja]
479 | % [joe]
480 | % ]
481 | % [usr
482 | % [bin]
483 | % [share]
484 | % ]
485 | % ]
486 | % \end{forest}
487 | % \end{forestexample}
488 | % \begin{macrocode}
489 | \forestset{
490 | declare dimen register=folder indent,
491 | folder indent=.45em,
492 | folder/.style={
493 | parent anchor=-children last,
494 | anchor=parent first,
495 | calign=child,
496 | calign primary child=1,
497 | for children={
498 | child anchor=parent,
499 | anchor=parent first,
500 | edge={rotate/.option=!parent.grow},
501 | edge path'/.expanded={
502 | ([xshift=\forestregister{folder indent}]!u.parent anchor) |- (.child anchor)
503 | },
504 | },
505 | after packing node={
506 | if n children=0{}{
507 | tempdiml=l_sep()-l("!1"),
508 | tempdims={-abs(max_s("","")-min_s("",""))-s_sep()},
509 | for children={
510 | l+=tempdiml,
511 | s+=tempdims()*(reversed()-0.5)*2,
512 | },
513 | },
514 | },
515 | }
516 | }
517 | % \end{macrocode}
518 | %\iffalse
519 | %
520 | %\fi
521 | % \forestset{every index end/.style={}}
522 | % \endinput
523 | % Local Variables:
524 | % mode: doctex
525 | % TeX-command-default: "sty"
526 | % fill-column: 100
527 | % TeX-master: "forest"
528 | % End:
529 |
--------------------------------------------------------------------------------
/forest-test.tex:
--------------------------------------------------------------------------------
1 | \documentclass{article}
2 | \usepackage[margin=1cm,landscape,twocolumn]{geometry}
3 | \usepackage{forest}
4 |
5 | \usepackage{titlesec}
6 | \newcommand{\sectionbreak}{\clearpage}
7 |
8 | \parindent 0pt
9 |
10 | \makeatletter
11 |
12 | \def\testmacro#1#2{% #1 = result, #2 = expected
13 | \def\test@result{#1}%
14 | \def\test@expected{#2}%
15 | \ifx\test@result\test@expected
16 | {#1}%
17 | \else
18 | {\textcolor{red}{#1} (expected: #2)}%
19 | \fi
20 | }
21 |
22 | \newcount\test@result@count
23 | \newcount\test@expected@count
24 | \def\testcount#1#2{% #1 = result, #2 = expected
25 | \test@result@count=#1\relax
26 | \test@expected@count=#2\relax
27 | \ifnum\test@result@count=\test@expected@count
28 | {#1}%
29 | \else
30 | {\textcolor{red}{#1} (expected: #2)}%
31 | \fi
32 | }
33 |
34 |
35 | \newdimen\test@result@dimen
36 | \newdimen\test@expected@dimen
37 | \def\testdimen#1#2{% #1 = result, #2 = expected
38 | \test@result@dimen=#1\relax
39 | \test@expected@dimen=#2\relax
40 | \ifdim\test@result@dimen=\test@expected@dimen
41 | {#1}%
42 | \else
43 | {\textcolor{red}{#1} (expected: #2)}%
44 | \fi
45 | }
46 |
47 |
48 | \begin{document}
49 |
50 | \section{Is it a number or dimension?}
51 | \label{sec:test-num-dim}
52 |
53 | \def\testnumdim#1#2#3{%
54 | % #1 = test for a number or dimension (num/dim)
55 | % #2 = expression to be tested
56 | % #3 = correct result (true/false)
57 | is \texttt{\detokenize{"#2"}} a #1?
58 | \begingroup
59 | %\tracingall
60 | \csname forest@is#1\endcsname{#2}{\forest@temptrue}{\forest@tempfalse}% test
61 | \csname testnumdim@collect@\ifforest@temp true\else false\fi @#1\endcsname
62 | \ifforest@temp\endgroup\forest@temptrue\else\endgroup\forest@tempfalse\fi
63 | \csname if#3\endcsname
64 | % "true" is the correct result
65 | \csname testnumdim@texeval@#1\endcsname{#2}% store correct num/dim result into \forest@temp
66 | expecting yes (\forest@temp),
67 | \ifforest@temp
68 | \ifx\forest@temp\forest@global@temp
69 | got it!
70 | \else
71 | but got yes (\textcolor{red}{\forest@global@temp}).
72 | \fi
73 | \else
74 | but got \textcolor{red}{no} (\forest@global@temp).
75 | \fi
76 | \else
77 | % "false" is the correct result
78 | expecting no,
79 | \ifforest@temp
80 | but got \textcolor{red}{yes} (\forest@global@temp).
81 | \else
82 | got it!
83 | \fi
84 | \fi
85 | }
86 | \def\testnumdim@collect@true@num{\xdef\forest@global@temp{\the\forest@isnum@count}}%
87 | \def\testnumdim@collect@false@num{\xdef\forest@global@temp{\the\forest@isnum@count}}%
88 | \def\testnumdim@texeval@num#1{\count0 #1\relax\edef\forest@temp{\the\count0}}%
89 |
90 | \def\testnumdim@collect@true@dim{\xdef\forest@global@temp{\the\forest@isdim@dimen}}%
91 | \def\testnumdim@collect@false@dim{\xdef\forest@global@temp{\the\forest@isnum@count.\forest@isdim@leadingzeros\the\forest@isdim@nonintpart\forest@isdim@unit}}%
92 | \def\testnumdim@texeval@dim#1{\dimen0 #1\relax\edef\forest@temp{\the\dimen0}}%
93 |
94 | \let\testnumdim@collect@true@baredim\testnumdim@collect@true@dim
95 | \let\testnumdim@collect@false@baredim\testnumdim@collect@false@dim
96 | \def\testnumdim@texeval@baredim#1{\dimen0 #1pt\relax\edef\forest@temp{\the\dimen0}}%
97 | \let\forest@isbaredim\forest@isdim
98 |
99 |
100 | \testnumdim{num}{42}{true}
101 | \\\newcount\mynum\testnumdim{num}{\the\mynum}{true}
102 | \\\testnumdim{num}{42 }{true}
103 | \\\testnumdim{num}{ 42}{true}
104 | \\\testnumdim{num}{ 42 }{true}
105 | \\\testnumdim{num}{0}{true}
106 | \\\testnumdim{num}{00}{true}
107 | \\\testnumdim{num}{01}{true}
108 | \\\testnumdim{num}{-0}{true}
109 | \\\testnumdim{num}{a}{false}
110 | \\\testnumdim{num}{a42}{false}
111 | \\\testnumdim{num}{42a}{false}
112 | \\\testnumdim{num}{-a}{false}
113 | \\\testnumdim{num}{a42a}{false}
114 | \\\testnumdim{num}{+42a}{false}
115 | \\\testnumdim{num}{+42}{true}
116 | \\\testnumdim{num}{-42}{true}
117 | \\\testnumdim{num}{--42}{true}
118 | \\\testnumdim{num}{- -42}{true}
119 | \\\testnumdim{num}{- -+ +42}{true}
120 | \\\testnumdim{num}{42!}{false}
121 | \\\testnumdim{num}{!42!}{false}
122 | \\\testnumdim{num}{!42}{false}
123 | \\\testnumdim{num}{42!a}{false}
124 | \\\testnumdim{num}{42a!}{false}
125 | \\\testnumdim{num}{042}{true}
126 | \\\testnumdim{num}{-042}{true}
127 | \\\testnumdim{num}{- 0a}{false}
128 | \\\testnumdim{num}{+ 0}{true}
129 | \\\testnumdim{num}{- 0}{true}
130 | \\\testnumdim{num}{0}{true}
131 | \\\testnumdim{num}{2147483647}{true}
132 | \\\testnumdim{num}{-2147483647}{true}
133 | \\\testnumdim{num}{-- - + 002147483647}{true}
134 | %\\\testnumdim{num}{2147483648}{} % number yes, but too big
135 | %\\\testnumdim{num}{-2147483648}{} % number yes, but too big
136 | \\\testnumdim{num}{0\space}{true}
137 | \\\testnumdim{num}{\space0}{true}
138 | \\\testnumdim{num}{\space0}{true}
139 | \\\testnumdim{num}{0\space\space\space}{false}
140 | \\\testnumdim{num}{0 }{true}
141 | \\\testnumdim{num}{0 \space}{false}
142 | \\\testnumdim{num}{\space0}{true}
143 | \\\testnumdim{num}{\space\space0}{true}
144 | \\\testnumdim{num}{\space\space\space0}{true}
145 | \\\testnumdim{num}{\the\count0}{true}
146 | \\\testnumdim{num}{\space0\the\count0}{true}
147 | \\\testnumdim{dim}{4.2pt}{true}
148 | \\\testnumdim{dim}{4.2p}{false}
149 | \\\testnumdim{dim}{4.cm}{true}
150 | \\\testnumdim{dim}{.42mm}{true}
151 | \\\testnumdim{dim}{.42mm }{true}
152 | \\\testnumdim{dim}{.42mm \space}{false}
153 | \\\testnumdim{dim}{.42mm a}{false}
154 | \\\testnumdim{baredim}{.42}{true}
155 | \\\testnumdim{dim}{cm}{false}
156 | \\\testnumdim{dim}{.cm}{true}
157 | \\\testnumdim{baredim}{.}{true}% pgfmath is inconsistent here: accepts this as a dimension but not as a count
158 | \\\testnumdim{dim}{ 1. pt}{true}
159 | \\\testnumdim{baredim}{42}{true}
160 | \\\testnumdim{baredim}{42.0}{true}
161 | \\\testnumdim{dim}{42cm}{true}
162 | \\\testnumdim{dim}{42 cm}{true}
163 | \\\testnumdim{dim}{16383.99998pt}{true}
164 | \\\testnumdim{dim}{16383.99998pt}{true}
165 | \\\testnumdim{dim}{-16383.99998pt}{true}
166 | \\\testnumdim{dim}{11PT}{true}
167 | \\\testnumdim{dim}{11PT }{true}
168 | \\\testnumdim{dim}{11ptt}{false}
169 | \\\testnumdim{dim}{11pt }{true}
170 | \\\testnumdim{dim}{21cm+21cm}{false}
171 | \\\testnumdim{dim}{4. 2cm}{false}
172 | \\\testnumdim{dim}{ 4.2 cm }{true}
173 |
174 | \section{Aggregate functions}
175 | \label{sec:aggregate-functions}
176 |
177 | \begin{forest}(stages={
178 | for root'={
179 | process keylist=given options,
180 | TeX={%
181 | \def\forestdebugtypeouttreenodeinfo{\forestoption{content}}%
182 | {\tt\forestdebug@typeouttree\forest@cn\temp\temp\\}
183 | },
184 | %
185 | tempcounta/.count=children,
186 | TeX/.process=Rw{tempcounta}{Number of root's children: \testcount{##1}{3}\\},
187 | %
188 | tempcounta/.sum={>O+n{content}}{tree},
189 | TeX/.process=Rw{tempcounta}{Sum of all nodes: \testcount{##1}{21}\\},
190 | %
191 | tempcounta/.average={>O+n{content}}{fake=2,1n},
192 | TeX/.process=Rw{tempcounta}{Average (rounded) of bottom nodes: \testcount{##1}{5}\\},
193 | %
194 | tempcounta/.product={>O+n{content}}{fake={21},current and ancestors},
195 | TeX/.process=Rw{tempcounta}{Product from root to 5: \testcount{##1}{15}\\},
196 | %
197 | tempcounta/.min={>O+n{content}}{tree},
198 | TeX/.process=Rw{tempcounta}{Minimum in tree: \testcount{##1}{1}\\},
199 | %
200 | tempcounta/.max={>O+n{content}}{tree},
201 | TeX/.process=Rw{tempcounta}{Maximum in tree: \testcount{##1}{6}\\},
202 | %
203 | TeX={Again: now interpret content as dimensions in points.\\},
204 | tempdima/.sum={>O+n{content}}{tree},
205 | TeX/.process=Rw{tempdima}{Sum of all nodes: \testdimen{##1}{21pt}\\},
206 | %
207 | tempdima/.average={>O+n{content}}{fake=2,1n},
208 | TeX/.process=Rw{tempdima}{Average (rounded) of bottom nodes: \testdimen{##1}{5.5pt}\\},
209 | %
210 | tempdima/.product={>O+n{content}}{fake={21},current and ancestors},
211 | TeX/.process=Rw{tempdima}{Product from root to 5: \testdimen{##1}{15pt}\\},
212 | %
213 | tempdima/.min={>O+n{content}}{tree},
214 | TeX/.process=Rw{tempdima}{Minimum in tree: \testdimen{##1}{1pt}\\},
215 | %
216 | tempdima/.max={>O+n{content}}{tree},
217 | TeX/.process=Rw{tempdima}{Maximum in tree: \testdimen{##1}{6pt}\\},
218 | %
219 | TeX={Sums again. Now sum using pgfmath:\\},
220 | temptoksa/.sum={content}{tree},
221 | TeX/.process=Rw{temptoksa}{Assign to toks: \testmacro{##1}{21.0}\\},
222 | tempdima/.sum={content}{tree},
223 | TeX/.process=Rw{tempdima}{Assign to dimen: \testdimen{##1}{21pt}\\},
224 | tempcounta/.sum={content}{tree},
225 | TeX/.process=Rw{tempcounta}{Assign to count: \testcount{##1}{21}\\},
226 | }
227 | })
228 | [1
229 | [2]
230 | [3
231 | [5]
232 | [6]
233 | ]
234 | [4]
235 | ]
236 | \end{forest}
237 |
238 |
239 | \end{document}
240 |
--------------------------------------------------------------------------------
/forest.ins:
--------------------------------------------------------------------------------
1 | %% forest.ins
2 | %%
3 | %% Copyright (c) 2012-2017 Saso Zivanovic
4 | %% saso.zivanovic@guest.arnes.si
5 | %%
6 | %% This work may be distributed and/or modified under the
7 | %% conditions of the LaTeX Project Public License, either version 1.3
8 | %% of this license or (at your option) any later version.
9 | %% The latest version of this license is in
10 | %%
11 | %% http://www.latex-project.org/lppl.txt
12 | %%
13 | %% and version 1.3 or later is part of all distributions of LaTeX
14 | %% version 2005/12/01 or later.
15 | %%
16 | %% This file is a part of package `forest'. For the list of files
17 | %% constituting the package see main source file of the package,
18 | %% `forest.dtx', or the derived `forest.sty'.
19 | %%
20 | \input docstrip.tex
21 | \keepsilent
22 | \preamble
23 | \endpreamble
24 | \askforoverwritefalse
25 | \generate{\file{forest.sty}{\from{forest.dtx}{}}}
26 | \generate{\file{forest-lib-linguistics.sty}{\from{forest-libs.dtx}{linguistics}}}
27 | \generate{\file{forest-lib-edges.sty}{\from{forest-libs.dtx}{edges}}}
28 | \endbatchfile
29 |
--------------------------------------------------------------------------------
/readme.tex:
--------------------------------------------------------------------------------
1 | \documentclass{minimal}
2 | \usepackage{forest}
3 | \def\getforestyear#1/#2/#3 v#4 #5\getforestyear{#1}
4 | \edef\forestyear{\expandafter\expandafter\expandafter\getforestyear\csname ver@forest.sty\endcsname\getforestyear}
5 | \begin{document}
6 | \newwrite\readme
7 | \immediate\openout\readme=README.txt
8 | \immediate\write\readme{%
9 | LaTeX package: forest [\csname ver@forest.sty\endcsname]^^J%
10 | ^^J%
11 | Copyright (c) 2012-\forestyear\space Saso Zivanovic^^J%
12 | \space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space(Sa\string\v{s}o \string\v{Z}ivanovi\string\'{c})^^J%
13 | saso.zivanovic@guest.arnes.si^^J%
14 | ^^J%
15 | ^^J%
16 | ABSTRACT^^J%
17 | ^^J%
18 | `forest' is a pgf/tikz-based package for drawing linguistic (and other^^J%
19 | kinds of) trees. Its main features are:^^J%
20 | - a packing algorithm which can produce very compact trees;^^J%
21 | - a user-friendly interface consisting of the familiar bracket^^J%
22 | encoding of trees plus the key--value interface to option-setting;^^J%
23 | - many tree-formatting options, with control over option values of^^J%
24 | individual nodes and mechanisms for their manipulation;^^J%
25 | - a powerful mechanism for traversing the tree;^^J%
26 | - the possibility to decorate the tree using the full power of pgf/tikz;^^J%
27 | - an externalization mechanism sensitive to code-changes.^^J%
28 | ^^J%
29 | ^^J%
30 | LICENSE^^J%
31 | ^^J%
32 | This work may be distributed and/or modified under the^^J%
33 | conditions of the LaTeX Project Public License, either version 1.3^^J%
34 | of this license or (at your option) any later version.^^J%
35 | The latest version of this license is in^^J%
36 | ^^J%
37 | http://www.latex-project.org/lppl.txt^^J%
38 | ^^J%
39 | and version 1.3 or later is part of all distributions of LaTeX^^J%
40 | version 2005/12/01 or later.^^J%
41 | ^^J%
42 | ^^J%
43 | For the list of files constituting the work see the main source file^^J%
44 | of the package, `forest.dtx', or the derived `forest.sty'.^^J%
45 | }
46 | \immediate\closeout\readme
47 | \end{document}
48 |
49 | %%% Local Variables:
50 | %%% mode: latex
51 | %%% TeX-master: t
52 | %%% End:
53 |
--------------------------------------------------------------------------------
/tex.bib:
--------------------------------------------------------------------------------
1 | @Manual{tikzpgf2.10,
2 | title = {TikZ \& PGF, Manual for Version 2.10},
3 | author = {Till Tantau},
4 | year = 2007,
5 | url = {http://sourceforge.net/projects/pgf}
6 | }
7 |
8 | @book{texbook,
9 | author = "Donald E. Knuth",
10 | title = "The {TeX}book",
11 | publisher = "Addison-Wesley",
12 | year = 1996,
13 | }
14 |
15 | @Manual{tikzpgf3.0.0,
16 | title = {TikZ \& PGF, Manual for Version 3.0.0},
17 | author = {Till Tantau},
18 | year = 2013,
19 | url = {http://sourceforge.net/projects/pgf}
20 | }
21 |
--------------------------------------------------------------------------------
/version.tex:
--------------------------------------------------------------------------------
1 | \documentclass{minimal}
2 | \usepackage{forest}
3 | \def\getforestversion#1/#2/#3 v#4 #5\getforestversion{#4}
4 | \edef\forestversion{\expandafter\expandafter\expandafter\getforestversion\csname ver@forest.sty\endcsname\getforestversion}
5 | \begin{document}
6 | \newwrite\version
7 | \immediate\openout\version=VERSION.txt
8 | \immediate\write\version{\forestversion}
9 | \immediate\closeout\version
10 | \end{document}
11 |
12 | %%% Local Variables:
13 | %%% mode: latex
14 | %%% TeX-master: t
15 | %%% End:
16 |
--------------------------------------------------------------------------------