├── .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 | --------------------------------------------------------------------------------