From 0b2ead45bf575abccc62ffb395140b6c32464a7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C5=A1o=20=C5=BDivanovi=C4=87?= Date: Tue, 17 Oct 2023 16:57:40 +0200 Subject: [PATCH] A complete, fully documented reimplementation. --- .gitignore | 38 + INSTALL.md | 216 + LICENCE | 8 +- Makefile | 141 +- Makefile.advice | 34 + Makefile.collargs | 32 + Makefile.package | 202 + Makefile.runtimes | 8 + README.md | 207 +- advice.edtx | 1095 ++ advice.ins | 33 + collargs.edtx | 2938 ++++++ collargs.ins | 33 + doc/.gitignore | 5 + doc/INSTALL.advice.md | 69 + doc/INSTALL.collargs.md | 68 + doc/README.advice.md | 8 + doc/README.collargs.md | 8 + doc/README.memoize.md | 11 + doc/examples/.gitignore | 6 + doc/examples/ConTeXt.tex.dtx | 11 + doc/examples/Makefile | 36 + doc/examples/_auto-ref.tex.dtx | 5 + .../_collargs-ignore-other-tags.tex.dtx | 7 + doc/examples/_collargs-verbatim.tex.dtx | 6 + doc/examples/automemoize-command.tex.dtx | 12 + doc/examples/automemoize-environment.tex.dtx | 14 + doc/examples/beamer.tex.dtx | 27 + doc/examples/book.tex.dtx | 22 + doc/examples/chained-advice.tex.dtx | 15 + doc/examples/chapters/chapter1.tex.dtx | 22 + doc/examples/clean-house.tex.dtx | 17 + doc/examples/collargs-makebox.tex.dtx | 11 + doc/examples/collargs-minipage.tex.dtx | 13 + doc/examples/collargs-nodelimiters.tex.dtx | 12 + doc/examples/collargs-processor.tex.dtx | 24 + .../collargs-transition-comment.tex.dtx | 14 + doc/examples/collargs-transition-cs.tex.dtx | 14 + doc/examples/collargs-transition-ok.tex.dtx | 10 + doc/examples/collargs-verbatim.tex.dtx | 11 + doc/examples/countdown.sty.dtx | 71 + doc/examples/countdown.tex.dtx | 16 + doc/examples/dirty-house.tex.dtx | 17 + doc/examples/disable-auto-cmd.tex.dtx | 10 + doc/examples/disable-auto-env.tex.dtx | 10 + doc/examples/disable-bad.tex.dtx | 11 + doc/examples/disable-good.tex.dtx | 12 + doc/examples/disable-nomemoize.tex.dtx | 7 + doc/examples/disable-nommz.tex.dtx | 7 + doc/examples/disable.tex.dtx | 23 + doc/examples/fontsize.tex.dtx | 24 + doc/examples/ins.begin | 6 + doc/examples/ins.end | 2 + doc/examples/ins.mid | 3 + doc/examples/label+.tex.dtx | 90 + doc/examples/label.tex.dtx | 32 + doc/examples/manual.tex.dtx | 19 + doc/examples/meaning-to-context.tex.dtx | 27 + doc/examples/memoize-internal.tex.dtx | 15 + doc/examples/memoize.cfg._region_.tex.dtx | 23 + doc/examples/memoize.cfg.dtx | 5 + doc/examples/mmztikz.tex.dtx | 24 + doc/examples/no-linebreaking.tex.dtx | 12 + .../om-collector-NewDocumentCommand.tex.dtx | 19 + doc/examples/om-collector-newcommand.tex.dtx | 17 + doc/examples/overlay.tex.dtx | 37 + doc/examples/per-overlay-v1.sty.dtx | 13 + doc/examples/pgfmathparse-embellished.tex.dtx | 25 + doc/examples/pgfmathparse.tex.dtx | 18 + doc/examples/plainTeX.tex.dtx | 12 + doc/examples/poormansbox-driver.sty.dtx | 51 + doc/examples/poormansbox-driver.tex.dtx | 44 + doc/examples/poormansbox-memoizable.sty.dtx | 34 + doc/examples/poormansbox-memoizable.tex.dtx | 44 + doc/examples/poormansbox.sty.dtx | 25 + doc/examples/poormansbox.tex.dtx | 44 + doc/examples/progressbar.tex.dtx | 12 + doc/examples/readonly.tex.dtx | 22 + doc/examples/recompile.tex.dtx | 31 + doc/examples/record-extern-pages.tex.dtx | 9 + doc/examples/record-files.tex.dtx | 15 + doc/examples/redefinitions.tex.dtx | 49 + doc/examples/ref.tex.dtx | 32 + doc/examples/sectionbox.tex.dtx | 13 + doc/examples/skak.tex.dtx | 18 + doc/examples/test.tex.dtx | 20 + doc/examples/titlepage.tex.dtx | 13 + doc/examples/verbatim-auto.tex.dtx | 23 + doc/examples/verbatim-manual.tex.dtx | 22 + doc/examples/vref.tex.dtx | 26 + doc/memoize-clean.1.md | 62 + doc/memoize-code.sty | 276 + doc/memoize-code.tex | 120 + doc/memoize-doc-common.sty | 173 + doc/memoize-doc.sty | 711 ++ doc/memoize-extract.1.md | 94 + doc/memoize.mst | 1 + doc/memoize.tex | 9094 +++++++++++++++++ doc/yadoc.sty | 491 + examples/1-basic.pdf | Bin 97470 -> 0 bytes examples/1-basic.tex | 74 - examples/2-memodir.memo.dir/.dummy | 0 examples/2-memodir.pdf | Bin 68065 -> 0 bytes examples/2-memodir.tex | 55 - .../3-enable-disable-prevent.memo.dir/.dummy | 0 examples/3-enable-disable-prevent.pdf | Bin 120337 -> 0 bytes examples/3-enable-disable-prevent.tex | 103 - examples/4-main.pdf | Bin 93199 -> 0 bytes examples/4-main.tex | 69 - examples/5-overlay.memo.dir/.dummy | 0 examples/5-overlay.pdf | Bin 155561 -> 0 bytes examples/5-overlay.tex | 108 - examples/Makefile | 21 - examples/chapters/4-chapter.tex | 35 - examples/chapters/book.memo.dir/.dummy | 0 memoize-clean.pl | 163 + memoize-clean.py | 159 + memoize-extract.pl | 205 + memoize-extract.py | 183 + memoize-tikz.tex | 41 - memoize.edtx | 3597 +++++++ memoize.ins | 39 + memoize.sty | 923 -- memomanager.py | 148 - nomemoize.sty | 22 - xparse-arglist.sty | 72 - 126 files changed, 21792 insertions(+), 1864 deletions(-) create mode 100644 INSTALL.md create mode 100644 Makefile.advice create mode 100644 Makefile.collargs create mode 100644 Makefile.package create mode 100644 Makefile.runtimes create mode 100644 advice.edtx create mode 100644 advice.ins create mode 100644 collargs.edtx create mode 100644 collargs.ins create mode 100644 doc/.gitignore create mode 100644 doc/INSTALL.advice.md create mode 100644 doc/INSTALL.collargs.md create mode 100644 doc/README.advice.md create mode 100644 doc/README.collargs.md create mode 100644 doc/README.memoize.md create mode 100644 doc/examples/.gitignore create mode 100644 doc/examples/ConTeXt.tex.dtx create mode 100644 doc/examples/Makefile create mode 100644 doc/examples/_auto-ref.tex.dtx create mode 100644 doc/examples/_collargs-ignore-other-tags.tex.dtx create mode 100644 doc/examples/_collargs-verbatim.tex.dtx create mode 100644 doc/examples/automemoize-command.tex.dtx create mode 100644 doc/examples/automemoize-environment.tex.dtx create mode 100644 doc/examples/beamer.tex.dtx create mode 100644 doc/examples/book.tex.dtx create mode 100644 doc/examples/chained-advice.tex.dtx create mode 100644 doc/examples/chapters/chapter1.tex.dtx create mode 100644 doc/examples/clean-house.tex.dtx create mode 100644 doc/examples/collargs-makebox.tex.dtx create mode 100644 doc/examples/collargs-minipage.tex.dtx create mode 100644 doc/examples/collargs-nodelimiters.tex.dtx create mode 100644 doc/examples/collargs-processor.tex.dtx create mode 100644 doc/examples/collargs-transition-comment.tex.dtx create mode 100644 doc/examples/collargs-transition-cs.tex.dtx create mode 100644 doc/examples/collargs-transition-ok.tex.dtx create mode 100644 doc/examples/collargs-verbatim.tex.dtx create mode 100644 doc/examples/countdown.sty.dtx create mode 100644 doc/examples/countdown.tex.dtx create mode 100644 doc/examples/dirty-house.tex.dtx create mode 100644 doc/examples/disable-auto-cmd.tex.dtx create mode 100644 doc/examples/disable-auto-env.tex.dtx create mode 100644 doc/examples/disable-bad.tex.dtx create mode 100644 doc/examples/disable-good.tex.dtx create mode 100644 doc/examples/disable-nomemoize.tex.dtx create mode 100644 doc/examples/disable-nommz.tex.dtx create mode 100644 doc/examples/disable.tex.dtx create mode 100644 doc/examples/fontsize.tex.dtx create mode 100644 doc/examples/ins.begin create mode 100644 doc/examples/ins.end create mode 100644 doc/examples/ins.mid create mode 100644 doc/examples/label+.tex.dtx create mode 100644 doc/examples/label.tex.dtx create mode 100644 doc/examples/manual.tex.dtx create mode 100644 doc/examples/meaning-to-context.tex.dtx create mode 100644 doc/examples/memoize-internal.tex.dtx create mode 100644 doc/examples/memoize.cfg._region_.tex.dtx create mode 100644 doc/examples/memoize.cfg.dtx create mode 100644 doc/examples/mmztikz.tex.dtx create mode 100644 doc/examples/no-linebreaking.tex.dtx create mode 100644 doc/examples/om-collector-NewDocumentCommand.tex.dtx create mode 100644 doc/examples/om-collector-newcommand.tex.dtx create mode 100644 doc/examples/overlay.tex.dtx create mode 100644 doc/examples/per-overlay-v1.sty.dtx create mode 100644 doc/examples/pgfmathparse-embellished.tex.dtx create mode 100644 doc/examples/pgfmathparse.tex.dtx create mode 100644 doc/examples/plainTeX.tex.dtx create mode 100644 doc/examples/poormansbox-driver.sty.dtx create mode 100644 doc/examples/poormansbox-driver.tex.dtx create mode 100644 doc/examples/poormansbox-memoizable.sty.dtx create mode 100644 doc/examples/poormansbox-memoizable.tex.dtx create mode 100644 doc/examples/poormansbox.sty.dtx create mode 100644 doc/examples/poormansbox.tex.dtx create mode 100644 doc/examples/progressbar.tex.dtx create mode 100644 doc/examples/readonly.tex.dtx create mode 100644 doc/examples/recompile.tex.dtx create mode 100644 doc/examples/record-extern-pages.tex.dtx create mode 100644 doc/examples/record-files.tex.dtx create mode 100644 doc/examples/redefinitions.tex.dtx create mode 100644 doc/examples/ref.tex.dtx create mode 100644 doc/examples/sectionbox.tex.dtx create mode 100644 doc/examples/skak.tex.dtx create mode 100644 doc/examples/test.tex.dtx create mode 100644 doc/examples/titlepage.tex.dtx create mode 100644 doc/examples/verbatim-auto.tex.dtx create mode 100644 doc/examples/verbatim-manual.tex.dtx create mode 100644 doc/examples/vref.tex.dtx create mode 100644 doc/memoize-clean.1.md create mode 100644 doc/memoize-code.sty create mode 100644 doc/memoize-code.tex create mode 100644 doc/memoize-doc-common.sty create mode 100644 doc/memoize-doc.sty create mode 100644 doc/memoize-extract.1.md create mode 100644 doc/memoize.mst create mode 100644 doc/memoize.tex create mode 100644 doc/yadoc.sty delete mode 100644 examples/1-basic.pdf delete mode 100644 examples/1-basic.tex delete mode 100644 examples/2-memodir.memo.dir/.dummy delete mode 100644 examples/2-memodir.pdf delete mode 100644 examples/2-memodir.tex delete mode 100644 examples/3-enable-disable-prevent.memo.dir/.dummy delete mode 100644 examples/3-enable-disable-prevent.pdf delete mode 100644 examples/3-enable-disable-prevent.tex delete mode 100644 examples/4-main.pdf delete mode 100644 examples/4-main.tex delete mode 100644 examples/5-overlay.memo.dir/.dummy delete mode 100644 examples/5-overlay.pdf delete mode 100644 examples/5-overlay.tex delete mode 100644 examples/Makefile delete mode 100644 examples/chapters/4-chapter.tex delete mode 100644 examples/chapters/book.memo.dir/.dummy create mode 100755 memoize-clean.pl create mode 100755 memoize-clean.py create mode 100755 memoize-extract.pl create mode 100755 memoize-extract.py delete mode 100644 memoize-tikz.tex create mode 100644 memoize.edtx create mode 100644 memoize.ins delete mode 100644 memoize.sty delete mode 100755 memomanager.py delete mode 100644 nomemoize.sty delete mode 100644 xparse-arglist.sty diff --git a/.gitignore b/.gitignore index d5d3403..34e2e3f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,39 @@ +*.codetoc +*.cpt +*.hd +*.idx +*.ilg +*.ind +*.pdf +*.synctex(busy) +/ctan +/texmf +/releases +_region_.tex +advice-tikz.code.tex +advice.dtx +advice.sty +advice.tex +advice.zip +collargs.dtx +collargs.sty +collargs.tex +collargs.zip +link-generated-files-into-texmf.sh +memoizable.sty +memoizable.tex +memoize-extract-one.tex +memoize.dtx +memoize.sty +memoize.tex +memoize.zip +nomemoize.sty +nomemoize.tex +t-advice.tex +t-collargs.tex +t-memoizable.tex +t-memoize.tex +t-nomemoize.tex test* +*.1 +oldtest diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..99957a9 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,216 @@ +# Installation from the TDS archive + +If Memoize is not (yet) offered by your TeX distribution, the easiest way to +install it is by downloading the TDS archive `memoize.tds.zip` from [Memoize's +CTAN page](https://ctan.org/pkg/memoize), and unpacking it into your `texmf` +directory. You will most likely also have to do the same for two auxiliary +packages Memoize depends on: [Advice](https://ctan.org/pkg/advice) and +[CollArgs](https://ctan.org/pkg/collargs). + +Read on only if you have an unstoppable urge to install from source and/or +compile the manual or the documented source code. + +# Installation from the source + +# Getting the sources + +There are several options: + +* Download and unpack the zip archive of the package from [Memoize's CTAN + page](https://ctan.org/pkg/memoize). + +* Download and unpack the TDS archive, or copy the files from your local + distribution. The sources reside in `/source/generic/memoize`. + +* Clone the [GitHub repository](https://github.com/sasozivanovic/memoize). + +## Generating runtime files + +The easiest way to generate the runtime files is by running `make`. The +following command will generate (i) runtime TeX files for all supported formats +(currently: LaTeX, plain TeX and ConTeXt), and (ii) the man pages for the +accompanying scripts: + +``` +make runtime +``` + +To only generate the runtime TeX files, execute + +``` +make memoize.sty +``` + +Alternatively, you can generate the runtime files manually. The source of this +package was written using [EasyDTX](https://ctan.org/pkg/easydtx). Therefore, +you first have to convert the `.edtx` file into a regular `.dtx`: + +``` +edtx2dtx memoize.edtx > memoize.dtx +``` + +The next step is standard. Produce the runtime files by compiling the +installation file: + +``` +tex memoize.ins +``` + +If you require the ConTeXt runtime, replace all instances of `\expanded` and +`\unexpanded` in `t-memoize.tex` by `\normalexpanded` and `\normalunexpanded`, +respectively. One way to do this is: + +``` +sed -i -s -e 's/\\\(un\)\?expanded/\\normal\1expanded/g;' t-memoize.tex +``` + +The man pages are produced by converting their MarkDown sources by `pandoc` +(execute this in the `doc` subdirectory): + +``` +pandoc memoize-extract.1.md -s -t man -o memoize-extract.1 +pandoc memoize-clean.1.md -s -t man -o memoize-clean.1 +``` + +Additionally, links from `memoize-x.pl.1` and `memoize-x.py.1` to `memoize-x.1` +can be created by: + +``` +echo .so man1/memoize-extract.1 > memoize-extract.pl.1 +echo .so man1/memoize-extract.1 > memoize-extract.py.1 +echo .so man1/memoize-clean.1 > memoize-clean.pl.1 +echo .so man1/memoize-clean.1 > memoize-clean.py.1 +``` + +## Installation + +It is recommended to install the files into a TDS-compliant `texmf` directory, +as usual. Inspect file `FILES` or the TDS archive `memoize.tds.zip` to see +what goes where. + +Next, the scripts residing in `/scripts/memoize` should be linked into +some directory listed in the executable search `PATH`. The scripts are the +following: + +* `memoize-extract.pl` +* `memoize-extract.py` +* `memoize-clean.pl` +* `memoize-clean.py` + +If you have downloaded the sources from GitHub, you can build the TDS +directories/archives of both Memoize and its auxiliary packages Advice and +CollArgs by issuing + +``` +make +``` + +This command creates: + +* TDS directories `memoize.tds`, `advice.tds` and `collargs.tds`, + +* CTAN directories `ctan/memoize`, `ctan/advice` and `ctan/memoize`, + +* TDS archives `memoize.tds.zip`, `advice.tds.zip` and `collargs.tds.zip` + inside the CTAN directories, and + +* CTAN archives `memoize.zip`, `advice.zip` and `collargs.zip` inside directory + `ctan`. + +The plain `make` shown above will also attempt to compile the documentation. +If you're not ready for that (yet), you can avoid that by executing this +instead: + +``` +make PDF= +``` + +# Compiling the documentation + +Compiling both the documented code listing and the manual requires a Unix-like +operating system. I have developed Memoize on Linux, but the documentation +should also be compilable under Cygwin on Windows (not tested). + +The documentation of Advice and CollArgs, both their manuals and documented +code listings, is included within Memoize's documentation. + +## Getting the source + +In principle, the options are the same as for the installation from the source, +but the GitHub option is strongly preferred here, as the other two options +require manually copying the sources of Advice and CollArgs into the Memoize +directory. That said: + +* Clone the [GitHub repository](https://github.com/sasozivanovic/memoize). + You're done. + +* Download and unpack the zip archives of all three packages from their CTAN + pages: https://ctan.org/pkg/memoize, https://ctan.org/pkg/advice and + https://ctan.org/pkg/collargs. + + Copy `advice.edtx` and `collargs.edtx` into the Memoize directory, alongside + `memoize.edtx`. + +* From TDS archives (of all three packages), or your local distribution's + `` folder. This is not straightforward: + + 1. Make a local copy of directory `/source/generic/memoize`; we'll + call it "the Memoize directory". + + 2. Copy directory `/doc/generic/memoize` into the the Memoize + directory as `doc`. + + 3. Copy `memoize-extract.pl`, `memoize-extract.py`, `memoize-clean.pl` and + `memoize-clean.py` from directory `/scripts` into the Memoize + directory. + + 4. Copy `advice.edtx` from `/source/generic/advice` and + `collargs.edtx` from `/source/generic/collargs` into the the + Memoize directory. + +## Compiling the documented code listing + +I have compiled the code docs with LuaLaTeX on a Linux system with +TeXLive 2023. If you have `make`, the easiest way to compile them is by +issuing + +``` +make doc/memoize-code.pdf +``` + +Alternatively, you can use `latexmk`, but you first have to convert the `.edtx` +sources of all three packages into `.dtx`, if you haven't done so yet: + +``` +edtx2dtx memoize.edtx > memoize.dtx +edtx2dtx advice.edtx > advice.dtx +edtx2dtx collargs.edtx > collargs.dtx +``` + +Then, you can execute `latexmk` from the `doc` subdirectory: + +``` +latexmk -lualatex -bibtex memoize-code +``` + +To compile the code docs manually, three iterations of `lualatex memoize-code` +with `makeindex -s gind.ist memoize-code.idx` between them should suffice. + +## Compiling the manual + +I have compiled the manual with LuaLaTeX on a Linux system with TeXLive 2023, +`make`, `latexmk`, `perl` and `sed` installed. Furthermore, you absolutely +have to run the compilation with some form of `--shell-escape`, as it executes +`make` and `sed` to build the examples. (There is no way to compile these from +the command line, as the instructions are baked into the manual source.) + +Given all this, either of the following should do the trick: + +* `make doc/memoize.pdf` from the Memoize directory; + +* `latexmk -lualatex -bibtex memoize` for the `doc` subdirectory; or + +* quite a few runs of `lualatex memoize` interspersed by `makeindex memoize.idx`. + +If all worked well, you can change `\usepackage{nomemoize}` in +`doc/memoize.tex` to `\usepackage{memoize}` and observe Memoize at work. diff --git a/LICENCE b/LICENCE index 2244313..1b57559 100644 --- a/LICENCE +++ b/LICENCE @@ -352,15 +352,15 @@ component is constrained by the conditions in this license. Here is an example of such a notice and statement: %% pig.dtx - %% Copyright 2005 M. Y. Name + %% Copyright 2008 M. Y. Name % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in - % http://www.latex-project.org/lppl.txt - % and version 1.3 or later is part of all distributions of LaTeX - % version 2005/12/01 or later. + % https://www.latex-project.org/lppl.txt + % and version 1.3c or later is part of all distributions of LaTeX + % version 2008 or later. % % This work has the LPPL maintenance status `maintained'. % diff --git a/Makefile b/Makefile index 92ba1e1..7edbd7b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,139 @@ -.PHONY: clean +# Prepare the CTAN submission for all three packages. -clean: - rm -f *.mmz test*.memo.dir/* +PACKAGES = memoize advice collargs + +all: ctan/memoize.zip + $(MAKE) -f Makefile.advice ctan/advice.zip + $(MAKE) -f Makefile.collargs ctan/collargs.zip + +# Prepare the CTAN submission. + +PACKAGE = memoize +VERSION = 1.0.0 +YEAR = 2023 +MONTH = 10 +DAY = 10 + +FORMAT = generic + +COMMON = memoize nomemoize memoizable +PLAIN = memoize-extract-one.tex +SOURCE = memoize.edtx memoize.ins # $(makefiles) + +SCRIPTS := memoize-extract memoize-clean +man-src := $(SCRIPTS:%=doc/%.1.md) +MAN := $(SCRIPTS:%=%.1) $(SCRIPTS:%=%.pl.1) $(SCRIPTS:%=%.py.1) +MAN := $(MAN:%=doc/%) +SCRIPTS := $(SCRIPTS:%=%.pl) $(SCRIPTS:%=%.py) + +%.pl.1: %.1 + echo .so man1/$*.1 > $@ # link to .1 man page +%.py.1: %.1 + echo .so man1/$*.1 > $@ # link to .1 man page + +.PHONY: runtime +runtime: $(RUNTIME) + +README = doc/README.memoize.md +INSTALL = INSTALL.md +MAKEFILE = Makefile +LICENCE = LICENCE + +makefiles = Makefile.package Makefile.runtimes Makefile.advice Makefile.collargs + +codedoc-source = memoize-code.tex \ + memoize-code.sty memoize-doc-common.sty + +manual-source = memoize.tex \ + memoize-doc.sty memoize-doc-common.sty yadoc.sty \ + memoize.mst + +PDF = memoize.pdf memoize-code.pdf + +codedoc-source := $(codedoc-source:%=doc/%) +manual-source := $(manual-source:%=doc/%) +pdf := $(PDF:%=doc/%) +DOC = $(sort $(codedoc-source) $(manual-source)) $(pdf) $(man-src) + +examples-src := Makefile ins.begin ins.mid ins.end +examples-src := $(examples-src:%=doc/examples/%) +#examples-src += $(shell git ls-files | grep ^doc/examples/.*dtx$) +examples-src += $(shell find doc/examples -name '*.dtx') + +# doc/attachments.lst is produced by compiling memoize.tex (without memoization). +# doc-examples will hold soft links to the relevant generated example files. +doc-examples := $(shell sed 's/^.* \(.*\) ##.*$$/\1/' doc/attachments.lst) +doc-examples := $(doc-examples:%=doc/examples/%) + +ctan/$(PACKAGE).zip: + $(TDS-BEGIN) +# Check for duplicate filenames: + echo $(doc-examples) | tr ' ' '\n' | uniq -d | ifne false + cd doc && zip ../$(TDS-DOC-DIR)/examples-src.zip $(examples-src:doc/%=%) +# For each line ($1 $2) in attachments.lst, link $1 to $2 ... + cd doc/examples && sed 's!^examples/!ln -sfr !' ../attachments.lst | sh +# ... and zip those links. + cd doc && zip -r ../$(TDS-DOC-DIR)/examples.zip $(doc-examples:doc/%=%) + $(TDS-END) + $(CTAN-BEGIN) + ln -sr $(TDS-DOC-DIR)/examples-src.zip $(CTAN-DIR)/doc + ln -sr $(TDS-DOC-DIR)/examples.zip $(CTAN-DIR)/doc + $(CTAN-END) + + + +doc/memoize-code.pdf: $(SOURCE) $(codedoc-source) + +doc/memoize.pdf: $(manual-source) $(examples-src) + +%.pdf: %.tex + latexmk -cd -lualatex -bibtex- $< && touch $@ + + + +# Maintanence + +test.tex = $(wildcard test*.tex) + +.PHONY: all runtime force clean versions-show + +.PRECIOUS: %.1 + +clean: # clean this directory + memoize-clean.py -a $(test.tex:%.tex=-p %.) $(test.tex:%.tex=-p %.memo.dir/) + latexmk -C -f $(test.tex) _region_ + +version: + $(MAKE) -f Makefile.collargs version + $(MAKE) -f Makefile.advice version + $(call EDIT-VERSION-LATEX,memoize.edtx,memoize) + $(call EDIT-VERSION-LATEX,memoize.edtx,nomemoize) + $(call EDIT-VERSION-LATEX,memoize.edtx,memoizable) + $(call EDIT-VERSION-CONTEXT,memoize.edtx) + $(call EDIT-VERSION-PLAIN,memoize.edtx,memoize) + $(call EDIT-VERSION-PLAIN,memoize.edtx,nomemoize) + $(call EDIT-VERSION-PLAIN,memoize.edtx,memoizable) + $(call EDIT-VERSION-PERL,memoize-extract.pl) + $(call EDIT-VERSION-PERL,memoize-clean.pl) + $(call EDIT-VERSION-PYTHON,memoize-extract.py) + $(call EDIT-VERSION-PYTHON,memoize-clean.py) + $(call EDIT-VERSION-MAN,doc/memoize-extract.1.md) + $(call EDIT-VERSION-MAN,doc/memoize-clean.1.md) +# Change the date of the latest release (identified by the version). + sed -Ei 's!^\\item\[\\githubrelease\{[0-9]{4}/[0-9]{2}/[0-9]{2}\}\{v$(VERSION)\}\] *$$!\\item\[\\githubrelease\{$(YEAR)/$(MONTH)/$(DAY)\}\{v$(VERSION)\}\]!' doc/memoize.tex + +define COLOR_VERSION +grep -E --color '[0-9]{4}[/-][0-9]{2}[/-][0-9]{2}|v?[0-9]\.[0-9]\.[0-9]|(January|February|March|April|May|June|July|August|September|October|November|December) [0-9]+, [0-9]{4}' +endef + +versions-show: + @grep -E '%\\ProvidesPackage|^%%D\s*(version|date)=' $(PACKAGES:%=%.edtx) | ${COLOR_VERSION} + @grep __version__ *.py | ${COLOR_VERSION} + @grep VERSION *.pl | ${COLOR_VERSION} + @grep -E '^(footer|date):' doc/memoize-*.md | ${COLOR_VERSION} + @grep -E 'githubrelease' doc/memoize.tex | ${COLOR_VERSION} + +include Makefile.package +include Makefile.runtimes + +VERSION-MAN = of Memoize v$(VERSION) diff --git a/Makefile.advice b/Makefile.advice new file mode 100644 index 0000000..c49494a --- /dev/null +++ b/Makefile.advice @@ -0,0 +1,34 @@ +# Prepare the CTAN submission. + +# This file is indented to be used from Memoize's source directory, which +# should also contain the files assigned below to SOURCE. + +PACKAGE = advice +VERSION = 1.0.0 +YEAR = 2023 +MONTH = 10 +DAY = 10 + +FORMAT = generic + +COMMON = advice +GENERIC = advice-tikz.code.tex +SOURCE = advice.edtx advice.ins + +README = doc/README.advice.md +INSTALL = doc/INSTALL.advice.md +MAKEFILE = Makefile.runtimes +LICENCE = LICENCE + +ctan/$(PACKAGE).zip: + $(TDS-BEGIN) + $(TDS-END) + $(CTAN-BEGIN) + $(CTAN-END) + +version: + $(call EDIT-VERSION-LATEX,advice.edtx,advice,$(YEAR)/$(MONTH)/$(DAY) v$(VERSION)) + $(call EDIT-VERSION-CONTEXT,advice.edtx,$(YEAR)-$(MONTH)-$(DAY),$(VERSION)) + +include Makefile.package + diff --git a/Makefile.collargs b/Makefile.collargs new file mode 100644 index 0000000..6eedd11 --- /dev/null +++ b/Makefile.collargs @@ -0,0 +1,32 @@ +# Prepare the CTAN submission. + +# This file is indented to be used from Memoize's source directory, which +# should also contain collargs.edtx and collargs.ins. + +PACKAGE = collargs +VERSION = 1.0.0 +YEAR = 2023 +MONTH = 10 +DAY = 10 + +FORMAT = generic + +COMMON = collargs +SOURCE = collargs.edtx collargs.ins + +README = doc/README.collargs.md +INSTALL = doc/INSTALL.collargs.md +MAKEFILE = Makefile.runtimes +LICENCE = LICENCE + +ctan/$(PACKAGE).zip: + $(TDS-BEGIN) + $(TDS-END) + $(CTAN-BEGIN) + $(CTAN-END) + +version: + $(call EDIT-VERSION-LATEX,collargs.edtx,collargs,$(YEAR)/$(MONTH)/$(DAY) v$(VERSION)) + $(call EDIT-VERSION-CONTEXT,collargs.edtx,$(YEAR)-$(MONTH)-$(DAY),$(VERSION)) + +include Makefile.package diff --git a/Makefile.package b/Makefile.package new file mode 100644 index 0000000..ca0b720 --- /dev/null +++ b/Makefile.package @@ -0,0 +1,202 @@ +# This Makefile must be included at the end of the including file. + +latex = $(COMMON:%=%.sty) $(LATEX) +plain = $(COMMON:%=%.tex) $(PLAIN) +context = $(COMMON:%=t-%.tex) $(CONTEXT) + +TEX = $(latex) $(plain) $(context) $(GENERIC) + +RUNTIME = $(TEX) $(SCRIPTS) $(MAN) + +ALL = $(RUNTIME) $(SOURCE) $(DOC) \ + $(README) $(INSTALL) $(LICENCE) $(MAKEFILE) + +ctan/$(PACKAGE).zip: $(ALL) + +CTAN-DIR = ctan/$(PACKAGE) +CTAN-DOC-DIR = ctan/$(PACKAGE)/doc + +TDS-DIR = texmf/$(PACKAGE).tds +TDS-SCRIPTS-DIR = $(TDS-DIR)/scripts/$(PACKAGE) +TDS-DOC-DIR = $(TDS-DIR)/doc/$(FORMAT)/$(PACKAGE) +TDS-SOURCE-DIR = $(TDS-DIR)/source/$(FORMAT)/$(PACKAGE) +TDS-MAN-DIR = $(TDS-DIR)/doc/man/man +TDS-ALL-DIRS = $(TDS-SCRIPTS-DIR) $(TDS-SOURCE-DIR) $(TDS-DOC-DIR) \ + $(TDS-DIR)/tex/{latex,plain,context,generic}/$(PACKAGE) \ + $(TDS-MAN-DIR){1,2,3,4,5,6,7,8,9} + +readme?md = README$(findstring .md, $(suffix $(README))) +install?md = INSTALL$(findstring .md, $(suffix $(INSTALL))) +licence?md = LICENCE$(findstring .md, $(suffix $(LICENCE))) + +man1 = $(filter %.1,$(MAN)) +man2 = $(filter %.2,$(MAN)) +man3 = $(filter %.3,$(MAN)) +man4 = $(filter %.4,$(MAN)) +man5 = $(filter %.5,$(MAN)) +man6 = $(filter %.6,$(MAN)) +man7 = $(filter %.7,$(MAN)) +man8 = $(filter %.8,$(MAN)) +man9 = $(filter %.9,$(MAN)) + +define MAKE-CTAN + $(CTAN-BEGIN) + $(CTAN-END) +endef + +define CTAN-BEGIN + rm -rf $(CTAN-DIR) ctan/$(PACKAGE).zip + mkdir -p $(CTAN-DIR) $(CTAN-DOC-DIR) + $(call cp,$(SOURCE) $(SCRIPTS) $(CTAN),$(CTAN-DIR)) + $(call cp,$(README),$(CTAN-DIR)/$(readme?md)) + $(call cp,$(INSTALL),$(CTAN-DIR)/$(install?md)) + $(call cp,$(LICENCE),$(CTAN-DIR)/$(licence?md)) + $(call cp,$(MAKEFILE),$(CTAN-DIR)/Makefile) + $(call cp,$(DOC),$(CTAN-DOC-DIR)) +endef + +define CTAN-END + if [[ -d $(TDS-DIR) ]] ; then \ + cd $(TDS-DIR) && \ + zip -r $(PACKAGE).tds.zip * ; \ + fi + if [[ -a $(TDS-DIR)/$(PACKAGE).tds.zip ]] ; then \ + mv $(TDS-DIR)/$(PACKAGE).tds.zip $(CTAN-DIR) ; \ + fi + if [[ -a $(TDS-DIR)/FILES ]] ; then cp $(TDS-DOC-DIR)/FILES $(CTAN-DIR) ; fi + rmdir -p --ignore-fail-on-non-empty `find $(CTAN-DIR) -type d` + cd ctan && zip -r $(PACKAGE).zip $(PACKAGE) +endef + +define MAKE-TDS + $(TDS-BEGIN) + $(TDS-END) +endef + +define TDS-BEGIN + rm -rf $(TDS-DIR) + $(TDS-MKDIR) + $(TDS-CP) +endef +define TDS-MKDIR + mkdir -p $(TDS-ALL-DIRS) +endef +define TDS-CP + $(call cp,$(latex),$(TDS-DIR)/tex/latex/$(PACKAGE)) + $(call cp,$(plain),$(TDS-DIR)/tex/plain/$(PACKAGE)) + $(call cp,$(context),$(TDS-DIR)/tex/context/$(PACKAGE)) + $(call cp,$(GENERIC),$(TDS-DIR)/tex/generic/$(PACKAGE)) + $(call cp,$(SCRIPTS),$(TDS-SCRIPTS-DIR)) + $(call cp,$(SOURCE),$(TDS-SOURCE-DIR)) + $(call cp,$(MAKEFILE),$(TDS-SOURCE-DIR)/Makefile) + $(call cp,$(DOC),$(TDS-DOC-DIR)) + $(call cp,$(README),$(TDS-DOC-DIR)/$(readme?md)) + $(call cp,$(INSTALL),$(TDS-DOC-DIR)/$(install?md)) + $(call cp,$(LICENCE),$(TDS-DOC-DIR)/$(licence?md)) + $(call cp,$(man1),$(TDS-MAN-DIR)1) + $(call cp,$(man2),$(TDS-MAN-DIR)2) + $(call cp,$(man3),$(TDS-MAN-DIR)3) + $(call cp,$(man4),$(TDS-MAN-DIR)4) + $(call cp,$(man5),$(TDS-MAN-DIR)5) + $(call cp,$(man6),$(TDS-MAN-DIR)6) + $(call cp,$(man7),$(TDS-MAN-DIR)7) + $(call cp,$(man8),$(TDS-MAN-DIR)8) + $(call cp,$(man9),$(TDS-MAN-DIR)9) +endef + +define TDS-END + $(TDS-FILES) + $(TDS-PRUNE) +endef +define TDS-FILES + cd $(TDS-DIR) ; find . -type f | sed 's!^\./!!' \ + > doc/$(FORMAT)/$(PACKAGE)/FILES +endef +define TDS-PRUNE + rmdir -p --ignore-fail-on-non-empty `find $(TDS-DIR) -type d` +endef + +%.1: %.1.md + pandoc $< -s -t man -o $@ +%.2: %.2.md + pandoc $< -s -t man -o $@ +%.3: %.3.md + pandoc $< -s -t man -o $@ +%.4: %.4.md + pandoc $< -s -t man -o $@ +%.5: %.5.md + pandoc $< -s -t man -o $@ +%.6: %.6.md + pandoc $< -s -t man -o $@ +%.7: %.7.md + pandoc $< -s -t man -o $@ +%.8: %.8.md + pandoc $< -s -t man -o $@ +%.9: %.9.md + pandoc $< -s -t man -o $@ + +.PHONY: link-runtimes unlink-runtimes version +.IGNORE: unlink-runtimes + +cp=$(intcmp $(words $(1)),0,,,cp $(1) $(2)) + +link-runtimes: + $(eval TDS-DIR=~/texmf) + $(eval cp=$$(intcmp $$(words $$(1)),0,,,ln -srf $$(1) $$(2))) + $(TDS-MKDIR) + $(TDS-CP) + $(TDS-PRUNE) + texconfig rehash + +unlink-runtimes: + $(eval TDS-DIR=~/texmf) + $(eval cp=$$(intcmp $$(words $$(1)),0,,,\ + if [[ -d $$(2) ]] ; then rm -f $$(foreach f,$$(1),$$(2)/$$(notdir $$(f))) ; \ + else rm -f $$(2) ; fi \ + )) + $(TDS-CP) + $(TDS-PRUNE) + texconfig rehash + + +# $1 = source file, $2 = package name +VERSION-LATEX = $(YEAR)/$(MONTH)/$(DAY) v$(VERSION) +define EDIT-VERSION-LATEX + sed -Ei 's!\\ProvidesPackage\{$(2)\}\[[0-9]{4}/[0-9]{2}/[0-9]{2} v[0-9.]* !\\ProvidesPackage{$(2)}[$(VERSION-LATEX) !' $(1) +endef + +# $1 = source file +# This assumes that all the \modules in the file have the same date and version. +VERSION-CONTEXT = $(VERSION) +DATE-CONTEXT = $(YEAR)-$(MONTH)-$(DAY) +define EDIT-VERSION-CONTEXT + sed -Ei 's!(%D *version=)[0-9.]*,!\1$(VERSION-CONTEXT),!;s!(%D *date=)[-0-9]*,!\1$(DATE-CONTEXT),!' $(1) +endef + +# $1 = source .pl file, $2 = version +VERSION-PERL = $(YEAR)/$(MONTH)/$(DAY) v$(VERSION) +define EDIT-VERSION-PERL + sed -i "s!^my \$$VERSION = .*!my \$$VERSION = '$(VERSION-PERL)';!" $(1) +endef + +# $1 = source .py file, $2 = version +VERSION-PYTHON = $(YEAR)/$(MONTH)/$(DAY) v$(VERSION) +define EDIT-VERSION-PYTHON + sed -i "s!^__version__ = .*!__version__ = '$(VERSION-PYTHON)'!" $(1) +endef + +# $1 = source file +VERSION-MAN = $(VERSION) +DATE-MAN = $(shell LANG=en date -d '$(YEAR)-$(MONTH)-$(DAY)' +"%B %d, %Y") +# This assumes that the source filename is file..md, because it strips away two suffixes. +define EDIT-VERSION-MAN + sed -i '/^date:/c date: $(DATE-MAN)' $(1) + sed -i '/^footer:/c footer: $(basename $(basename $(notdir $(1)))) $(VERSION-MAN)' $(1) +endef + +# $1 = source file, $2 = package name +VERSION-PLAIN = $(VERSION-LATEX) +define EDIT-VERSION-PLAIN + sed -Ei 's!^(%<[^\>]*>% Package $(2) ).*!\1$(VERSION-PLAIN)!' $(1) +endef + diff --git a/Makefile.runtimes b/Makefile.runtimes new file mode 100644 index 0000000..421bcdb --- /dev/null +++ b/Makefile.runtimes @@ -0,0 +1,8 @@ +.PRECIOUS: %.dtx + +%.dtx: %.edtx + edtx2dtx $< > $@ + +%.sty %.tex t-%.tex &: %.ins %.dtx + tex $< + sed -i -s -e 's/\\\(un\)\?expanded/\\normal\1expanded/g;' t-$*.tex diff --git a/README.md b/README.md index 151a47d..6d0e227 100644 --- a/README.md +++ b/README.md @@ -1,186 +1,21 @@ -# What and why? # - -Memoize is yet another package for *externalization*. The idea is that if your -document contains code that doesn't change but takes a long time to compile, -you compile it once and reuse it in subsequent compilations. It is common to -externalize complex TikZ pictures or Forest trees. (Yes, I'm also the author -of Forest.) - -Memoize is called as it is because the plan is to make it do more than -externalize -graphics. [Occasionally](https://tex.stackexchange.com/q/16016/16819), one also -wants to "externalize" a non-graphical result of some lengthy computation, and -that's sometimes called *memoization*. General memoization does not work in -this alpha version --- the goal here was to implement a proof of concept for -the idea described below --- but it's near the top of the todo list. - -But why yet another externalization package? PGF/TikZ contains an -externalization library, after all. (This library is documented in section 53 -of the PGF/TikZ manual.) - -In a single compilation, TeX can produce only a single output file, but we want -each externalized picture to reside in its own file. Externalization in TikZ -therefore requires a separate compilation for externalizing each and every -picture. While this is not a problem if you externalize as you write, but what -happens if you're editing a 1000+ pages book and you want to externalize 200+ -TikZ pictures and Forest trees? You wait for hours, that's what happens.[^1] - -Enter Memoize. The basic idea is very simple. A PDF can contain multiple pages, -right? So *why not externalize all the pictures in one go, and use them by -including a specific page from the resulting PDF?* Pure magic: the -computational complexity drops from quadratic to linear. Or in plain English, -those 5 hours turn into (less than) 5 minutes. - -In more detail, memoization/externalization in Memoize works in two stages: - -1. Everything that needs to be externalized is plopped right in the middle of a - document --- during the normal compilation of the document. - -2. When you compile the document again, all the externalized stuff is split off - the main document into separate files, called *memos*. - -A memo is identified by the md5 sum of the code that produced it, so if you -change the code, the memo will be recompiled (in fact, a new memo will be -produced). - -# Basic usage # - -If you want to externalize TikZ pictures and Forest trees, say -`\usepackage{memoize}`. That's it. If your situation is more complicated, read -on. - -What can be memoized and how do we specify what should be memoized? -While PGF, TikZ and Forest can only externalize their respective products, -Memoize can externalize anything: `\memoize{}` will externalize -whatever is typeset by ``. - -Of course, we often want to memoize results of every invocation of certain -environment or command, like all the TikZ pictures and/or all Forest trees. -Memoize makes this easy: if you say `\memoizeset{enable=}`, -all instances of this environment will be externalized --- in fact, -auto-memoization of environments `tikzpicture` and `forest` is enabled by -default, so nothing needs to be done for those but loading Memoize. - -Auto-memoization of commands is a bit more complicated than auto-memoization of -environments. It is (reasonably) clear where the end of an environment is, but -a command can take any number of arguments, it can take various kinds of -optional arguments and such. We need to teach Memoize about the argument -structure of a command we want to auto-memoize. This can be achieved by -`\memoizeset{register=\command{}`, which defines a *command -handler* we then enable by `\memoizeset{enable=\command}`. The `` should be given in `xparse` syntax. And don't worry about the -`\tikz` command, it is registered and enabled by default. - -However, there might be exceptions. For example, maybe you want to externalize -all TikZ pictures but not `\todo` notes of package Todonotes, which uses TikZ -internally. (Those notes are usually short, plus they use the as-of-yet -unsupported `remember picture` key.) Solution: register the command and then -prevent memoization within it: `\memoizeset{register=\todo{O{}+m}, -prevent=\todo}`. (The `prevent` key is hopefully transparent, but the xparse -argument specification might not be: `O{}` means the optional argument with an -empty default; `+m` means a long mandatory argument.) - -# What works? # - -You might like the fact that TikZ `overlay`s are allowed, even though an -overlay which sticks out of the bounding box more than an inch requires (a -one-time) manual intervention by setting one or more of the `padding ...` -options. - -What about `\label`--`\ref` support, you ask? Bad news first: it is not yet -implemented, because it falls under the more general issue of context -dependency (see the TODO list below), which is not yet implemented. And the -good news: preliminary experiments show that `\label`--`\ref` more or less just -works, and this includes `\pageref`s. This is so because the pictures are -externalized during a normal compilation. - -Memoize supports PdfTeX, LuaTeX and XeTeX engine; they must be run in the PDF -output mode. At the moment, only the LaTeX format is supported. - -Under texlive 2019 (or any distro using "graphics" package version "2017/06/25 -v1.2c") you will get error "Unknown graphics extension: .memo.pdf" with the -default settings. Workaround: "\usepackage{grffile}". This error does not -occur with texlive 2020 ("graphics" package version "2019/11/30 v1.4a"). - -# Different ways of doing it # - -The two stages of operation outlined above are not set in stone. - -1. You can externalize the pictures in `document.tex` into a PDF other than - `document.pdf`, by invoking LaTeX with the `-jobname` option. But sensible - support for this is still lacking. - -2. Out of the box, splitting is done by LaTeX, specifically by the `pdfpages` - package. When you compile your document for the second time, Memoize - notices there is stuff to split off the existing PDF, and invokes an - embedded instance of LaTeX to do that. This means that the out-of-box - approach only works if your TeX has sufficient `-shell-escape` permissions. - - But we already know that TeX can only produce one PDF at a time. So our - outer compilation needs to execute a separate embedded compilation for every - externalized picture. While this is ok if we have only a few pictures, it - takes a while if you have many. (But it is still *much* faster than TikZ - externalization!) The solution offered by Memoize is an external splitting - tool. While TeX-based splitting needs to run TeX and the big PDF as many - times as there are externalized pictures, the included Python script - `memomanager` is executed once and spits out the memos in no - time. (MemoManager has been tested with Python 3.7 and requires packages - `pdfrw` and `pyparsing`.) - -Some other stuff is configurable as well, in particular the file structure. By -allowing you to keep the memos where you need them, Memoize can be -transparently used in complicated setups --- for example, you can (easily!) set -it up so that a compilation of an individual chapter of a book will use the -same memos as the compilation of the entire book (and vice versa). To -customize the landing site of your memos, use memoize keys `memo filename -prefix` and `memo filename suffix`. But if you only want to put the memos out -of the way in a special directory, key `memo dir` will probably suffice --- if -you are compiling `document.tex`, you fill find your memos in directory -`document.memo.dir`, but note that *you have to create the directory yourself*. - -# The future # - -All this said, there's still lots of stuff to be done yet before this package -is ripe for CTAN: - -* Proper documentation. For now, there is only the comments in `memoize.sty` - --- but for once, they are plentiful --- and some examples (in the `examples` - directory). - -* Context dependency, including support for `\label`--`\ref` and beamer - overlays. Context dependency will be implemented like in Forest (which - features TikZ-based externalization) but with a friendlier UI. The idea is - to define a context, which can contain values of counters, definitions of - macros etc., and reexternalize if that context changes. - -* (Some kind of) support for TikZ pictures using `remember picture`. - -* Named memos (as in TikZ, see manual section 53.4.2). - -* General memoization. At the moment, only externalization works, and even that - is limited to externalizing a single picture per a piece of memoized code. - -* More flexibility in the workflow. - -* Customizable verbosity level. - -* Testing. If you use the package, please report (github, email) any problems - you encounter! - - * How robust is the package? Do we ever lose any data due to a - compilation error? (We should not, even if the error occurs elsewhere!) - - * Compatibility with other packages. - -Some long-term ideas: - -* Externalize into formats other than PDF. - -* Support for TeX formats other than LaTeX --- in particular, Plain TeX and - ConTeXt. - - -[^1]: This is what happened to Stefan Müller when he was working on the [HPSG - Handbook](https://github.com/langsci/hpsg-handbook/). We have a nice - symbiotic relatioship here: I save him some time (at least in the long run, - I hope), and he finds my bugs. Thanks, Stefan! +Memoize is a package for externalization of graphics and memoization of +compilation results in general, allowing the author to reuse the results of +compilation-intensive code. + +Memoize (i) induces very little overhead, as all externalized graphics is +produced in a single compilation. It features (ii) automatic recompilation upon +the change of code or user-adjustable context, and (iii) automatic +externalization of TikZ pictures and Forest trees, easily extensible to other +commands and environments. Furthermore, Memoize (iv) supports +cross-referencing, TikZ overlays and Beamer, (v) works with all major engines +and formats, and (vi) is adaptable to any workflow. + +This repository also contains the code of two generic auxiliary packages +developed and documented alongside Memoize. Package Advice implements a generic +framework for extending the functionality of selected commands and +environments, and package CollArgs provides a command which can determine the +argument scope of any command whose argument structure conforms to +[xparse](https://ctan.org/pkg/xparse)'s argument specification. + +See [INSTALL.md](INSTALL.md) for instructions on how to generate runtime files +and compile the documentation. diff --git a/advice.edtx b/advice.edtx new file mode 100644 index 0000000..ee94862 --- /dev/null +++ b/advice.edtx @@ -0,0 +1,1095 @@ +% \iffalse +% +% advice.edtx (this is not a .dtx file; to produce a .dtx, process it with edtx2dtx) +% +%% This file is a part of Advice, a TeX package implementing a generic +%% framework for extending the functionality of selected commands and +%% environments, available at https://ctan.org/pkg/advice and +%% https://github.com/sasozivanovic/advice. +%% +%% Copyright (c) 2023- Saso Zivanovic +%% (Sa\v{s}o \v{Z}ivanovi\'{c}) +%% +%% This work may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License, either version 1.3c of this license or (at +%% your option) any later version. The latest version of this license is in +%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of +%% all distributions of LaTeX version 2008 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Saso Zivanovic. +%% +%% The files belonging to this work and covered by LPPL are listed in `FILES`. +% +% \fi +% +% \begin{macrocode} +% +% \relax +% +%<*main> +%\ProvidesPackage{advice}[2023/10/10 v1.0.0 Extend commands and environments] +%%D \module[ +%%D file=t-advice.tex, +%%D version=1.0.0, +%%D title=Advice, +%%D subtitle=Extend commands and environments, +%%D author=Saso Zivanovic, +%%D date=2023-10-10, +%%D copyright=Saso Zivanovic, +%%D license=LPPL, +%%D ] +%\writestatus{loading}{ConTeXt User Module / advice} +%\unprotect +%\startmodule[advice] +% \paragraph{Required packages} +%\RequirePackage{collargs} +%\input collargs +%\input t-collargs +% +% \subsubsection{Installation into a keypath} +% +% \begin{handlerskey}{.install advice} +% This handler installs the advising mechanism into the handled path, which +% we shall henceforth also call the (advice) namespace. +\pgfkeys{ + /handlers/.install advice/.code={% + \edef\auto@install@namespace{\pgfkeyscurrentpath}% + \def\advice@install@setupkey{advice}% + \def\advice@install@activation{immediate}% + \pgfqkeys{/advice/install}{#1}% + \expanded{\noexpand\advice@install + {\auto@install@namespace}% + {\advice@install@setupkey}% + {\advice@install@activation}% + }% + }, +% \end{handlerskey} +% +% \begin{adviceinstallkey}{setup key,activation} +% These keys can be used in the argument of |.install advice| to configure +% the installation. By default, the setup key is |advice| and |activation| is +% |immediate|. + /advice/install/.cd, + setup key/.store in=\advice@install@setupkey, + activation/.is choice, + activation/.append code=\def\advice@install@activation{#1}, + activation/immediate/.code={}, + activation/deferred/.code={}, +} +% \end{adviceinstallkey} +% +% |#1| is the installation keypath (in Memoize, |/mmz|); |#2| is the setup key +% name (in Memoize, |auto|, and this is why we document it as such); |#3| is +% the initial activation regime. +\def\advice@install#1#2#3{% + % Switch to the installation keypath. + \pgfqkeys{#1}{% + % \begin{key}{auto, auto csname, auto key, auto', auto csname', auto key'} + % These keys submit a command or environment to advising. The + % namespace is hard-coded into these keys via |#1|; their arguments are + % the command/environment (cs)name, and setup keys belonging to path + % \meta{installation keypath}|/\meta{setup key name}|. + #2/.code 2 args={% + % Call the internal setup macro, wrapping the received keylist into a + % |pgfkeys| invocation. + \AdviceSetup{#1}{#2}{##1}{\pgfqkeys{#1/#2}{##2}}% + % Activate if not already activated (this can happen when updating the + % configuration). Note we don't call |\advice@activate| directly, but use + % the public keys; in this way, activation is automatically deferred if + % so requested. (We don't use |\pgfkeysalso| to allow |auto| being called + % from any path.) + \pgfqkeys{#1}{try activate, activate={##1}}% + }, + % A variant without activation. + #2'/.code 2 args={% + \AdviceSetup{#1}{#2}{##1}{\pgfqkeys{#1/#2}{##2}}% + }, + #2 csname/.style 2 args={ + #2/.expand once=\expandafter{\csname ##1\endcsname}{##2}, + }, + #2 csname'/.style 2 args={ + #2'/.expand once=\expandafter{\csname ##1\endcsname}{##2}, + }, + #2 key/.style 2 args={ + #2/.expand once=% + \expandafter{\csname pgfk@##1/.@cmd\endcsname}% + {collector=\advice@pgfkeys@collector,##2}, + }, + #2 key'/.style 2 args={ + #2'/.expand once=% + \expandafter{\csname pgfk@##1/.@cmd\endcsname}% + {collector=\advice@pgfkeys@collector,##2}, + }, + % \end{key} + % + % \begin{key}{activation} + % This key, residing in the installation keypath, forwards the request to + % the |/advice| path |activation| subkeys, which define |activate| and + % friends in the installation keypath. Initially, the activation regime + % is whatever the user has requested using the |.install advice| argument + % (here |#3|). + activation/.style={/advice/activation/##1={#1}}, + activation=#3, + % \end{key} + % + % \begin{key}{activate deferred} + % The deferred activations are collected in this style, see + % section~ref{sec:code:advice:activation} for details. + activate deferred/.code={}, + % \end{key} + % + % \begin{key}{activate csname, deactivate csname} + % For simplicity of implementation, the |csname| versions of |activate| + % and |deactivate| accept a single \meta{csname}. This way, they can be + % defined right away, as they don't change with the type of activation + % (immediate vs.\ deferred). + activate csname/.style={activate/.expand once={\csname##1\endcsname}}, + deactivate csname/.style={activate/.expand once={\csname##1\endcsname}}, + % \end{key} + % + % \begin{key}{activate key, deactivate key} + % (De)activation of |pgfkeys| keys. Accepts a list of key names, requires + % full key names. + activate key/.style={activate@key={#1/activate}{##1}}, + deactivate key/.style={activate@key={#1/deactivate}{##1}}, + activate@key/.code n args=2{% + \def\advice@temp{}% + \def\advice@do####1{% + \eappto\advice@temp{,\expandonce{\csname pgfk@####1/.@cmd\endcsname}}}% + \forcsvlist\advice@do{##2}% + \pgfkeysalso{##1/.expand once=\advice@temp}% + }, + % \end{key} + % + % The rest of the keys defined below reside in the |auto| subfolder of the + % installation keypath. + #2/.cd, + % + % \begin{mmzautokey}{run conditions, outer handler, bailout handler, collector, + % args, collector options, clear collector options, raw collector options, + % clear raw collector options, inner handler, options, clear options} + % These keys are used to setup the handling of the command or + % environment. The storage macros (|\AdviceRunConditions| etc.) have + % public names as they also play a crucial role in the handler + % definitions, see section~\ref{sec:code:advice:handle}. \indentmacrocode + run conditions/.store in=\AdviceRunConditions, + bailout handler/.store in=\AdviceBailoutHandler, + outer handler/.store in=\AdviceOuterHandler, + collector/.store in=\AdviceCollector, + collector options/.code={\appto\AdviceCollectorOptions{,##1}}, + clear collector options/.code={\def\AdviceCollectorOptions{}}, + raw collector options/.code={\appto\AdviceRawCollectorOptions{##1}}, + clear raw collector options/.code={\def\AdviceRawCollectorOptions{}}, + args/.store in=\AdviceArgs, + inner handler/.store in=\AdviceInnerHandler, + options/.code={\appto\AdviceOptions{,##1}}, + clear options/.code={\def\AdviceOptions{}}, + % \noindentmacrocode + % A user-friendly way to set |options|: any unknown key is an option. + .unknown/.code={% + \eappto{\AdviceOptions}{,\pgfkeyscurrentname={\unexpanded{##1}}}% + }, + % The default values of the keys, which equal the initial values for + % commands, as assigned by |\advice@setup@init@command|. + run conditions/.default=\AdviceRuntrue, + bailout handler/.default=\relax, + outer handler/.default=\advice@default@outer@handler, + collector/.default=\advice@CollectArgumentsRaw, + collector options/.value required, + raw collector options/.value required, + args/.default=\advice@noargs, + inner handler/.default=\advice@error@noinnerhandler, + options/.value required, + % \end{mmzautokey} + % + % \begin{mmzautokey}{reset} + % This key resets the advice settings to their initial values, which + % depend on whether we're handling a command or environment. + reset/.code={\csname\advice@setup@init@\AdviceType\endcsname}, + % \end{mmzautokey} + % + % \begin{mmzautokey} + % The code given here will be executed once we exit the setup group. + % |integrated driver| of Memoize uses it to declare a conditional. + after setup/.code={\appto\AdviceAfterSetup{##1}}, + % \end{mmzautokey} + % + % In \hologo{LaTeX}, we finish the installation by submitting |\begin|; the + % submission is funky, because the run conditions handler actually hacks + % the standard handling procedure. Note that if |\begin| is not + % activated, environments will not be handled, and that the automatic + % activation might be deffered. + %#1/#2=\begin{run conditions=\advice@begin@rc}, + }% +} +% +% +% \subsubsection{Submitting a command or environment} +% \label{sec:code:advice:setup} +% +% \begin{macro}{\AdviceSetup,\AdviceName,\AdviceType} +% Macro |\advice@setup| is called by key |auto| to submit a command or +% environment to advising. It receives four arguments: |#1| is the +% installation keypath / storage namespace: |#2| is the name of the setup +% key; |#3| is the submitted command or environment; |#4| is the setup code +% (which is only grabbed by |\advice@setup@i|). +% +% Executing this macro defines macros |\AdviceName|, holding the control +% sequence of the submitted command or the environment name, and |\AdviceType|, +% holding |command| or |environment|; they are used to set up some initial +% values, and may be used by user-defined keys in the |auto| path, as well +% (see |/mmz/auto/noop| for an example). The macro then performs internal +% initialization, and finally calls the second part, |\advice@setup@i|, with +% the command's \emph{storage} name as the first argument. +% +% This macro also serves as the programmer's interface to |auto|, the idea +% being that an advanced user may write code |#4| which defined the settings +% macros (|\AdviceOuterHandler| etc.) without deploying |pgfkeys|. (Also note +% that activation at the end only occurs through the |auto| interface.) +\def\AdviceSetup#1#2#3{% + % Open a group, so that we allow for embedded |auto| invocations. + \begingroup + \def\AdviceName{#3}% + % Command, complain, or environment? + \collargs@cs@cases{#3}{% + \def\AdviceType{command}% + \advice@setup@init@command + \advice@setup@i{#3}{#1}{#3}% + }{% + \advice@error@advice@notcs{#1/#2}{#3}% + }{% + \def\AdviceType{environment}% + \advice@setup@init@environment + %\advice@setup@i{#3}% + %\expandafter\advice@setup@i\expandafter{\csname #3\endcsname}% + %\expandafter\advice@setup@i\expandafter{\csname start#3\endcsname}% + {#1}{#3}% + }% +} +% The arguments of |\advice@setup@i| are a bit different than for +% |\advice@setup|, because we have inserted the storage name as |#1| above, and +% we lost the setup key name |#2|. Here, |#2| is the installation keypath / +% storage namespace, |#3| is the submitted command or environment; and |#4| is +% the setup code. +% +% What is the difference between the storage name (|#1|) and the command\slash +% environment name (|#3|, and also the contents of |\AdviceName|), and why do we +% need both? For commands, there is actually no difference; for example, when +% submitting command |\foo|, we end up with |#1|=|#3|=|\foo|. And there is +% also no difference for \hologo{LaTeX} environments; when submitting +% environment |foo|, we get |#1|=|#3|=|foo|. But in \hologo{plainTeX}, +% |#1|=|\foo| and |#3|=|foo|, and in \hologo{ConTeXt}, |#1|=|\startfoo| and +% |#3|=|foo| --- which should explain the guards and |\expandafter|s above. +% +% And why both |#1| and |#3|? When a handled command is executed, it loads its +% configuration from a macro determined by the storage namespace and the +% (|\string|ified) storage name, e.g.\ |/mmz| and |\foo|. In \hologo{plainTeX} +% and \hologo{ConTeXt}, each environment is started by a dedicated command, +% |\foo| or |\startfoo|, so these control sequences (|\string|ified) must act +% as storage names. (Not so in \hologo{LaTeX}, where an environment +% configuration is loaded by |\begin|'s handler, which can easily work with +% storage name |foo|. Even more, having |\foo| as an environment storage +% name would conflict with the storage name for the (environment-internal) +% command |\foo| --- yes, we can submit either |foo| or |\foo|, or both, to +% advising.) +\def\advice@setup@i#1#2#3#4{% + % Load the current configuration of the handled command or environment --- if + % it exists. + \advice@setup@init@i{#2}{#1}% + \advice@setup@init@I{#2}{#1}% + \def\AdviceAfterSetup{}% + % Apply the setup code/keys. + #4% + % Save the resulting configuration. This closes the group, because the config + % is saved outside it. + \advice@setup@save{#2}{#1}% +} +% \end{macro} +% +% \paragraph{Initialize} the configuration of a command or environment. Note +% that the default values of the keys equal the initial values for commands. +% Nothing would go wrong if these were not the same, but it's nice that the +% end-user can easily revert to the initial values. +\def\advice@setup@init@common{% + \def\AdviceRunConditions{\AdviceRuntrue}% + \def\AdviceBailoutHandler{\relax}% + \def\AdviceOuterHandler{\advice@default@outer@handler}% + \def\AdviceCollector{\advice@CollectArgumentsRaw}% + \def\AdviceCollectorOptions{}% + \def\AdviceInnerHandler{\advice@error@noinnerhandler}% + \def\AdviceOptions{}% +} +\def\advice@setup@init@command{% + \advice@setup@init@common + \def\AdviceRawCollectorOptions{}% + \def\AdviceArgs{\advice@noargs}% +} +\def\advice@setup@init@environment{% + \advice@setup@init@common + \edef\AdviceRawCollectorOptions{% + \noexpand\collargsEnvironment{\AdviceName}% + % When grabbing an environment body, the end-tag will be included. This + % makes it possible to have the same inner handler for commands and + % environments. + \noexpand\collargsEndTagtrue + }% + \def\AdviceArgs{+b}% +} +% We need to initialize |\AdviceOuterHandler| etc.\ so that |\advice@setup@store| +% will work. +\advice@setup@init@command +% +% \paragraph.{The configuration storage} +% +% The remaining macros in this subsection deal with the configuration storage +% space, which is set up in a way to facilitate fast loading during the +% execution of handled commands and environments. +% +% The configuration of a command or environment is stored in two parts: the +% first stage settings comprise the run conditions, the bailout handler and the +% outer handler; the second stage settings contain the rest. When a handled +% command is invoked, only the first stage settings are immediately loaded, for +% speed; the second stage settings are only loaded if the run conditions are +% satisfied. +% +% \begin{macro}{\advice@init@i,\advice@init@I} +% The two-stage settings are stored in control sequences +% |\advice@i|\meta{namespace}|//|\meta{storage name} and +% |\advice@I|\meta{namespace}|//|\meta{storage name}, respectively, and +% accessed using macros |\advice@init@i| and |\advice@init@I|. +% +% Each setting storage macro contains a sequence of items, where each item is +% either of form |\def\AdviceSetting|\marg{value}. This allows us store +% multiple settings in a single macro (rather than define each +% control-sequence-valued setting separately, which would use more string +% memory), and also has the consequence that we don't require the handlers to +% be defined when submitting a command (whether that's good or bad could be +% debated: as things stand, any typos in handler declarations will only yield +% an error once the handled command is executed). +\def\advice@init@i#1#2{\csname advice@i#1//\string#2\endcsname} +\def\advice@init@I#1#2{\csname advice@I#1//\string#2\endcsname} +% We make a copy of these for setup; the originals might be swapped for +% tracing purposes. +\let\advice@setup@init@i\advice@init@i +\let\advice@setup@init@I\advice@init@I +% \end{macro} +% +% \begin{macro}{\advice@setup@save} +% To save the configuration at the end of the setup, we construct the storage +% macros out of |\AdviceRunConditions| and friends. Stage-one contains only +% |\AdviceRunConditions| and |\AdviceBailoutHandler|, so that +% |\advice@handle| can bail out as quickly as possible if the run conditions +% are not met. +\def\advice@setup@save#1#2{% + \expanded{% + % Close the group before saving. Note that |\expanded| has already expanded + % the settings macros. + \endgroup + \noexpand\csdef{advice@i#1//\string#2}{% + \def\noexpand\AdviceRunConditions{\expandonce\AdviceRunConditions}% + \def\noexpand\AdviceBailoutHandler{\expandonce\AdviceBailoutHandler}% + }% + \noexpand\csdef{advice@I#1//\string#2}{% + \def\noexpand\AdviceOuterHandler{\expandonce\AdviceOuterHandler}% + \def\noexpand\AdviceCollector{\expandonce\AdviceCollector}% + \def\noexpand\AdviceRawCollectorOptions{\expandonce\AdviceRawCollectorOptions}% + \def\noexpand\AdviceCollectorOptions{\expandonce\AdviceCollectorOptions}% + \def\noexpand\AdviceArgs{\expandonce\AdviceArgs}% + \def\noexpand\AdviceInnerHandler{\expandonce\AdviceInnerHandler}% + \def\noexpand\AdviceOptions{\expandonce\AdviceOptions}% + }% + \expandonce{\AdviceAfterSetup}% + }% +} +% \end{macro} +% \label{sec:code:advice:activation} +% +% \begin{advicekey}{activation/immediate, activation/deferred} +% The two subkeys of |/advice/activation| install the immediate and the +% deferred activation code into the installation keypath. They are invoked +% by \meta{installation keypath}|/activation=|\meta{type}. +% +% Under the deferred activation regime, the commands are not (de)activated +% right away. Rather, the (de)activation calls are collected in style +% |activate deferred|, which should be executed by the installation keypath +% owner, if and when they so desire. (Be sure to switch to +% |activation=immediate| before executing |activate deferred|, otherwise the +% activation will only be deferred once again.) +\pgfkeys{ + /advice/activation/deferred/.style={ + #1/activate/.style={% + activate deferred/.append style={#1/activate={##1}}}, + #1/deactivate/.style={% + activate deferred/.append style={#1/deactivate={##1}}}, + #1/force activate/.style={% + activate deferred/.append style={#1/force activate={##1}}}, + #1/try activate/.style={% + activate deferred/.append style={#1/try activate={##1}}}, + }, +% \end{advicekey} +% +% \begin{key}{activate, deactivate, force activate, try activate} +% The ``real,'' immediate |activate| and |deactivate| take a comma-separated +% list of commands or environments and (de)activate them. If |try activate| +% is in effect, no error is thrown upon failure. If |force activate| is in +% effect, activation proceeds even if we already had the original definition; +% it does not apply to deactivation. These conditionals are set to false +% after every invocation of key |(de)activate|, so that they only apply to +% the immediately following |(de)activate|. (|#1| below is the +% \meta{namespace}; |##1| is the list of commands to be (de)activated.) + /advice/activation/immediate/.style={ + #1/activate/.code={% + \forcsvlist{\advice@activate{#1}}{##1}% + \advice@activate@forcefalse + \advice@activate@tryfalse + }, + #1/deactivate/.code={% + \forcsvlist{\advice@deactivate{#1}}{##1}% + \advice@activate@forcefalse + \advice@activate@tryfalse + }, + #1/force activate/.is if=advice@activate@force, + #1/try activate/.is if=advice@activate@try, + }, +} +\newif\ifadvice@activate@force +\newif\ifadvice@activate@try +% \end{key} +% +% \begin{macro}{\advice@original@csname,\advice@original@cs,\AdviceGetOriginal} +% Activation replaces the original meaning of the handled command with our +% definition. We store the original definition into control sequence +% |\advice@o|\meta{namespace}|//|\meta{storage name} (with a |\string|ified +% \meta{storage name}). Internally, during (de)activation and handling, we +% access it using |\advice@original@csname| and |\advice@original@cs|. Publicly +% it should always be accessed by |\AdviceGetOriginal|, which returns the +% argument control sequence if that control sequence is not handled. +% +% Using the internal command outside the handling context, we could fall +% victim to scenario such as the following. When we memoize something +% containing a |\label|, the produced cc-memo contains code eventually +% executing the original |\label|. If we called the original |\label| via +% the internal macro there, and the user |deactivate|d |\label| on a +% subsequent compilation, the cc-memo would not call |\label| anymore, but +% |\relax|, resulting in a silent error. Using |\AdviceGetOriginal|, the +% original |\label| will be executed even when not activated. +% +% However, not all is bright with |\AdviceGetOriginal|. Given an activated +% control sequence (|#2|), a typo in the namespace argument (|#1|) will lead +% to an infinite loop upon the execution of |\AdviceGetOriginal|. In the +% manual, we recommend defining a namespace-specific macro to avoid such +% typos. +\def\advice@original@csname#1#2{advice@o#1//\string#2} +\def\advice@original@cs#1#2{\csname advice@o#1//\string#2\endcsname} +\def\AdviceGetOriginal#1#2{% + \ifcsname advice@o#1//\string#2\endcsname + \csname advice@o#1//\string#2\expandafter\endcsname + \else + \expandafter#2% + \fi +} +% \end{macro} +% +% \begin{macro}{\advice@activate,\advice@deactivate} +% These macros execute either the command, or the environment (de)activator. +\def\advice@activate#1#2{% + \collargs@cs@cases{#2}% + {\advice@activate@cmd{#1}{#2}}% + {\advice@error@activate@notcsorenv{}{#1}}% + {\advice@activate@env{#1}{#2}}% +} +\def\advice@deactivate#1#2{% + \collargs@cs@cases{#2}% + {\advice@deactivate@cmd{#1}{#2}}% + {\advice@error@activate@notcsorenv{de}{#1}}% + {\advice@deactivate@env{#1}{#2}}% +} +% \end{macro} +% +% \begin{macro}{\advice@activate@cmd} +% We are very careful when we're activating a command, because activating +% means rewriting its original definition. Configuration by |auto| did not +% touch the original command; activation will. So, the leitmotif of this +% macro: safety first. (|#1| is the namespace, and |#2| is the command to be +% activated.) +\def\advice@activate@cmd#1#2{% + % Is the command defined? + \ifdef{#2}{% + % Yes, the command is defined. Let's see if it's safe to activate it. + % We'll do this by checking whether we have its original definition in our + % storage. If we do, this means that we have already activated the + % command. Activating it twice would lead to the loss of the original + % definition (because the second activation would store our own + % redefinition as the original definition) and consequently an infinite + % loop (because once --- well, if --- the handler tries to invoke the + % original command, it will execute itself all over). + \ifcsdef{\advice@original@csname{#1}{#2}}{% + % Yes, we have the original definition, so the safety check failed, and + % we shouldn't activate again. Unless \dots\ how does its current + % definition look like? + \advice@if@our@definition{#1}{#2}{% + % Well, the current definition of the command matches what we would put + % there ourselves. The command is definitely activated, and we refuse + % to activate again, as that would destroy the original definition. + \advice@activate@error@activated{#1}{#2}{Command}{already}% + }{% + % We don't recognize the current definition as our own code (despite + % the fact that we have surely activated the commmand before, given the + % result of the first safety check). It appears that someone else was + % playing fast and loose with the same command, and redefined it after + % our activation. (In fact, if that someone else was another instance + % of Advice, from another namespace, forcing the activation will result + % in the loss of the original definition and the infinite loop.) So it + % \emph{should} be safe to activate it (again) \dots\ but we won't do + % it unless the user specifically requested this using |force + % activate|. Note that without |force activate|, we would be stuck in + % this branch, as we could neither activate (again) nor deactivate the + % command. + \ifadvice@activate@force + \advice@activate@cmd@do{#1}{#2}% + \else + \advice@activate@error@activated{#1}{#2}{Command}{already}% + \fi + }% + }{% + % No, we don't have the command's original definition, so it was not yet + % activated, and we may activate it. + \advice@activate@cmd@do{#1}{#2}% + }% + }{% + \advice@activate@error@undefined{#1}{#2}{Command}{}% + }% +} +% \end{macro} +% +% \begin{macro}{\advice@deactivate@cmd} +% The deactivation of a command follows the same template as activation, but +% with a different logic, and of course a different effect. In order to +% deactivate a command, both safety checks discussed above must be satisfied: +% we must have the command's original definition, \emph{and} our redefinition +% must still reside in the command's control sequence --- the latter +% condition prevents overwriting someone else's redefinition with the +% original command. As both conditions must be unavoidably fulfilled, |force +% activate| has no effect in deactivation (but |try activate| has). +\def\advice@deactivate@cmd#1#2{% + \ifdef{#2}{% + \ifcsdef{\advice@original@csname{#1}{#2}}{% + \advice@if@our@definition{#1}{#2}{% + \advice@deactivate@cmd@do{#1}{#2}% + }{% + \advice@deactivate@error@changed{#1}{#2}% + }% + }{% + \advice@activate@error@activated{#1}{#2}{Command}{not yet}% + }% + }{% + \advice@activate@error@undefined{#1}{#2}{Command}{de}% + }% +} +% \end{macro} +% +% \begin{macro}{\advice@if@our@definition} +% This macro checks whether control sequence |#2| was already activated (in +% namespace |#1|) in the sense that its current definition contains the code +% our activation would put there: |\advice@handle{#1}{#2}| (protected). +\def\advice@if@our@definition#1#2{% + \protected\def\advice@temp{\advice@handle{#1}{#2}}% + \ifx#2\advice@temp + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi +} +% \end{macro} +% +% \begin{macro}{\advice@activate@cmd@do} +% This macro saves the original command, and redefines its control sequence. +% Our redefinition must be |\protected| --- even if the original command +% wasn't fragile, our replacement certainly is. (Note that as we require +% \hologo{eTeX} anyway, we don't have to pay attention to \hologo{LaTeX}'s +% robust commands by redefining their ``inner'' command. Protecting our +% replacement suffices.) +\def\advice@activate@cmd@do#1#2{% + \cslet{\advice@original@csname{#1}{#2}}#2% + \protected\def#2{\advice@handle{#1}{#2}}% + \PackageInfo{advice (#1)}{Activated command "\string#2"}% +} +% \end{macro} +% +% \begin{macro}{\advice@deactivate@cmd@do} +% This macro restores the original command, and removes its definition from +% our storage --- this also serves as a signal that the command is not +% activated anymore. +\def\advice@deactivate@cmd@do#1#2{% + \letcs#2{\advice@original@csname{#1}{#2}}% + \csundef{\advice@original@csname{#1}{#2}}% + \PackageInfo{advice (#1)}{Deactivated command "\string#2"}% +} +% \end{macro} +% +% +% \subsubsection{Executing a handled command} +% \label{sec:code:advice:handle} +% +% \begin{macro}{\advice@handle} +% An invocation of this macro is what replaces the original command and runs +% the whole shebang. The system is designed to bail out as quickly as +% necessary if the run conditions are not met (plus \hologo{LaTeX}'s |\begin| +% will receive a very special treatment for this reason). +% +% We first check the run conditions, and bail out if they are not satisfied. +% Note that only the stage-one config is loaded at this point. It sets up +% the following macros (while they are public, neither the end user not the +% installation keypath owner should ever have to use them): +% +% \begin{itemize} +% \item \PrintMainMacro{\AdviceRunConditions} executes |\AdviceRuntrue| if the +% command should be handled; set by |run conditions|. +% \item \PrintMainMacro{\AdviceBailoutHandler} will be executed if the +% command will not be handled, after all; set by |bailout handler|. +% \end{itemize} +\def\advice@handle#1#2{% + \advice@init@i{#1}{#2}% + \AdviceRunfalse + \AdviceRunConditions + \advice@handle@rc{#1}{#2}% +} +% \end{macro} +% +% \begin{macro}{\advice@handle@rc} +% We continue the handling in a new macro, because this is the point where +% the handler for |\begin| will hack into the regular flow of events. +\def\advice@handle@rc#1#2{% + \ifAdviceRun + \expandafter\advice@handle@outer + \else + % Bailout is simple: we first execute the handler, and then the original command. + \AdviceBailoutHandler + \expandafter\advice@original@cs + \fi + {#1}{#2}% +} +% \end{macro} +% +% \begin{macro}{\advice@handle@outer} +% To actually handle the command, we first setup some macros: +% +% \begin{itemize} +% \item \PrintMainMacro{\AdviceNamespace} holds the installation keypath / +% storage name space. +% \item \PrintMainMacro{\AdviceName} holds the control sequence of the handled +% command, or the environment name. +% \item \PrintMainMacro{\AdviceReplaced} holds the ``substituted'' code. For +% commands, this is the same as |\AdviceName|. For environment |foo|, it +% equals |\begin{foo}| in \hologo{LaTeX}, |\foo| in \hologo{plainTeX} and +% |\startfoo| in \hologo{ConTeXt}. +% \item \PrintMainMacro{\AdviceOriginal} executes the original definition of +% the handled command or environment. +% \end{itemize} +\def\advice@handle@outer#1#2{% + \def\AdviceNamespace{#1}% + \def\AdviceName{#2}% + \let\AdviceReplaced\AdviceName + \def\AdviceOriginal{\AdviceGetOriginal{#1}{#2}}% + % We then load the stage-two settings. This defines the following macros: + % \begin{itemize} + % \item \PrintMainMacro{\AdviceOuterHandler} will effectively replace the + % command, if it will be handled; set by |outer handler|. + % \item \PrintMainMacro{\AdviceCollector} collects the arguments of the handled + % command, perhaps consulting |\AdviceArgs| to learn about its argument + % structure. + % \item \PrintMainMacro{\AdviceRawCollectorOptions} contains the options which + % will be passed to the argument collector, in the ``raw'' format. + % \item \PrintMainMacro{\AdviceCollectorOptions} contains the additional, + % user-specified options which will be passed to the argument collector. + % \item \PrintMainMacro{\AdviceArgs} contains the |xparse|-style argument + % specification of the command, or equals |\advice@noargs| to signal that + % command was defined using |xparse| and that the argument specification + % should be retrieved automatically. + % \item \PrintMainMacro{\AdviceInnerHandler} is called by the argument + % collector once it finishes its work. It receives all the collected + % arguments as a single (braced) argument. + % \item \PrintMainMacro{\AdviceOptions} holds options which may be used by the + % outer or the inner handler; Advice does not need or touch + % them. + % \end{itemize} + \advice@init@I{#1}{#2}% + % All prepared, we execute the outer handler. + \AdviceOuterHandler +} +% \end{macro} +% +% \begin{macro}{\ifAdviceRun} +% This conditional is set by the run conditions macro to signal whether we +% should run the outer (true) or the bailout (false) handler. +\newif\ifAdviceRun +% \end{macro} +% +% \begin{macro}{\advice@default@outer@handler} +% The default outer handler merely executes the argument collector. Note +% that it works for both commands and environments. +\def\advice@default@outer@handler{% + \AdviceCollector +} +% \end{macro} +% +% \begin{macro}{\advice@CollectArgumentsRaw} +% This is the default collector, which will collect the argument using +% CollArgs' command |\CollectArgumentsRaw|. It will provide that command +% with: +% \begin{itemize} +% \item the collector options, given in the raw format: the caller +% (|\collargsCaller|), the raw options (|\AdviceRawCollectorOptions|) and the +% user options (|\AdviceRawCollectorOptions|, wrapped in |\collargsSet|; +% \item the argument specification |\AdviceArgs| of the handled command; and +% \item the inner handler |\AdviceInnerHandler| to execute after collecting the +% arguments; the inner handler receives the collected arguments as a single +% braced argument. +% \end{itemize} +% If the argument specification is not defined (either the user did not set +% it, or has reset it by writing |args| without a value), it is assumed that +% the handled command was defined by |xparse| and |\AdviceArgs| will be +% retrieved by |\GetDocumentCommandArgSpec|. +% \begin{listingregion}{_advice-CollectArgumentsRaw.tex} +\def\advice@CollectArgumentsRaw{% + \AdviceIfArgs{}{% + \expandafter\GetDocumentCommandArgSpec\expandafter{\AdviceName}% + \let\AdviceArgs\ArgumentSpecification + }% + \expanded{% + \noexpand\CollectArgumentsRaw{% + \noexpand\collargsCaller{\expandonce\AdviceName}% + \expandonce\AdviceRawCollectorOptions + \ifdefempty\AdviceCollectorOptions{}{% + \noexpand\collargsSet{\expandonce\AdviceCollectorOptions}% + }% + }% + {\expandonce\AdviceArgs}% + {\expandonce\AdviceInnerHandler}% + }% +} +% \end{listingregion} +% \end{macro} +% +% \begin{macro}{\AdviceIfArgs} +% If the value of |args| is ``real'', i.e.\ an |xparse| argument +% specification, execute the first argument. If |args| was set to the +% special value |\advice@noargs|, signaling a command defined by +% |\NewDocumentCommand| or friends, execute the second argument. (Ok, in +% reality anything other than |\advice@noargs| counts as real ``real''.) +\def\advice@noargs@text{\advice@noargs} +\def\AdviceIfArgs{% + \ifx\AdviceArgs\advice@noargs@text + \expandafter\@secondoftwo + \else + \expandafter\@firstoftwo + \fi +} +% \end{macro} +% +% \begin{macro}{\advice@pgfkeys@collector} +% A |pgfkeys| collector is very simple: the sole argument of the any key +% macro, regardless of the argument structure of the key, is everything up to +% |\pgfeov|. +\def\advice@pgfkeys@collector#1\pgfeov{% + \AdviceInnerHandler{#1}% +} +% \end{macro} +% +% \subsubsection{Environments} +% \label{sec:code:advice:environments} +% +% \begin{macro}{\advice@activate@env,\advice@deactivate@env} +% Things are simple in \hologo{TeX} and \hologo{ConTeXt}, as their environments +% are really commands. So rather than activating environment name |#2|, we +% (de)activate command |\#2| or |\start#2|, depending on the format. +%<*plain,context> +\def\advice@activate@env#1#2{% + \expanded{% + \noexpand\advice@activate@cmd{#1}{\expandonce{\csname + %start% + #2\endcsname}}% + }% +} +\def\advice@deactivate@env#1#2{% + \expanded{% + \noexpand\advice@deactivate@cmd{#1}{\expandonce{\csname + %start% + #2\endcsname}}% + }% +} +% +% +% We activate commands by redefining them; that's the only way to do it. But +% we won't activate a \hologo{LaTeX} environment |foo| by redefining command +% |\foo|, where the user's definition for the start of the environment actually +% resides, as such a redefinition would be executed too late, deep within the +% group opened by |\begin|, following many internal operations and public +% hooks. We handle \hologo{LaTeX} environments by defining an outer handler +% for |\begin| (consequently, \hologo{LaTeX} environment support can be +% (de)activated by the user by saying (|de|)|activate=\begin|), and +% activating an environment will be nothing but setting a mark, by +% defining a dummy control sequence |\advice@original@csname{#1}{#2}|, +% which that handler will inspect. Note that |force activate| has no +% effect here. +%<*latex> +\def\advice@activate@env#1#2{% + \ifcsdef{\advice@original@csname{#1}{#2}}{% + \advice@activate@error@activated{#1}{#2}{Environment}{already}% + }{% + \csdef{\advice@original@csname{#1}{#2}}{}% + }% +} +\def\advice@deactivate@env#1#2{% + \ifcsdef{\advice@original@csname{#1}{#2}}{% + \csundef{\advice@original@csname{#1}{#2}}{}% + }{% + \advice@activate@error@activated{#1}{#2}{Environment}{not yet}% + }% +} +% \end{macro} +% +% \begin{macro}{\advice@begin@rc} +% This is the handler for |\begin|. It is very special, for speed. It is +% meant to be declared as the run conditions component, and it hacks into +% the normal flow of handling. It knows that after executing the run +% conditions macro, |\advice@handle| eventually (the tracing info may +% interrupt here as |#1|) continues by +% |\advice@handle@rc|\marg{namespace}\marg{handled control sequence}, so it +% grabs all these (|#2| is the \meta{namespace} and |#3| is the +% \meta{handled control sequence}, i.e.\ |\begin|) plus the environment +% name (|#4|). +\def\advice@begin@rc#1\advice@handle@rc#2#3#4{% + % We check whether environment |#4| is activated (in namespace |#2|) by + % inspecting whether activation dummy is defined. If it is not, we execute + % the original |\begin| (|\advice@original@cs{#2}{#3}|), followed by the + % environment name (|#4|). Note that we \emph{don't} execute the + % environment's bailout handler here: we haven't checked its run conditions + % yet, as the environment is simply not activated. + \ifcsname\advice@original@csname{#2}{#4}\endcsname + \expandafter\advice@begin@env@rc + \else + \expandafter\advice@original@cs + \fi + {#2}{#3}{#4}% +} +% \end{macro} +% +% \begin{macro}{\advice@begin@env@rc} +% Starting from this point, we essentially replicate the workings of +% |\advice@handle|, adapted to \hologo{LaTeX} environments. +\def\advice@begin@env@rc#1#2#3{% + % We first load the stage-one configuration for environment |#3| in namespace + % |#1|. + \advice@init@i{#1}{#3}% + % This defined |\AdviceRunConditions| for the environment. We can now check its + % run conditions. If they are not satisfied, we bail out by executing the + % environment's bailout handler followed by the original |\begin| + % (|\advice@original@cs{#1}{#2}|) plus the environment name (|#3|). + \AdviceRunConditions + \ifAdviceRun + \expandafter\advice@begin@env@outer + \else + \AdviceBailoutHandler + \expandafter\advice@original@cs + \fi + {#1}{#2}{#3}% +} +% \end{macro} +% +% \begin{macro}{\advice@begin@env@outer} +% We define the macros expected by the outer handler, see +% |\advice@handle@outer|, load the second-stage configuration, and execute the +% environment's outer handler. +\def\advice@begin@env@outer#1#2#3{% + \def\AdviceNamespace{#1}% + \def\AdviceName{#3}% + \def\AdviceReplaced{#2{#3}}% + \def\AdviceOriginal{\AdviceGetOriginal{#1}{#2}{#3}}% + \advice@init@I{#1}{#3}% + \AdviceOuterHandler +} +% +% \end{macro} +% +% +% \subsubsection{Error messages} +% +% Define error messages for the entire package. Note that +% |\advice@(de)activate@error@...| implement |try activate|. +% +\def\advice@activate@error@activated#1#2#3#4{% + \ifadvice@activate@try + \else + \PackageError{advice (#1)}{#3 "\string#2" is #4 activated}{}% + \fi +} +\def\advice@activate@error@undefined#1#2#3#4{% + \ifadvice@activate@try + \else + \PackageError{advice (#1)}{% + #3 "\string#2" you are trying to #4activate is not defined}{}% + \fi +} +\def\advice@deactivate@error@changed#1#2{% + \ifadvice@activate@try + \else + \PackageError{advice (#1)}{The definition of "\string#2" has changed since we + have activated it. Has somebody overridden our command?}{If you have tried + to deactivate so that you could immediately reactivate, you may want to try + "force activate".}% + \fi +} +\def\advice@error@advice@notcs#1#2{% + \PackageError{advice}{The first argument of key "#1" should be either a single + control sequence or an environment name, not "#2"}{}% +} +\def\advice@error@activate@notcsorenv#1#2{% + \PackageError{advice}{Each item in the value of key "#1activate" should be + either a control sequence or an environment name, not "#2".}{}% +} +\def\advice@error@storecs@notcs#1#2{% + \PackageError{advice}{The value of key "#1" should be a single control sequence, + not "\string#2"}{}% +} +\def\advice@error@noinnerhandler#1{% + \PackageError{advice (\AdviceNamespace)}{The inner handler for + "\expandafter\string\AdviceName" is not defined}{}% +} +% \subsubsection{Tracing} +% +% \begin{macro}{\AdviceTracingOn,\AdviceTracingOff} +% We implement tracing by adding the tracing information to the handlers +% after we load them. So it is the handlers themselves which, if and when +% they are executed, will print out that this is happening. +\def\AdviceTracingOn{% + \let\advice@init@i\advice@trace@init@i + \let\advice@init@I\advice@trace@init@I +} +\def\AdviceTracingOff{% + \let\advice@init@i\advice@setup@init@i + \let\advice@init@I\advice@setup@init@I +} +% \end{macro} +\def\advice@trace#1{\immediate\write16{[tracing advice] #1}} +\def\advice@trace@init@i#1#2{% + \advice@trace{Advising \detokenize\expandafter{\string#2} (\detokenize{#1})}% + \advice@setup@init@i{#1}{#2}% + \edef\AdviceRunConditions{% + % We first execute the original run conditions, so that we can show the + % result. + \expandonce\AdviceRunConditions + \noexpand\advice@trace{\space\space + Executing run conditions: + \detokenize\expandafter{\AdviceRunConditions} + --> + \noexpand\ifAdviceRun true\noexpand\else false\noexpand\fi + }% + }% + \edef\AdviceBailoutHandler{% + \noexpand\advice@trace{\space\space + Executing bailout handler: + \detokenize\expandafter{\AdviceBailoutHandler}}% + \expandonce\AdviceBailoutHandler + }% +} +\def\advice@trace@init@I#1#2{% + \advice@setup@init@I{#1}{#2}% + \edef\AdviceOuterHandler{% + \noexpand\advice@trace{\space\space + Executing outer handler: + \detokenize\expandafter{\AdviceOuterHandler}}% + \expandonce\AdviceOuterHandler + }% + \edef\AdviceCollector{% + \noexpand\advice@trace{\space\space + Executing collector: + \detokenize\expandafter{\AdviceCollector}}% + \noexpand\advice@trace{\space\space\space\space + argument specification: + \detokenize\expandafter{\AdviceArgs}}% + \noexpand\advice@trace{\space\space\space\space + options: + \detokenize\expandafter{\AdviceCollectorOptions}}% + \noexpand\advice@trace{\space\space\space\space + raw options: + \detokenize\expandafter{\AdviceRawCollectorOptions}}% + \expandonce\AdviceCollector + }% + % The tracing inner handler must grab the provided argument, if it's to show + % what it is. + \edef\advice@inner@handler@trace##1{% + \noexpand\advice@trace{\space\space + Executing inner handler: + \detokenize\expandafter{\AdviceInnerHandler}}% + \noexpand\advice@trace{\space\space\space\space + Received arguments: + \noexpand\detokenize{##1}}% + \noexpand\advice@trace{\space\space\space\space + options: + \detokenize\expandafter{\AdviceOptions}}% + \expandonce{\AdviceInnerHandler}{##1}% + }% + \def\AdviceInnerHandler{\advice@inner@handler@trace}% +} +%\resetatcatcode +%\stopmodule +%\protect +% +% +% \subsubsection{The \TikZ; collector} +% \label{sec:code:advice:tikz} +% +% In this section, we implement the argument collector for command |\tikz|, +% which has idiosyncratic syntax, see \PGFmanual{12.2.2}: +% \begin{itemize} +% \item |\tikz|\meta{animation spec}|[|\meta{options}|]{|\meta{picture code}|}| +% \item |\tikz|\meta{animation spec}|[|\meta{options}|]|\meta{picture command}|;| +% \end{itemize} +% where \meta{animation spec} = +% (|:|\meta{key}|={|\meta{value}|}|)*. +% +% The \TikZ; code resides in a special file. It is meant to be |\input| at any +% time, so we need to temporarily assign |@| category code 11. +%<*tikz> +\edef\mmzresetatcatcode{\catcode`\noexpand\@\the\catcode`\@\relax}% +\catcode`\@=11 +\def\AdviceCollectTikZArguments{% +% We initialize the token register which will hold the collected arguments, and +% start the collection. Nothing of note happens until \dots + \mmz@temptoks={}% + \mmz@tikz@anim +} +\def\mmz@tikz@anim{% + \pgfutil@ifnextchar[{\mmz@tikz@opt}{% + \pgfutil@ifnextchar:{\mmz@tikz@anim@a}{% + \mmz@tikz@code}}%] +} +\def\mmz@tikz@anim@a#1=#2{% + \toksapp\mmz@temptoks{#1={#2}}% + \mmz@tikz@anim +} +\def\mmz@tikz@opt[#1]{% + \toksapp\mmz@temptoks{[#1]}% + \mmz@tikz@code +} +\def\mmz@tikz@code{% + \pgfutil@ifnextchar\bgroup\mmz@tikz@braced\mmz@tikz@single +} +\long\def\mmz@tikz@braced#1{\toksapp\mmz@temptoks{{#1}}\mmz@tikz@done} +\def\mmz@tikz@single#1;{\toksapp\mmz@temptoks{#1;}\mmz@tikz@done} +% \dots\ we finish collecting the arguments, when we execute the inner handler, +% with the (braced) collected arguments is its sole argument. +\def\mmz@tikz@done{% + \expandafter\AdviceInnerHandler\expandafter{\the\mmz@temptoks}% +} +\mmzresetatcatcode +% +% \end{macrocode} +% +% Local Variables: +% TeX-engine: luatex +% TeX-master: "doc/memoize-code.tex" +% TeX-auto-save: nil +% End: \ No newline at end of file diff --git a/advice.ins b/advice.ins new file mode 100644 index 0000000..b1b1df6 --- /dev/null +++ b/advice.ins @@ -0,0 +1,33 @@ +%% advice.ins +%% +%% This file is a part of Advice, a TeX package implementing a generic +%% framework for extending the functionality of selected commands and +%% environments, available at https://ctan.org/pkg/advice and +%% https://github.com/sasozivanovic/advice. +%% +%% Copyright (c) 2023- Saso Zivanovic +%% (Sa\v{s}o \v{Z}ivanovi\'{c}) +%% +%% This work may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License, either version 1.3c of this license or (at +%% your option) any later version. The latest version of this license is in +%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of +%% all distributions of LaTeX version 2008 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Saso Zivanovic. +%% +%% The files belonging to this work and covered by LPPL are listed in `FILES`. +%% +\input docstrip.tex +\keepsilent +\preamble +\endpreamble +\askforoverwritefalse +\generate{% + \file{advice.sty}{\from{advice.dtx}{main,latex}}% + \file{advice.tex}{\from{advice.dtx}{main,plain}}% + \file{t-advice.tex}{\from{advice.dtx}{main,context}}% + \file{advice-tikz.code.tex}{\from{advice.dtx}{tikz}}% +} +\endbatchfile diff --git a/collargs.edtx b/collargs.edtx new file mode 100644 index 0000000..40a102c --- /dev/null +++ b/collargs.edtx @@ -0,0 +1,2938 @@ +% \iffalse +% collargs.edtx (this is not a .dtx file; to produce a .dtx, process it with edtx2dtx) +%% +%% This file is a part of CollArgs, a TeX package providing a command which can +%% determine the argument scope of any command whose argument structure +%% conforms to xparse's argument specification, available at +%% https://ctan.org/pkg/advice and https://github.com/sasozivanovic/advice. +%% +%% Copyright (c) 2023- Saso Zivanovic +%% (Sa\v{s}o \v{Z}ivanovi\'{c}) +%% +%% This work may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License, either version 1.3 of this license or (at your +%% option) any later version. The latest version of this license is in +%% http://www.latex-project.org/lppl.txt and version 1.3 or later is part of +%% all distributions of LaTeX version 2005/12/01 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Saso Zivanovic. +%% +%% The files belonging to this work and covered by LPPL are listed in +%% (/doc/generic/collargs/)FILES. +% +% \fi +% +% \begin{macrocode} +% +% Package CollArgs provides commands |\CollectArguments| and +% |\CollectArgumentsRaw|, which (what a surprise!) collect the arguments +% conforming to the given (slightly extended) |xparse| argument specification. +% The package was developed to help out with automemoization (see +% section~\ref{sec:code:automemoization}). It started out as a few lines of +% code, but had grown once I realized I want automemoization to work for +% verbatim environments as well --- the environment-collecting code is based on +% Bruno Le Floch's package |cprotect| --- and had then grown some more once I +% decided to support the |xparse| argument specification in full detail, and to +% make the verbatim mode flexible enough to deal with a variety of situations. +% +% The implementation of this package does not depend on |xparse|. Perhaps this +% is a mistake, especially as the |xparse| code is now included in the base +% \hologo{LaTeX}, but the idea was to have a light-weight package (not sure +% this is the case anymore, given all the bells and whistles), to have its +% functionality available in plain \hologo{TeX} and \hologo{ConTeXt} as well +% (same as Memoize), and, perhaps most importantly, to have the ability to +% collect the arguments verbatim. +% +% +% \paragraph{Identification} +%\ProvidesPackage{collargs}[2023/10/10 v1.0.0 Collect arguments of any command] +%%D \module[ +%%D file=t-collargs.tex, +%%D version=1.0.0, +%%D title=CollArgs, +%%D subtitle=Collect arguments of any command, +%%D author=Saso Zivanovic, +%%D date=2023-10-10, +%%D copyright=Saso Zivanovic, +%%D license=LPPL, +%%D ] +%\writestatus{loading}{ConTeXt User Module / collargs} +%\unprotect +%\startmodule[collargs] +% \paragraph{Required packages} +%\RequirePackage{pgfkeys} +%\input pgfkeys +%\input t-pgfkey +%\RequirePackage{etoolbox} +%\input etoolbox-generic +%\edef\resetatcatcode{\catcode`\noexpand\@\the\catcode`\@\relax} +%\catcode`\@11\relax +% +% \begin{macro}{\toksapp,\gtoksapp,\etoksapp,\xtoksapp} +% Our macros for appending to a token register only accept a control sequence +% defined by |\toksdef| (like |\mytoks|) but not an explicit register +% designation like |\toks0|, so we only define them if noone else did; the +% names of the macros match the \hologo{LuaTeX} primitives, so they surely +% won't be defined there. +\ifdefined\toksapp\else + \long\def\toksapp#1#2{#1\expandafter{\the#1#2}}% +\fi +\ifdefined\etoksapp\else + \long\def\etoksapp#1#2{#1\expandafter{\expanded{\the#1#2}}}% +\fi +\ifdefined\gtoksapp\else + \long\def\gtoksapp#1#2{\global#1\expandafter{\the#1#2}}% +\fi +\ifdefined\xtoksapp\else + \long\def\xtoksapp#1#2{\global#1\expandafter{\expanded{\the#1#2}}}% +\fi +\ifdefined\toks@\else\toksdef\toks@=0 \fi +% \end{macro} +% +% \begin{macro}{\CollectArguments,\CollectArgumentsRaw} +% These are the only public commands provided by the +% package. |\CollectArguments| takes three arguments: the optional |#1| is +% the option list, processed by |pgfkeys| (given the grouping structure, +% these options will apply to all arguments); the mandatory |#2| is the +% |xparse|-style argument specification; the mandatory |#3| is the ``next'' +% command (or a sequence of commands). The argument list is expected to +% start immediately after the final argument; |\CollectArguments| parses it, +% effectively figuring out its extent, and then passes the entire argument +% list to the ``next'' command (as a single argument). +% +% |\CollectArgumentsRaw| differs only in how it takes and processes the +% options. For one, these should be given as a mandatory argument. +% Furthermore, they do not take the form of a keylist, but should deploy the +% ``programmer's interface.'' |#1| should thus be a sequence of invocations +% of the macro counterparts of the keys defined in +% section~\ref{sec:code:collargs:keys}, which can be recognized as starting +% with |\collargs| followed by a capital letter, e.g.\ |\collargsCaller|. +% Note that |\collargsSet| may also be used in |#1|. (The ``optional,'' +% i.e.\ bracketed, argument of |\CollectArgumentsRaw| is in fact mandatory.) +\protected\def\CollectArguments{% + \pgf@keys@utilifnextchar[\CollectArguments@i{\CollectArgumentsRaw{}}%] +} +\def\CollectArguments@i[#1]{\CollectArgumentsRaw{\collargsSet{#1}}} +\protected\def\CollectArgumentsRaw#1#2#3{% + % This group will be closed by |\collargs@.| once we grinded through the + % argument specification. + \begingroup + % Initialize category code fixing; see section~\ref{sec:code:collargs:fix} + % for details. We have to do this before applying the settings, so that + % |\collargsFixFromNoVerbatim| et al can take effect. + \global\let\ifcollargs@last@verbatim\ifcollargs@verbatim + \global\let\ifcollargs@last@verbatimbraces\ifcollargs@verbatimbraces + \global\collargs@double@fixfalse + % Apply the settings. + \collargs@verbatim@wrap{#1}% + % Initialize the space-grabber. + \collargs@init@grabspaces + % Remember the code to execute after collection. + \def\collargs@next{#3}% + % Initialize the token register holding the collected arguments. + \global\collargs@toks{}% + % Execute the central loop macro, which expects the argument specification + % |#2| to be delimited from the following argument tokens by a dot. + \collargs@#2.% +} +% \end{macro} +% +% \begin{macro}{\collargsSet} +% This macro processes the given keys in the |/collargs| keypath. When it is +% used to process options given by the end user (the optional argument to +% |\CollectArguments|, and the options given within the argument +% specification, using the new modifier |&|), its invocation should be +% wrapped in |\collargs@verbatim@wrap| to correctly deal with the changes of +% the verbatim mode. +\def\collargsSet#1{\pgfqkeys{/collargs}{#1}} +% \end{macro} +% +% +% \subsubsection{The keys} +% \label{sec:code:collargs:keys} +% +% \begin{macro}{\collargs@cs@cases} +% If the first argument of this auxiliary macro is a single control sequence, +% then the second argument is executed. If the first argument starts with a +% control sequence but this control sequence does not form the entire +% argument, the third argument is executed. Otherwise, the fourth argument +% is executed. +% +% This macro is defined in package CollArgs because we use it in key |caller| +% below, but it is really useful in package Auto, where having it we don't +% have to bother the end-user with a separate keys for commands and +% environments, but automatically detect whether the argument of |auto| and +% (|de|)|activate| is a command or an environment. +\def\collargs@cs@cases#1{\collargs@cs@cases@i#1\collargs@cs@cases@end} +\let\collargs@cs@cases@end\relax +\def\collargs@cs@cases@i{\futurelet\collargs@temp\collargs@cs@cases@ii} +\def\collargs@cs@cases@ii#1#2\collargs@cs@cases@end{% + \ifcat\noexpand\collargs@temp\relax + \ifx\relax#2\relax + \expandafter\expandafter\expandafter\@firstofthree + \else + \expandafter\expandafter\expandafter\@secondofthree + \fi + \else + \expandafter\@thirdofthree + \fi +} +\def\@firstofthree#1#2#3{#1} +\def\@secondofthree#1#2#3{#2} +\def\@thirdofthree#1#2#3{#3} +% \end{macro} +% +% \begin{collargskey}{caller} +% \begin{macro}{\collargsCaller} +% Every macro which grabs a part of the argument list will be accessed +% through the ``caller'' control sequence, so that \hologo{TeX}'s reports +% of any errors in the argument structure can contain a command name +% familiar to the author.\footnote{The idea is borrowed from package +% |environ|, which is in turn based on code from |amsmath|.} For example, +% if the argument list ``originally'' belonged to command |\foo| with +% argument structure |r()|, but no parentheses follow in the input, we want +% \hologo{TeX} to complain that |Use of \foo doesn't match its definition|. +% This can be achieved by setting |caller=\foo|; the default is +% |caller=\CollectArguments|, which is still better than seeing an error +% involving some random internal control sequence. It is also ok to set an +% environment name as the caller, see below. +% +% The key and macro defined below store the caller control sequence into +% |\collargs@caller|, e.g.\ when we say |caller=\foo|, we effectively +% execute |\def\collargs@caller{\foo}|. +\collargsSet{ + caller/.code={\collargsCaller{#1}}, +} +\def\collargsCaller#1{% + \collargs@cs@cases{#1}{% + \let\collargs@temp\collargs@caller@cs + }{% + \let\collargs@temp\collargs@caller@csandmore + }{% + \let\collargs@temp\collargs@caller@env + }% + \collargs@temp{#1}% +} +\def\collargs@caller@cs#1{% + % If |#1| is a single control sequence, just use that as the caller. + \def\collargs@caller{#1}% +} +\def\collargs@caller@csandmore#1{% + % If |#1| starts with a control sequence, we don't complain, but convert the + % entire |#1| into a control sequence. + \begingroup + \escapechar -1 + \expandafter\endgroup + \expandafter\def\expandafter\collargs@caller\expandafter{% + \csname\string#1\endcsname + }% +} +\def\collargs@caller@env#1{% + % If |#1| does not start with a control sequence, we assume that is an + % environment name, so we prepend |start| in \hologo{ConTeXt}, and dress it + % up into |\begin{#1}| in \hologo{LaTeX}. + \expandafter\def\expandafter\collargs@caller\expandafter{% + \csname + %start% + %begin{% + #1% + %}% + \endcsname + }% +} +\collargsCaller\CollectArguments +% \end{macro} +% \end{collargskey} +% +% \begin{macro}{\ifcollargs@verbatim,\ifcollargs@verbatimbraces} +% The first of these conditional +% signals that we're collecting the arguments in one of the verbatim +% modes; the second one signals the |verb| mode in particular. +\newif\ifcollargs@verbatim +\newif\ifcollargs@verbatimbraces +% \end{macro} +% +% \begin{collargskey}{verbatim, verb, no verbatim} +% \begin{macro}{\collargs@verbatim@wrap} +% These keys set the verbatim mode macro which will be executed by +% |\collargsSet| after processing all keys. +% The verbatim mode macros |\collargsVerbatim|, |\collargsVerb| and +% |\collargsNoVerbatim| are somewhat complex; we postpone their definition +% until section~\ref{sec:code:collargs:verbatim}. Their main effect is to +% set conditionals |\ifcollargs@verbatim| and |\ifcollargs@verbatimbraces|, +% which are be inspected by the argument type handlers --- and to make +% the requested category code changes, of course. +% +% Here, note that the verbatim-selection code is not executed while the +% keylist is being processed. Rather, the verbatim keys simply set the macro +% which will be executed \emph{after} the keylist is processed, and this is +% why processing of a keylist given by the user must be always wrapped in +% |\collargs@verbatim@wrap|. +\collargsSet{ + verbatim/.code={\let\collargs@apply@verbatim\collargsVerbatim}, + verb/.code={\let\collargs@apply@verbatim\collargsVerb}, + no verbatim/.code={\let\collargs@apply@verbatim\collargsNoVerbatim}, +} +\def\collargs@verbatim@wrap#1{% + \let\collargs@apply@verbatim\relax + #1% + \collargs@apply@verbatim +} +% \end{macro} +% \end{collargskey} +% +% \begin{collargskey}{fix from verbatim, fix from verb, fix from no verbatim} +% \begin{macro}{\collargsFixFromVerbatim,\collargsFixFromVerb,\collargsFixFromNoVerbatim} +% These keys and macros should be used to request a category code fix, when +% the offending tokenization took place prior to invoking +% |\CollectArguments|; see section~\ref{sec:code:collargs:fix} for details. +% While I assume that only |\collargsFixFromNoVerbatim| will ever be used +% (and it is used by |\mmz|), we provide macros for all three transitions, +% for completeness.\indentmacrocode +\collargsSet{ + fix from verbatim/.code={\collargsFixFromVerbatim}, + fix from verb/.code={\collargsFixFromVerb}, + fix from no verbatim/.code={\collargsFixFromNoVerbatim}, +} +% \noindentmacrocode +\def\collargsFixFromNoVerbatim{% + \global\collargs@fix@requestedtrue + \global\let\ifcollargs@last@verbatim\iffalse +} +\def\collargsFixFromVerbatim{% + \global\collargs@fix@requestedtrue + \global\let\ifcollargs@last@verbatim\iftrue + \global\let\ifcollargs@last@verbatimbraces\iftrue +} +\def\collargsFixFromVerb{% + \global\collargs@fix@requestedtrue + \global\let\ifcollargs@last@verbatim\iftrue + \global\let\ifcollargs@last@verbatimbraces\iffalse +} +% \end{macro} +% \end{collargskey} +% +% \begin{collargskey}{braces} +% Set the characters which are used as the grouping characters in the full +% verbatim mode. The user is only required to do this when multiple +% character pairs serve as the grouping characters. The underlying macro, +% |\collargsBraces|, will be defined in +% section~\ref{sec:code:collargs:verbatim}. +\collargsSet{ + braces/.code={\collargsBraces{#1}}% +} +% \end{collargskey} +% +% \begin{collargskey}{environment} +% \begin{macro}{\collargsEnvironment} +% Set the environment name. +% \indentmacrocode +\collargsSet{ + environment/.estore in=\collargs@b@envname +} +\def\collargsEnvironment#1{\edef\collargs@b@envname{#1}} +\collargsEnvironment{} +% \end{macro} +% \end{collargskey} +% +% \begin{collargskey}{begin tag, end tag, tags} +% \begin{macro}{\ifcollargsBeginTag,\ifcollargsEndTag,\ifcollargsAddTags} +% When |begin tag|\slash|end tag| is in effect, the begin\slash end-tag will +% be will be prepended/appended to the environment body. |tags| is a +% shortcut for setting |begin tag| and |end tag| simultaneously. +% \indentmacrocode +\collargsSet{ + begin tag/.is if=collargsBeginTag, + end tag/.is if=collargsEndTag, + tags/.style={begin tag=#1, end tag=#1}, + tags/.default=true, +} +\newif\ifcollargsBeginTag +\newif\ifcollargsEndTag +% \end{macro} +% \end{collargskey} +% +% \begin{collargskey}{ignore nesting} +% \begin{macro}{\ifcollargsIgnoreNesting} +% When this key is in effect, we will +% ignore any \cs{begin}\marg{name}s and simply grab everything up to +% the first \cs{end}\marg{name} (again, the markers are automatically +% adapted to the format). +\collargsSet{ + ignore nesting/.is if=collargsIgnoreNesting, +} +\newif\ifcollargsIgnoreNesting +% \end{macro} +% \end{collargskey} +% +% \begin{collargskey}{ignore other tags} +% \begin{macro}{\ifcollargsIgnoreOtherTags} +% This key is only relevant in the +% non-verbatim and partial verbatim modes in \hologo{LaTeX}. When it +% is in effect, CollArgs checks the environment name following each +% |\begin| and |\end|, ignoring the tags with an environment name other +% than |\collargs@b@envname|. +\collargsSet{ + ignore other tags/.is if=collargsIgnoreOtherTags, +} +\newif\ifcollargsIgnoreOtherTags +% \end{macro} +% \end{collargskey} +% +% \begin{collargskey}[noindex]{(append/prepend) (pre/post)processor} +% \begin{macro}[noindex]{\collargs(Append/Prepend)(Pre/Post)processor} +% \begin{collargskey}[noprint]{append preprocessor, prepend preprocessor, +% append postprocessor, prepend postprocessor} +% \begin{macro}[noprint]{\collargsAppendPreprocessor,\collargsPrependPreprocessor,\collargsAppendPostprocessor,\collargsPrependPostprocessor} +% These keys and +% macros populate the list of preprocessors, +% |\collargs@preprocess@arg|, and the list of post-processors, +% |\collargs@postprocess@arg|, executed in |\collargs@appendarg|. +\collargsSet{ + append preprocessor/.code={\collargsAppendPreprocessor{#1}}, + prepend preprocessor/.code={\collargsPrependPreprocessor{#1}}, + append postprocessor/.code={\collargsAppendPostprocessor{#1}}, + prepend postprocessor/.code={\collargsPrependPostprocessor{#1}}, +} +\def\collargsAppendPreprocessor{% + \collargs@addprocessor\appto\collargs@preprocess@arg} +\def\collargsPrependPreprocessor{% + \collargs@addprocessor\preto\collargs@preprocess@arg} +\def\collargsAppendPostprocessor{% + \collargs@addprocessor\appto\collargs@postprocess@arg} +\def\collargsPrependPostprocessor{% + \collargs@addprocessor\preto\collargs@postprocess@arg} +% Here, |#1| will be either |\appto| or |\preto|, and |#2| will be either +% |\collargs@preprocess@arg| or |\collargs@postprocess@arg|. |#3| is the +% processor code. +\def\collargs@addprocessor#1#2#3{% + #1#2{% + \expanded{% + \unexpanded{#3}{\the\collargsArg}% + }% + }% +} +% \end{macro} +% \end{collargskey} +% \end{macro} +% \end{collargskey} +% +% \begin{collargskey}[noindex]{clear (pre/post)processors} +% \begin{macro}[noindex]{\collargsClear(Pre/Post)processors} +% \begin{collargskey}[noprint]{clear preprocessors, clear postprocessors} +% \begin{macro}[noprint]{\collargsClearPreprocessors,\collargsClearPostprocessors} +% These keys and macros +% clear the pre- and post-processor lists, which are initially empty as +% well. +\def\collargs@preprocess@arg{} +\def\collargs@postprocess@arg{} +\collargsSet{ + clear preprocessors/.code={\collargsClearPreprocessors}, + clear postprocessors/.code={\collargsClearPostprocessors}, +} +\def\collargsClearPreprocessors{\def\collargs@preprocess@arg{}}% +\def\collargsClearPostprocessors{\def\collargs@postprocess@arg{}}% +% \end{macro} +% \end{collargskey} +% \end{macro} +% \end{collargskey} +% +% \begin{collargskey}[noindex]{(append/prepend) expandable (pre/post)processor} +% \begin{macro}[noindex]{\collargs(Append/Prepend)Expandable(Pre/Post)processor} +% \begin{collargskey}[noprint]{append expandable preprocessor, prepend expandable preprocessor, append expandable postprocessor, prepend expandable postprocessor} +% \begin{macro}[noprint]{\collargsAppendExpandablePreprocessor,\collargsPrependExpandablePreprocessor,\collargsAppendExpandablePostprocessor,\collargsPrependExpandablePostprocessor} +% These keys +% and macros simplify the definition of fully expandable processors. Note +% that expandable processors are added to the same list as non-expandable +% processors. +\collargsSet{ + append expandable preprocessor/.code={% + \collargsAppendExpandablePreprocessor{#1}}, + prepend expandable preprocessor/.code={% + \collargsPrependExpandablePreprocessor{#1}}, + append expandable postprocessor/.code={% + \collargsAppendExpandablePostprocessor{#1}}, + prepend expandable postprocessor/.code={% + \collargsPrependExpandablePostprocessor{#1}}, +} +\def\collargsAppendExpandablePreprocessor{% + \collargs@addeprocessor\appto\collargs@preprocess@arg} +\def\collargsPrependExpandablePreprocessor{% + \collargs@addeprocessor\preto\collargs@preprocess@arg} +\def\collargsAppendExpandablePostprocessor{% + \collargs@addeprocessor\appto\collargs@postprocess@arg} +\def\collargsPrependExpandablePostprocessor{% + \collargs@addeprocessor\preto\collargs@postprocess@arg} +\def\collargs@addeprocessor#1#2#3{% + #1#2{% + \expanded{% + \edef\noexpand\collargs@temp{\unexpanded{#3}{\the\collargsArg}}% + \unexpanded{\expandafter\collargsArg\expandafter{\collargs@temp}}% + }% + }% +} +% \end{macro} +% \end{collargskey} +% \end{macro} +% \end{collargskey} +% +% \begin{collargskey}[noindex]{(append/prepend) (pre/post)wrap} +% \begin{macro}[noindex]{\collargs(Append/Prepend)(Pre/Post)wrap} +% \begin{collargskey}[noprint]{append prewrap, prepend prewrap, append postwrap, prepend postwrap} +% \begin{macro}[noprint]{\collargsAppendPrewrap,\collargsPrependPrewrap,\collargsAppendPostwrap,\collargsPrependPostwrap} +% These keys and macros +% simplify the definition of processors which yield the result after a +% single expansion. Again, they are added to the same list as other +% processors. +\collargsSet{ + append prewrap/.code={\collargsAppendPrewrap{#1}}, + prepend prewrap/.code={\collargsPrependPrewrap{#1}}, + append postwrap/.code={\collargsAppendPostwrap{#1}}, + prepend postwrap/.code={\collargsPrependPostwrap{#1}}, +} +\def\collargsAppendPrewrap{\collargs@addwrap\appto\collargs@preprocess@arg} +\def\collargsPrependPrewrap{\collargs@addwrap\preto\collargs@preprocess@arg} +\def\collargsAppendPostwrap{\collargs@addwrap\appto\collargs@postprocess@arg} +\def\collargsPrependPostwrap{\collargs@addwrap\preto\collargs@postprocess@arg} +\def\collargs@addwrap#1#2#3{% + #1#2{% + \long\def\collargs@temp##1{#3}% + \expandafter\expandafter\expandafter\collargsArg + \expandafter\expandafter\expandafter{% + \expandafter\collargs@temp\expandafter{\the\collargsArg}% + }% + }% +} +% \end{macro} +% \end{collargskey} +% \end{macro} +% \end{collargskey} +% +% +% \begin{collargskey}{no delimiters} +% \begin{macro}{\ifcollargsNoDelimiters} +% When this conditional is in effect, the +% delimiter wrappers set by |\collargs@wrap| are ignored by +% |\collargs@appendarg|. +\collargsSet{% + no delimiters/.is if=collargsNoDelimiters, +} +\newif\ifcollargsNoDelimiters +% \end{macro} +% \end{collargskey} +% +% \subsubsection{The central loop} +% \label{sec:code:collargs:central-loop} +% +% The central loop is where we grab the next \meta{token} from the argument +% specification and execute the corresponding argument type or modifier +% handler, |\collargs@|\meta{token}. The central loop consumes the argument +% type \meta{token}; the handler will see the remainder of the argument +% specification (which starts with the arguments to the argument type, if any, +% e.g.\ by |()| of |d()|), followed by a dot, and then the tokens list from +% which the arguments are to be collected. It is the responsibility of handler +% to preserve the rest of the argument specification and reexecute the central +% loop once it is finished. +% +% \begin{macro}{\collargs@} +% Each argument is processed in a group to allow for local settings. This +% group is closed by |\collargs@appendarg|. +\def\collargs@{% + \begingroup + \collargs@@@ +} +% \end{macro} +% +% \begin{macro}{\collargs@@@} +% This macro is where modifier handlers reenter the central loop --- we don't +% want modifers to open a group, because their settings should remain in +% effect until the next argument. Furthermore, modifiers do not trigger +% category code fixes. +\def\collargs@@@#1{% + \collargs@in@{#1}{&+!>.}% + \ifcollargs@in@ + \expandafter\collargs@@@iii + \else + \expandafter\collargs@@@i + \fi + #1% +} +\def\collargs@@@i#1.{% + % Fix the category code of the next argument token, if necessary, and then + % proceed with the main loop. + \collargs@fix{\collargs@@@ii#1.}% +} +% Reset the fix request and set the last verbatim conditionals to the current +% state. +\def\collargs@@@ii{% + \global\collargs@fix@requestedfalse + \global\let\ifcollargs@last@verbatim\ifcollargs@verbatim + \global\let\ifcollargs@last@verbatimbraces\ifcollargs@verbatimbraces + \collargs@@@iii +} +% Call the modifier or argument type handler denoted by the first token of the +% remainder of the argument specification. +\def\collargs@@@iii#1{% + \ifcsname collargs@#1\endcsname + \csname collargs@#1\expandafter\endcsname + \else + % We throw an error if the token refers to no argument type or modifier. + \collargs@error@badtype{#1}% + \fi +} +% Throwing an error stops the processing of the argument specification, and +% closes the group opened in |\collargs@i|. +\def\collargs@error@badtype#1#2.{% + \PackageError{collargs}{Unknown xparse argument type or modifier "#1" + for "\expandafter\string\collargs@caller\space"}{}% + \endgroup +} +% \end{macro} +% +% {\catcode`\&=11 +% \begin{macro}{\collargs@&} +% We extend the |xparse| syntax with modifier |&|, which applies the given +% options to the following (and only the following) argument. If |&| is +% followed by another |&|, the options are expected to occur in the raw +% format, like the options given to |\CollectArgumentsRaw|. Otherwise, the +% options should take the form of a keylist, which will be processed by +% |\collargsSet|. In any case, the options should be given within the +% argument specification, immediately following the (single or double) |&|. +\csdef{collargs@&}{% + \futurelet\collargs@temp\collargs@amp@i +} +\def\collargs@amp@i{% + % In \hologo{ConTeXt}, |&| has character code ``other'' in the text. + %\ifx\collargs@temp&% + %\expandafter\ifx\detokenize{&}\collargs@temp + \expandafter\collargs@amp@raw + \else + \expandafter\collargs@amp@set + \fi +} +\def\collargs@amp@raw#1#2{% + \collargs@verbatim@wrap{#2}% + \collargs@@@ +} +\def\collargs@amp@set#1{% + \collargs@verbatim@wrap{\collargsSet{#1}}% + \collargs@@@ +} +% \end{macro}} +% +% \begin{macro}[noindex]{\collargs@+} +% \MyIndex{collargs@+}{\texttt{\textbackslash collargs@+}}{main} +% This modifier makes the next argument long, i.e.\ accept paragraph tokens. +\csdef{collargs@+}{% + \collargs@longtrue + \collargs@@@ +} +\newif\ifcollargs@long +% \end{macro} +% +% \begin{macro}{\collargs@>} +% We can simply ignore the processor modifier. (This, |xparse|'s processor, +% should not be confused with CollArgs's processors, which are set using +% keys |append preprocessor| etc.) +\csdef{collargs@>}#1{\collargs@@@} +% \end{macro} +% +% \begin{macro}[noindex]{\collargs@!} +% \MyIndex{collargs@!}{\texttt{\textbackslash collargs@\exclamationmark}}{main} +% Should we accept spaces before an optional argument following a mandatory +% argument (\pkg{xparse} manual, \S1.1)? By default, yes. This modifier is +% only applicable to types |d| and |t|, and derived types, but, unlike +% |xparse|, we don't bother to enforce this; when used with other types, |!| +% simply has no effect. +\csdef{collargs@!}{% + \collargs@grabspacesfalse + \collargs@@@ +} +% \end{macro} +% +% \begin{macro}{\collargs@toks} +% This token register is where we store the collected argument tokens. All +% assignments to this register are global, because it needs to survive the +% groups opened for individual arguments. +\newtoks\collargs@toks +% \end{macro} +% +% \begin{macro}{\collargsArg} +% An auxiliary, but publicly available token register, used for processing +% the argument, and by some argument type handlers. +\newtoks\collargsArg +% \end{macro} +% +% \begin{macro}{\collargs@.} +% This fake argument type is used to signal the end of the argument list. +% Note that this really counts as an extension of the |xparse| argument +% specification. +\csdef{collargs@.}{% + % Close the group opened in |\collargs@|. + \endgroup + % Close the main |\CollectArguments| group, fix the category code of the next + % token if necessary, and execute the next-code, followed by the collected + % arguments in braces. Any over-grabbed spaces are reinserted into the input + % stream, non-verbatim. + \expanded{% + \endgroup + \noexpand\collargs@fix{% + \expandonce\collargs@next{\the\collargs@toks}% + \collargs@spaces + }% + }% +} +% \end{macro} +% +% \subsubsection{Auxiliary macros} +% \label{sec:code:collargs:aux} +% +% \begin{macro}{\collargs@appendarg} +% This macro is used by the argument type +% handlers to append the collected argument to the storage +% (|\collargs@toks|). +\long\def\collargs@appendarg#1{% + % Temporarily store the collected argument into a token register. The + % processors will manipulate the contents of this register. + \collargsArg={#1}% + % This will clear the double-fix conditional, and potentially request a + % normal, single fix. We can do this here because this macro is only called + % when something is actually collected. For details, see + % section~\ref{sec:code:collargs:fix}. + \ifcollargs@double@fix + \collargs@cancel@double@fix + \fi + % Process the argument with user-definable preprocessors, the wrapper defined + % by the argument type, and user-definable postprocessors. + \collargs@preprocess@arg + \ifcollargsNoDelimiters + \else + \collargs@process@arg + \fi + \collargs@postprocess@arg + % Append the processed argument, preceded by any grabbed spaces (in the + % correct mode), to the storage. + \xtoksapp\collargs@toks{\collargs@grabbed@spaces\the\collargsArg}% + % Initialize the space-grabber. + \collargs@init@grabspaces + % Once the argument was appended to the list, we can close its group, opened + % by |\collargs@|. + \endgroup +} +% \end{macro} +% +% \begin{macro}{\collargs@wrap} +% This macro is used by argument type handlers to declare their delimiter +% wrap, like square brackets around the optional argument of type |o|. It +% uses |\collargs@addwrap|, defined in section~\ref{sec:code:collargs:keys}, +% but adds to |\collargs@process@arg|, which holds the delimiter wrapper +% defined by the argument type handler. Note that this macro \emph{appends} +% a wrapper, so multiple wrappers are allowed --- this is used by type |e| +% handler. +\def\collargs@wrap{\collargs@addwrap\appto\collargs@process@arg} +\def\collargs@process@arg{} +% \end{macro} +% +% \begin{macro}{\collargs@defcollector,\collargs@defusecollector,\collargs@letusecollector} +% These macros streamline the usage of +% the ``caller'' control sequence. They are like a |\def|, but should not +% be given the control sequence to define, as they will automatically +% define the control sequence residing in |\collargs@caller|; the usage is +% thus |\collargs@defcollector{}|. For example, if +% |\collargs@caller| holds |\foo|, |\collargs@defcollector#1{(#1)}| is +% equivalent to |\def\foo#1{(#1)}|. Macro |\collargs@defcollector| will +% only define the caller control sequence to be the collector, while +% |\collargs@defusecollector| will also immediately execute it. +\def\collargs@defcollector#1#{% + \ifcollargs@long\long\fi + \expandafter\def\collargs@caller#1% +} +\def\collargs@defusecollector#1#{% + \afterassignment\collargs@caller + \ifcollargs@long\long\fi + \expandafter\def\collargs@caller#1% +} +\def\collargs@letusecollector#1{% + \expandafter\let\collargs@caller#1% + \collargs@caller +} +\newif\ifcollargs@grabspaces +\collargs@grabspacestrue +% \end{macro} +% +% \begin{macro}{\collargs@init@grabspaces} +% The space-grabber macro +% |\collargs@grabspaces| should be initialized by executing this macro. If +% |\collargs@grabspaces| is called twice without an intermediate +% initialization, it will assume it is in the same position in the input +% stream and simply bail out. +\def\collargs@init@grabspaces{% + \gdef\collargs@gs@state{0}% + \gdef\collargs@spaces{}% + \gdef\collargs@otherspaces{}% +} +% \end{macro} +% +% \begin{macro}{\collargs@grabspaces} +% This auxiliary macro grabs any following +% spaces, and then executes the next-code given as the sole argument. The +% spaces will be stored into two macros, |\collargs@spaces| and +% |\collargs@otherspaces|, which store the spaces in the non-verbatim and the +% verbatim form. With the double storage, we can grab the spaces in the +% verbatim mode and use them non-verbatim, or vice versa. The macro takes a +% single argument, the code to execute after maybe grabbing the spaces. +% +\def\collargs@grabspaces#1{% + \edef\collargs@gs@next{\unexpanded{#1}}% + \ifnum\collargs@gs@state=0 + \gdef\collargs@gs@state{1}% + \expandafter\collargs@gs@i + \else + \expandafter\collargs@gs@next + \fi +} +\def\collargs@gs@i{% + \futurelet\collargs@temp\collargs@gs@g +} +% We check for grouping characters even in the verbatim mode, because we might +% be in the partial verbatim. +\def\collargs@gs@g{% + \ifcat\noexpand\collargs@temp\bgroup + \expandafter\collargs@gs@next + \else + \ifcat\noexpand\collargs@temp\egroup + \expandafter\expandafter\expandafter\collargs@gs@next + \else + \expandafter\expandafter\expandafter\collargs@gs@ii + \fi + \fi +} +\def\collargs@gs@ii{% + \ifcollargs@verbatim + \expandafter\collargs@gos@iii + \else + \expandafter\collargs@gs@iii + \fi +} +% This works because the character code of a space token is always 32. +\def\collargs@gs@iii{% + \expandafter\ifx\space\collargs@temp + \expandafter\collargs@gs@iv + \else + \expandafter\collargs@gs@next + \fi +} +\expandafter\def\expandafter\collargs@gs@iv\space{% + \gappto\collargs@spaces{ }% + \xappto\collargs@otherspaces{\collargs@otherspace}% + \collargs@gs@i +} +% We need the space of category 12 above. +\begingroup\catcode`\ =12\relax\gdef\collargs@otherspace{ }\endgroup +\def\collargs@gos@iii#1{% + % Macro |\collargs@cc| recalls the ``outside'' category code of character + % |#1|; see section~\ref{sec:code:collargs:verbatim}. + \ifnum\collargs@cc{#1}=10 + % We have a space. + \expandafter\collargs@gos@iv + \else + \ifnum\collargs@cc{#1}=5 + % We have a newline. + \expandafter\expandafter\expandafter\collargs@gos@v + \else + \expandafter\expandafter\expandafter\collargs@gs@next + \fi + \fi + #1% +} +\def\collargs@gos@iv#1{% + \gappto\collargs@otherspaces{#1}% + % No matter how many verbatim spaces we collect, they equal a single + % non-verbatim space. + \gdef\collargs@spaces{ }% + \collargs@gs@i +} +\def\collargs@gos@v{% + % Only add the first newline. + \ifnum\collargs@gs@state=2 + \expandafter\collargs@gs@next + \else + \expandafter\collargs@gs@vi + \fi +} +\def\collargs@gs@vi#1{% + \gdef\collargs@gs@state{2}% + \gappto\collargs@otherspaces{#1}% + \gdef\collargs@spaces{ }% + \collargs@gs@i +} +% \end{macro} +% +% \begin{macro}{\collargs@maybegrabspaces} +% This macro grabs any following spaces, but it will do so only when +% conditional |\ifcollargs@grabspaces|, which can be \emph{un}set by modifier +% |!|, is in effect. The macro is used by handlers for types |d| and |t|. +\def\collargs@maybegrabspaces{% + \ifcollargs@grabspaces + \expandafter\collargs@grabspaces + \else + \expandafter\@firstofone + \fi +} +% \end{macro} +% +% \begin{macro}{\collargs@grabbed@spaces} +% This macro expands to either the verbatim +% or the non-verbatim variant of the grabbed spaces, depending on the +% verbatim mode in effect at the time of expansion. +\def\collargs@grabbed@spaces{% + \ifcollargs@verbatim + \collargs@otherspaces + \else + \collargs@spaces + \fi +} +% \end{macro} +% +% \begin{macro}{\collargs@reinsert@spaces} +% Inserts the grabbed spaces back into the +% input stream, but with the category code appropriate for the verbatim mode +% then in effect. After the insertion, the space-grabber is initialized and +% the given next-code is executed in front of the inserted spaces. +\def\collargs@reinsert@spaces#1{% + \expanded{% + \unexpanded{% + \collargs@init@grabspaces + #1% + }% + \collargs@grabbed@spaces + }% +} +% \end{macro} +% +% \begin{macro}{\collargs@ifnextcat} +% An adaptation of |\pgf@keys@utilifnextchar| +% which checks whether the \emph{category} code of the next non-space +% character matches the category code of |#1|. +\long\def\collargs@ifnextcat#1#2#3{% + \let\pgf@keys@utilreserved@d=#1% + \def\pgf@keys@utilreserved@a{#2}% + \def\pgf@keys@utilreserved@b{#3}% + \futurelet\pgf@keys@utillet@token\collargs@ifncat} +\def\collargs@ifncat{% + \ifx\pgf@keys@utillet@token\pgf@keys@utilsptoken + \let\pgf@keys@utilreserved@c\collargsxifnch + \else + \ifcat\noexpand\pgf@keys@utillet@token\pgf@keys@utilreserved@d + \let\pgf@keys@utilreserved@c\pgf@keys@utilreserved@a + \else + \let\pgf@keys@utilreserved@c\pgf@keys@utilreserved@b + \fi + \fi + \pgf@keys@utilreserved@c} +{% + \def\:{\collargs@xifncat} + \expandafter\gdef\: {\futurelet\pgf@keys@utillet@token\collargs@ifncat} +} +% \end{macro} +% +% \begin{macro}{\collargs@forrange} +% This macro executes macro |\collargs@do| for every integer from |#1| and +% |#2|, both inclusive. |\collargs@do| should take a single parameter, the +% current number. +\def\collargs@forrange#1#2{% + \expanded{% + \noexpand\collargs@forrange@i{\number#1}{\number#2}% + }% + } +\def\collargs@forrange@i#1#2{% + \ifnum#1>#2 % + \expandafter\@gobble + \else + \expandafter\@firstofone + \fi + {% + \collargs@do{#1}% + \expandafter\collargs@forrange@i\expandafter{\number\numexpr#1+1\relax}{#2}% + }% +} +% \end{macro} +% +% \begin{macro}{\collargs@forranges} +% This macro executes macro |\collargs@do| for every integer falling into the +% ranges specified in |#1|. The ranges should be given as a comma-separated +% list of |from-to| items, e.g.\ |1-5,10-11|. +\def\collargs@forranges{\forcsvlist\collarg@forrange@i} +\def\collarg@forrange@i#1{\collarg@forrange@ii#1-} +\def\collarg@forrange@ii#1-#2-{\collargs@forrange{#1}{#2}} +% \end{macro} +% +% \begin{macro}{\collargs@percentchar} +% This macro holds the percent character of category 12. +\begingroup +\catcode`\%=12 +\gdef\collargs@percentchar{%} +\endgroup +% \end{macro} +% +% +% \subsubsection{The handlers} +% \label{sec:code:collargs:handlers} +% +% \begin{macro}{\collargs@l} +% We will first define the handler for the very funky argument type |l|, +% which corresponds to \hologo{TeX}'s |\def\foo#1#{...}|, which grabs (into +% |#1|) everything up to the first opening brace --- not because this type is +% important or even recommended to use, but because the definition of the +% handler is very simple, at least for the non-verbatim case. +% +\def\collargs@l#1.{% + % Any pre-grabbed spaces in fact belong into the argument. + \collargs@reinsert@spaces{\collargs@l@i#1.}% +} +\def\collargs@l@i{% + % We request a correction of the category code of the delimiting brace if the + % verbatim mode changes for the next argument; for details, see + % section~\ref{sec:code:collargs:fix}. + \global\collargs@fix@requestedtrue + % Most handlers will branch into the verbatim and the non-verbatim part using + % conditional |\ifcollargs@verbatim|. This handler is a bit special, because + % it needs to distinguish verbatim and non-verbatim \emph{braces}, and + % braces are verbatim only in the full verbatim mode, i.e.\ when + % |\ifcollargs@verbatimbraces| is true. + \ifcollargs@verbatimbraces + \expandafter\collargs@l@verb + \else + \expandafter\collargs@l@ii + \fi +} +% We grab the rest of the argument specification (|#1|), to be reinserted into +% the token stream when we reexecute the central loop. +\def\collargs@l@ii#1.{% + % In the non-verbatim mode, we merely have to define and execute the + % collector macro. The parameter text |##1##| (note the doubled hashes), + % which will put everything up to the first opening brace into the first + % argument, looks funky, but that's all. + \collargs@defusecollector##1##{% + % We append the collected argument, |##1|, to |\collargs@toks|, the token + % register holding the collected argument tokens. + \collargs@appendarg{##1}% + % Back to the central loop, with the rest of the argument specification + % reinserted. + \collargs@#1.% + }% +} +\def\collargs@l@verb#1.{% + % In the verbatim branch, we need to grab everything up to the first opening + % brace of category code 12, so we want to define the collector with + % parameter text |##1{|, with the opening brace of category 12. We have + % stored this token in macro |\collargs@other@bgroup|, which we now need to + % expand. + \expandafter\collargs@defusecollector + \expandafter##\expandafter1\collargs@other@bgroup{% + % Appending the argument works the same as in the non-verbatim case. + \collargs@appendarg{##1}% + % Reexecuting the central loop macro is a bit more involved, as we need to + % reinsert the verbatim opening brace (contrary to the regular brace above, + % the verbatim brace is consumed by the collector macro) back into the + % token stream, behind the reinserted argument specification. + \expanded{% + \noexpand\collargs@\unexpanded{#1.}% + \collargs@other@bgroup + }% + }% +} +% \end{macro} +% +% \begin{macro}{\collargs@u} +% Another weird type --- |u|\meta{tokens} reads everything up to the given +% \meta{tokens}, i.e.\ this is \hologo{TeX}'s +% |\def\foo#1|\meta{tokens}|{...}| --- but again, simple enough to allow us +% to showcase solutions to two recurring problems. +% +% We start by branching into the verbatim mode (full or partial) or the +% non-verbatim mode. +\def\collargs@u{% + \ifcollargs@verbatim + \expandafter\collargs@u@verb + \else + \expandafter\collargs@u@i + \fi +} +% To deal with the verbatim mode, we only need to convert the above +% \meta{tokens} (i.e.\ the argument of |u| in the argument specification) to +% category 12, i.e.\ we have to |\detokenize| them. Then, we may proceed as in +% the non-verbatim branch, |\collargs@u@ii|. +\def\collargs@u@verb#1{% + % The |\string| here is a temporary solution to a problem with spaces. Our + % verbatim mode has them of category ``other'', but |\detokenize| produces a + % space of category ``space'' behind control words. ^^A todo + \expandafter\collargs@u@i\expandafter{\detokenize\expandafter{\string#1}}% +} +% We then reinsert any pre-grabbed spaces into the stream, but we take care not +% to destroy the braces around our delimiter in the argument specification. +\def\collargs@u@i#1#2.{% + \collargs@reinsert@spaces{\collargs@u@ii{#1}#2.}% +} +\def\collargs@u@ii#1#2.{% + % |#1| contains the delimiter tokens, so |##1| below will receive everything + % in the token stream up to these. But we have a problem: if we defined the + % collector as for the non-verbatim |l|, and the delimiter happened to be + % preceded by a single brace group, we would lose the braces. For example, + % if the delimiter was |-| and we received |{foo}-|, we would collect |foo-|. + % We solve this problem by inserting |\collargs@empty| (with an empty + % definition) into the input stream (at the end of this macro) --- this way, + % the delimiter can never be preceded by a single brace group --- and then + % expanding it away before appending to storage (within the argument of + % |\collargs@defusecollector|). + \collargs@defusecollector##1#1{% + % Define the wrapper which will add the delimiter tokens (|#1|) after the + % collected argument. The wrapper will be applied during argument + % processing in |\collargs@appendarg| (sandwiched between used-definable + % pre- and post-processors). + \collargs@wrap{####1#1}% + % Expand the first token in |##1|, which we know to be |\collargs@empty|, + % with empty expansion. + \expandafter\collargs@appendarg\expandafter{##1}% + \collargs@#2.% + }% + % Insert |\collargs@empty| into the input stream, in front of the ``real'' + % argument tokens. + \collargs@empty +} +\def\collargs@empty{} +% \end{macro} +% +% \begin{macro}{\collargs@r} +% Finally, a real argument type: required delimited argument. +\def\collargs@r{% + \ifcollargs@verbatim + \expandafter\collargs@r@verb + \else + \expandafter\collargs@r@i + \fi +} +\def\collargs@r@verb#1#2{% + \expandafter\collargs@r@i\detokenize{#1#2}% +} +\def\collargs@r@i#1#2#3.{% + % We will need to use the |\collargs@empty| trick from type |u|, but with an + % additional twist: we need to insert it \emph{after} the opening delimiter + % |#1|. To do this, we consume the opening delimiter by the ``outer'' + % collector below --- we need to use the collector so that we get a nice + % error message when the opening delimiter is not present --- and have this + % collector define the ``inner'' collector in the spirit of type |u|. + % + % The outer collector has no parameters, it just requires the presence of the + % opening delimiter. + \collargs@defcollector#1{% + % The inner collector will grab everything up to the closing delimiter. + \collargs@defusecollector####1#2{% + % Append the collected argument |####1| to the list, wrapping it into the + % delimiters (|#1| and |#2|), but not before expanding its first token, + % which we know to be |\collargs@empty|. + \collargs@wrap{#1########1#2}% + \expandafter\collargs@appendarg\expandafter{####1}% + \collargs@#3.% + }% + \collargs@empty + }% + % Another complication: our delimited argument may be preceded by spaces. To + % replicate the argument tokens faithfully, we need to collect them before + % trying to grab the argument itself. + \collargs@grabspaces\collargs@caller +} +% \end{macro} +% +% \begin{macro}{\collargs@R} +% Discard the default and execute |r|. +\def\collargs@R#1#2#3{\collargs@r#1#2} +% \end{macro} +% +% \begin{macro}{\collargs@d} +% Optional delimited argument. Very similar to |r|. +\def\collargs@d{% + \ifcollargs@verbatim + \expandafter\collargs@d@verb + \else + \expandafter\collargs@d@i + \fi +} +\def\collargs@d@verb#1#2{% + \expandafter\collargs@d@i\detokenize{#1#2}% +} +\def\collargs@d@i#1#2#3.{% + % This macro will be executed when the optional argument is not present. It + % simply closes the argument's group and reexecutes the central loop. + \def\collargs@d@noopt{% + \global\collargs@fix@requestedtrue + \endgroup + \collargs@#3.% + }% + % The collector(s) are exactly as for |r|. + \collargs@defcollector#1{% + \collargs@defusecollector####1#2{% + \collargs@wrap{#1########1#2}% + \expandafter\collargs@appendarg\expandafter{####1}% + \collargs@#3.% + }% + \collargs@empty + }% + % This macro will check, in conjunction with |\futurelet| below, whether the + % optional argument is present or not. + \def\collargs@d@ii{% + \ifx#1\collargs@temp + \expandafter\collargs@caller + \else + \expandafter\collargs@d@noopt + \fi + }% + % Whether spaces are allowed in front of this type of argument depends on the + % presence of modifier |!|. + \collargs@maybegrabspaces{\futurelet\collargs@temp\collargs@d@ii}% +} +% \end{macro} +% +% \begin{macro}{\collargs@D} +% Discard the default and execute |d|. +\def\collargs@D#1#2#3{\collargs@d#1#2} +% \end{macro} +% +% \begin{macro}{\collargs@o} +% |o| is just |d| with delimiters |[| and |]|. +\def\collargs@o{\collargs@d[]} +% \end{macro} +% +% \begin{macro}{\collargs@O} +% |O| is just |d| with delimiters |[| and |]| and the discarded default. +\def\collargs@O#1{\collargs@d[]} +% \end{macro} +% +% \begin{macro}{\collargs@t} +% An optional token. Similar to |d|. +\def\collargs@t{% + \ifcollargs@verbatim + \expandafter\collargs@t@verb + \else + \expandafter\collargs@t@i + \fi +} +\def\collargs@t@space{ } +\def\collargs@t@verb#1{% + \let\collargs@t@space\collargs@otherspace + \expandafter\collargs@t@i\expandafter{\detokenize{#1}}% +} +\def\collargs@t@i#1{% + \expandafter\ifx\space#1% + \expandafter\collargs@t@s + \else + \expandafter\collargs@t@I\expandafter#1% + \fi +} +\def\collargs@t@s#1.{% + \collargs@grabspaces{% + \ifcollargs@grabspaces + \collargs@appendarg{}% + \else + \expanded{% + \noexpand\collargs@init@grabspaces + \noexpand\collargs@appendarg{\collargs@grabbed@spaces}% + }% + \fi + \collargs@#1.% + }% +} +\def\collargs@t@I#1#2.{% + \def\collargs@t@noopt{% + \global\collargs@fix@requestedtrue + \endgroup + \collargs@#2.% + }% + \def\collargs@t@opt##1{% + \collargs@appendarg{#1}% + \collargs@#2.% + }% + \def\collargs@t@ii{% + \ifx#1\collargs@temp + \expandafter\collargs@t@opt + \else + \expandafter\collargs@t@noopt + \fi + }% + \collargs@maybegrabspaces{\futurelet\collargs@temp\collargs@t@ii}% +} +\def\collargs@t@opt@space{% + \expanded{\noexpand\collargs@t@opt{\space}\expandafter}\romannumeral-0% +}% +% \end{macro} +% +% \begin{macro}{\collargs@s} +% The optional star is just a special case of |t|. +\def\collargs@s{\collargs@t*} +% \end{macro} +% +% \begin{macro}{\collargs@m} +% Mandatory argument. Interestingly, here's where things get complicated, +% because we have to take care of several \hologo{TeX} quirks. +\def\collargs@m{% + \ifcollargs@verbatim + \expandafter\collargs@m@verb + \else + \expandafter\collargs@m@i + \fi +} +% The non-verbatim mode. First, collect any spaces in front of the argument. +\def\collargs@m@i#1.{% + \collargs@grabspaces{\collargs@m@checkforgroup#1.}% +} +% Is the argument in braces or not? +\def\collargs@m@checkforgroup#1.{% + \edef\collargs@action{\unexpanded{\collargs@m@checkforgroup@i#1.}}% + \futurelet\collargs@token\collargs@action +} +\def\collargs@m@checkforgroup@i{% + \ifcat\noexpand\collargs@token\bgroup + \expandafter\collargs@m@group + \else + \expandafter\collargs@m@token + \fi +} +% The argument is given in braces, so we put them back around it +% (|\collargs@wrap|) when appending to the storage. +\def\collargs@m@group#1.{% + \collargs@defusecollector##1{% + \collargs@wrap{{####1}}% + \collargs@appendarg{##1}% + \collargs@#1.% + }% +} +% The argument is a single token, we append it to the storage as is. +\def\collargs@m@token#1.{% + \collargs@defusecollector##1{% + \collargs@appendarg{##1}% + \collargs@#1.% + }% +} +% The verbatim mode. Again, we first collect any spaces in front of the +% argument. +\def\collargs@m@verb#1.{% + \collargs@grabspaces{\collargs@m@verb@checkforgroup#1.}% +} +% We want to check whether we're dealing with a braced argument. We're in the +% verbatim mode, but are braces verbatim as well? In other words, are we in +% |verbatim| or |verb| mode? In the latter case, braces are regular, so we +% redirect to the regular mode. +\def\collargs@m@verb@checkforgroup{% + \ifcollargs@verbatimbraces + \expandafter\collargs@m@verb@checkforgroup@i + \else + \expandafter\collargs@m@checkforgroup + \fi +} +% Is the argument in verbatim braces? +\def\collargs@m@verb@checkforgroup@i#1.{% + \def\collargs@m@verb@checkforgroup@ii{\collargs@m@verb@checkforgroup@iii#1.}% + \futurelet\collargs@temp\collargs@m@verb@checkforgroup@ii +} +\def\collargs@m@verb@checkforgroup@iii#1.{% + \expandafter\ifx\collargs@other@bgroup\collargs@temp + % Yes, the argument is in (verbatim) braces. + \expandafter\collargs@m@verb@group + \else + % We need to manually check whether the following token is a (verbatim) + % closing brace, and throw an error if it is. + \expandafter\ifx\collargs@other@egroup\collargs@temp + \expandafter\expandafter\expandafter\collargs@m@verb@egrouperror + \else + % The argument is a single token. + \expandafter\expandafter\expandafter\collargs@m@v@token + \fi + \fi + #1.% +} +\def\collargs@m@verb@egrouperror#1.{% + \PackageError{collargs}{% + Argument of \expandafter\string\collargs@caller\space has an extra + \iffalse{\else\string}}{}% +} +% A single-token verbatim argument. +\def\collargs@m@v@token#1.#2{% + % Is it a control sequence? (Macro |\collargs@cc| recalls the ``outside'' + % category code of character |#1|; see + % section~\ref{sec:code:collargs:verbatim}.) + \ifnum\collargs@cc{#2}=0 + \expandafter\collargs@m@v@token@cs + \else + \expandafter\collargs@m@token + \fi + #1.#2% +} +% Is it a one-character control sequence? +\def\collargs@m@v@token@cs#1.#2#3{% + \ifnum\collargs@cc{#3}=11 + \expandafter\collargs@m@v@token@cs@letter + \else + \expandafter\collargs@m@v@token@cs@nonletter + \fi + #1.#2#3% +} +% Store |\|. +\def\collargs@m@v@token@cs@nonletter#1.#2#3{% + \collargs@appendarg{#2#3}% + \collargs@#1.% +} +% Store |\| to a temporary register, we'll parse the control sequence name now. +\def\collargs@m@v@token@cs@letter#1.#2{% + \collargsArg{#2}% + \def\collargs@tempa{#1}% + \collargs@m@v@token@cs@letter@i +} +% Append a letter to the control sequence. +\def\collargs@m@v@token@cs@letter@i#1{% + \ifnum\collargs@cc{#1}=11 + \toksapp\collargsArg{#1}% + \expandafter\collargs@m@v@token@cs@letter@i + \else + % Finish, returning the non-letter to the input stream. + \expandafter\collargs@m@v@token@cs@letter@ii\expandafter#1% + \fi +} +% Store the verbatim control sequence. +\def\collargs@m@v@token@cs@letter@ii{% + \expanded{% + \unexpanded{% + \expandafter\collargs@appendarg\expandafter{\the\collargsArg}% + }% + \noexpand\collargs@\expandonce\collargs@tempa.% + }% +} +% The verbatim mandatory argument is delimited by verbatim braces. We have to +% use the heavy machinery adapted from |cprotect|. +\def\collargs@m@verb@group#1.#2{% + \let\collargs@begintag\collargs@other@bgroup + \let\collargs@endtag\collargs@other@egroup + \def\collargs@tagarg{}% + \def\collargs@commandatend{\collargs@m@verb@group@i#1.}% + \collargs@readContent +} +% This macro appends the result given by the heavy machinery, waiting for us in +% macro |\collargsArg|, to |\collargs@toks|, but not before dressing +% it up (via |\collargs@wrap|) in a pair of verbatim braces. +\def\collargs@m@verb@group@i{% + \edef\collargs@temp{% + \collargs@other@bgroup\unexpanded{##1}\collargs@other@egroup}% + \expandafter\collargs@wrap\expandafter{\collargs@temp}% + \expandafter\collargs@appendarg\expandafter{\the\collargsArg}% + \collargs@ +} +% \end{macro} +% +% \begin{macro}{\collargs@g} +% An optional group: same as |m|, but we simply bail out if we don't find the +% group character. +\def\collargs@g{% + \def\collargs@m@token{% + \global\collargs@fix@requestedtrue + \endgroup + \collargs@ + }% + \let\collargs@m@v@token\collargs@m@token + \collargs@m +} +% \end{macro} +% +% \begin{macro}{\collargs@G} +% Discard the default and execute |g|. +\def\collargs@G#1{\collargs@g} +% \end{macro} +% +% \begin{macro}{\collargs@v} +% Verbatim argument. The code is executed in the group, deploying +% |\collargsVerbatim|. The grouping characters are always set to braces, to +% mimick |xparse| perfectly. +\def\collargs@v#1.{% + \begingroup + \collargsBraces{{}}% + \collargsVerbatim + \collargs@grabspaces{\collargs@v@i#1.}% +} +\def\collargs@v@i#1.#2{% + \expandafter\ifx\collargs@other@bgroup#2% + % If the first token we see is an opening brace, use the |cprotect| + % adaptation to grab the group. + \let\collargs@begintag\collargs@other@bgroup + \let\collargs@endtag\collargs@other@egroup + \def\collargs@tagarg{}% + \def\collargs@commandatend{% + \edef\collargs@temp{% + \collargs@other@bgroup\unexpanded{####1}\collargs@other@egroup}% + \expandafter\collargs@wrap\expandafter{\collargs@temp}% + \expandafter\collargs@appendarg\expandafter{\the\collargsArg}% + \endgroup + \collargs@#1.% + }% + \expandafter\collargs@readContent + \else + % Otherwise, the verbatim argument is delimited by two identical characters + % (|#2|). + \collargs@defcollector##1#2{% + \collargs@wrap{#2####1#2}% + \collargs@appendarg{##1}% + \endgroup + \collargs@#1.% + }% + \expandafter\collargs@caller + \fi +} +% \end{macro} +% +% \begin{macro}{\collargs@b} +% Environments. Here's where all hell breaks loose. We survive by adapting +% some code from Bruno Le Floch's |cprotect|. We first define the +% environment-related keys, then provide the handler code, and finish with +% the adaptation of |cprotect|'s environment-grabbing code. +% +% The argument type |b| token may be followed by a braced environment name +% (in the argument specification). +\def\collargs@b{% + \collargs@ifnextcat\bgroup\collargs@bg\collargs@bi +} +\def\collargs@bg#1{% + \edef\collargs@b@envname{#1}% + \collargs@bi +} +\def\collargs@bi#1.{% + % Convert the environment name to verbatim if necessary. + \ifcollargs@verbatim + \edef\collargs@b@envname{\detokenize\expandafter{\collargs@b@envname}}% + \fi + % This is a format-specific macro which sets up |\collargs@begintag| and + % |\collargs@endtag|. + \collargs@bi@defCPTbeginend + \edef\collargs@tagarg{% + \ifcollargs@verbatimbraces + \else + \ifcollargsIgnoreOtherTags + \collargs@b@envname + \fi + \fi + }% + % Run this after collecting the body. + \def\collargs@commandatend{% + % In \hologo{LaTeX}, we might, depending on the verbatim mode, need to + % check whether the environment name is correct. + %\collargs@bii + % In \hologo{plainTeX} and \hologo{ConTeXt}, we can skip directly to + % |\collargs@biii|. + %\collargs@biii + #1.% + }% + % Collect the environment body, but first, put any grabbed spaces back into + % the input stream. + \collargs@reinsert@spaces\collargs@readContent +} +%<*latex> +% In \hologo{LaTeX} in the regular and the partial verbatim mode, we search for +% |\begin|\slash|\end| --- as we cannot search for braces --- either as control +% sequences in the regular mode, or as strings in the partial verbatim +% mode. (After search, we will have to check whether the argument of +% |\begin|\slash|\end| matches our environment name.) In the full verbatim +% mode, we can search for the entire string |\begin|\slash|\end|\marg{name}. +\def\collargs@bi@defCPTbeginend{% + \edef\collargs@begintag{% + \ifcollargs@verbatim + \expandafter\string + \else + \expandafter\noexpand + \fi + \begin + \ifcollargs@verbatimbraces + \collargs@other@bgroup\collargs@b@envname\collargs@other@egroup + \fi + }% + \edef\collargs@endtag{% + \ifcollargs@verbatim + \expandafter\string + \else + \expandafter\noexpand + \fi + \end + \ifcollargs@verbatimbraces + \collargs@other@bgroup\collargs@b@envname\collargs@other@egroup + \fi + }% +} +% +%<*plain,context> +% We can search for the entire |\|\meta{name}\slash|\end|\meta{name} (in +% \hologo{TeX}) or |\start|\meta{name}\slash|\stop|\meta{name} (in +% \hologo{ConTeXt}), either as a control sequence (in the regular mode), or as +% a string (in the verbatim modes). +\def\collargs@bi@defCPTbeginend{% + \edef\collargs@begintag{% + \ifcollargs@verbatim + \expandafter\expandafter\expandafter\string + \else + \expandafter\expandafter\expandafter\noexpand + \fi + \csname + %start% + \collargs@b@envname + \endcsname + }% + \edef\collargs@endtag{% + \ifcollargs@verbatim + \expandafter\expandafter\expandafter\string + \else + \expandafter\expandafter\expandafter\noexpand + \fi + \csname + %end% + %stop% + \collargs@b@envname + \endcsname + }% +} +% +%<*latex> +% Check whether we're in front of the (braced) environment name (in +% \hologo{LaTeX}), and consume it. +\def\collargs@bii{% + \ifcollargs@verbatimbraces + \expandafter\collargs@biii + \else + \ifcollargsIgnoreOtherTags + % We shouldn't check the name in this case, because it was already + % checked, and consumed. + \expandafter\expandafter\expandafter\collargs@biii + \else + \expandafter\expandafter\expandafter\collargs@b@checkend + \fi + \fi +} +\def\collargs@b@checkend#1.{% + \collargs@grabspaces{\collargs@b@checkend@i#1.}% +} +\def\collargs@b@checkend@i#1.#2{% + \def\collargs@temp{#2}% + \ifx\collargs@temp\collargs@b@envname + \else + \collargs@b@checkend@error + \fi + \collargs@biii#1.% +} +\def\collargs@b@checkend@error{% + \PackageError{collargs}{Environment "\collargs@b@envname" ended as + "\collargs@temp"}{}% +} +% +% This macro stores the collected body. +\def\collargs@biii{% + % Define the wrapper macro (|\collargs@temp|). + \collargs@b@def@wrapper + % Execute |\collargs@appendarg| to append the body to the list. Expand the + % wrapper in |\collargs@temp| first and the body in |\collargsArg| next. + \expandafter\collargs@appendarg\expandafter{\the\collargsArg}% + % Reexecute the central loop. + \collargs@ +} +\def\collargs@b@def@wrapper{% + %\edef\collargs@temp{{\collargs@b@envname}}% + \edef\collargs@temp{% + % Was the begin-tag requested? + \ifcollargsBeginTag + % |\collargs@begintag| is already adapted to the format and the verbatim mode. + \expandonce\collargs@begintag + % Add the braced environment name in \hologo{LaTeX} in the regular and + % partial verbatim mode. + % + %<*latex> + \ifcollargs@verbatimbraces\else\collargs@temp\fi + % + \fi + % This is the body. + ####1% + % Rinse and repeat for the end-tag. + \ifcollargsEndTag + \expandonce\collargs@endtag + %<*latex> + \ifcollargs@verbatimbraces\else\collargs@temp\fi + % + \fi + }% + \expandafter\collargs@wrap\expandafter{\collargs@temp}% +} +% \end{macro} +% +% \begin{macro}{\collargs@readContent} +% This macro, which is an adaptation of +% \texttt{cprotect}'s environment-grabbing code, collects some delimited +% text, leaving the result in |\collargsArg|. Before calling it, one must +% define the following macros: |\collargs@begintag| and |\collargs@endtag| +% are the content delimiters; |\collargs@tagarg|, if non-empty, is the token +% or grouped text which must follow a delimiter to be taken into account; +% |\collargs@commandatend| is the command that will be executed once the +% content is collected. +\def\collargs@readContent{% + % Define macro which will search for the first begin-tag. + \ifcollargs@long\long\fi + \collargs@CPT@def\collargs@gobbleOneB\collargs@begintag{% + % Assign the collected tokens into a register. The first token in |##1| + % will be |\collargs@empty|, so we expand to get rid of it. + \expandafter\toks@\expandafter{##1}% + % |cprotect| simply grabs the token following the |\collargs@begintag| with + % a parameter. We can't do this, because we need the code to work in the + % non-verbatim mode, as well, and we might stumble upon a brace there. So + % we take a peek. + \futurelet\collargs@temp\collargs@gobbleOneB@i + }% + % Define macro which will search for the first end-tag. We make it long if + % so required (by |+|). + \ifcollargs@long\long\fi + \collargs@CPT@def\collargs@gobbleUntilE\collargs@endtag{% + % Expand |\collargs@empty| at the start of |##1|. + \expandafter\toksapp\expandafter\toks@\expandafter{##1}% + \collargs@gobbleUntilE@i + }% + % Initialize. + \collargs@begins=0\relax + \collargsArg{}% + \toks@{}% + % We will call |\collargs@gobbleUntilE| via the caller control sequence. + \collargs@letusecollector\collargs@gobbleUntilE + % We insert |\collargs@empty| to avoid the potential debracing problem. + \collargs@empty +} +% How many begin-tags do we have opened? +\newcount\collargs@begins +% An auxiliary macro which |\def|s |#1| so that it will grab everything up +% until |#2|. Additional parameters may be present before the definition. +\def\collargs@CPT@def#1#2{% + \expandafter\def\expandafter#1% + \expandafter##\expandafter1#2% +} +% A quark quard. +\def\collargs@qend{\collargs@qend} +% This macro will collect the ``environment'', leaving the result in +% |\collargsArg|. It expects |\collargs@begintag|, |\collargs@endtag| and +% |\collargs@commandatend| to be set. +\def\collargs@gobbleOneB@i{% + \def\collargs@begins@increment{1}% + \ifx\collargs@qend\collargs@temp + % We have reached the fake begin-tag. Note that we found the end-tag. + \def\collargs@begins@increment{-1}% + % Gobble the quark guard. + \expandafter\collargs@gobbleOneB@v + \else + % Append the real begin-tag to the temporary tokens. + \etoksapp\toks@{\expandonce\collargs@begintag}% + \expandafter\collargs@gobbleOneB@ii + \fi +}% +% Do we have to check the tag argument (i.e.\ the environment name after |\begin|)? +\def\collargs@gobbleOneB@ii{% + \expandafter\ifx\expandafter\relax\collargs@tagarg\relax + \expandafter\collargs@gobbleOneB@vi + \else + % Yup, so let's (carefully) collect the tag argument. + \expandafter\collargs@gobbleOneB@iii + \fi +} +\def\collargs@gobbleOneB@iii{% + \collargs@grabspaces{% + \collargs@letusecollector\collargs@gobbleOneB@iv + }% +} +\def\collargs@gobbleOneB@iv#1{% + \def\collargs@temp{#1}% + \ifx\collargs@temp\collargs@tagarg + % This is the tag argument we've been waiting for! + \else + % Nope, this |\begin| belongs to someone else. + \def\collargs@begins@increment{0}% + \fi + % Whatever the result was, we have to append the gobbled group to the + % temporary toks. + \etoksapp\toks@{\collargs@grabbed@spaces\unexpanded{{#1}}}% + \collargs@init@grabspaces + \collargs@gobbleOneB@vi +} +\def\collargs@gobbleOneB@v#1{\collargs@gobbleOneB@vi} +\def\collargs@gobbleOneB@vi{% + % Store. + \etoksapp\collargsArg{\the\toks@}% + % Advance the begin-tag counter. + \advance\collargs@begins\collargs@begins@increment\relax + % Find more begin-tags, unless this was the final one. + \ifnum\collargs@begins@increment=-1 + \else + \expandafter\collargs@gobbleOneB\expandafter\collargs@empty + \fi +} +\def\collargs@gobbleUntilE@i{% + % Do we have to check the tag argument (i.e.\ the environment name after |\end|)? + \expandafter\ifx\expandafter\relax\collargs@tagarg\relax + \expandafter\collargs@gobbleUntilE@iv + \else + % Yup, so let's (carefully) collect the tag argument. + \expandafter\collargs@gobbleUntilE@ii + \fi +} +\def\collargs@gobbleUntilE@ii{% + \collargs@grabspaces{% + \collargs@letusecollector\collargs@gobbleUntilE@iii + }% +} +\def\collargs@gobbleUntilE@iii#1{% + \etoksapp\toks@{\collargs@grabbed@spaces}% + \collargs@init@grabspaces + \def\collargs@tempa{#1}% + \ifx\collargs@tempa\collargs@tagarg + % This is the tag argument we've been waiting for! + \expandafter\collargs@gobbleUntilE@iv + \else + % Nope, this |\end| belongs to someone else. Insert the end tag plus the + % tag argument, and collect until the next |\end|. + \expandafter\toksapp\expandafter\toks@\expandafter{\collargs@endtag{#1}}% + \expandafter\collargs@letusecollector\expandafter\collargs@gobbleUntilE + \fi +} +\def\collargs@gobbleUntilE@iv{% + % Invoke |\collargs@gobbleOneB| with the collected material, plus a fake + % begin-tag and a quark guard. + \ifcollargsIgnoreNesting + \expandafter\collargsArg\expandafter{\the\toks@}% + \expandafter\collargs@commandatend + \else + \expandafter\collargs@gobbleUntilE@v + \fi +} +\def\collargs@gobbleUntilE@v{% + \expanded{% + \noexpand\collargs@letusecollector\noexpand\collargs@gobbleOneB + \noexpand\collargs@empty + \the\toks@ + % Add a fake begin-tag and a quark guard. + \expandonce\collargs@begintag + \noexpand\collargs@qend + }% + \ifnum\collargs@begins<0 + \expandafter\collargs@commandatend + \else + \etoksapp\collargsArg{% + \expandonce\collargs@endtag + \expandafter\ifx\expandafter\relax\collargs@tagarg\relax\else{% + \expandonce\collargs@tagarg}\fi + }% + \toks@={}% + \expandafter\collargs@letusecollector\expandafter\collargs@gobbleUntilE + \expandafter\collargs@empty + \fi +} +% \end{macro} +% +% \begin{macro}{\collargs@e} +% Embellishments. Each embellishment counts as an argument, in the sense +% that we will execute |\collargs@appendarg|, with all the processors, for +% each embellishment separately. +\def\collargs@e{% + % We open an extra group, because |\collargs@appendarg| will close a group + % for each embellishment. + \global\collargs@fix@requestedtrue + \begingroup + \ifcollargs@verbatim + \expandafter\collargs@e@verbatim + \else + \expandafter\collargs@e@i + \fi +} +% Detokenize the embellishment tokens in the verbatim mode. +\def\collargs@e@verbatim#1{% + \expandafter\collargs@e@i\expandafter{\detokenize{#1}}% +} +% Ungroup the embellishment tokens, separating them from the rest of the +% argument specification by a dot. +\def\collargs@e@i#1{\collargs@e@ii#1.} +% We now have embellishment tokens in |#1| and the rest of the argument +% specification in |#2|. Let's grab spaces first. +\def\collargs@e@ii#1.#2.{% + \collargs@grabspaces{\collargs@e@iii#1.#2.}% +} +% What's the argument token? +\def\collargs@e@iii#1.#2.{% + \def\collargs@e@iv{\collargs@e@v#1.#2.}% + \futurelet\collargs@temp\collargs@e@iv +} +% If it is a open or close group character, we surely don't have an +% embellishment. +\def\collargs@e@v{% + \ifcat\noexpand\collargs@temp\bgroup\relax + \let\collargs@marshal\collargs@e@z + \else + \ifcat\noexpand\collargs@temp\egroup\relax + \let\collargs@marshal\collargs@e@z + \else + \let\collargs@marshal\collargs@e@vi + \fi + \fi + \collargs@marshal +} +% We borrow the ``Does |#1| occur within |#2|?'' macro from |pgfutil-common|, +% but we fix it by executing |\collargs@in@@| in a braced group. This will +% prevent an |&| in an argument to function as an alignment character; the +% minor price to pay is that we assign the conditional globally. +\newif\ifcollargs@in@ +\def\collargs@in@#1#2{% + \def\collargs@in@@##1#1##2##3\collargs@in@@{% + \ifx\collargs@in@##2\global\collargs@in@false\else\global\collargs@in@true\fi + }% + {\collargs@in@@#2#1\collargs@in@\collargs@in@@}% +} +% Let' see whether the following token, now |#3|, is an embellishment token. +\def\collargs@e@vi#1.#2.#3{% + \collargs@in@{#3}{#1}% + \ifcollargs@in@ + \expandafter\collargs@e@vii + \else + \expandafter\collargs@e@z + \fi + #1.#2.#3% +} +% |#3| is the current embellishment token. We'll collect its argument using +% |\collargs@m|, but to do that, we have to (locally) redefine +% |\collargs@appendarg| and |\collargs@|, which get called by |\collargs@m|. +\def\collargs@e@vii#1.#2.#3{% + % We'll have to execute the original |\collargs@appendarg| later, so let's + % remember it. The temporary |\collargs@appendarg| simply stores the + % collected argument into |\collargsArg| --- we'll do the processing etc.\ + % later. + \let\collargs@real@appendarg\collargs@appendarg + \def\collargs@appendarg##1{\collargsArg{##1}}% + % Once |\collargs@m| is done, it will call the redefined |\collargs@| and + % thereby get us back into this handler. + \def\collargs@{\collargs@e@viii#1.#3}% + \collargs@m#2.% +} +% The parameters here are as follows. |#1| are the embellishment tokens, and +% |#2| is the current embellishment token; these get here via our local +% redefinition of |\collargs@| in |\collargs@e@vii|. |#3| are the rest of the +% argument specification, which is put behind control sequence |\collargs@| by +% the |m| handler. +\def\collargs@e@viii#1.#2#3.{% + % Our wrapper puts the current embellishment token in front of the collected + % embellishment argument. Note that if the embellishment argument was in + % braces, |\collargs@m| has already set one wrapper (which will apply first). + \collargs@wrap{#2##1}% + % We need to get rid of the current embellishment from embellishments, not to + % catch the same embellishment twice. + \def\collargs@e@ix##1#2{\collargs@e@x##1}% + \collargs@e@ix#1.#3.% +} +% When this is executed, the input stream starts with the (remaining) +% embellishment tokens, followed by a dot, then the rest of the argument +% specification, also followed by a dot. +\def\collargs@e@x{% + % Process the argument and append it to the storage. + \expandafter\collargs@real@appendarg\expandafter{\the\collargsArg}% + % |\collargs@real@appendarg| has closed a group, so we open it again, and + % start looking for another embellishment token in the input stream. + \begingroup + \collargs@e@ii +} +% The first argument token in not an embellishment token. We finish by +% consuming the list of embellishment tokens, closing the two groups opened by +% this handler, and reexecuting the central loop. +\def\collargs@e@z#1.{\endgroup\endgroup\collargs@} +% \end{macro} +% +% \begin{macro}{\collargs@E} +% Discard the defaults and execute |e|. +\def\collargs@E#1#2{\collargs@e{#1}} +% \end{macro} +% +% +% \subsubsection{The verbatim modes} +% \label{sec:code:collargs:verbatim} +% +% \begin{macro}{\collargsVerbatim,\collargsVerb,\collargsNoVerbatim} +% These macros set the two verbatim-related +% conditionals, |\ifcollargs@verbatim| and |\ifcollargs@verbatimbraces|, +% and then call |\collargs@make@verbatim| to effect the requested +% category code changes (among other things). A group should be opened +% prior to executing either of them. After execution, they are +% redefined to minimize the effort needed to enter into another mode in +% an embedded group. Below, we first define all the possible transitions. +\let\collargs@NoVerbatimAfterNoVerbatim\relax +\def\collargs@VerbAfterNoVerbatim{% + \collargs@verbatimtrue + \collargs@verbatimbracesfalse + \collargs@make@verbatim + \collargs@after{Verb}% +} +\def\collargs@VerbatimAfterNoVerbatim{% + \collargs@verbatimtrue + \collargs@verbatimbracestrue + \collargs@make@verbatim + \collargs@after{Verbatim}% +} +\def\collargs@NoVerbatimAfterVerb{% + \collargs@verbatimfalse + \collargs@verbatimbracesfalse + \collargs@make@other@groups + \collargs@make@no@verbatim + \collargs@after{NoVerbatim}% +} +\def\collargs@VerbAfterVerb{% + \collargs@make@other@groups +} +\def\collargs@VerbatimAfterVerb{% + \collargs@verbatimbracestrue + \collargs@make@other@groups + % Process the lists of grouping characters, created by + % |\collargs@make@verbatim|, making these characters of category ``other''. + \def\collargs@do##1{\catcode##1=12 }% + \collargs@bgroups + \collargs@egroups + \collargs@after{Verbatim}% +}% +\let\collargs@NoVerbatimAfterVerbatim\collargs@NoVerbatimAfterVerb +\def\collargs@VerbAfterVerbatim{% + \collargs@verbatimbracesfalse + \collargs@make@other@groups + % Process the lists of grouping characters, created by + % |\collargs@make@verbatim|, making these characters be of their normal + % category. + \def\collargs@do##1{\catcode##1=1 }% + \collargs@bgroups + \def\collargs@do##1{\catcode##1=2 }% + \collargs@egroups + \collargs@after{Verb}% +}% +\let\collargs@VerbatimAfterVerbatim\collargs@VerbAfterVerb +% This macro expects |#1| to be the mode just entered (|Verbatim|, |Verb| or +% |NoVerbatim|), and points macros |\collargsVerbatim|, |\collargsVerb| and +% |\collargsNoVerbatim| to the appropriate transition macro. +\def\collargs@after#1{% + \letcs\collargsVerbatim{collargs@VerbatimAfter#1}% + \letcs\collargsVerb{collargs@VerbAfter#1}% + \letcs\collargsNoVerbatim{collargs@NoVerbatimAfter#1}% +} +% The first transition is always from the non-verbatim mode. +\collargs@after{NoVerbatim} +% \end{macro} +% +% \begin{macro}{\collargs@bgroups,\collargs@egroups} +% Initialize the lists of the current grouping characters used in the +% redefinitions of macros |\collargsVerbatim| and |\collargsVerb| above. +% Each entry is of form |\collargs@do|\marg{character code}. These lists +% will be populated by |\collargs@make@verbatim|. They may be local, as they +% only used within the group opened for a verbatim environment. +\def\collargs@bgroups{}% +\def\collargs@egroups{}% +% \end{macro} +% +% \begin{macro}{\collargs@cc} +% This macro recalls the category code of character |#1|. In +% \hologo{LuaTeX}, we simply look up the category code in the original +% category code table; in other engines, we have stored the original category +% code into |\collargs@cc@|\meta{character code} by +% |\collargs@make@verbatim|. (Note that |#1| is a character, not a number.) +\ifdefined\luatexversion + \def\collargs@cc#1{% + \directlua{tex.sprint(tex.getcatcode(\collargs@catcodetable@original, + \the\numexpr\expandafter`\csname#1\endcsname\relax))}% + } +\else + \def\collargs@cc#1{% + \ifcsname collargs@cc@\the\numexpr\expandafter`\csname#1\endcsname\endcsname + \csname collargs@cc@\the\numexpr\expandafter`\csname#1\endcsname\endcsname + \else + 12% + \fi + } +\fi +% \end{macro} +% +% +% \begin{macro}{\collargs@other@bgroup,\collargs@other@egroup,\collargsBraces} +% Macros |\collargs@other@bgroup| and +% |\collargs@other@egroup| hold the characters of category code ``other'' +% which will play the role of grouping characters in the full verbatim mode. +% They are usually defined when entering a verbatim mode in +% |\collargs@make@verbatim|, but may be also set by the user via +% |\collargsBraces| (it is not even necessary to select characters which +% indeed have the grouping function in the outside category code regime). +% The setting process is indirect: executing |\collargsBraces| merely sets +% |\collargs@make@other@groups|, which gets executed by the subsequent +% |\collargsVerbatim|, |\collargsVerb| or |\collargsNoVerbatim| (either +% directly or via |\collargs@make@verbatim|). +\def\collargsBraces#1{% + \expandafter\collargs@braces@i\detokenize{#1}\relax +} +\def\collargs@braces@i#1#2#3\relax{% + \def\collargs@make@other@groups{% + \def\collargs@other@bgroup{#1}% + \def\collargs@other@egroup{#2}% + }% +} +\def\collargs@make@other@groups{} +% \end{macro} +% +% \begin{macro}{\collargs@catcodetable@verbatim,\catcodetable@atletter,\collargs@catcodetable@initex} +% We declare several new catcode tables in \hologo{LuaTeX}, the most +% important one being |\collargs@catcodetable@verbatim|, where all characters +% have category code 12. We only need the other two tables in some formats: +% |\collargs@catcodetable@atletter| holds the catcode in effect at the time +% of loading the package, and |\collargs@catcodetable@initex| is the +% \hologo{iniTeX} table. +\ifdefined\luatexversion + %<*latex,context> + \newcatcodetable\collargs@catcodetable@verbatim + %\let\collargs@catcodetable@atletter\catcodetable@atletter + %\newcatcodetable\collargs@catcodetable@atletter + % + %<*plain> + \ifdefined\collargs@catcodetable@verbatim\else + \chardef\collargs@catcodetable@verbatim=4242 + \fi + \chardef\collargs@catcodetable@atletter=% + \number\numexpr\collargs@catcodetable@verbatim+1\relax + \chardef\collargs@catcodetable@initex=% + \number\numexpr\collargs@catcodetable@verbatim+2\relax + \initcatcodetable\collargs@catcodetable@initex + % + %\savecatcodetable\collargs@catcodetable@atletter + \begingroup + \@firstofone{% + %\catcodetable\catcodetable@initex + %\catcodetable\collargs@catcodetable@initex + %\catcodetable\inicatcodes + \catcode`\\=12 + \catcode13=12 + \catcode0=12 + \catcode32=12 + \catcode`\%=12 + \catcode127=12 + \def\collargs@do#1{\catcode#1=12 }% + \collargs@forrange{`\a}{`\z}% + \collargs@forrange{`\A}{`\Z}% + \savecatcodetable\collargs@catcodetable@verbatim + \endgroup + }% +\fi +% \end{macro} +% +% \begin{collargskey}{verbatim ranges} +% \begin{macro}{\collargsVerbatimRanges,\collargs@verbatim@ranges} +% This key and macro set the character ranges to which the verbatim mode +% will apply (in \hologo{pdfTeX} and \hologo{XeTeX}), or which will be +% inspected for grouping and comment characters (in \hologo{LuaTeX}). In +% \hologo{pdfTeX}, the default value |0-255| should really remain +% unchanged. +\collargsSet{ + verbatim ranges/.store in=\collargs@verbatim@ranges, +} +\def\collargsVerbatimRanges#1{\def\collargs@verbatim@ranges{#1}} +\def\collargs@verbatim@ranges{0-255} +% \end{macro} +% \end{collargskey} +% +% \begin{macro}{\collargs@make@verbatim} +% This macro changes the category code of all characters to ``other'' --- +% except the grouping characters in the partial verbatim mode. While doing +% that, it also stores (unless we're in \hologo{LuaTeX}) the current category +% codes into |\collargs@cc@|\meta{character code} (easily recallable by +% |\collargs@cc|), redefines the ``primary'' grouping characters +% |\collargs@make@other@bgroup| and |\collargs@make@other@egroup| if +% necessary, and ``remembers'' the grouping characters (storing them into +% |\collargs@bgroups| and |\collargs@egroups|) and the comment characters +% (storing them into |\collargs@comments|). +% +% In \hologo{LuaTeX}, we can use catcode tables, so we change the category +% codes by switching to category code table +% |\collargs@catcodetable@verbatim|. In other engines, we have to change the +% codes manually. In order to offer some flexibility in \hologo{XeTeX}, we +% perform the change for characters in |verbatim ranges|. +\ifdefined\luatexversion + \def\collargs@make@verbatim{% + \directlua{% + for from, to in string.gmatch( + "\luaescapestring{\collargs@verbatim@ranges}", + "(\collargs@percentchar d+)-(\collargs@percentchar d+)" + ) do + for char = tex.round(from), tex.round(to) do + catcode = tex.catcode[char] + % For category codes 1, 2 and 14, we have to call macros + % |\collargs@make@verbatim@bgroup|, |\collargs@make@verbatim@egroup| + % and |\collargs@make@verbatim@comment|, same as for engines other + % than \hologo{LuaTeX}. + if catcode == 1 then + tex.sprint( + \number\collargs@catcodetable@atletter, + "\noexpand\\collargs@make@verbatim@bgroup{" .. char .. "}") + elseif catcode == 2 then + tex.sprint( + \number\collargs@catcodetable@atletter, + "\noexpand\\collargs@make@verbatim@egroup{" .. char .. "}") + elseif catcode == 14 then + tex.sprint( + \number\collargs@catcodetable@atletter, + "\noexpand\\collargs@make@verbatim@comment{" .. char .. "}") + end + end + end + }% + \edef\collargs@catcodetable@original{\the\catcodetable}% + \catcodetable\collargs@catcodetable@verbatim + % Even in \hologo{LuaTeX}, we switch between the verbatim braces regimes by + % hand. + \ifcollargs@verbatimbraces + \else + \def\collargs@do##1{\catcode##1=1\relax}% + \collargs@bgroups + \def\collargs@do##1{\catcode##1=2\relax}% + \collargs@egroups + \fi + } +\else + % The non-\hologo{LuaTeX} version: + \def\collargs@make@verbatim{% + \ifdefempty\collargs@make@other@groups{}{% + % The user has executed |\collargsBraces|. We first apply that setting + % by executing macro |\collargs@make@other@groups|, and then disable our + % automatic setting of the primary grouping characters. + \collargs@make@other@groups + \def\collargs@make@other@groups{}% + \let\collargs@make@other@bgroup\@gobble + \let\collargs@make@other@egroup\@gobble + }% + % Initialize the list of current comment characters. Each entry is of + % form |\collargs@do|\marg{character code}. The definition must be global, + % because the macro will be used only once we exit the current group (by + % |\collargs@fix@cc@from@other@comment|, if at all). + \gdef\collargs@comments{}% + \let\collargs@do\collargs@make@verbatim@char + \expandafter\collargs@forranges\expandafter{\collargs@verbatim@ranges}% + } + \def\collargs@make@verbatim@char#1{% + % Store the current category code of the current character. + \ifnum\catcode#1=12 + \else + \csedef{collargs@cc@#1}{\the\catcode#1}% + \fi + \ifnum\catcode#1=1 + \collargs@make@verbatim@bgroup{#1}% + \else + \ifnum\catcode#1=2 + \collargs@make@verbatim@egroup{#1}% + \else + \ifnum\catcode#1=14 + \collargs@make@verbatim@comment{#1}% + \fi + % Change the category code of the current character (including the + % comment characters). + \ifnum\catcode#1=12 + \else + \catcode#1=12\relax + \fi + \fi + \fi + } +\fi +% \end{macro} +% +% \begin{macro}{\collargs@make@verbatim@bgroup} +% This macro changes the category of +% the opening group character to ``other'', but only in the full verbatim +% mode. Next, it populates |\collargs@bgroups|, to facilitate the potential +% transition into the other verbatim mode. Finally, it executes +% |\collargs@make@other@bgroup|, which stores the ``other'' variant of the +% current character into |\collargs@other@bgroup|, and automatically disables +% itself, so that it is only executed for the first encountered opening group +% character --- unless it was already |\relax|ed at the top of +% |\collargs@make@verbatim| as a consequence of the user executing +% |\collargsBraces|. +\def\collargs@make@verbatim@bgroup#1{% + \ifcollargs@verbatimbraces + \catcode#1=12\relax + \fi + \appto\collargs@bgroups{\collargs@do{#1}}% + \collargs@make@other@bgroup{#1}% +} +\def\collargs@make@other@bgroup#1{% + \collargs@make@char\collargs@other@bgroup{#1}{12}% + \let\collargs@make@other@bgroup\@gobble +} +% \end{macro} +% +% \begin{macro}{\collargs@make@verbatim@egroup} +% Ditto for the closing group character. +\def\collargs@make@verbatim@egroup#1{% + \ifcollargs@verbatimbraces + \catcode#1=12\relax + \fi + \appto\collargs@egroups{\collargs@do{#1}}% + \collargs@make@other@egroup{#1}% +} +\def\collargs@make@other@egroup#1{% + \collargs@make@char\collargs@other@egroup{#1}{12}% + \let\collargs@make@other@egroup\@gobble +} +% \end{macro} +% +% \begin{macro}{\collargs@make@verbatim@comment} +% This macro populates +% |\collargs@make@comments@other|. +\def\collargs@make@verbatim@comment#1{% + \gappto\collargs@comments{\collargs@do{#1}}% +} +% \end{macro} +% +% \begin{macro}{\collargs@make@no@verbatim} +% This macro switches back to the non-verbatim mode: in \hologo{LuaTeX}, by +% switching to the original catcode table; in other engines, by recalling the +% stored category codes. +\ifdefined\luatexversion + \def\collargs@make@no@verbatim{% + \catcodetable\collargs@catcodetable@original\relax + }% +\else +\def\collargs@make@no@verbatim{% + \let\collargs@do\collargs@make@no@verbatim@char + \expandafter\collargs@forranges\expandafter{\collargs@verbatim@ranges}% +} +\fi +\def\collargs@make@no@verbatim@char#1{% + % The original category code of a characted was stored into + % |\collargs@cc@|\meta{character code} by |\collargs@make@verbatim|. (We don't + % use |\collargs@cc|, because we have a number.) + \ifcsname collargs@cc@#1\endcsname + \catcode#1=\csname collargs@cc@#1\endcsname\relax + % We don't have to restore category code 12. + \fi +} +% \end{macro} +% +% +% \subsubsection{Transition between the verbatim and the non-verbatim mode} +% \label{sec:code:collargs:fix} +% +% At the transition from verbatim to non-verbatim mode, and vice versa, we +% sometimes have to fix the category code of the next argument token. This +% happens when we have an optional argument type in one mode followed by an +% argument type in another mode, but the optional argument is absent, or when +% an optional, but absent, verbatim argument is the last argument in the +% specification. The problem arises because the presence of optional arguments +% is determined by looking ahead in the input stream; when the argument is +% absent, this means that we have fixed the category code of the next token. +% CollArgs addresses this issue by noting the situations where a token receives +% the wrong category code, and then does its best to replace that token with +% the same character of the appropriate category code. +% +% \begin{macro}{\ifcollargs@fix@requested} +% This conditional is set, globally, +% by the optional argument handlers when the argument is in fact absent, +% and reset in the central loop after applying the fix if necessary. +\newif\ifcollargs@fix@requested +% \end{macro} +% +% \begin{macro}{\collargs@fix} +% This macro selects the fixer appropriate to the transition between the +% previous verbatim mode (determined by |\ifcollargs@last@verbatim| and +% |\ifcollargs@last@verbatimbraces|) and the current verbatim mode (which +% is determined by macros |\ifcollargs@verbatim| and +% |\ifcollargs@verbatimbraces|); if the category code fix was not +% requested (for this, we check |\ifcollargs@fix@requested|), the +% macro simply executes the next-code given as the sole argument. +% The name of the fixer macro has the form +% |\collargs@fix@|\meta{last mode}|to|\meta{current mode}, where +% the modes are given by mnemonic codes: |V| = full verbatim, |v| = +% partial verbatim, and |N| = non-verbatim. +\long\def\collargs@fix#1{% + % Going through |\edef| + |\unexpanded| avoids doubling the hashes. + \edef\collargs@fix@next{\unexpanded{#1}}% + \ifcollargs@fix@requested + \letcs\collargs@action{collargs@fix@% + \ifcollargs@last@verbatim + \ifcollargs@last@verbatimbraces V\else v\fi + \else + N% + \fi + to% + \ifcollargs@verbatim + \ifcollargs@verbatimbraces V\else v\fi + \else + N% + \fi + }% + \else + \let\collargs@action\collargs@fix@next + \fi + \collargs@action +} +% \end{macro} +% +% \begin{macro}{\collargs@fix@NtoN,\collargs@fix@vtov,\collargs@fix@VtoV} +% \indentmacrocode +% Nothing to do, continue with the next-code. +\def\collargs@fix@NtoN{\collargs@fix@next} +\let\collargs@fix@vtov\collargs@fix@NtoN +\let\collargs@fix@VtoV\collargs@fix@NtoN +% \end{macro} +% +% \begin{macro}{\collargs@fix@Ntov} +% We do nothing for the group tokens; for other tokens, we redirect to +% |\collargs@fix@NtoV|. +\def\collargs@fix@Ntov{% + \futurelet\collargs@temp\collargs@fix@cc@to@other@ii +} +\def\collargs@fix@cc@to@other@ii{% + \ifcat\noexpand\collargs@temp\bgroup + \let\collargs@action\collargs@fix@next + \else + \ifcat\noexpand\collargs@temp\egroup + \let\collargs@action\collargs@fix@next + \else + \let\collargs@action\collargs@fix@NtoV + \fi + \fi + \collargs@action +} +% \end{macro} +% +% \begin{macro}{\collargs@fix@NtoV} +% The only complication here is that we might be in front of a control +% sequence that was a result of a previous fix in the other direction. +\def\collargs@fix@NtoV{% + \ifcollargs@double@fix + \ifcollargs@in@second@fix + \expandafter\expandafter\expandafter\collargs@fix@NtoV@secondfix + \else + \expandafter\expandafter\expandafter\collargs@fix@NtoV@onemore + \fi + \else + \expandafter\collargs@fix@NtoV@singlefix + \fi +} +% This is the usual situation of a single fix. We just use |\string| on +% the next token here (but note that some situations can't be saved: noone +% can bring a comment back to life, or distinguish a newline and a space) +\def\collargs@fix@NtoV@singlefix{% + \expandafter\collargs@fix@next\string +} +% If this is the first fix of two, we know |#1| is a control sequence, so it is +% safe to grab it. +\def\collargs@fix@NtoV@onemore#1{% + \collargs@do@one@more@fix{% + \expandafter\collargs@fix@next\string#1% + }% +} +% If this is the second fix of the two, we have to check whether the next token +% is a control sequence, and if it is, we need to remember it. Afterwards, we +% redirect to the single-fix. +\def\collargs@fix@NtoV@secondfix{% + \if\noexpand\collargs@temp\relax + \expandafter\collargs@fix@NtoV@secondfix@i + \else + \expandafter\collargs@fix@NtoV@singlefix + \fi +} +\def\collargs@fix@NtoV@secondfix@i#1{% + \gdef\collargs@double@fix@cs@ii{#1}% + \collargs@fix@NtoV@singlefix#1% +} +% \end{macro} +% +% \begin{macro}{\collargs@fix@vtoN} +% Do nothing for the grouping tokens, redirect to |\collargs@fix@VtoN| for +% other tokens. +\def\collargs@fix@vtoN{% + \futurelet\collargs@token\collargs@fix@vtoN@i +} +\def\collargs@fix@vtoN@i{% + \ifcat\noexpand\collargs@token\bgroup + \expandafter\collargs@fix@next + \else + \ifcat\noexpand\collargs@token\egroup + \expandafter\expandafter\expandafter\collargs@fix@next + \else + \expandafter\expandafter\expandafter\collargs@fix@VtoN + \fi + \fi +} +% \end{macro} +% +% \begin{macro}{\collargs@fix@vtoV} +% Redirect group tokens to |\collargs@fix@NtoV|, and do nothing for other +% tokens. +\def\collargs@fix@vtoV{% + \futurelet\collargs@token\collargs@fix@vtoV@i +} +\def\collargs@fix@vtoV@i{% + \ifcat\noexpand\collargs@token\bgroup + \expandafter\collargs@fix@NtoV + \else + \ifcat\noexpand\collargs@token\egroup + \expandafter\expandafter\expandafter\collargs@fix@NtoV + \else + \expandafter\expandafter\expandafter\collargs@fix@next + \fi + \fi +} +% \end{macro} +% +% \begin{macro}{\collargs@fix@Vtov} +% Redirect group tokens to |\collargs@fix@VtoN|, and do nothing for other +% tokens. |#1| is surely of category 12, so we can safely grab it. +\def\collargs@fix@catcode@of@braces@fromverbatim#1{% + \ifnum\catcode`#1=1 + \expandafter\collargs@fix@VtoN + \expandafter#1% + \else + \ifnum\catcode`#1=2 + \expandafter\expandafter\expandafter\collargs@fix@cc@VtoN + \expandafter\expandafter\expandafter#1% + \else + \expandafter\expandafter\expandafter\collargs@fix@next + \fi + \fi +} +% \end{macro} +% +% \begin{macro}{\collargs@fix@VtoN} +% This is the only complicated part. Control sequences and comments (but not +% grouping characters!) require special attention. We're fine to grab the +% token right away, as we know it is of category 12. +\def\collargs@fix@VtoN#1{% + \ifnum\catcode`#1=0 + \expandafter\collargs@fix@VtoN@escape + \else + \ifnum\catcode`#1=14 + \expandafter\expandafter\expandafter\collargs@fix@VtoN@comment + \else + \expandafter\expandafter\expandafter\collargs@fix@VtoN@token + \fi + \fi + #1% +} +% \end{macro} +% +% \begin{macro}{\collargs@fix@VtoN@token} +% We create a new character with the current +% category code behing the next-code. This works even for grouping +% characters. +\def\collargs@fix@VtoN@token#1{% + \collargs@insert@char\collargs@fix@next{`#1}{\the\catcode`#1}% +} +% \end{macro} +% +% \begin{macro}{\collargs@fix@VtoN@comment} +% This macro defines a macro which will, +% when placed at a comment character, remove the tokens until the end of the +% line. The code is adapted from the TeX.SE answer at +% \url(https://){tex.stackexchange.com/a/10454/16819} by Bruno Le Floch. +\def\collargs@defcommentstripper#1#2{% + % We chuck a parameter into the following definition, to grab the (verbatim) + % comment character. This is why this macro must be executed precisely + % before the (verbatim) comment character. + \def#1##1{% + \begingroup% + \escapechar=`\\% + \catcode\endlinechar=\active% + % We assign the ``other'' category code to comment characters. Without + % this, comment characters behind the first one make trouble: there would + % be no |^||^M| at the end of the line, so the comment stripper would + % gobble the following line as well; in fact, it would gobble all + % subsequent lines containing a comment character. We also make sure to + % change the category code of \emph{all} comment characters, even if there + % is usually just one. + \def\collargs@do####1{\catcode####1=12 }% + \collargs@comments + \csname\string#1\endcsname% + }% + \begingroup% + \escapechar=`\\% + \lccode`\~=\endlinechar% + \lowercase{% + \expandafter\endgroup + \expandafter\def\csname\string#1\endcsname##1~% + }{% + % I have removed |\space| from the end of the following line. We don't + % want it for our application. + \endgroup#2% + }% +} +\collargs@defcommentstripper\collargs@fix@VtoN@comment{% + \collargs@fix@next +} +% We don't need the generator any more. +\let\collargs@defcommentstripper\relax +% \end{macro} +% +% \begin{macro}{\collargs@fix@VtoN@escape} +% An escape character of category code 12 +% is the most challenging --- and we won't get things completely right --- as +% we have swim further down the input stream to create a control sequence. +% This macro will throw away the verbatim escape character |#1|. +\def\collargs@fix@VtoN@escape#1{% + \ifcollargs@double@fix + % We need to do things in a special way if we're in the double-fix + % situation triggered by the previous fixing of a control sequence + % (probably this very one). In that case, we can't collect it in the usual + % way because the entire control sequence is spelled out in verbatim. + \expandafter\collargs@fix@VtoN@escape@d + \else + % This here is the usual situation where the escape character was tokenized + % verbatim, but the control sequence name itself will be collected (right + % away) in the non-verbatim regime. + \expandafter\collargs@fix@VtoN@escape@i + \fi +} +\def\collargs@fix@VtoN@escape@i{% + % The sole character forming a control symbol name may be of any category. + % Temporarily redefining the category codes of the craziest characters allows + % |\collargs@fix@VtoN@escape@ii| to simply grab the following + % character. + \begingroup + \catcode`\\=12 + \catcode`\{=12 + \catcode`\}=12 + \catcode`\ =12 + \collargs@fix@VtoN@escape@ii +} +% The argument is the first character of the control sequence name. +\def\collargs@fix@VtoN@escape@ii#1{% + \endgroup + \def\collargs@csname{#1}% + % Only if |#1| is a letter may the control sequence name continue. + \ifnum\catcode`#1=11 + \expandafter\collargs@fix@VtoN@escape@iii + \else + % In the case of a control space, we have to throw away the following + % spaces. + \ifnum\catcode`#1=10 + \expandafter\expandafter\expandafter\collargs@fix@VtoN@escape@s + \else + % We have a control symbol. That means that we haven't peeked ahead and + % can thus skip |\collargs@fix@VtoN@escape@z|. + \expandafter\expandafter\expandafter\collargs@fix@VtoN@escape@z@i + \fi + \fi +} +% We still have to collect the rest of the control sequence name. Braces have +% their usual meaning again, so we have to check for them explicitly (and bail +% out if we stumble upon them). +\def\collargs@fix@VtoN@escape@iii{% + \futurelet\collargs@temp\collargs@fix@VtoN@escape@iv +} +\def\collargs@fix@VtoN@escape@iv{% + \ifcat\noexpand\collargs@temp\bgroup + \let\collargs@action\collargs@fix@VtoN@escape@z + \else + \ifcat\noexpand\collargs@temp\egroup + \let\collargs@action\collargs@fix@VtoN@escape@z + \else + \expandafter\ifx\space\collargs@temp + \let\collargs@action\collargs@fix@VtoN@escape@s + \else + \let\collargs@action\collargs@fix@VtoN@escape@v + \fi + \fi + \fi + \collargs@action +} +% If we have a letter, store it and loop back, otherwise finish. +\def\collargs@fix@VtoN@escape@v#1{% + \ifcat\noexpand#1a% + \appto\collargs@csname{#1}% + \expandafter\collargs@fix@VtoN@escape@iii + \else + \expandafter\collargs@fix@VtoN@escape@z\expandafter#1% + \fi +} +% Throw away the following spaces. +\def\collargs@fix@VtoN@escape@s{% + \futurelet\collargs@temp\collargs@fix@VtoN@escape@s@i +} +\def\collargs@fix@VtoN@escape@s@i{% + \expandafter\ifx\space\collargs@temp + \expandafter\collargs@fix@VtoN@escape@s@ii + \else + \expandafter\collargs@fix@VtoN@escape@z + \fi +} +\def\collargs@fix@VtoN@escape@s@ii{% + \expandafter\collargs@fix@VtoN@escape@z\romannumeral-0% +} +% Once we have collected the control sequence name into |\collargs@csname|, we +% will create the control sequence behind the next-code. However, we have two +% complications. The minor one is that |\csname| defines an unexisting control +% sequence to mean |\relax|, so we have to check whether the control sequence +% we will create is defined, and if not, ``undefine'' it in advance. +% ^^A todo: do nicer +\def\collargs@fix@VtoN@escape@z@i{% + \collargs@fix@VtoN@escape@z@maybe@undefine@cs@begin + \collargs@fix@VtoN@escape@z@ii +}% +\def\collargs@fix@VtoN@escape@z@maybe@undefine@cs@begin{% + \ifcsname\collargs@csname\endcsname + \@tempswatrue + \else + \@tempswafalse + \fi +} +\def\collargs@fix@VtoN@escape@z@maybe@undefine@cs@end{% + \if@tempswa + \else + \cslet{\collargs@csname}\collargs@undefined + \fi +} +\def\collargs@fix@VtoN@escape@z@ii{% + \expandafter\collargs@fix@VtoN@escape@z@maybe@undefine@cs@end + \expandafter\collargs@fix@next\csname\collargs@csname\endcsname +} +% The second complication is much greater, but it only applies to control words +% and spaces, and that's why control symbols went directly to the macro above. +% Control words and spaces will only get there via a detour through the +% following macro. +% +% The problem is that collecting the control word\slash space name peeked ahead +% in the stream, so the character following the control sequence (name) is +% already tokenized. We will (at least partially) address this by requesting a +% ``double-fix'': until the control sequence we're about to create is consumed +% into some argument, each category code fix will fix two ``tokens'' rather +% than one. +\def\collargs@fix@VtoN@escape@z{% + \collargs@if@one@more@fix{% + % Some previous fixing has requested a double fix, so let's do it. + % Afterwards, redirect to the control symbol code + % |\collargs@fix@VtoN@escape@z@i|. It will surely use the correct + % |\collargs@csname| because we do the second fix in a group. + \collargs@do@one@more@fix\collargs@fix@VtoN@escape@z@i + }{% + % Remember the collected control sequence. It will be used in + % |\collargs@cancel@double@fix|. + \collargs@fix@VtoN@escape@z@maybe@undefine@cs@begin + \xdef\collargs@double@fix@cs@i{\expandonce{\csname\collargs@csname\endcsname}}% + \collargs@fix@VtoN@escape@z@maybe@undefine@cs@end + % Request the double-fix. + \global\collargs@double@fixtrue + % The complication is addressed, redirect to the control symbol finish. + \collargs@fix@VtoN@escape@z@ii + }% +} +% When we have to ``redo'' a control sequence, because it was ping-ponged back +% into the verbatim mode, we cannot collect it by +% |\collargs@fix@VtoN@escape@i|, because it is spelled out entirely in +% verbatim. However, we have seen this control sequence before, and remembered +% it, so we'll simply grab it. Another complication is that we might be either +% at the ``first'' control sequence, whose fixing created all these double-fix +% trouble, or at the ``second'' control sequence, if the first one was +% immediately followed by another one. But we have remembered both of them: +% the first one in |\collargs@fix@VtoN@escape@z|, the second one in +% |\collargs@fix@NtoV@secondfix|. +\def\collargs@fix@VtoN@escape@d{% + \ifcollargs@in@second@fix + \expandafter\collargs@fix@VtoN@escape@d@i + \expandafter\collargs@double@fix@cs@ii + \else + \expandafter\collargs@fix@VtoN@escape@d@i + \expandafter\collargs@double@fix@cs@i + \fi +} +% We have the contents of either |\collargs@double@fix@cs@i| or +% |\collargs@double@fix@cs@ii| here, a control sequence in both cases. +\def\collargs@fix@VtoN@escape@d@i#1{% + \expandafter\expandafter\expandafter\collargs@fix@VtoN@escape@d@ii + \expandafter\string#1\relax +} +% We have the verbatimized control sequence name in |#2| (|#1| is the escape +% character). By storing it into |\collargs@csname|, we pretend we have +% collected it. By defining and executing |\collargs@fix@VtoN@escape@d@iii|, +% we actually gobble it from the input stream. Finally, we reroute to +% |\collargs@fix@VtoN@escape@z|. +\def\collargs@fix@VtoN@escape@d@ii#1#2\relax{% + \def\collargs@csname{#2}% + \def\collargs@fix@VtoN@escape@d@iii#2{% + \collargs@fix@VtoN@escape@z + }% + \collargs@fix@VtoN@escape@d@iii +} +% This conditional signals a double-fix request. It should be always set +% globally, because it is cleared by |\collargs@double@fixfalse| in a group. +\newif\ifcollargs@double@fix +% This conditional signals that we're currently performing the second fix. +\newif\ifcollargs@in@second@fix +% Inspect the two conditionals above to decide whether we have to perform +% another fix: if so, execute the first argument, otherwise the second one. +% This macro is called only from |\collargs@fix@VtoN@escape@z| and +% |\collargs@fix@NtoV|, because these are the only two places where we might +% need the second fix, ping-ponging a control sequence between the verbatim and +% the non-verbatim mode. +\def\collargs@if@one@more@fix{% + \ifcollargs@double@fix + \ifcollargs@in@second@fix + \expandafter\expandafter\expandafter\@secondoftwo + \else + \expandafter\expandafter\expandafter\@firstoftwo + \fi + \else + \expandafter\@secondoftwo + \fi +} +\def\collargs@do@one@more@fix#1{% + % We perform the second fix in a group, signalling that we're performing + % it. + \begingroup + \collargs@in@second@fixtrue + % Reexecute the fixing routine, at the end, close the group and execute + % the given code afterwards. + \collargs@fix{% + \endgroup + #1% + }% +} +% This macro is called from |\collargs@appendarg| to cancel the double-fix +% request. +\def\collargs@cancel@double@fix{% + % |\collargs@appendarg| is only executed when something was actually + % consumed. We thus know that at least one of the problematic ``tokens'' is + % gone, so the double fix is not necessary anymore. + \global\collargs@double@fixfalse + % What we have to figure out, still, is whether both problematic ``tokens'' + % we consumed. If so, no more fixing is required. But if only one of them + % was consumed, we need to request the normal, single, fix for the remaining + % ``token''. + \begingroup + % This will attach the delimiters directly to the argument, so we'll see what + % was actually consumed. + \collargs@process@arg + % We compare what was consumed when collecting the current argument with the + % control word that triggered double-fixing. If they match, only the + % offending control word was consumed, so we need to set the fix request to + % true for the following token. + \edef\collargs@temp{\the\collargsArg}% + \edef\collargs@tempa{\expandafter\string\collargs@double@fix@cs@i}% + \ifx\collargs@temp\collargs@tempa + \global\collargs@fix@requestedtrue + \fi + \endgroup +} +% \end{macro} +% +% +% \begin{macro}{\collargs@insert@char,\collargs@make@char} +% These macros create a character of character code |#2| and category code +% |#3|. The first macro inserts it into the stream behind the code in |#1|; +% the second one defines the control sequence in |#1| to hold the created +% character (clearly, it should not be used for categories 1 and 2). +% +% We use the facilities of \hologo{LuaTeX}, \hologo{XeTeX} and \hologo{LaTeX} +% where possible. In the end, we only have to implement our own macros for +% plain \hologo{pdfTeX}. +%\ifdefined\luatexversion + \def\collargs@insert@char#1#2#3{% + \edef\collargs@temp{\unexpanded{#1}}% + \expandafter\collargs@temp\directlua{% + tex.cprint(\number#3,string.char(\number#2))}% + }% + \def\collargs@make@char#1#2#3{% + \edef#1{\directlua{tex.cprint(\number#3,string.char(\number#2))}}% + }% +%<*!context> +\else + \ifdefined\XeTeXversion + \def\collargs@insert@char#1#2#3{% + \edef\collargs@temp{\unexpanded{#1}}% + \expandafter\collargs@temp\Ucharcat #2 #3 + }% + \def\collargs@make@char#1#2#3{% + \edef#1{\Ucharcat#2 #3}% + }% + \else + %<*latex> + \ExplSyntaxOn + \def\collargs@insert@char#1#2#3{% + \edef\collargs@temp{\unexpanded{#1}}% + \expandafter\expandafter\expandafter\collargs@temp\char_generate:nn{#2}{#3}% + }% + \def\collargs@make@char#1#2#3{% + \edef#1{\char_generate:nn{#2}{#3}}% + }% + \ExplSyntaxOff + % + %<*plain> + % The implementation is inspired by |expl3|'s implementation of + % |\char_generate:nn|, but our implementation is not expandable, for + % simplicity. We first store an (arbitrary) character |^||^@| of category + % code $n$ into control sequence |\collargs@charofcat@|$n$, for every + % (implementable) category code. + \begingroup + \catcode`\^^@=1 \csgdef{collargs@charofcat@1}{% + \noexpand\expandafter^^@\iffalse}\fi} + \catcode`\^^@=2 \csgdef{collargs@charofcat@2}{\iffalse{\fi^^@} + \catcode`\^^@=3 \csgdef{collargs@charofcat@3}{^^@} + \catcode`\^^@=4 \csgdef{collargs@charofcat@4}{^^@} + % As we have grabbed the spaces already, a remaining newline should surely be + % fixed into a |\par|. + \csgdef{collargs@charofcat@5}{\par} + \catcode`\^^@=6 \csxdef{collargs@charofcat@6}{\unexpanded{^^@}} + \catcode`\^^@=7 \csgdef{collargs@charofcat@7}{^^@} + \catcode`\^^@=8 \csgdef{collargs@charofcat@8}{^^@} + \csgdef{collargs@charofcat@10}{\noexpand\space} + \catcode`\^^@=11 \csgdef{collargs@charofcat@11}{^^@} + \catcode`\^^@=12 \csgdef{collargs@charofcat@12}{^^@} + \catcode`\^^@=13 \csgdef{collargs@charofcat@13}{^^@} + \endgroup + \def\collargs@insert@char#1#2#3{% + % Temporarily change the lowercase code of |^||^@| to the requested character + % |#2|. + \begingroup + \lccode`\^^@=#2\relax + % We'll have to close the group before executing the next-code. + \def\collargs@temp{\endgroup#1}% + % |\collargs@charofcat@|\meta{requested category code} is f-expanded first, + % leaving us to lowercase |\expandafter\collargs@temp^||^@|. Clearly, + % lowercasing |\expandafter\collargs@temp| is a no-op, but lowercasing + % |^||^@| gets us the requested character of the requested category. + % |\expandafter| is executed next, and this gets rid of the conditional for + % category codes 1 and 2. + \expandafter\lowercase\expandafter{% + \expandafter\expandafter\expandafter\collargs@temp + \romannumeral-`0\csname collargs@charofcat@\the\numexpr#3\relax\endcsname + }% + } + % This macro cannot not work for category code 6 (because we assign the + % result to a macro), but no matter, we only use it for category code 12 + % anyway. + \def\collargs@make@char#1#2#3{% + \begingroup + \lccode`\^^@=#2\relax + % Define |\collargs@temp| to hold |^||^@| of the appropriate category. + \edef\collargs@temp{% + \csname collargs@charofcat@\the\numexpr#3\relax\endcsname}% + % Preexpand the second |\collargs@temp| so that we lowercase + % |\def\collargs@temp{^||^@}|, with |^||^@| of the appropriate category. + \expandafter\lowercase\expandafter{% + \expandafter\def\expandafter\collargs@temp\expandafter{\collargs@temp}% + }% + \expandafter\endgroup + \expandafter\def\expandafter#1\expandafter{\collargs@temp}% + } + % + \fi +\fi +% +% \end{macro} +% +%\resetatcatcode +%\stopmodule +%\protect +% \end{macrocode} +% +% Local Variables: +% TeX-engine: luatex +% TeX-master: "doc/memoize-code.tex" +% TeX-auto-save: nil +% End: \ No newline at end of file diff --git a/collargs.ins b/collargs.ins new file mode 100644 index 0000000..a8673b6 --- /dev/null +++ b/collargs.ins @@ -0,0 +1,33 @@ +%% collargs.ins +%% +%% This file is a part of CollArgs, a TeX package providing a command which can +%% determine the argument scope of any command whose argument structure +%% conforms to xparse's argument specification, available at +%% https://ctan.org/pkg/advice and https://github.com/sasozivanovic/advice. +%% +%% Copyright (c) 2023- Saso Zivanovic +%% (Sa\v{s}o \v{Z}ivanovi\'{c}) +%% +%% This work may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License, either version 1.3 of this license or (at your +%% option) any later version. The latest version of this license is in +%% http://www.latex-project.org/lppl.txt and version 1.3 or later is part of +%% all distributions of LaTeX version 2005/12/01 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Saso Zivanovic. +%% +%% The files belonging to this work and covered by LPPL are listed in +%% (/doc/generic/collargs/)FILES. +%% +\input docstrip.tex +\keepsilent +\preamble +\endpreamble +\askforoverwritefalse +\generate{% + \file{collargs.sty}{\from{collargs.dtx}{latex}}% + \file{collargs.tex}{\from{collargs.dtx}{plain}}% + \file{t-collargs.tex}{\from{collargs.dtx}{context}}% +} +\endbatchfile diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..3e4f8e6 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,5 @@ +*.listing.attachment +latexmkrc +_fn.tex +attachments.lst +*idx.orig diff --git a/doc/INSTALL.advice.md b/doc/INSTALL.advice.md new file mode 100644 index 0000000..96844ef --- /dev/null +++ b/doc/INSTALL.advice.md @@ -0,0 +1,69 @@ +# Installation from the TDS archive + +If Advice is not (yet) offered by your TeX distribution, the easiest way to +install it is by downloading the TDS archive `advice.tds.zip` from [Advice's +CTAN page](https://ctan.org/pkg/advice), and unpacking it into your `texmf` +directory. You will most likely also have to do the same for an auxiliary +package Advice depends on: [CollArgs](https://ctan.org/pkg/collargs). + +Read on only if you have an unstoppable urge to install from source and/or +compile the manual or the documented source code. + +# Installation from the source + +## Getting the sources + +There are several options: + +* Download and unpack the zip archive of the package from [Advice's CTAN + page](https://ctan.org/pkg/advice). + +* Download and unpack the TDS archive, or copy the files from your local + distribution. The sources reside in `/source/generic/advice`. + +* Clone the [GitHub repository of + Memoize](https://github.com/sasozivanovic/memoize). + +## Generating the runtime files + +The easiest way to generate the runtime files is by running `make`. The +following command will generate runtime files for all supported formats +(currently: LaTeX, plain TeX and ConTeXt). + +``` +make advice.sty +``` + +Alternatively, you can generate these files manually. The source of this +package was written using [EasyDTX](https://ctan.org/pkg/easydtx). Therefore, +you first have to convert the `.edtx` file into a regular `.dtx`: + +``` +edtx2dtx advice.edtx > advice.dtx +``` + +The next step is standard. Produce the runtime files by compiling the +installation file: + +``` +tex advice.ins +``` + +Finally, if you require the ConTeXt runtime, replace all instances of +`\expanded` and `\unexpanded` in `t-advice.tex` by `\normalexpanded` and +`\normalunexpanded`, respectively. One way to do this is: + +``` +sed -i -s -e 's/\\\(un\)\?expanded/\\normal\1expanded/g;' t-advice.tex +``` + +## Installation + +It is recommended to install the files into a TDS-compliant `texmf` directory, +as usual. Inspect file `FILES` or the TDS archive `advice.tds.zip` to see what +goes where. + +# Compiling the documentation + +The documentation of this package is integrated into the documentation of +[Memoize](https://ctan.org/pkg/memoize), please continue there. diff --git a/doc/INSTALL.collargs.md b/doc/INSTALL.collargs.md new file mode 100644 index 0000000..df93bc8 --- /dev/null +++ b/doc/INSTALL.collargs.md @@ -0,0 +1,68 @@ +# Installation from the TDS archive + +If CollArgs is not (yet) offered by your TeX distribution, the easiest way to +install it is by downloading the TDS archive `collargs.tds.zip` from +[CollArgs's CTAN page](https://ctan.org/pkg/collargs), and unpacking it into +your `texmf` directory. + +Read on only if you have an unstoppable urge to install from source and/or +compile the manual or the documented source code. + +# Installation from the source + +## Getting the sources + +There are several options: + +* Download and unpack the zip archive of the package from [CollArgs's CTAN + page](https://ctan.org/pkg/collargs). + +* Download and unpack the TDS archive, or copy the files from your local + distribution. The sources reside in `/source/generic/collargs`. + +* Clone the [GitHub repository of + Memoize](https://github.com/sasozivanovic/memoize). + +## Generating the runtime files + +The easiest way to generate the runtime files is by running `make`. The +following command will generate runtime files for all supported formats +(currently: LaTeX, plain TeX and ConTeXt). + +``` +make collargs.sty +``` + +Alternatively, you can generate these files manually. The source of this +package was written using [EasyDTX](https://ctan.org/pkg/easydtx). Therefore, +you first have to convert the `.edtx` file into a regular `.dtx`: + +``` +edtx2dtx collargs.edtx > collargs.dtx +``` + +The next step is standard. Produce the runtime files by compiling the +installation file: + +``` +tex collargs.ins +``` + +Finally, if you require the ConTeXt runtime, replace all instances of +`\expanded` and `\unexpanded` in `t-collargs.tex` by `\normalexpanded` and +`\normalunexpanded`, respectively. One way to do this is: + +``` +sed -i -s -e 's/\\\(un\)\?expanded/\\normal\1expanded/g;' t-collargs.tex +``` + +## Installation + +It is recommended to install the files into a TDS-compliant `texmf` directory, +as usual. Inspect file `FILES` or the TDS archive `collargs.tds.zip` to see +what goes where. + +# Compiling the documentation + +The documentation of this package is integrated into the documentation of +[Memoize](https://ctan.org/pkg/memoize), please continue there. diff --git a/doc/README.advice.md b/doc/README.advice.md new file mode 100644 index 0000000..0b001d9 --- /dev/null +++ b/doc/README.advice.md @@ -0,0 +1,8 @@ +Like its namesake from the Emacs world, package Advice implements a generic +framework for extending the functionality of selected commands and +environments. + +This package was developed as an auxiliary package of +[Memoize](https://ctan.org/pkg/memoize). This is why it is, somewhat +unconventionally, documented alongside that package. This applies to both the +manual and the documented code listing. diff --git a/doc/README.collargs.md b/doc/README.collargs.md new file mode 100644 index 0000000..f36abea --- /dev/null +++ b/doc/README.collargs.md @@ -0,0 +1,8 @@ +Package CollArgs provides a command which can determine the argument scope of +any command whose argument structure conforms to +[xparse](https://ctan.org/pkg/xparse)'s argument specification. + +This package was developed as an auxiliary package of +[Memoize](https://ctan.org/pkg/memoize). This is why it is, somewhat +unconventionally, documented alongside that package. This applies to both the +manual and the documented code listing. diff --git a/doc/README.memoize.md b/doc/README.memoize.md new file mode 100644 index 0000000..9acde7b --- /dev/null +++ b/doc/README.memoize.md @@ -0,0 +1,11 @@ +Memoize is a package for externalization of graphics and memoization of +compilation results in general, allowing the author to reuse the results of +compilation-intensive code. + +Memoize (i) induces very little overhead, as all externalized graphics is +produced in a single compilation. It features (ii) automatic recompilation upon +the change of code or user-adjustable context, and (iii) automatic +externalization of TikZ pictures and Forest trees, easily extensible to other +commands and environments. Furthermore, Memoize (iv) supports +cross-referencing, TikZ overlays and Beamer, (v) works with all major engines +and formats, and (vi) is adaptable to any workflow. diff --git a/doc/examples/.gitignore b/doc/examples/.gitignore new file mode 100644 index 0000000..5ad2257 --- /dev/null +++ b/doc/examples/.gitignore @@ -0,0 +1,6 @@ +* +!*.dtx +!ins.begin +!ins.mid +!ins.end +!*.gitignore diff --git a/doc/examples/ConTeXt.tex.dtx b/doc/examples/ConTeXt.tex.dtx new file mode 100644 index 0000000..7cddf11 --- /dev/null +++ b/doc/examples/ConTeXt.tex.dtx @@ -0,0 +1,11 @@ +\usemodule[memoize] + +%% ... + +\mmzset{~at begin document~} +\starttext + +Hello, \mmz{world}! + +\stoptext +\mmzset{~at end document~} diff --git a/doc/examples/Makefile b/doc/examples/Makefile new file mode 100644 index 0000000..f3e4fa6 --- /dev/null +++ b/doc/examples/Makefile @@ -0,0 +1,36 @@ +SHELL := /bin/bash +N = 1 + +.PRECIOUS: %.c1 + +%.ins: ins.begin ins.mid ins.end + sed 's|example|$*|g;' $< > $@ + cat ins.begin > $@ + for n in {1..$N} ; do sed "s|example|$*|g; s/c1/c$$n/g;" ins.mid >> $@ ; done + cat ins.end >> $@ + +%.c1: %.dtx %.ins + tex -interaction batchmode $*.ins + sed -i 's/~//g;' $*.c? $*.c?.attachment + echo $@ + +%.pdf: %.tex.c1 + cp $*.tex.c1 $*.tex + touch $*.mmz ; memoize-clean.py --all --yes $*.mmz + rm -f $*.mmz + latexmk -C $* + for n in {1..$N}; do cp $*.tex.c$$n $*.tex ; pdflatex -interaction batchmode $* ; cp $*.pdf $*.c$$n.pdf ; if [[ -a $*.mmz ]] ; then cp $*.mmz $*.mmz.c$$n ; fi ; done + +%.sty: %.sty.c1 + cp $*.sty.c$N $@ + +.ONESHELL: +%.excerpt: ${SOURCE} + perl -e '$$f=q{$*}; while(<>) {$$r &&= !/^ *% *\\\Qend{listingregion}/; print if $$r; $$r ||= /^ *% *\\\Qbegin{listingregion}{$$f}/; }' ${SOURCE} > $@ + +%.listing.attachment: %.listing + sed 's/~//g;' $< > $@ + +.PHONY: clean +clean: + find . -type f -not \( -name '*.dtx' -or -name 'ins.*' -or -name .gitignore -or -name Makefile \) -delete diff --git a/doc/examples/_auto-ref.tex.dtx b/doc/examples/_auto-ref.tex.dtx new file mode 100644 index 0000000..c7d7a8b --- /dev/null +++ b/doc/examples/_auto-ref.tex.dtx @@ -0,0 +1,5 @@ +\mmzset{auto/ref.style={outer handler=\mmz@auto@ref, run if memoizing}} +\def\mmz@auto@ref#1{% + \mmzNoRef{#1}% + \AdviceOriginal{#1}% +} diff --git a/doc/examples/_collargs-ignore-other-tags.tex.dtx b/doc/examples/_collargs-ignore-other-tags.tex.dtx new file mode 100644 index 0000000..5dd2bfd --- /dev/null +++ b/doc/examples/_collargs-ignore-other-tags.tex.dtx @@ -0,0 +1,7 @@ +%\CollectArguments +%\CollectArguments[~ignore other tags~] + {\NextCommand}{b{foo}} + ... + \end{bar} + ... +\end{foo} diff --git a/doc/examples/_collargs-verbatim.tex.dtx b/doc/examples/_collargs-verbatim.tex.dtx new file mode 100644 index 0000000..9527842 --- /dev/null +++ b/doc/examples/_collargs-verbatim.tex.dtx @@ -0,0 +1,6 @@ + ... + \begin{verbatim} + ... + \end{verbatim} + ... +\end{verbatim} diff --git a/doc/examples/automemoize-command.tex.dtx b/doc/examples/automemoize-command.tex.dtx new file mode 100644 index 0000000..fc94d51 --- /dev/null +++ b/doc/examples/automemoize-command.tex.dtx @@ -0,0 +1,12 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} +\usepackage{qrcode} +\usepackage{memoize} +% +\mmzset{auto=\qrcode{memoize, ~args=om~}} +%% ... +%\begin{document} +\qrcode{https://ctan.org/pkg/memoize} +\qrcode[height=1cm]{https://ctan.org/pkg/memoize} +%\end{document} diff --git a/doc/examples/automemoize-environment.tex.dtx b/doc/examples/automemoize-environment.tex.dtx new file mode 100644 index 0000000..6c6612c --- /dev/null +++ b/doc/examples/automemoize-environment.tex.dtx @@ -0,0 +1,14 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} +\usepackage{circuitikz} +\usepackage{memoize} +% +\mmzset{~auto={circuitikz}{memoize}~} +%\begin{document} +%% ... +\begin{circuitikz} + \draw (0,0) to[isource] (0,3) -- (2,3) + to[R] (2,0) -- (0,0); +\end{circuitikz} +%\end{document} diff --git a/doc/examples/beamer.tex.dtx b/doc/examples/beamer.tex.dtx new file mode 100644 index 0000000..a37d619 --- /dev/null +++ b/doc/examples/beamer.tex.dtx @@ -0,0 +1,27 @@ +~\RequirePackage~{memoize} +\documentclass{beamer} +%<*!lst> +\mode +{ + \usetheme[secheader]{Boadilla} +} + +\mmzset{include context in ccmemo} + +\usepackage{tikz} +\usetikzlibrary{shapes.geometric} +% +\tikzset{only/.code 2 args={\only<#1>{\pgfkeysalso{#2}}}} +%<*!lst> + +\begin{document} +\centering +% +\begin{frame}{A frame with a memoized Ti\emph{k}Z picture} + \begin{tikzpicture}[~/mmz/per overlay~] + \node[ellipse, fill=yellow, ~only={2}~{ + pin={[overlay, fill=red, pin edge={overlay, red}]60:An important remark!} + }]{An important concept}; + \end{tikzpicture} +\end{frame} +%\end{document} diff --git a/doc/examples/book.tex.dtx b/doc/examples/book.tex.dtx new file mode 100644 index 0000000..1e2718c --- /dev/null +++ b/doc/examples/book.tex.dtx @@ -0,0 +1,22 @@ +\documentclass{book} +\usepackage{docmute} + +\usepackage{memoize} +\mmzset{~memo dir=chapters/book~} + +\usepackage{tikz} + +\begin{document} + +\chapter{Introduction} +This example demonstrates how to share +memos and externs between the book and +the chapters. + +\chapter{A chapter} +\input{chapters/chapter1.tex} + +\chapter{Conclusion} +Easy, right? + +\end{document} diff --git a/doc/examples/chained-advice.tex.dtx b/doc/examples/chained-advice.tex.dtx new file mode 100644 index 0000000..04ca644 --- /dev/null +++ b/doc/examples/chained-advice.tex.dtx @@ -0,0 +1,15 @@ +%\documentclass[varwidth]{standalone} +%\documentclass{article} +%\usepackage{advice} + +\def\foo#1{``#1''} +\def\fboxWrap#1{\fbox{\AdviceOriginal{#1}}} +\def\parenWrap#1{(\AdviceOriginal{#1})} + +\pgfqkeys{~/one~}{.install advice, advice'=\foo{args=m, outer handler=~\fboxWrap~}} +\pgfqkeys{~/two~}{.install advice, advice'=\foo{args=m, outer handler=~\parenWrap~}} + +%\begin{document} +{\pgfkeys{~/one~/activate=\foo, ~/two~/activate=\foo}\foo{bar}} +{\pgfkeys{~/two~/activate=\foo, ~/one~/activate=\foo}\foo{bar}} +%\end{document} diff --git a/doc/examples/chapters/chapter1.tex.dtx b/doc/examples/chapters/chapter1.tex.dtx new file mode 100644 index 0000000..c737fd2 --- /dev/null +++ b/doc/examples/chapters/chapter1.tex.dtx @@ -0,0 +1,22 @@ +\documentclass{article} + +\usepackage{memoize} +\mmzset{~memo dir=book~} + +\usepackage{tikz} + +\begin{document} + +\begin{tikzpicture} + \node[ + text width=5cm, + align=flush left, + ] + {This picture can be externalized + by compiling the chapter (twice, + as we need to extract it as well). + The extern will be picked up + when compiling the book.}; +\end{tikzpicture} + +\end{document} diff --git a/doc/examples/clean-house.tex.dtx b/doc/examples/clean-house.tex.dtx new file mode 100644 index 0000000..f6b76c3 --- /dev/null +++ b/doc/examples/clean-house.tex.dtx @@ -0,0 +1,17 @@ +%<*!lst> +\documentclass{article} +\usepackage{tikz} + +\usepackage{memoize} +% +~\mmzset{memo dir}~ +%<*!lst> + +\begin{document} + +For this document, the auxiliary files produced by +\tikz \node[fill=yellow,draw=red]{Memoize}; +will reside in their own folder. + +\end{document} +% \ No newline at end of file diff --git a/doc/examples/collargs-makebox.tex.dtx b/doc/examples/collargs-makebox.tex.dtx new file mode 100644 index 0000000..89cd4e0 --- /dev/null +++ b/doc/examples/collargs-makebox.tex.dtx @@ -0,0 +1,11 @@ +%\documentclass{article} +%\usepackage{collargs} +\newcommand\PrintAndDo[2]{% + Executing \texttt{\string#1} with arguments ``\texttt{\detokenize{#2}}'' + yields ``#1#2''.\par +} +%\begin{document} +~\CollectArguments~{oom}{\PrintAndDo\makebox}[5em][r]{text} +~\CollectArguments~{oom}{\PrintAndDo\makebox}[5em]{text} +~\CollectArguments~{oom}{\PrintAndDo\makebox}{text} +%\end{document} diff --git a/doc/examples/collargs-minipage.tex.dtx b/doc/examples/collargs-minipage.tex.dtx new file mode 100644 index 0000000..1d80ab4 --- /dev/null +++ b/doc/examples/collargs-minipage.tex.dtx @@ -0,0 +1,13 @@ +%\documentclass{article} +%\usepackage{collargs} +\newcommand\PrintAndDoEnv[2]{% +% Executing environment ``#1'' with body ``\texttt{\detokenize{#2}}'' +% Executing environment ``#1'' with body ``\code{\detokenize{#2}}'' + yields \fbox{\begin{#1}#2\end{#1}}.\par +} +%\begin{document} +\CollectArguments[~environment=minipage~]{+~b~}{\PrintAndDoEnv{minipage}}[t]{6cm} + This forms the body of a minipage environment, even if it is not preceded by + \texttt{\string\begin\{minipage\}}.% +\end{minipage} +%\end{document} diff --git a/doc/examples/collargs-nodelimiters.tex.dtx b/doc/examples/collargs-nodelimiters.tex.dtx new file mode 100644 index 0000000..6169638 --- /dev/null +++ b/doc/examples/collargs-nodelimiters.tex.dtx @@ -0,0 +1,12 @@ +%\documentclass{article} +%\usepackage{collargs} +%\usepackage{xcolor} +%\long\def\ShowArguments#1{{\color{green!50!black}\tt\detokenize{#1}}} +%\begin{document} +before +\CollectArguments + {&{~no delimiters~, ~append postwrap={{{{#1}}}}~}o m} + \ShowArguments + [optional]{mandatory} +after +%\end{document} diff --git a/doc/examples/collargs-processor.tex.dtx b/doc/examples/collargs-processor.tex.dtx new file mode 100644 index 0000000..009c00d --- /dev/null +++ b/doc/examples/collargs-processor.tex.dtx @@ -0,0 +1,24 @@ +%<*att> +\documentclass{article} +\usepackage{collargs} + +% +\newwrite\argfile +\newcommand\writetofile[2]{% + \immediate\openout\argfile{#1}% + \newlinechar=13 + \immediate\write\argfile{#2}% + \immediate\closeout\argfile + \collargsArg={\input{#1}}% +} +% +%\begin{document} +% +We write the argument of \verb!\footnote! into a file,% +\CollectArguments{ + &{verbatim, ~append preprocessor=\writetofile{_fn.tex}~, no delimiters} + m +}{\footnote}{This footnote was read from a file by command \verb!\input!, + so it may contain verbatim material!} and then read it back in. +% +%\end{document} diff --git a/doc/examples/collargs-transition-comment.tex.dtx b/doc/examples/collargs-transition-comment.tex.dtx new file mode 100644 index 0000000..13bbbac --- /dev/null +++ b/doc/examples/collargs-transition-comment.tex.dtx @@ -0,0 +1,14 @@ +%\documentclass{article} +%\usepackage{collargs} +%\usepackage{xcolor} +%\long\def\ShowArgs#1{Collected: ``{\color{red}\tt\detokenize{#1}}''} +% +%\begin{document} +% +\CollectArguments{o&{verbatim}m}{\ShowArgs}[opt]% comment +{more text} + +\CollectArguments{o&{verbatim}m}{\ShowArgs}% comment +{more text} +% +%\end{document} \ No newline at end of file diff --git a/doc/examples/collargs-transition-cs.tex.dtx b/doc/examples/collargs-transition-cs.tex.dtx new file mode 100644 index 0000000..43dd601 --- /dev/null +++ b/doc/examples/collargs-transition-cs.tex.dtx @@ -0,0 +1,14 @@ +%\documentclass{article} +%\usepackage{collargs} +%\usepackage{xcolor} +%\long\def\ShowArgs#1{Collected: ``{\color{red}\tt\detokenize{#1}}''} +% +% +%\author{Sa\v so \v Zivanovi\'c} +% +%\begin{document} +% +\makeatletter\@author\makeatother\par +\CollectArguments[verbatim]{o}{\ShowArgs}~\~makeatletter~\@~author\makeatother +% +%\end{document} diff --git a/doc/examples/collargs-transition-ok.tex.dtx b/doc/examples/collargs-transition-ok.tex.dtx new file mode 100644 index 0000000..8569a09 --- /dev/null +++ b/doc/examples/collargs-transition-ok.tex.dtx @@ -0,0 +1,10 @@ +%\documentclass{article} +%\usepackage{collargs} +%\usepackage{xcolor} +%\long\def\ShowArgs#1{Collected: ``{\color{red}\tt\detokenize{#1}}''} +% +%\begin{document} +% +\CollectArguments[verbatim]{o}{\ShowArgs}~$~2^2=4$ +% +%\end{document} \ No newline at end of file diff --git a/doc/examples/collargs-verbatim.tex.dtx b/doc/examples/collargs-verbatim.tex.dtx new file mode 100644 index 0000000..90916ed --- /dev/null +++ b/doc/examples/collargs-verbatim.tex.dtx @@ -0,0 +1,11 @@ +%\documentclass{article} +%\usepackage{collargs} +%\usepackage{verbatim} +\newcommand\PrintAndDoEnv[1]{% + Executing \texttt{#1} yields this: ~\scantokens~{#1} +} +%\begin{document} +\CollectArguments[environment=verbatim, ~verbatim~, ~tags~]{+b}{\PrintAndDoEnv} + Here is some \LaTeX{} code. +\end{verbatim} +%\end{document} diff --git a/doc/examples/countdown.sty.dtx b/doc/examples/countdown.sty.dtx new file mode 100644 index 0000000..35a3c2b --- /dev/null +++ b/doc/examples/countdown.sty.dtx @@ -0,0 +1,71 @@ +%% This file should be saved as "countdown.sty". +%<*!lst,c1> +\ProvidesPackage{countdown} +\RequirePackage{memoizable} + +%% ... +% +% +%<*!lst>% +\newbox\countdownbox +\newcount\countdowncount + +\def\countdown#1{% + \countdowncount=#1\relax + \edef\countdownpagetotal{\the\pagetotal}% + \countdowni +} + +\def\countdowni{% + \ifnum\countdowncount=0 + \countdowntypeset + \else + \expandafter\countdownii + \fi +} + +\def\leaderfill{\leaders\hbox to 0.25em{\hss.\hss}\hfill} +\def\countdownii{% + \setbox0=\hbox to \linewidth{\leaderfill\strut\the\countdowncount\leaderfill}% + \ifdim\dimexpr\ht\countdownbox+\dp\countdownbox+\ht0+\dp0\relax + >\dimexpr\textheight-\countdownpagetotal\relax + \def\countdownpagetotal{0pt}% + \countdowntypeset + \fi + \setbox\countdownbox=\vbox{\unvbox\countdownbox\box0}% + \advance\countdowncount -1 + \countdowni +} + +% +%~\newif\ifmemoizingcountdown~ +\def\countdowntypeset{% +% ~\IfMemoizing~{countdown}{% +% ~\ifmemoizingcountdown~ + \mmzExternalizeBox\countdownbox{\toks0}% + \xtoksapp\mmzCCMemo{\the\toks0}% +% }{}% +% \fi + \noindent\box\countdownbox\par +} + +%<*c1> +\def\countdowndriver#1{% + ~\memoizingcountdowntrue~ + #1% +} + +% +\mmzset{ +%% trace context, include context in ccmemo, + auto=\countdown{ + args=m, memoize, +% ~integrated driver~=countdown, +% ~driver~=\countdowndriver, +%<*!lst,c1> + context={fsize=\csname f@size\endcsname,textheight=\the\textheight}, + options={context/.expanded={pagetotal=\the\pagetotal}}, + }, +} +% +% % ... \ No newline at end of file diff --git a/doc/examples/countdown.tex.dtx b/doc/examples/countdown.tex.dtx new file mode 100644 index 0000000..1ac1a1f --- /dev/null +++ b/doc/examples/countdown.tex.dtx @@ -0,0 +1,16 @@ +%<*!lst> +\documentclass{article} +\usepackage[a6paper,margin=5mm]{geometry} +\pagestyle{empty} +\usepackage{lipsum} + +\usepackage{memoize} +\usepackage{countdown} + +\parskip 2ex +\begin{document} +%% +\lipsum[66]\par +{\Huge\countdown{30}}\par +\lipsum[66]\par +%\end{document} diff --git a/doc/examples/dirty-house.tex.dtx b/doc/examples/dirty-house.tex.dtx new file mode 100644 index 0000000..0f1e9ea --- /dev/null +++ b/doc/examples/dirty-house.tex.dtx @@ -0,0 +1,17 @@ +%<*!lst> +\documentclass{article} +\usepackage{tikz} + +\usepackage{memoize} +% +%~\mmzset{no memo dir}~ +%<*!lst> + +\begin{document} + +For this document, the auxiliary files produced by +\tikz \node[fill=yellow,draw=red]{Memoize}; +will reside in the same folder as the source. + +\end{document} +% diff --git a/doc/examples/disable-auto-cmd.tex.dtx b/doc/examples/disable-auto-cmd.tex.dtx new file mode 100644 index 0000000..3be31ea --- /dev/null +++ b/doc/examples/disable-auto-cmd.tex.dtx @@ -0,0 +1,10 @@ +%\documentclass{article} +%\usepackage{memoize} +\mmzset{auto=\foo{args=m, ~nomemoize~}} +%\begin{document} +%% ... +\foo{...} +%% ... +\foo{...} +%% ... +%\end{document} diff --git a/doc/examples/disable-auto-env.tex.dtx b/doc/examples/disable-auto-env.tex.dtx new file mode 100644 index 0000000..1b9d306 --- /dev/null +++ b/doc/examples/disable-auto-env.tex.dtx @@ -0,0 +1,10 @@ +%\documentclass{article} +%\usepackage{memoize} +\mmzset{auto={bar}{~nomemoize~}} +%\begin{document} +%% ... +\begin{bar} + % ... +\end{bar} +%% ... +%\end{document} diff --git a/doc/examples/disable-bad.tex.dtx b/doc/examples/disable-bad.tex.dtx new file mode 100644 index 0000000..eb7f9ab --- /dev/null +++ b/doc/examples/disable-bad.tex.dtx @@ -0,0 +1,11 @@ +%\documentclass{article} +\usepackage{memoize} +~\mmzset{disable}~ +\begin{document} +%% ... +~\mmzset{disable}~ +%% ... +%% ... +~\mmzset{enable}~ +%% ... +\end{document} diff --git a/doc/examples/disable-good.tex.dtx b/doc/examples/disable-good.tex.dtx new file mode 100644 index 0000000..b178ce3 --- /dev/null +++ b/doc/examples/disable-good.tex.dtx @@ -0,0 +1,12 @@ +%\documentclass{article} +\usepackage{memoize} +~\mmzset{disable}~ +\begin{document} +%% ... +~{~ + % ... + ~\mmzset{disable}~ + % ... +~}~ +%% ... +\end{document} diff --git a/doc/examples/disable-nomemoize.tex.dtx b/doc/examples/disable-nomemoize.tex.dtx new file mode 100644 index 0000000..931ccb7 --- /dev/null +++ b/doc/examples/disable-nomemoize.tex.dtx @@ -0,0 +1,7 @@ +%\documentclass{article} +%\usepackage{memoize} +%\begin{document} +~\begin{nomemoize}~ +% % ... +~\end{nomemoize}~ +%\end{document} diff --git a/doc/examples/disable-nommz.tex.dtx b/doc/examples/disable-nommz.tex.dtx new file mode 100644 index 0000000..2469f76 --- /dev/null +++ b/doc/examples/disable-nommz.tex.dtx @@ -0,0 +1,7 @@ +%\documentclass{article} +%\usepackage{memoize} +%\begin{document} +%% ... +~\nommz{...}~ +%% ... +%\end{document} diff --git a/doc/examples/disable.tex.dtx b/doc/examples/disable.tex.dtx new file mode 100644 index 0000000..82d4d28 --- /dev/null +++ b/doc/examples/disable.tex.dtx @@ -0,0 +1,23 @@ +%<*!lst> +%\documentclass[varwidth=0.4\linewidth]{standalone} +%\documentclass{article} + +\usepackage{tikz} +\usepackage{memoize} + +\begin{document} +\small + +% +\tikz\node[draw=green]{An externalized node.}; +~{~ + \mmzset{~disable~} + \tikz\node[draw=red]{ + This node is not externalized.}; + \tikz\node[draw=red]{ + And neither is this one.}; +~}~ +\tikz\node[draw=green]{ + Another externalized node}; + +%\end{document} diff --git a/doc/examples/fontsize.tex.dtx b/doc/examples/fontsize.tex.dtx new file mode 100644 index 0000000..f4cf5d3 --- /dev/null +++ b/doc/examples/fontsize.tex.dtx @@ -0,0 +1,24 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} +\usepackage{tikz} +\usepackage{memoize} + +% +\mmzset{~context~={fsize={\csname f@size\endcsname}}} +%<*!lst> + +\begin{document} + +%%\small % uncomment for v2 +% +%~\small~ +\begin{tikzpicture} +%<*!lst,c1> + \node[text width=8em, align=center, fill=yellow] + {This picture is sensitive to the current font size.}; +% +% % ... +\end{tikzpicture} + +%\end{document} diff --git a/doc/examples/ins.begin b/doc/examples/ins.begin new file mode 100644 index 0000000..46fbef5 --- /dev/null +++ b/doc/examples/ins.begin @@ -0,0 +1,6 @@ +\input docstrip.tex +\keepsilent +\nopreamble +\nopostamble +\askforoverwritefalse +\generate{% diff --git a/doc/examples/ins.end b/doc/examples/ins.end new file mode 100644 index 0000000..1d3073b --- /dev/null +++ b/doc/examples/ins.end @@ -0,0 +1,2 @@ +} +\endbatchfile diff --git a/doc/examples/ins.mid b/doc/examples/ins.mid new file mode 100644 index 0000000..bbd555f --- /dev/null +++ b/doc/examples/ins.mid @@ -0,0 +1,3 @@ + \file{example.c1}{\from{example.dtx}{c1,t}}% + \file{example.c1.listing}{\from{example.dtx}{c1,lst,t}}% + \file{example.c1.attachment}{\from{example.dtx}{c1,att,t}}% diff --git a/doc/examples/label+.tex.dtx b/doc/examples/label+.tex.dtx new file mode 100644 index 0000000..e449ae4 --- /dev/null +++ b/doc/examples/label+.tex.dtx @@ -0,0 +1,90 @@ +%<*!lst> +%\documentclass[varwidth,margin={0pt 0pt 0pt 5pt}]{standalone} +%\documentclass{article} + +\makeatletter +\newcounter{counti} +\newenvironment{listi}{% + \setcounter{counti}{0}% + \def\item{% + \par\strut + \stepcounter{counti}% + \edef\@currentlabel{\thecounti}% + \thecounti. + }% +}{\par} + +\newcounter{countii} +\gdef\thecountii{\alph{countii}} +\newenvironment{listii}{% + \setcounter{countii}{0}% + \def\item{% + \par\strut + \stepcounter{countii}% +% \edef\@currentlabel{\thecounti\thecountii}% +% \edef\@currentlabel{\unexpanded{\thecounti}\thecountii}% + \quad\thecountii) + }% +}{\par} +\makeatother + +\usepackage{memoize} +% +%<*!c2> +\mmzset{ + auto={listii}{memoize, +% % ... +%<*c6,!lst> + capture=vbox, + at begin memoization={% + \csuse{par}\gtoksapp\mmzCCMemo{\csuse{par}}% +%<*c6> + \AdviceSetup{/mmz}\label{% + \preto\AdviceOuterHandler{% + \gappto\mmzAtEndMemoizationExtra{\outerlabeltocontext} + }% + }% +% + }, +% +% context={@currentlabel={\csuse{@currentlabel}}}, + }, +} +% +%<*c6> +\def\outerlabeltocontext{% + \gtoksapp\mmzContextExtra{@currentlabel={\csuse{@currentlabel}}}% + \let\outerlabeltocontext\relax +} +% +% +%<*!(c6&lst)> +%% ... +%\begin{document} +% +\begin{listi} +%\item pets: +%\item\label{item:pets} pets: + \begin{listii} +% \item\label{item:dog} dog +% \item\label{item:dog}\mmzNoRef{item:pets} dog +% % ... +%<*!lst> + \item cat + \end{listii} +\item domestic: + \begin{listii} + \item cow + \item sheep + \end{listii} +\item wild: + \begin{listii} + \item tiger + \item lion + \end{listii} +% +\end{listi} +The dog can be found in (\ref{item:dog}). +% +%\end{document} +% diff --git a/doc/examples/label.tex.dtx b/doc/examples/label.tex.dtx new file mode 100644 index 0000000..c0ffca9 --- /dev/null +++ b/doc/examples/label.tex.dtx @@ -0,0 +1,32 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} +\usepackage{memoize} +\usepackage{tikzlings} + +%% Uncomment this if you dare! +%% \mmzset{ +%% recompile, % for the first compilation +%% deactivate=\label, +%% } + +\begin{document} + +% +The titlepage Ti\emph{k}Zlings are: + +~\begin{memoize}~ + \begin{minipage}{5em} + \tikzset{x=1.3ex, y=1.3ex, baseline=0.5ex}% + \begin{enumerate} + \item~\label{item:penguin}~ \tikz\penguin; + \item\label{item:koala} \tikz\koala; + \item\label{item:owl} \tikz\owl; + \end{enumerate} + \end{minipage} +~\end{memoize}~ + +%\medskip +The penguin lives in item ~\ref{item:penguin}~. + +%\end{document} diff --git a/doc/examples/manual.tex.dtx b/doc/examples/manual.tex.dtx new file mode 100644 index 0000000..bc29945 --- /dev/null +++ b/doc/examples/manual.tex.dtx @@ -0,0 +1,19 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} +\usepackage{circuitikz} +\usepackage{qrcode} +\usepackage{memoize} + +\begin{document} +% +~\begin{memoize}~ + \begin{circuitikz} + \draw (0,0) + to[isource] (0,3) -- (2,3) + to[R] (2,0) -- (0,0); + \end{circuitikz} +~\end{memoize}~ +%% ... +~\mmz~{\qrcode{https://ctan.org/pkg/memoize}} +%\end{document} \ No newline at end of file diff --git a/doc/examples/meaning-to-context.tex.dtx b/doc/examples/meaning-to-context.tex.dtx new file mode 100644 index 0000000..c7de00b --- /dev/null +++ b/doc/examples/meaning-to-context.tex.dtx @@ -0,0 +1,27 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} + +\usepackage{tikz} +\usepackage{memoize} + +% +%% Changing definition +%\newcommand\answer{24} +%\newcommand\answer{~42~} +%% and/or +%\mmznext{~meaning to context~=\answer} +%\tikzset{ +% emph/.style={fill=red, text=blue}, +% emph/.style={fill=~yellow~, text=blue}, +%% leads to recompilation of the extern. +% emph/~.meaning to context~, +%} +% +%\begin{document} +%<*!lst,c1> +\begin{tikzpicture} + \node[emph]{The answer is \answer!}; +\end{tikzpicture} +% +%\end{document} diff --git a/doc/examples/memoize-internal.tex.dtx b/doc/examples/memoize-internal.tex.dtx new file mode 100644 index 0000000..5c83340 --- /dev/null +++ b/doc/examples/memoize-internal.tex.dtx @@ -0,0 +1,15 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} +\usepackage{memoize} + +\begin{document} +% +%% The following line internally invokes +%% \Memoize{Will this get memoized?}{Will this get memoized?} +\mmz{Will this get memoized?} + +\begingroup +\Memoize{Will this get memoized?}{Something entirely different got memoized!} +%% \endgroup % Don't uncomment! \Memoize already closed this group! +%\end{document} \ No newline at end of file diff --git a/doc/examples/memoize.cfg._region_.tex.dtx b/doc/examples/memoize.cfg._region_.tex.dtx new file mode 100644 index 0000000..8616f79 --- /dev/null +++ b/doc/examples/memoize.cfg._region_.tex.dtx @@ -0,0 +1,23 @@ +%% The contents of this file belong into "memoize.cfg". +\edef\regionfilename{\detokenize{_region_}} +\def\ifregion{% + \edef\jobfilename{\jobname}% + \ifx\jobfilename\regionfilename + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi +} +\ifregion{% + \mmzset{readonly}% +% % Automatically adapt "memo dir" to the real document: +% % (This assumes that "memo dir" is in effect for that document!) + \begingroup + \openin0{\regionfilename.tex}\readline0 to \regionheader \closein0 + \edef\temp{##1\detokenize{(}##2\detokenize{.tex)}##3}% + \expandafter\def\expandafter\parseregionheader\temp\endregionheader{% + \endgroup + \mmzset{memo dir=#2}% + }% + \expandafter\parseregionheader\regionheader\endregionheader +}{} diff --git a/doc/examples/memoize.cfg.dtx b/doc/examples/memoize.cfg.dtx new file mode 100644 index 0000000..4db3f4a --- /dev/null +++ b/doc/examples/memoize.cfg.dtx @@ -0,0 +1,5 @@ +\mmzset{ + memo dir, % Put the memo and extern files into a subdirectory. + extract=python, % Use the Python-based extern extraction method. + memoize=circuitikz, % Are you working on electrical circuits all the time? +} diff --git a/doc/examples/mmztikz.tex.dtx b/doc/examples/mmztikz.tex.dtx new file mode 100644 index 0000000..29225f3 --- /dev/null +++ b/doc/examples/mmztikz.tex.dtx @@ -0,0 +1,24 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} +\usepackage{tikz} +\usepackage{memoize} + +\tikzset{ + every node/.style={ + text width=7em, align=center, + fill,top color=white, bottom color=blue!20, + alias=last, + }, + every picture/.style={baseline=(last.base)}, +} + +% +\mmzset{deactivate=\tikz} +\newcommand{~\mmztikz~}[2][]{~\mmz~{% + \tikz[#1]{#2}% +}} +%\begin{document} +Compare ~\tikz~{\node{this picture which \emph{won't} be externalized};} to +~\mmztikz~{\node{this picture which \emph{will} be externalized}} +%\end{document} diff --git a/doc/examples/no-linebreaking.tex.dtx b/doc/examples/no-linebreaking.tex.dtx new file mode 100644 index 0000000..936b0a0 --- /dev/null +++ b/doc/examples/no-linebreaking.tex.dtx @@ -0,0 +1,12 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} +\documentclass[varwidth]{standalone} +\usepackage{lipsum} +\usepackage{memoize} +\begin{document} +% +%Here's some externalized text: ~\mmz~{\emph{\lipsum[66]}} +%Here's some externalized text: \emph{\lipsum[66]} +As you can see, the text is not integrated into the paragraph. +%\end{document} diff --git a/doc/examples/om-collector-NewDocumentCommand.tex.dtx b/doc/examples/om-collector-NewDocumentCommand.tex.dtx new file mode 100644 index 0000000..0417e7c --- /dev/null +++ b/doc/examples/om-collector-NewDocumentCommand.tex.dtx @@ -0,0 +1,19 @@ +%<*!lst> +\documentclass{article} +\usepackage{xcolor} +\usepackage{memoize} + +% +\NewDocumentCommand\omCollector{om}{% the collector + \IfValueTF{#1}{\AdviceInnerHandler~{[#1]{#2}}}~{\AdviceInnerHandler~{{#2}}}~} +%<*!lst> + +\newcommand\foo[2][green]{\textcolor{#1}{``#2''}\\}% the advised command +\mmzset{auto=\foo{memoize, collector=\omCollector}}% the advice + +\begin{document} +\foo[red]{red memoized text} +\foo[green]{memoized text of the default color} +\foo{memoized text of the default color} +\end{document} +% diff --git a/doc/examples/om-collector-newcommand.tex.dtx b/doc/examples/om-collector-newcommand.tex.dtx new file mode 100644 index 0000000..ce0b3f8 --- /dev/null +++ b/doc/examples/om-collector-newcommand.tex.dtx @@ -0,0 +1,17 @@ +%<*!lst> +\documentclass{article} +\usepackage{xcolor} +\usepackage{memoize} + +% +\newcommand\omCollector[2][~green~]{% the collector + \AdviceInnerHandler{[#1]{#2}}} + +\newcommand\foo[2][~green~]{\textcolor{#1}{``#2''}\\}% the advised command +\mmzset{auto=\foo{memoize, collector=\omCollector}}% the advice + +\begin{document} +\foo[red]{red memoized text} +\foo[green]{memoized text of the default color} +\foo{memoized text of the default color} +\end{document} diff --git a/doc/examples/overlay.tex.dtx b/doc/examples/overlay.tex.dtx new file mode 100644 index 0000000..24a8091 --- /dev/null +++ b/doc/examples/overlay.tex.dtx @@ -0,0 +1,37 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} +\usepackage{memoize} +\usepackage{tikz,lipsum} +\setlength{\textfloatsep}{2ex} + +\begin{document} + +% +%\mmznext{disable} +%\mmznext{~padding=0pt~} +%\mmznext{~padding=1in~} % this is the default +%\mmznext{~padding right=1in+4em~} +%<*!lst,c1> +\begin{figure} + \centering + \begin{tikzpicture} + \node[align=center, text width=0.4\linewidth, draw=blue, thick, pin={ + [~overlay~, pin edge={~overlay~}, green!50!black] east:an \texttt{overlay}ed pin} + ]{To horizontally center this node (rather than the entire picture), + we make \TeX{} ignore the pin by \texttt{overlay}ing it.}; + \end{tikzpicture} +% \caption{Without memoization} +% \caption{No padding} +% \caption{The default padding} +% \caption{With extra padding (on the right)} +\end{figure} +\lipsum[66] +% +% +%\end{document} +%<*lst&c2> +\begin{tikzpicture} + % ... +\end{tikzpicture} +% diff --git a/doc/examples/per-overlay-v1.sty.dtx b/doc/examples/per-overlay-v1.sty.dtx new file mode 100644 index 0000000..5cad73c --- /dev/null +++ b/doc/examples/per-overlay-v1.sty.dtx @@ -0,0 +1,13 @@ +\mmzset{ + per overlay/.style={ + /mmz/~context~={overlay=\csname ~beamer@overlaynumber~\endcsname}, + /mmz/at begin memoization={% + \xtoksapp~\mmzCMemo~{% + \gdef\noexpand~\mmzBeamerOverlays~{\beamer@overlaynumber}% + }% + \gtoksapp~\mmzCCMemo~{% + \only<~\mmzBeamerOverlays~>{}% + }% + }, + } +} diff --git a/doc/examples/pgfmathparse-embellished.tex.dtx b/doc/examples/pgfmathparse-embellished.tex.dtx new file mode 100644 index 0000000..0693188 --- /dev/null +++ b/doc/examples/pgfmathparse-embellished.tex.dtx @@ -0,0 +1,25 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} + +\usepackage{pgfmath} +\usepackage{memoize} + +% +\def\mmzSmuggleOneDriver#1#2{% #1 = the macro to smuggle, #2 = the memoized code + #2% + \xtoksapp\mmzCCMemo{\def\noexpand#1{#1}}% + \xappto\mmzAfterMemoizationExtra{\the\mmzCCMemo}% +} +\mmzset{ + auto=\pgfmathparse{ + args=m, memoize, + clear context, + driver=\mmzSmuggleOneDriver\pgfmathresult, + }, +} +% +%\begin{document} +\pgfmathparse{6*7}% +$6*7=\pgfmathresult$ +%\end{document} diff --git a/doc/examples/pgfmathparse.tex.dtx b/doc/examples/pgfmathparse.tex.dtx new file mode 100644 index 0000000..b8020f3 --- /dev/null +++ b/doc/examples/pgfmathparse.tex.dtx @@ -0,0 +1,18 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} + +\usepackage{pgfmath} +\usepackage{memoize} + +% +\def\mmzPgfmathDriver#1{% + #1% + \xtoksapp\mmzCCMemo{\def\noexpand\pgfmathresult{\pgfmathresult}}% + \xappto\mmzAfterMemoizationExtra{\def\noexpand\pgfmathresult{\pgfmathresult}}% +} +% +%\begin{document} +\mmz[driver=\mmzPgfmathDriver]{\pgfmathparse{6*7}}% +$6*7=\pgfmathresult$ +%\end{document} diff --git a/doc/examples/plainTeX.tex.dtx b/doc/examples/plainTeX.tex.dtx new file mode 100644 index 0000000..6fa0b1b --- /dev/null +++ b/doc/examples/plainTeX.tex.dtx @@ -0,0 +1,12 @@ +\input memoize +\mmzset{~extract~} + +%% ... + +\mmzset{~at begin document~} + +Hello, \mmz{world}! + +\mmzset{~at end document~} + +\bye diff --git a/doc/examples/poormansbox-driver.sty.dtx b/doc/examples/poormansbox-driver.sty.dtx new file mode 100644 index 0000000..84de2ac --- /dev/null +++ b/doc/examples/poormansbox-driver.sty.dtx @@ -0,0 +1,51 @@ +%<*!lst> +\ProvidesPackage{poormansbox-driver} +\RequirePackage{memoizable} + +\newcommand\pmbset[1]{\pgfqkeys{/pmb}{#1}} +\pmbset{ + width/.store in=\pmb@width, + frame/.is if=pmb@frame, + before/.store in=\pmb@before, + after/.store in=\pmb@after, +} +\def\pmb@width{\linewidth} +\newif\ifpmb@frame +\def\pmb@before{} +\def\pmb@after{} + +% +\NewDocumentEnvironment{poormansbox}{% the environment + o % the options + +b % the environment body +}{% + \poormansbox@outer{#1}{\poormansbox@inner{#1}{#2}}% +}{} + +\def\poormansbox@outer#1#2{% the outer command + \pmbset{#1}% apply the options + \pmb@before % the pre-code + #2% this will be either the inner command, or |\mmzIncludeExtern| + \pmb@after % the post-code +} +\def\poormansbox@inner#1#2{% the inner command + \setbox0=\hbox{% typeset our product into a box + \ifpmb@frame\expandafter\fbox\else\expandafter\@firstofone\fi + {% + \begin{minipage}{\pmb@width}% + #2% + \end{minipage}% + }% + }% + \IfMemoizing[1]{pmb}{% if memoizing the this instance of poormansbox + \mmzExternalizeBox0{\toks0}% externalize the box + \xtoksapp\mmzCCMemo{% append to cc-memo + \noexpand\csuse{poormansbox@outer}% call the outer command + {\unexpanded{#1}}% the options + {\the\toks0}% the extern-inclusion code (|\mmzIncludeExtern...|) + }% + }{}% + \quitvmode + \box0 % put the extern box into the document +} +\mmzset{auto={poormansbox}{memoize, integrated driver=pmb}} diff --git a/doc/examples/poormansbox-driver.tex.dtx b/doc/examples/poormansbox-driver.tex.dtx new file mode 100644 index 0000000..78eb0ff --- /dev/null +++ b/doc/examples/poormansbox-driver.tex.dtx @@ -0,0 +1,44 @@ +%<*!lst> +\documentclass{article} +\usepackage[a5paper,margin=1cm,noheadfoot]{geometry} +\pagestyle{empty} +\usepackage{lipsum} + +%% This document works with all the poormanbox packages developed in the +%% manual. Uncomment the one one you want to test. Also feel free to remove the +%% line loading Memoize, all poormanbox packages should work without it, even if +%% they support it. + +\usepackage{memoize} + +%% \usepackage{poormansbox} +%% \usepackage{poormansbox-memoizable} +\usepackage{poormansbox-driver} + +% +\parskip 1ex plus 0.5ex minus 0.5ex + +\begin{document} +\lipsum[3] + +\begin{~poormansbox~}[width=.8\linewidth] + ~\pmbset~{width=\linewidth} + \lipsum[101] + \begin{~poormansbox~}[frame] + \footnotesize\lipsum[66] + \end{~poormansbox~} + \lipsum[75] +\end{~poormansbox~} + +\lipsum[4] + +\begin{~poormansbox~}[ + width=.6\linewidth, frame, + before=\noindent\llap{---}, + after=--- + ] + \lipsum[65] +\end{~poormansbox~}Framed. + +\lipsum[144] +\end{document} diff --git a/doc/examples/poormansbox-memoizable.sty.dtx b/doc/examples/poormansbox-memoizable.sty.dtx new file mode 100644 index 0000000..5b603c4 --- /dev/null +++ b/doc/examples/poormansbox-memoizable.sty.dtx @@ -0,0 +1,34 @@ +%<*!lst> +\ProvidesPackage{poormansbox-memoizable} +\RequirePackage{pgfkeys} + +\newcommand\pmbset[1]{\pgfqkeys{/pmb}{#1}\ignorespaces} +\newif\ifpmb@frame +\pmbset{ + frame/.is if=pmb@frame, + width/.store in=\pmb@width, width=\linewidth, + before/.store in=\pmb@before, before=\vskip 2ex plus 1ex minus 1ex \centering, + after/.store in=\pmb@after, after=\vskip 2ex plus 1ex minus 1ex, +} + +% +\NewDocumentEnvironment{poormansbox}{ o +b }{% the outer part of the definition + \pmbset{#1}% + \pmb@before + \@poormansbox[#1]{#2}% + \pmb@after +}{} + +\newcommand~\@poormansbox~[2][]{% the inner part of the definition + \ifpmb@frame\expandafter\fbox\else\expandafter\@firstofone\fi{% + \begin{minipage}{\pmb@width}% + #2% + \end{minipage}% + }% +} + +\mmzset{ + auto=~\@poormansbox~{% submit the *inner* command to automemoization + args=om, memoize, + }, +} diff --git a/doc/examples/poormansbox-memoizable.tex.dtx b/doc/examples/poormansbox-memoizable.tex.dtx new file mode 100644 index 0000000..d774dac --- /dev/null +++ b/doc/examples/poormansbox-memoizable.tex.dtx @@ -0,0 +1,44 @@ +%<*!lst> +\documentclass{article} +\usepackage[a5paper,margin=1cm,noheadfoot]{geometry} +\pagestyle{empty} +\usepackage{lipsum} + +%% This document works with all the poormanbox packages developed in the +%% manual. Uncomment the one one you want to test. Also feel free to remove the +%% line loading Memoize, all poormanbox packages should work without it, even if +%% they support it. + +\usepackage{memoize} + +%% \usepackage{poormansbox} +\usepackage{poormansbox-memoizable} +%% \usepackage{poormansbox-driver} + +% +\parskip 1ex plus 0.5ex minus 0.5ex + +\begin{document} +\lipsum[3] + +\begin{~poormansbox~}[width=.8\linewidth] + ~\pmbset~{width=\linewidth} + \lipsum[101] + \begin{~poormansbox~}[frame] + \footnotesize\lipsum[66] + \end{~poormansbox~} + \lipsum[75] +\end{~poormansbox~} + +\lipsum[4] + +\begin{~poormansbox~}[ + width=.6\linewidth, frame, + before=\noindent\llap{---}, + after=--- + ] + \lipsum[65] +\end{~poormansbox~}Framed. + +\lipsum[144] +\end{document} diff --git a/doc/examples/poormansbox.sty.dtx b/doc/examples/poormansbox.sty.dtx new file mode 100644 index 0000000..be17e86 --- /dev/null +++ b/doc/examples/poormansbox.sty.dtx @@ -0,0 +1,25 @@ +\ProvidesPackage{poormansbox} +\RequirePackage{pgfkeys} + +\newcommand~\pmbset~[1]{\pgfqkeys{/pmb}{#1}\ignorespaces} +\newif\ifpmb@frame +~\pmbset~{ + frame/.is if=pmb@frame, + width/.store in=\pmb@width, width=\linewidth, + before/.store in=\pmb@before, before=\vskip 2ex plus 1ex minus 1ex \centering, + after/.store in=\pmb@after, after=\vskip 2ex plus 1ex minus 1ex, +} + +\NewDocumentEnvironment{~poormansbox~}{ + o % the options + +b % the environment body +}{% + \pmbset{#1}% apply the options + \pmb@before % execute the pre-code + \ifpmb@frame\expandafter\fbox\else\expandafter\@firstofone\fi{% add the frame, maybe + \begin{minipage}{\pmb@width}% create the minipage + #2 + \end{minipage}% + }% + \pmb@after % execute the post-code +}{} diff --git a/doc/examples/poormansbox.tex.dtx b/doc/examples/poormansbox.tex.dtx new file mode 100644 index 0000000..71fdd63 --- /dev/null +++ b/doc/examples/poormansbox.tex.dtx @@ -0,0 +1,44 @@ +%<*!lst> +\documentclass{article} +\usepackage[a5paper,margin=1cm,noheadfoot]{geometry} +\pagestyle{empty} +\usepackage{lipsum} + +%% This document works with all the poormanbox packages developed in the +%% manual. Uncomment the one one you want to test. Also feel free to remove the +%% line loading Memoize, all poormanbox packages should work without it, even if +%% they support it. + +\usepackage{memoize} + +\usepackage{poormansbox} +%% \usepackage{poormansbox-memoizable} +%% \usepackage{poormansbox-driver} + +% +\parskip 1ex plus 0.5ex minus 0.5ex + +\begin{document} +\lipsum[3] + +\begin{~poormansbox~}[width=.8\linewidth] + ~\pmbset~{width=\linewidth} + \lipsum[101] + \begin{~poormansbox~}[frame] + \footnotesize\lipsum[66] + \end{~poormansbox~} + \lipsum[75] +\end{~poormansbox~} + +\lipsum[4] + +\begin{~poormansbox~}[ + width=.6\linewidth, frame, + before=\noindent\llap{---}, + after=--- + ] + \lipsum[65] +\end{~poormansbox~}Framed. + +\lipsum[144] +\end{document} diff --git a/doc/examples/progressbar.tex.dtx b/doc/examples/progressbar.tex.dtx new file mode 100644 index 0000000..f321583 --- /dev/null +++ b/doc/examples/progressbar.tex.dtx @@ -0,0 +1,12 @@ +%<*!lst> +%\documentclass[varwidth=0.2\linewidth]{standalone} +%\documentclass{article} +\usepackage{progressbar} +% +\usepackage[auto={progressbar}{memoize}]{memoize} +%% ... +%\begin{document} +\progressbar{0.85} +\progressbarchange{roundnessr=0.5, filledcolor=red!30} +\progressbar{0.85} +%\end{document} diff --git a/doc/examples/readonly.tex.dtx b/doc/examples/readonly.tex.dtx new file mode 100644 index 0000000..72c07cd --- /dev/null +++ b/doc/examples/readonly.tex.dtx @@ -0,0 +1,22 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} + +\usepackage{tikz} + +% +%% Use this for work in progress. No externs will be created. +%\usepackage[~readonly~]{memoize} +% +%% Use this for the final version. Now the picture will be externalized. +%% \usepackage{memoize} +%\usepackage{memoize} +%% ... +% +%\begin{document} +% +%\tikz\node{work in progress}; +%\tikz\node{the final version\vphantom{g}}; +%\tikz\node{the final version}; + +%\end{document} diff --git a/doc/examples/recompile.tex.dtx b/doc/examples/recompile.tex.dtx new file mode 100644 index 0000000..f6b7a5b --- /dev/null +++ b/doc/examples/recompile.tex.dtx @@ -0,0 +1,31 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} + +\usepackage{tikz} +\usepackage{memoize} +% +% +%% First compile this document twice to externalize the picture and +%% extract the extern. If you then change "red" to "yellow" in the +%% definition of style "emph", the emphasized node will remain red +%% until you uncomment the "recompile" directive below for one +%% compilation. +% +%<*c1,c2> +\tikzset{ +% emph/.style={fill=red, text=blue}, +% emph/.style={fill=~yellow~, text=blue}, +} +% +%\tikzset{emph/.style={fill=~yellow~, text=blue}} +% +%\begin{document} +% +%% \mmznext{recompile} +%\mmznext{~recompile~} % for one compilation +\begin{tikzpicture} + \node[emph]{an emphasized node}; +\end{tikzpicture} +% +%\end{document} diff --git a/doc/examples/record-extern-pages.tex.dtx b/doc/examples/record-extern-pages.tex.dtx new file mode 100644 index 0000000..1197683 --- /dev/null +++ b/doc/examples/record-extern-pages.tex.dtx @@ -0,0 +1,9 @@ +\newout\mmzexternpagesout +\mmzset{ + record/pages/begin/.code={ + \immediate\openout\mmzexternpagesout{\jobname.extern-pages}}, + record/pages/new extern/.code={% + \immediate\write\mmzexternpagesout{\pagenumber\space#1}}, + record/pages/end/.code={ + \immediate\closeout\mmzexternpagesout}, +} \ No newline at end of file diff --git a/doc/examples/record-files.tex.dtx b/doc/examples/record-files.tex.dtx new file mode 100644 index 0000000..2effde1 --- /dev/null +++ b/doc/examples/record-files.tex.dtx @@ -0,0 +1,15 @@ +\newout\mmzfilesout +\mmzset{ + record/files/begin/.code={ + \immediate\openout\mmzfilesout{\jobname.files}% + }, + record/files/new extern/.code={\immediate\write\mmzfilesout{#1}}, + record/files/new cmemo/.code={\immediate\write\mmzfilesout{#1}}, + record/files/new ccmemo/.code={\immediate\write\mmzfilesout{#1}}, + record/files/used extern/.code={\immediate\write\mmzfilesout{#1}}, + record/files/used cmemo/.code={\immediate\write\mmzfilesout{#1}}, + record/files/used ccmemo/.code={\immediate\write\mmzfilesout{#1}}, + record/files/end/.code={ + \immediate\closeout\mmzfilesout + }, +} \ No newline at end of file diff --git a/doc/examples/redefinitions.tex.dtx b/doc/examples/redefinitions.tex.dtx new file mode 100644 index 0000000..d919c2f --- /dev/null +++ b/doc/examples/redefinitions.tex.dtx @@ -0,0 +1,49 @@ +%<*!lst> +%\documentclass{standalone} +%\documentclass{article} + +\usepackage{tikz} +\usepackage{memoize} + +\begin{document} + +% +%% v1: +%\tikzset{emph/.style={fill=red, text=blue}} +%\tikz\node[emph]{an emphasized node}; +%\tikzset{emph/.style={fill=red, text=blue}} +%\tikz\node[emph, ~font=\itshape~]{an emphasized node}; +%\tikzset{emph/.style={~fill=yellow~, text=blue}} +%\tikz\node[emph, font=\itshape]{an emphasized node}; +%\mmznext{~recompile~} % only for one compilation! +%\tikzset{emph/.style={~fill=yellow~, text=blue}} +%\tikz\node[emph, font=\itshape]{an emphasized node}; +%\tikzset{emph/.style={~fill=yellow~, text=blue}} +%\tikz\node[emph]{an emphasized node}; +%\tikzset{emph/.style={~fill=yellow~, text=blue}} +%\mmznext{~recompile~} % only for one compilation! +%\tikz\node[emph]{an emphasized node}; +% +%% v2: +%%\tikzset{emph/.style={fill=red, text=blue}} +%%\tikz\node[emph, ~font=\itshape~]{an emphasized node}; +% +%% v3: +%%\tikzset{emph/.style={~fill=yellow~, text=blue}} +%%\tikz\node[emph, font=\itshape]{an emphasized node}; +% +%% v4: +%%\mmznext{~recompile~} % uncomment only for one compilation! +%%\tikzset{emph/.style={~fill=yellow~, text=blue}} +%%\tikz\node[emph, font=\itshape]{an emphasized node}; +% +%% v5: +%%\tikzset{emph/.style={~fill=yellow~, text=blue}} +%%\tikz\node[emph]{an emphasized node}; +% +%% v6: +%%\tikzset{emph/.style={~fill=yellow~, text=blue}} +%%\mmznext{~recompile~} % uncomment only for one compilation! +%%\tikz\node[emph]{an emphasized node}; + +%\end{document} diff --git a/doc/examples/ref.tex.dtx b/doc/examples/ref.tex.dtx new file mode 100644 index 0000000..4e6e5e6 --- /dev/null +++ b/doc/examples/ref.tex.dtx @@ -0,0 +1,32 @@ +%<*!lst> +%\documentclass[varwidth]{standalone} +%\documentclass{article} + +\usepackage{memoize} +% +%\mmzset{auto=\ref{~force ref~}} +%<*!lst> +\usepackage[inline]{enumitem} +\usepackage{tikzlings} + +\begin{document} +% +%<*!lst,c3> +Here's some Ti\emph{k}Zlings: +\begin{nomemoize} + \tikzset{x=1.3ex, y=1.3ex, baseline=0.5ex}% +% +%<*!lst,c3,c4> + \begin{enumerate*} +% ~\item\label{item:owl} \tikz\owl;~ +% %\item\label{item:owl} \tikz\owl; % uncomment for 4th compilation + \item\label{item:koala} \tikz\koala; + \item\label{item:penguin} \tikz\penguin; + \end{enumerate*} +% +%<*!lst,c3> +\end{nomemoize} +Where's the penguin? In \ref{item:penguin}. Yes, in +\tikz[baseline]\node[draw=red,thick,fill=yellow,anchor=base]{~\ref{item:penguin}~}; +% +%\end{document} diff --git a/doc/examples/sectionbox.tex.dtx b/doc/examples/sectionbox.tex.dtx new file mode 100644 index 0000000..34148de --- /dev/null +++ b/doc/examples/sectionbox.tex.dtx @@ -0,0 +1,13 @@ +%<*!lst> +\documentclass{article} +\usepackage{babel} + +% +\usepackage{sectionbox} +\usepackage{memoize} +\mmzset{auto={minipage}{memoize}} +\begin{document} +\begin{sectionbox}{Boxed section} + Some text in the box. +\end{sectionbox} +\end{document} diff --git a/doc/examples/skak.tex.dtx b/doc/examples/skak.tex.dtx new file mode 100644 index 0000000..c1b60fc --- /dev/null +++ b/doc/examples/skak.tex.dtx @@ -0,0 +1,18 @@ +%<*!lst> +\documentclass{article} +\usepackage{memoize} +% +\usepackage{skak} +\mmzset{ + auto=\showboard{ + memoize, args={}, + ~context~={fen={\csname chessgame.skak.mainline\endcsname}}, + }, +} +% +%\begin{document} +\newgame\showboard +% +\mainline{1. e4 e5}\par\showboard +% +%\end{document} diff --git a/doc/examples/test.tex.dtx b/doc/examples/test.tex.dtx new file mode 100644 index 0000000..705d5e7 --- /dev/null +++ b/doc/examples/test.tex.dtx @@ -0,0 +1,20 @@ +%\documentclass[varwidth]{standalone} +%\documentclass{article} +\usepackage{tikz,forest} + +~\usepackage{memoize}~ + +\begin{document} + +Memoize will automatically externalize\\ +\begin{tikzpicture} + \node(node) + [align=center,ellipse,draw] + {TikZ\\pictures}; +\end{tikzpicture} +\begin{forest} + [and Forest trees [and] + [Forest trees[Forest][trees]]] +\end{forest} + +\end{document} diff --git a/doc/examples/titlepage.tex.dtx b/doc/examples/titlepage.tex.dtx new file mode 100644 index 0000000..27aae88 --- /dev/null +++ b/doc/examples/titlepage.tex.dtx @@ -0,0 +1,13 @@ +%\documentclass[varwidth,11pt]{standalone} +%\documentclass{article} +~\usepackage{memoize}~ +\usepackage{tikzlings} +%\tikzset{x=0.3cm, y=0.3cm, baseline=0.5ex} + +\begin{document} +%\footnotesize + +We all love Ti\emph{k}Zlings! +~\tikz\penguin;~ is a penguin, ~\tikz\koala;~ is a koala, and ~\tikz\owl;~ is an owl. + +\end{document} diff --git a/doc/examples/verbatim-auto.tex.dtx b/doc/examples/verbatim-auto.tex.dtx new file mode 100644 index 0000000..b503e4a --- /dev/null +++ b/doc/examples/verbatim-auto.tex.dtx @@ -0,0 +1,23 @@ +%<*!lst> +%\documentclass[class=ltxdoc,varwidth]{standalone} +%\documentclass{ltxdoc} +\usepackage{tcolorbox} +\tcbuselibrary{listings} + +\usepackage{memoize} +% +\mmzset{auto={tcblisting}{ + memoize, ~verbatim~ +}} +%% ... +% +%\begin{document} +Use |\emph| to emphasize text: + +\begin{tcblisting}{width=15em} +This is an example +\emph{within} an example. +\end{tcblisting} + +Don't use |\textit| for emphasis! +%\end{document} diff --git a/doc/examples/verbatim-manual.tex.dtx b/doc/examples/verbatim-manual.tex.dtx new file mode 100644 index 0000000..ce4a872 --- /dev/null +++ b/doc/examples/verbatim-manual.tex.dtx @@ -0,0 +1,22 @@ +%<*!lst> +%\documentclass[class=ltxdoc,varwidth]{standalone} +%\documentclass{ltxdoc} + +\usepackage{tcolorbox} +\tcbuselibrary{listings} + +\usepackage{memoize} + +\begin{document} +% +Use |\emph| to emphasize text: + +\begin{memoize}[~verbatim~] + \begin{tcblisting}{width=15em} +This is an example +\emph{within} an example. + \end{tcblisting} +\end{memoize} + +Don't use |\textit| for emphasis! +%\end{document} diff --git a/doc/examples/vref.tex.dtx b/doc/examples/vref.tex.dtx new file mode 100644 index 0000000..57cc769 --- /dev/null +++ b/doc/examples/vref.tex.dtx @@ -0,0 +1,26 @@ +%<*!lst> +\documentclass{article} + +\usepackage{varioref} +\usepackage{memoize} + +% +\mmzset{auto=\vref{~ref~}} +%<*!lst> + +\begin{document} + +\section{Introduction} +\label{sec:intro} + +We will conclude the discussion in section~\mmz{\vref{sec:conclusion}}. + +%% \newpage +%% \section{A new section} +%% After uncommenting this, the reference above will (eventually) update. + +\section{Conclusion} +\label{sec:conclusion} + +\end{document} +% diff --git a/doc/memoize-clean.1.md b/doc/memoize-clean.1.md new file mode 100644 index 0000000..138e0ee --- /dev/null +++ b/doc/memoize-clean.1.md @@ -0,0 +1,62 @@ +--- +title: memoize-clean +section: 1 +header: User Manual +footer: memoize-clean of Memoize v1.0.0 +date: October 10, 2023 +hyphenate: false +--- + +# NAME +memoize-clean.pl, memoize-clean.py - Remove (stale) memo and extern files + + +# SYNOPSIS +**memoize-clean.pl** [*OPTIONS*] [*document1.mmz* ...] + +**memoize-clean.py** [*OPTIONS*] [*document1.mmz* ...] + + +# DESCRIPTION + +**memoize-clean** is a script accompanying Memoize, a TeX package which allows +the author to reuse the results of compilation-intensive code such as TikZ +pictures. + +By default, this script removes stale memo and extern files. A stale memo or +extern is an extern produced during a compilation of a previous version of the +document which was neither used nor produced during the last compilation of the +document. Typically, stale files arise when we change the memoized code (or +its context). + +**memoize-clean.pl** removes all memo and extern files with prefixes mentioned +in the listed **.mmz** files and by options **\--prefix** which are not +explicitly mentioned in the **.mmz** files. + +Before deleting anything, **memoize-clean.pl** lists all the files it would +delete and asks for confirmation. + +# OPTIONS + +**-p, \--prefix** +: Add a memo/extern prefix for cleaning. This option may be given multiple + times. + +**-a, \--all** +: Remove all memos and externs, rather than only the stale ones. + +**-y, \--yes** +: Do not ask for confirmation. + +**-q, \--quiet** +: Don't describe what's happening. + +**-h, \--help** +: Show help. + +**-V, \--version** +: Show the Memoize version number and exit. + +# SEE ALSO + +[Memoize manual](https://ctan.org/pkg/memoize), section 6.6.3. diff --git a/doc/memoize-code.sty b/doc/memoize-code.sty new file mode 100644 index 0000000..30d48f3 --- /dev/null +++ b/doc/memoize-code.sty @@ -0,0 +1,276 @@ +%% memoize-code.sty +%% +%% This file is a part of Memoize, a TeX package for externalization of +%% graphics and memoization of compilation results in general, available at +%% https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize. +%% +%% Copyright (c) 2020- Saso Zivanovic +%% (Sa\v{s}o \v{Z}ivanovi\'{c}) +%% +%% This work may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License, either version 1.3c of this license or (at +%% your option) any later version. The latest version of this license is in +%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of +%% all distributions of LaTeX version 2008 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Saso Zivanovic. +%% +%% The files belonging to this work and covered by LPPL are listed in +%% (/doc/generic/memoize/)FILES. + +\ProvidesPackage{memoize-code} +\RequirePackage{memoize-doc-common} + +% Typesetting the code & indentation +\MacroIndent=0pt +\MacroTopsep = 0pt +\MacrocodeTopsep = 7pt plus 2pt minus 2pt +\AddToHook{env/macrocode/before}{\macrocodepar}% +\let\macrocodepar\par + +% A mark for extraction into the manual. We need to remove some vertical space +% when this environment occurs alone in a doc block. +\newenvironment{listingregion}[1]{% + \ifvmode + \let\macrocodepar\relax + \AddToHookNext{env/macrocode/begin}{\MacrocodeTopsep=0pt\relax}% + \def\listingregionskip{\vspace{-\baselineskip}}% + \listingregionskip + \else + \def\listingregionskip{}% + \fi +}{\listingregionskip} + +\setlist{nosep} + +% Paragraph headings in the left margin, same as macro environments. +\RenewDocumentCommand\paragraph{s t. m}{% + \setbox0=\hbox{% + \mbox{% + \textcolor{blue}{% + #3% + \IfBooleanT{#1}{\mbox{\ ---}}% + \IfBooleanT{#2}{\hspace{0.7em}}% + }% + }% + }% + \noindent + \ifdim\wd0>\marginparwidth + \hangindent\dimexpr\wd0-\marginparwidth\relax + \hangafter-1\relax + \fi + \marginpar{\ifdim\wd0<\marginparwidth\hfill\fi\box0}% + \AddToHookNext{env/macrocode/before}{\par\nohang}% + \pgf@keys@utilifnextchar\par{\myparagraph@gobblepar}{\ignorespaces}% +} +\long\def\myparagraph@gobblepar#1{\ignorespaces} + +\def\macrocodeenvname{macrocode} +\def\MacroFont{\fontencoding\encodingdefault + \fontfamily\ttdefault + \fontseries\mddefault + \fontshape\shapedefault + \small + \ifx\@currenvir\macrocodeenvname\else\color{blue}\fi +} +\let\AltMacroFont\MacroFont % No special font for guarded code. + +% Typeset one-line guards to the left, +% indent multi-line guard begin/ends by the guard level, +% and let guards be orange. +% Move the codeline number left. +\def\Module#1{% + \begingroup + \IfBeginWith{#1}{*}{% + \def\next{}% + }{% + \IfBeginWith{#1}{/}{% + \def\next{}% + \advance\guard@level-1 + } + {% + \def\next##1{% + \guard@level0 + \setbox0=\lastbox + \llap{\unhbox0 ##1}% + }% + }% + }% + \next{% + \loop + \ifnum\guard@level>0 + \hskip 1em + \advance\guard@level-1 + \repeat + \color{orange}\mod@math@codes$\langle\mathsf{#1}\rangle$\hspace{0.1em}% + }% + \endgroup +} + + +% doc elements +\NewDocElement[idxgroup={\texttt{/mmz} keys}, idxtype={\texttt{/mmz}}]{Key}{key} +\NewDocElement[idxgroup={\texttt{/collargs} keys}, idxtype={\texttt{/collargs}}]{CollargsKey}{collargskey} +\NewDocElement[idxgroup={\texttt{/advice} keys}, idxtype={\texttt{/advice}}]{AdviceKey}{advicekey} +\NewDocElement[idxgroup={\texttt{/mmz/auto} keys}, idxtype={\texttt{/mmz/auto}}]{MmzAutoKey}{mmzautokey} +\NewDocElement[idxgroup={\texttt{/handlers} keys}, idxtype={\texttt{/handlers}}]{HandlersKey}{handlerskey} +\NewDocElement[idxgroup={\texttt{/advice/install} keys}, idxtype={\texttt{/advice/install}}]{AdviceInstallkey}{adviceinstallkey} + +% Funny: without repeating this here, I can't use commas to separate several macros. +\RenewDocElement[macrolike=true, idxtype=,idxgroup=,printtype=]{Macro}{macro} +\NewDocElement[idxtype={Lua function}, idxgroup=Lua functions]{LuaFunction}{luafun} + + +\newcommand\PrintMainMacro[1]{{\MacroFont\string#1}\SpecialMainMacroIndex{#1}} + +\newcommand\MyIndex[3]{% + \global\advance\c@CodelineNo 1 + \csuse{special@index}{#1\actualchar#2\encapchar#3}% + \global\advance\c@CodelineNo -1 + \ignorespaces +} +\NewDocumentCommand\exclamationmark{}{!} + + +% hanging indent for "key" and "macro" environments +\newcommand\hang[2]{% + \setbox0=\hbox{\MacroFont \string#2\relax}% "\relax" is short enough to never trigger a hanging indent + \ifdim\wd0>\dimexpr\marginparwidth\relax + \hangindent\dimexpr\wd0-\marginparwidth\relax + \hangafter-#1\relax + \AddToHookNext{env/macrocode/before}{\par\nohang}% + \AddToHookNext{para/after}{\aftergroup\nohang}% + \fi + \ignorespaces +} +\newcommand\nohang{\hangindent 0pt\relax} +\newcommand\indentmacrocode{% + \settowidth\MacroIndent{\theCodelineNo\ }% + \addtolength\MacroIndent{\hangindent}% +} +\newcommand\noindentmacrocode{% + \setlength\MacroIndent{0em}% + \AddToHookNext{env/macrocode/begin}{\MacrocodeTopsep 0pt\relax}% +} + +% and now ... autohang! +% (the macros should be listed without spaces after commas) +\usepackage{advice} +\pgfkeys{ + /my/.cd, + .install advice, + advice/hang/.style={outer handler=\autohang}, + advice=\key{hang}, + advice=\macro{hang}, + advice=\autokey{hang}, + advice=\mmzautokey{hang}, + advice=\collargskey{hang}, + advice=\handlerskey{hang}, + advice=\adviceinstallkey{hang}, + advice=\luafun{hang}, +} +\def\hangn{0} +\def\hanglength{0} +\def\hangstring{} +\newcommand\autohang[2][]{% + \ifstrequal{#1}{noprint}{}{% + \def\temp{#2}% + \@for\hangtemp:=\temp\do{\computehang}% + \edef\temp{\noexpand\hang{\hangn}{\expandonce\hangstring}}\temp + }% + \AdviceOriginal[#1]{#2}% +} +\def\computehang{% + \StrLen{\expandafter\string\hangtemp}[\temp]% + \edef\hangn{\the\numexpr\hangn+1} + \ifnum\temp>\hanglength\relax + \let\hanglength\temp + \let\hangstring\hangtemp + \fi +} + + + +%%% Various: +\newcommand\MS{\textsuperscript{M}\S} % manual section + +% Read in the manual .aux, for \MS cross-references. +\begingroup +\let\orig@newlabel\newlabel +\def\newlabel#1#2{% + \IfBeginWith{#1}{sec:}{\orig@newlabel{#1}{#2}}{}% +} +\def\doline{% + \expandafter\futurelet\expandafter\firsttoken\expandafter\dolinei\line\fi} +\def\dolinei{\ifx\firsttoken\newlabel}% +\openin0=memoize.aux +\loop + \unless\ifeof0 + \read0 to \line + \doline +\repeat +\closein0 +\endgroup + + + +%%%% Filter the index, keeping only the entries with a corresponding "main" +%%%% entry. + +\AddToHook{enddocument/end}{% + \immediate\closeout\@indexfile % it is never explicitly closed! + \filterindex +} + +\newwrite\tempidx +\def\filterindex{% + \IfFileExists{\jobname.idx}{% + \begingroup + \catcode`\%=12 + \def\indexentry{\filterindex@parse\filterindex@first@pass}% + \immediate\openout\tempidx \jobname.idx.orig + \input \jobname.idx + \immediate\closeout\tempidx + \def\indexentry{\filterindex@parse\filterindex@second@pass}% + \immediate\openout\tempidx \jobname.idx + % \tracingall + \input \jobname.idx.orig + \immediate\closeout\tempidx + \endgroup + }{}% +} + +\def\filterindex@parse{% + \catcode`\\=12 + \filterindex@parse@i +} +\long\def\filterindex@parse@i#1#2#3{\filterindex@parse@ii#1#2{#3}} +\long\def\filterindex@parse@ii#1#2=#3hdclindex#4#5#6{% + \catcode`\\=0 + #1{#2}{#3}{#4}{#5}{#6}% +} + +\long\def\filterindex@first@pass#1#2#3#4#5{% + \filterindex@write{#1}{#2}{#3}{#4}{#5}% + \IfStrEq{#4}{main}{% + \csdef{\detokenize{filt@#1}}{}% + }{}% +} +\long\def\filterindex@second@pass#1#2#3#4#5{% + \ifcsdef{\detokenize{filt@#1}}{% + \filterindex@write{#1}{#2}{#3}{#4}{#5}% + }{% + }% +} +\long\def\filterindex@write#1#2#3#4#5{% + \immediate\write\tempidx{\string\indexentry\detokenize{{#1=#2hdclindex{#3}{#4}}{#5}}}% +} + + + +% Local Variables: +% TeX-engine: luatex +% TeX-master: "memoize-code.tex" +% TeX-auto-save: nil +% End: \ No newline at end of file diff --git a/doc/memoize-code.tex b/doc/memoize-code.tex new file mode 100644 index 0000000..6daa583 --- /dev/null +++ b/doc/memoize-code.tex @@ -0,0 +1,120 @@ +\documentclass[a4paper,11pt]{ltxdoc} + +\usepackage[left=1cm,right=1cm,top=1cm,bottom=1cm, + marginparwidth=0cm,marginparsep=0pt, + nohead,includefoot +]{geometry} +\settowidth\marginparsep{\ } + +% There is a \mmzset in memoize-doc-common. +\usepackage{nomemoize} + +% Hypdoc (which loads hyperref) must be loaded before memoize-code. +\usepackage{hypdoc} +\hypersetup{colorlinks=true, allcolors=blue} + +\usepackage{memoize-code} % Also loads memoize-doc-common + +\pdfsystem{makeindex -s gind.ist \jobname.idx} + +\CodelineIndex +\EnableCrossrefs + +\title{The documented source of Memoize, Advice and CollArgs} +\author{SaÅ¡o Živanović\\[2mm] + \emailsymbol~\url(mailto:){saso.zivanovic@guest.arnes.si}\\ + \homepagesymbol~\url(http://){spj.ff.uni-lj.si/zivanovic}\\ + \faGithub~\url(https://){github.com/sasozivanovic}} + +\datefrompackageversion{collargs} +\edef\allpackagever{CollArgs v\packagever} +\datefrompackageversion{advice} +\epreto\allpackagever{Advice v\packagever, } +\datefrompackageversion{memoize} +\epreto\allpackagever{Memoize v\packagever, } +\let\packagever\allpackagever + +\hypersetup{ + % pdftitle={Memoize}, + pdfauthor={SaÅ¡o Živanović}, + pdfsubject={externalization}, + pdfkeywords={LaTeX, externalization, memoization} +} + +\begin{document} + +\maketitle + +\def\docdir{..} +\DocInput{\docdir/memoize.dtx} + +\section{Auxiliary packages} +\label{sec:code:utils} + +\subsection{Extending commands and environments with Advice} +\label{sec:code:auto} + +\DocInput{\docdir/advice.dtx} + +\subsection{Argument collection with CollArgs} +\label{sec:code:collargs} + +\DocInput{\docdir/collargs.dtx} + +\clearpage +\restoregeometry + +\section{The scripts} +\label{sec:code:scripts} + +\def\continuation{\llap{\textcolor{purple}{$\rightarrow$}\,}} + +\subsection{The Perl extraction script \texttt{memoize-extract.pl}} + +\lstinputlisting[firstline=20, % manual (exclude the license information) + language=Perl, + breaklines, breakindent=4em, postbreak=\continuation, + commentstyle=, +]{../memoize-extract.pl} + +\subsection{The Python extraction script \texttt{memoize-extract.py}} + +\lstinputlisting[firstline=20, % manual (exclude the license information) + language=Python, + breaklines, breakindent=4em, postbreak=\continuation, + commentstyle=, +]{../memoize-extract.py} + +\subsection{The Perl clean-up script \texttt{memoize-clean.pl}} + +\lstinputlisting[firstline=20, % manual (exclude the license information) + language=Perl, + breaklines, breakindent=4em, postbreak=\continuation, + commentstyle=, +]{../memoize-clean.pl} + +\subsection{The Python clean-up script \texttt{memoize-clean.py}} + +\lstinputlisting[firstline=20, % manual (exclude the license information) + language=Python, + breaklines, breakindent=4em, postbreak=\continuation, + commentstyle=, +]{../memoize-clean.py} + +\clearpage + +\IndexPrologue{\section*{Index}Numbers written in red refer to the code line + where the corresponding entry is defined; numbers in blue refer to the code + lines where the entry is used.} + +\setcounter{IndexColumns}{2} +\def\main#1{\begingroup\hypercolor{link}{red}#1\endgroup} +\PrintIndex + +\end{document} + +%%% Local Variables: +%%% mode: latex +%%% TeX-engine: luatex +%%% TeX-master: t +%%% End: diff --git a/doc/memoize-doc-common.sty b/doc/memoize-doc-common.sty new file mode 100644 index 0000000..fe6ab00 --- /dev/null +++ b/doc/memoize-doc-common.sty @@ -0,0 +1,173 @@ +%% memoize-doc-common.sty +%% +%% This file is a part of Memoize, a TeX package for externalization of +%% graphics and memoization of compilation results in general, available at +%% https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize. +%% +%% Copyright (c) 2020- Saso Zivanovic +%% (Sa\v{s}o \v{Z}ivanovi\'{c}) +%% +%% This work may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License, either version 1.3c of this license or (at +%% your option) any later version. The latest version of this license is in +%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of +%% all distributions of LaTeX version 2008 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Saso Zivanovic. +%% +%% The files belonging to this work and covered by LPPL are listed in +%% (/doc/generic/memoize/)FILES. + +\ProvidesPackage{memoize-doc-common} + +\usepackage[inline,shortlabels]{enumitem} +\usepackage{tcolorbox} +\tcbuselibrary{listings,hooks,raster,skins} +\usepackage{tikz} +\usepackage{xstring} +\usepackage{microtype} + +\usepackage{listings} +\lstset{ + language=[LaTeX]TeX, + columns=fullflexible, + basicstyle=\ttfamily\small, + commentstyle=\color{purple}, + moredelim={[is][\pstyle]{~}{~}} +} +\lstMakeShortInline[moredelim={[is][\pstyle]{~}{~}}]{ˇ}% +\tcbset{ + linerange/.style={listing options app={linerange=#1}}, +} + + +%%%%%%%%%%%%%% +% title page % + +\usepackage{pdftexcmds} +\let\pdfsystem\pdf@system + +% version and date +\def\datefrompackageversion#1{% + \setbox0=\hbox{% + \def\ProvidesPackage##1[##2]{% + \gdef\@packagever{##2}% + \endinput + }% + \input{#1.sty}% + }% + \expandafter\parsepackagever@\@packagever\parsepackagever@ +} +\def\parsepackagever@#1/#2/#3 v#4 #5\parsepackagever@{% + \year=#1\relax\month=#2\relax\day=#3\relax + \def\packagever{#4}\def\packagedesc{#5}% +} + +\renewcommand\maketitle{% + \begingroup + \mmzset{disable, auto={tcolorbox}{clear options}}% \mmznext does not work here -- todo: maybe it does now + \begin{tcolorbox}[ + colback=emphcolor, + fonttitle=\LARGE\bf, + halign title=center, + halign upper=center, + halign lower=center, + tikznode lower, + adjusted title=\@title, + ] + \packagever\\ + \@date + \tcblower + \Large\@author + \end{tcolorbox} + \endgroup +} +\colorlet{emphcolor}{yellow!90!black} +\usepackage{marvosym} +\let\emailsymbol\Letter +\let\homepagesymbol\ComputerMouse +\usepackage{fontawesome} % for \faGithub + + +%%%%%%%%%%%%%%%%%%%%%%%% +% \verb@eol@error hack % + +% The problem: doc.sty (re)defines \verb "to check for newlines in its argument +% since a missing delimiter is difficult to detect in doc source." In +% principle, that's great, but I really hate it that I can't use Emacs's +% "fill-paragraph" without fear of getting the "Text for \noexpand\verb command +% ended by end of line" error. +% +% Solution: the original \verb@eol@error defines a newline (which is active at +% that point) to throw an error. We redefine \verb@eol@error to define a +% newline to gobble an immediately following percent character (assuming that +% we are processing .dtx documentation) and spaces. + +\begingroup + \obeylines% + \gdef\verb@eol@error{\obeylines% + \def^^M{\futurelet\verb@eol@nextchar\verb@eol@peek}% + }% +\endgroup +\gdef\verb@eol@peek{% + \if\@percentchar\verb@eol@nextchar + \expandafter\verb@eol@ignorepercentchar + \else + \space % we need one space, though! + \expandafter\verb@eol@ignorespaces + \fi +} +\def\verb@eol@ignorepercentchar#1{% #1 = "%" + \@xobeysp\verb@eol@ignorespaces} +\begingroup\catcode`\ =13 \gdef\verb@eol@otherspace{ }\endgroup +% |\ignorespaces| wouldn't work here, as our spaces are of category 13 +\def\verb@eol@ignorespaces{% + \futurelet\verb@eol@nextchar\verb@eol@ignorespaces@peek} +\def\verb@eol@ignorespaces@peek{% + \expandafter\ifx\verb@eol@otherspace\verb@eol@nextchar + \expandafter\verb@eol@ignorespaces@space + \fi +} +\def\verb@eol@ignorespaces@space#1{\verb@eol@ignorespaces} + +% The same hack, but for \lstinline of package listings. +% https://tex.stackexchange.com/a/473459/16819 + +\def\lst@InlineM#1{\gdef\lst@inlinechars{% + \lst@Def{`#1}{\lst@DeInit\egroup\global\let\lst@inlinechars\@empty}% + \lst@Def{13}{\lst@ProcessSpace}}% <--- + \lst@inlinechars} + + +%%%%%%%%%%% +% various % + +\usepackage{hologo} +\def\TikZ;{{\rm Ti\emph{k}Z}} +\def\PGF;{PGF} +\newcommand\PGFmanual[1]{% + \href + {http://mirrors.ctan.org/graphics/pgf/base/doc/pgfmanual.pdf} + {\S#1 of the Ti\emph{k}Z \& \textsc{PGF} manual}% +} +\newcommand\Alt{\,$\vert$\,} +\newcommand\hyp{\discretionary{}{}{}} +\newcommand\fncomma{\ensuremath{{^,}}} + + +% load hyperref before this + +\protected\def\hypercolor#1#2{% #1 = url/link/.., #2 = color + \expanded{% + \noexpand\HyColor@HyperrefColor{#2}\expandonce{\csname @#1color\endcsname}% + }% +} + +\RenewDocumentCommand\url{ O{} D(){} m }{% + {\hypercolor{url}{#1}\href{#2#3}{\texttt{#3}}}} + +\def\pkgcolor{black} +\NewDocumentCommand\pkg{O{\pkgcolor}m}{{% + \hypercolor{url}{#1}% + \href{https://ctan.org/pkg/#2}{\texttt{#2}}}} diff --git a/doc/memoize-doc.sty b/doc/memoize-doc.sty new file mode 100644 index 0000000..2a1d748 --- /dev/null +++ b/doc/memoize-doc.sty @@ -0,0 +1,711 @@ +%% memoize-doc.sty +%% +%% This file is a part of Memoize, a TeX package for externalization of +%% graphics and memoization of compilation results in general, available at +%% https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize. +%% +%% Copyright (c) 2020- Saso Zivanovic +%% (Sa\v{s}o \v{Z}ivanovi\'{c}) +%% +%% This work may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License, either version 1.3c of this license or (at +%% your option) any later version. The latest version of this license is in +%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of +%% all distributions of LaTeX version 2008 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Saso Zivanovic. +%% +%% The files belonging to this work and covered by LPPL are listed in +%% (/doc/generic/memoize/)FILES. + +% \usepackage{lstdoc} % this must be loaded before hyperref +\usepackage{shortvrb} +\AtBeginDocument{\MakeShortVerb{\|}} +% \usepackage{hypdoc} +\usepackage[hyperindex=false]{hyperref} +\hypersetup{ + colorlinks=true, + allcolors=black, + linkcolor=Hyperlink, +} + +\usepackage{microtype} +%\SetExpansion[context=sloppy,stretch=30,shrink=50,step=1]{encoding=*}{}% + +\usepackage{fnpct} +\usepackage{memoize-doc-common} + +% explicitly load advice (and thereby collargs) for when we load nomemoize +\usepackage{advice} + +\usepackage{forest} +\useforestlibrary{edges} + +% \usepackage[extract=latex]{memoize} +% \usepackage{memoize} +\usepackage[infoshow]{tracefnt} + +\tcbuselibrary{xparse,breakable} + +\mmzset{ + auto={tcolorbox}{memoize, options=verbatim}, + auto={tcboxedraster}{memoize, options=verbatim}, + auto={tcbraster}{memoize, options={verbatim,ignore spaces}}, + auto={tcblisting}{memoize, options={verbatim,ignore spaces}}, + auto csname={tcbinputexample code}{memoize, args=mmm+m, ignore spaces}, + auto=\tcbinputlisting{memoize, args=m, options=ignore spaces}, + % The following doesn't work perfectly, but it's good enough. + auto key={/tcb/breakable}{run if memoizing, outer handler=\makeunmemoizableunless{false}}, + auto key={/tcb/float}{run if memoizing, outer handler=\makeunmemoizableunless{}}, +} + +\def\makeunmemoizableunless#1#2\pgfeov{% + \ifstrequal{#1}{#2}{}{\mmzUnmemoizable}% + \AdviceOriginal#1\pgfeov +} + +\newcommand\introboxtitle[1]{\strut\textcolor{emphcolor}{\textbf{#1}}} + +\usepackage{fancyhdr} +\usepackage[skip=0.3\baselineskip plus 2pt]{parskip} +\usepackage[bottom]{footmisc} +\usepackage{xparse} +\usepackage{multicol} + + + + +\usepackage{graphicx} + +\usepackage{cprotect} +\setlist[description]{ + itemsep=0.3\baselineskip plus 2pt minus 1pt, + parsep=0.3\baselineskip plus 2pt +} +\SetEnumitemKey{comma}{itemjoin={{, }}} +\SetEnumitemKey{and}{itemjoin={{, }}, itemjoin*={{, and }}} + +% \usepackage{lstdoc} % this must be loaded before hyperref +%\usepackage{lstautogobble} % todo: does not work! +\def\listings@file@value@in@reset{} +\tcbset{ + listing file/.append code={% + \ifmemoizing + \ifstrequal{#1}{\jobname.listing}{% + % We're in tcolorbox's reset, do nothing + }{% + \mmzset{ + context={% + listing file={#1}, + md5sum=\csuse{pdf@filemdfivesum}{#1}, + }, + }% + }% + \fi + }, + centering/.style={before=\centering}, +} +\colorlet{pointcolor}{green!50!black} +\def\pstyle{\color{pointcolor}}% todo: hyperlink? +\setlength\textfloatsep{0.5\baselineskip plus 2pt minus 2pt} +\tcbset{ + top=1mm, bottom=1mm, + beforeafter skip balanced=0.5\baselineskip plus 2pt minus 2pt, + raster every box/.style={top=1mm, bottom=1mm}, + before upper={\parskip0.3\baselineskip plus 2pt\relax}, + every box on layer 1/.style={ + fonttitle=\bfseries, + }, + my listing options/.style={ + listing options app={ + moredelim={[is][\pstyle]{~}{~}}, + commentstyle=\color{purple}, + morekeywords={unexpanded,expanded,expandonce,NewDocumentCommand,IfValueTF}, + breakindent=10pt, + }, + }, + my listing options, + % for listings inside a tcboxedraster ... + reset/.append style=my listing options, + % titles + attach shifted boxed title to top right/.style={ + attach boxed title to top right={ + xshift=1.5mm, yshift=-\tcboxedtitleheight/2, #1}, + }, + attach shifted boxed title to top right/.default={}, + attach shifted boxed title to top left/.style={ + attach boxed title to top left={ + xshift=-1.5mm, yshift=-\tcboxedtitleheight/2, #1}, + }, + attach shifted boxed title to top left/.default={}, + my boxed title/.style={ + enhanced, title={#1}, + fonttitle=\scriptsize, + boxed title style={size=small}, + }, + my boxed title/.value required, + extern page/.style={ + my boxed title=extern page, + boxed title style={colback=blue!70!black, colframe=blue!25!white}, + attach shifted boxed title to top right, + }, + document page/.style={ + my boxed title=document page, + boxed title style={colback=green!60!black, colframe=green!25!white}, + attach shifted boxed title to top right, + }, + % end titles + bad/.style={enhanced, + finish={ + \begin{tcbclipinterior} + \draw[red!40!white, opacity=0.4, line width=1cm] + (interior.south west)--(interior.north east); + \end{tcbclipinterior} + }, + }, + mark region/.style 2 args={ + enhanced, + underlay={ + \fill[pointcolor,opacity=0.1] + ([yshift=-\kvtcb@boxsep-\kvtcb@top-2.5ex*(#1-1)]interior.north west) rectangle ([yshift=-\kvtcb@boxsep-\kvtcb@top-2.5ex*#2]interior.north east); + }, + }, + warning/.style={colback=red!15}, + to be continued on right/.style={ + frame code={% line thickness is uniform and depends on tcolorbox's leftrule + \draw[color=tcbcolframe, + line width=2*\kvtcb@left@rule, rounded corners=2*\kvtcb@left@rule, + ] + (interior.north east)--(interior.north west) + --(interior.south west)--(interior.south east); + }, + interior code app={ + \draw[color=tcbcolframe,line width=\kvtcb@left@rule,dashed] + ([xshift=-0.5*\kvtcb@left@rule]interior.south east) + --([xshift=-0.5*\kvtcb@left@rule]interior.north east); + }, + }, +} +\def\examplepdfpath{\examplepath.c1.pdf} +\NewDocumentCommand{\includeexamplepdf}{ O{} O{\examplepdfpath} D(){} m}{% + \mbox{% + \tcbincludegraphics[reset,capture=hbox,graphics options={clip,#4},#1]{#2}#3% + }% +}% +\def\ExampleName#1{\edef\examplename{#1}\ignorespaces} +\def\makeexample#1{\pdfsystem{make -C \exampledir\space#1}\ignorespaces} +% \def\makeexample#1{\pdfsystem{make -B -C \exampledir\space#1}} +\def\examplepath{\exampledir\examplename} +\RequirePackage{intopdf} +\RequirePackage{fontawesome} +\tcbset{ + example title/.style={ + enhanced, + % uniform height and (zero) depth + before title={\begingroup \setbox0\hbox\bgroup}, + after title={\egroup\ht0 1.2ex \dp0 0pt \box0 \endgroup}, + title={\texttt{#1}}, + top=2mm, + attach shifted boxed title to top left, + fonttitle={\small\hypercolor{link}{white}}, + }, + example title/.default=\examplename.tex, + attachment/.estore in=\attachmentpath, + attachment name/.estore in=\attachmentname, + attachment name/.default=noname.tex, + no attachment/.style={attach/.style={}}, + attachment=\jobname.listing.attachment, + attachment name, + % attach example/.style={ + % attachment/.expanded=\examplepath.tex.work, + % attachment name/.expanded=\examplename.tex, + % attach, + % }, + attach/.style={ + overlay app={% + \node at (frame.north east) [ + fill=white, draw=gray, thick, + ellipse, inner xsep=-0.5mm, inner ysep=0, shift={(-2mm,-2mm)}, rotate=45, + ]{% + \pdfsystem{make -f examples/Makefile \attachmentpath}% + \expandafter\myattachandlink\expandafter[\attachmentname]{\attachmentpath}[application/x-tex]{Click here to open the code.}{\rotatebox{-45}{\faPaperclip}} + }; + } + }, + excerpt/.code 2 args={% + \makeexample{#2.excerpt SOURCE=#1}% + }, +} +\NewDocumentCommand\attachexample{O{\examplename.tex} O{\examplepath.tex.c1.attachment}}{% + {\textsuperscript{\kern-0.25em \expandafter\myattachandlink\expandafter[#1]{#2}[application/x-tex]{Click here to open the code.}{\rotatebox{-45}{\faPaperclip}}\kern-0.25em \relax}}} +\newcommand\myattachandlink[2][\filename]{% + \begingroup + \def\filename{#2}% + \immediate\write\attachments{#2 #1 ## line \the\inputlineno}% + \ifmemoizing + \xtoksapp\mmzCCMemo{% + \immediate\write\attachments{#2 #1 ## line \the\inputlineno}% + }% + \fi + \expanded{% + \endgroup + \noexpand\attachandlink[#1]{#2}% + }% +} +\newwrite\attachments +\immediate\openout\attachments attachments.lst +\AtEndDocument{\immediate\closeout\attachments} + +\NewTCBInputListing{\tcbinputexample}{ + >{\edef\ProcessedArgument} D(){\examplename} O{.tex} O{.c1} +m } +{% + /mmz/context={dtxmd5sum=\csuse{pdf@filemdfivesum}{\exampledir#1#2.dtx}}, + example title={#1#2}, + % enlarge left by=\leftmargin,% this takes care of using this box in lists + listing and comment, + one file/.style={ + listing file={\exampledir#1#2#3}, + attachment={\exampledir#1#2#3}, + }, + listing file=\exampledir#1#2#3.listing, + /utils/exec={\edef\examplepdfpath{\exampledir#1#3.pdf}},% + attachment=\exampledir#1#2#3.attachment, + attachment name=#1#2,% + #4, + attach, +} +\nommzkeys{context} + +\tcbset{ + full width/.style={grow to left by=\leftmargin}, + listing and compile/.style={ + listing and comment, + comment={% + \input\examplepath.tex.c#1 + } + }, + listing and compile/.default=1, +} + +\pgfkeys{ + /handlers/.detokenize/.style={\pgfkeyscurrentpath/.expand once=\detokenize{#1}}, + /utils/typeout/.code={\typeout{#1}}, +} +\let\pdfsystem\pdf@system +\let\pdffilemdfivesum\pdf@filemdfivesum + +\usepackage{booktabs} +\usepackage{tabularx} + + +\usetikzlibrary{decorations.pathmorphing, arrows.meta} +\usepackage{tikzlings-penguins,tikzlings-koalas,tikzlings-owls} +\tikzset{ + ->/.tip={Kite}, + snake arrow/.style= + {->, decorate, + decoration={snake, amplitude=.4mm, segment length=2mm, post length=2mm}, + }, +} + +% title page +\renewcommand\abstractname{\vskip-\baselineskip} + +% sections +\newtcbox{\section@box}[3]{tile,before=\noindent,after=, + fontupper=\normalfont#1\bfseries,capture=minipage, + colback=emphcolor, + boxsep=0mm,top=#2,bottom=#2,left=\oddsidemargin+1in,right=\oddsidemargin+1in, + spread sidewards,#3 +} + +\newif\ifsectionclearpage +\sectionclearpagetrue +\newif\ifsubsectionclearpage +\subsectionclearpagetrue + +\renewcommand\section{% + \ifsectionclearpage\clearpage\fi + \@startsection{section}{1}{\z@}% + {5mm}{5mm}% + {\section@box{\Large}{4mm}{fuzzy halo=1mm with blue!50!gray}}} +\renewcommand\subsection{% + \ifsubsectionclearpage\ifnum\c@subsection=0 \else\clearpage\fi\fi + \@startsection{subsection}{2}{\z@}% + {-3.25ex\@plus -1ex \@minus -.2ex}{1.5ex \@plus .2ex}% + {\section@box{\large}{2mm}{fuzzy halo=1mm with blue!50!gray}}} +\renewcommand\subsubsection{% + \mmznext{disable}% + \@startsection{subsubsection}{2}{\z@}% + {-3.25ex\@plus -1ex \@minus -.2ex}{1.5ex \@plus .2ex}% + {\section@box{}{2mm}{}}} +\newtcbox{\paragraph@box}{tile,before=,after=,capture=hbox, + fontupper=\normalfont\normalsize\bfseries\hypercolor{link}{black}\vphantom{dj}, + box align=base, + boxsep=0mm, + left=\oddsidemargin+1in, enlarge left by=-\oddsidemargin-1in, + top=1.2mm, enlarge top by=-1.2mm, + bottom=1mm, enlarge bottom by=-1mm, + right=12mm, enlarge right by=-8mm, arc=0mm, rightrule=0mm, + interior style={left color=emphcolor, right color=white}, +} +\let\oldparagraph\paragraph +\def\paragraphskip{3.25ex \@plus1ex \@minus.2ex} +\RenewDocumentCommand\paragraph{sm}{% + \mmznext{disable}% + \@startsection{paragraph}{4}{\z@}{\paragraphskip}{-1em}{\paragraph@box}{#2}% + \IfBooleanT{#1}{\hspace*{\dimexpr-8mm+0.5em}}% + \hskip 0pt plus .5em + \IfBooleanF{#1}{\nopagebreak}% % todo: this is bad, if the paragraph is long +} + +\NewTotalTCBox{\Emph}{m}{my code box, fontupper=\rm}{#1} +\NewTotalTCBox{\EmphTT}{m}{my code box}{#1} +\NewTotalTCBox{\EmphVerbatim}{v}{my code box}{#1} +\tikzset{ + emphshade/.style={ + opacity=0.6, + top color=#1, bottom color=#1, middle color=emphcolor, + }, + emphshade/.default=white, +} +\tcbset{ + my code box/.style={ + reset, enhanced, verbatim, + boxsep=0pt, left=0.3ex,right=0.3ex, box align=base, + interior hidden, frame hidden, + overlay={\shade[emphshade] + ([yshift=0.7ex]frame.north west) rectangle ([yshift=-0.7ex]frame.south east); + }, + }, +} + +% verbatim code in the implementation +\lstdefinestyle{code}{style=tcblatex,xleftmargin=\leftmargin,aboveskip=\parskip} + + + + + + +\newcommand\therefore{\ensuremath{\Rightarrow}} +\newcommand\nohyphen{\discretionary{}{}{}} +\let\gobble\@gobble + +\lstset{ + rangebeginprefix=\ \ \%\%\%\ begin\ listing\ region:\ , + rangebeginsuffix=, + rangeendprefix=\ \ \%\%\%\ end\ listing\ region:\ , + rangeendsuffix=, + includerangemarker=false, + keepspaces=true, +} + +\def\relaxmmzcommands{% + \let\mmzPrefix\gobble + \let\mmzNewCMemo\gobble + \let\mmzNewCCMemo\gobble + \def\mmzNewExtern##1##2##3##4##5{}% + \let\mmzUsedCMemo\gobble + \let\mmzUsedCCMemo\gobble + \let\mmzUsedExtern\gobble +} + +\usepackage{xstring} +\usepackage{placeins} + +\NewDocumentCommand\makeexcerpt{ m O{.tex} D(){../../memoize.edtx} }{% + \ExampleName{#1}% + \makeexample{#1#2.excerpt SOURCE=#3}% + \ignorespaces +} + +\newcommand\sed[2]{% + \begingroup + \def\cmd##1{\noexpand\\##1}% + \def\0{\bslash0}% + \def\1{\bslash1}% + \def\2{\bslash2}% + \def\3{\bslash3}% + \def\4{\bslash4}% + \def\5{\bslash5}% + \def\6{\bslash6}% + \def\7{\bslash7}% + \def\8{\bslash8}% + \def\9{\bslash9}% + \def~{\noexpand~}% + \def\n{\string\n}% + \def\({\bslash(}% + \def\){\bslash)}% + \let\lbrace\sedlbrace + \let\rbrace\sedrbrace + \edef\nobrace{[^\sedlbrace\sedrbrace]} + \edef\marg{{[^\sedrbrace]*}}% + \def\repeat##1{\bslash\sedlbrace##1\bslash\sedrbrace}% + \pdfsystem{sed -i "#1" #2}% + \endgroup +} +\begingroup +\catcode`\(=1 +\catcode`\)=2 +\catcode`\{=12 +\catcode`\}=12 +\gdef\sedlbrace({)% +\gdef\sedrbrace(})% +\endgroup + +\usepackage{pifont} +\newcommand\yes{{\small\ding{51}}} % pifont +\newcommand\no{{\small\ding{55}}} % pifont + +%\newcommand\oarg[1]{{\ttfamily[}\meta{#1}{\ttfamily]}} + +\definecolor{Option}{rgb}{0.118,0.546,0.222} +\definecolor{Definition}{rgb}{0.784,0.06,0.176} +\definecolor{ExampleFrame}{rgb}{0.628,0.705,0.942} +\definecolor{ExampleBack}{rgb}{0.963,0.971,0.994} +\definecolor{Hyperlink}{rgb}{0.281,0.275,0.485} +\definecolor{Fade}{rgb}{0.5,0.5,0.5} +\definecolor{EasyDefinition}{rgb}{0.06,0.784,0.176} + +{\catcode`\|=\z@ \catcode`\\=12 +|gdef|bslash{\}} +\DeclareRobustCommand\cs[1]{\texttt{\bslash\detokenize{#1}}}% +\DeclareRobustCommand\env[1]{\texttt{#1}}% +%\def\marg#1{{\ttfamily\char`\{}\meta{#1}{\ttfamily\char`\}}} +\def\marg#1{\hskip 0pt plus 1pt{\ttfamily\char`\{}\meta{#1}{\ttfamily\char`\}}} +\def\oarg#1{\hskip 0pt plus 1pt{\ttfamily[}\meta{#1}{\ttfamily]}} +\def\bracestt#1{\hskip 0pt plus 1pt{\ttfamily\char`\{#1\char`\}}} +\def\braces#1{\hskip 0pt plus 1pt{\ttfamily\char`\{}#1{\ttfamily\char`\}}} +\def\bracketstt#1{\hskip 0pt plus 1pt{\ttfamily[#1]}} +\def\brackets#1{\hskip 0pt plus 1pt{\ttfamily[}#1{\ttfamily]}} +\DeclareRobustCommand\meta[1]{% + \ensuremath\langle + \ifmmode \expandafter \nfss@text \fi + {% + \meta@font@select + \edef\meta@hyphen@restore{\hyphenchar\the\font\the\hyphenchar\font}% + \hyphenchar\font\m@ne + \language\l@nohyphenation + #1\/% + \meta@hyphen@restore + }% + \ensuremath\rangle +} +\def\meta@font@select{\rm\itshape} +\DeclareRobustCommand\metabf[1]{% + \begingroup + \def\meta@font@select{\rm\itshape\bfseries}% + \meta{#1}% + \endgroup +} +{\catcode`\%=12 \gdef\percentchar{%}} +\def\coloredpercentchar{\hbox{\textcolor{purple}{\percentchar}}} +\newcommand\alt{\ensuremath{\vert}}% without space around, unlike \Alt +\newcommand\code[1]{\texttt{\spaceskip 0.5em plus 0.2em minus 0.2em #1}} +\newcommand\Arg[1]{\texttt{\##1}} + +\def\TikZ{\href{https://ctan.org/pkg/pgf}{{\rm Ti\emph{k}Z}}\xspace} +\def\PGF{\href{https://ctan.org/pkg/pgf}{PGF}\xspace} +\def\Emacs{\href{https://www.gnu.org/software/emacs}{Emacs}\xspace} +\def\AucTeX{\href{https://www.gnu.org/software/auctex}{AUC\hologo{TeX}}\xspace} + +% collargs reference, pi = programmer's interface +% Shrink the glyphs in the footnote if necessary. +\tcbset{ + pi/.style={ + overlay={% + \node at (frame.north east) [anchor=north west, inner sep=0] {\footnotemark}; + }, + after app={% + \footnotetext{% + % \adjustspacing=2 % already 2 ... microtype? + \myfontexpansionon + \yadocset{before/.code={\cspreto{yadoc@name@prefix}{\myfontexpansionon}}}% + \mbox{The programmer's interface:} #1.% + }% + }, + }, +} +\DeclareRobustCommand\myfontexpansionon{% + \directlua{font.setexpansion(font.current(),50,50,1)}% +} +\DeclareRobustCommand\myfontexpansionoff{% + \directlua{font.setexpansion(font.current(),0,0,1)}% +} + +\AtBeginDocument{% + \setbox0=\hbox{% + \footnotesize\ttfamily + \directlua{ninettfont=font.current()}% + }% +} + +% \AtBeginDocument{% +% \setbox0=\hbox{% +% \footnotesize\ttfamily +% \global\expandafter\let\expandafter\fnttfont\font@name +% %\expandglyphsinfont\fnttfont 30 500 1 autoexpand +% }% +% } + +\usepackage{yadoc} +\newif\ifyadoc@short +\newif\ifyadoc@long +\yadocset{ + name color=Definition, + before body=\parskip 0.3\baselineskip plus 2pt, + % after body=\medskip, + head/.style={ + interior style={fill, left color=red!5,right color=red!5!black!2}, + }, + easy/.style={ + name color=green!50!black, + head/.style={ + interior style={fill, left color=green!5,right color=black!5}, + }, + }, + keypath color opacity=30, + index encapsulator={`}, + index annotation font=\color{gray}, + def options/.append style={index page number format=colorhyperpage{red}}, + aux options/.append style={index page number format=colorhyperpage{red}}, + ref options/.append style={index page number format=hyperpage}, + par/.style={parameters={#1}}, + desc/.style={description={#1}}, + keypath=/mmz, + xparse modifier item/.style={ + index annotation=\texttt{xparse} modifier, + label prefix=xparse, + }, + xparse type item/.style={ + index annotation=\texttt{xparse} type, + label prefix=xparse, + }, + script item/.style={ + index annotation=script, + label prefix=script, + parameters prefix=\space, + }, + key path item/.style={ + index annotation=keypath, + label prefix:=keypath:/, + name prefix=/, + description=keypath, + }, + option item/.style={ + name prefix={\ifdefempty\yadoc@short@name{}{-\yadoc@short@name\,\Alt\,}--}, + ref prefix={\protect\ifyadoc@short-\yadoc@short@name\protect\else--}, + ref suffix={\protect\fi}, + index prefix={--}, + index suffix={\ifdefempty\yadoc@short@name{}{\Alt-\yadoc@short@name}}, + parameters prefix=\ , + label prefix:={\yadoc@of--}, + index annotation=option of {\docref[into index=false,link color=gray]{\yadoc@of}}, + }, + short name/.store in=\yadoc@short@name, + short/.is if=yadoc@short, + long/.is if=yadoc@long, + conditional/.style={ + parameters={\texttt{true}\Alt\texttt{false}}, + /utils/exec={% + \appto\yadoc@description{default \texttt{true}, initially \texttt{#1}}% + }, + }, + conditional/.value required, + package item/.style={ + index annotation=package, + label prefix=pkg, + description=package, + }, + pkg/.style={ + after/.style={index annotation/.append={\space of package \pkg{#1}}} + }, + hook item/.style={ + label prefix=hook, + index annotation=hook, + }, + pdfvariable item/.style={ + label prefix=pdfvar, + index annotation={\hologo{LuaTeX}'s \refcmd{pdfvariable} register}, + }, + pdfcmd item/.style={ + label prefix=cmd, + name prefix={% + \textbackslash + \protect\ifyadoc@short + \protect\else + \protect\ifyadoc@long + pdf% + \protect\else + % todo: revert to the real original font rather than just say \rmfamily + \rmfamily(\ttfamily pdf\rmfamily)\ttfamily + \protect\fi + \protect\fi + }, + index prefix=\textbackslash, + }, +} +\def\colorhyperpage#1#2{% + \begingroup + \hypercolor{link}{#1}% + \hyperpage{#2}% + \endgroup +} + +\patchcmd{\@setref}{??}{#3??}{}{} +\patchcmd{\real@setref}{??}{#3??}{}{} + +\mmzset{ + auto={tcb@manual@entry}{nomemoize}, + auto={doc}{nomemoize}, +} + +\DeclareRobustCommand\refkey[2][]{\docref[#1]{key:#2}} +\DeclareRobustCommand\refmmz[2][]{\docref[#1]{key:/mmz/#2}} +\DeclareRobustCommand\refmmzauto[2][]{\docref[#1]{key:/mmz/auto/#2}} +\DeclareRobustCommand\refmmzpath[2][]{\docref[#1]{key:/mmz/path/#2}} +\DeclareRobustCommand\refcollargs[2][]{\docref[#1]{key:/collargs/#2}} +\DeclareRobustCommand\refenv[2][]{\docref[#1]{env:#2}} +\DeclareRobustCommand\refcmd[2][]{\docref[#1]{cmd:#2}} +\DeclareRobustCommand\reffile[2][]{\docref[#1]{file:#2}} +\DeclareRobustCommand\refkeypath[2][]{\docref[#1]{keypath:#2}} +\DeclareRobustCommand\refpkg[2][]{\docref[#1]{pkg:#2}} +\DeclareRobustCommand\refscript[2][]{\docref[#1]{script:#2}} + +\usepackage{xspace} +\newcommand\dmmz{\docref{file:mmz}\xspace} + +\newcommand\hreftt[2]{\href{#1}{\texttt{#2}}} + +\ifcsname ifregion\endcsname + \ifregion{% + \AddToHook{begindocument/before}{% + \makeatletter + \InputIfFileExists{memoize.aux}{}{}% + \makeatother + }% + \AddToHook{enddocument}{% + \printindex + }% + } +\fi + +\AddToHook{begindocument}{% + \robustify\hyperref + \robustify\hologo + \robustify\Alt +} + +\newcommand\noprint[1]{\setbox0=\hbox{#1}} +\usepackage{wrapfig} + + +% \usepackage{caption} +% \captionsetup{labelformat=empty} + +% Local Variables: +% TeX-master: "memoize.tex" +% TeX-engine: luatex +% End: diff --git a/doc/memoize-extract.1.md b/doc/memoize-extract.1.md new file mode 100644 index 0000000..434f2fe --- /dev/null +++ b/doc/memoize-extract.1.md @@ -0,0 +1,94 @@ +--- +title: memoize-extract +section: 1 +header: User Manual +footer: memoize-extract of Memoize v1.0.0 +date: October 10, 2023 +hyphenate: false +--- + +# NAME +memoize-extract.pl, memoize-extract.py - Extract extern pages out of the PDF + + +# SYNOPSIS +**memoize-extract.pl** [*OPTIONS*] *document.mmz* + +**memoize-extract.py** [*OPTIONS*] *document.mmz* + + +# DESCRIPTION + +**memoize-extract** is a script accompanying Memoize, a TeX package which +allows the author to reuse the results of compilation-intensive code such as +TikZ pictures. + +Memoize dumps the created externs (boxes containing the typeset material to be +reused) onto their own pages in the produced PDF file. It is the job of +**memoize-extract** to extract these extern pages into separate PDF files. At +subsequent compilations, Memoize will include those extern files into the +document, without compiling their source again. + +Memoize communicates with **memoize-extract** through file *document.mmz*. When +*document.tex* is compiled to produce *document.pdf*, Memoize produces +*document.mmz*, which records which pages in the produced document are extern +pages and to which extern files they should be extracted. Therefore, after +compiling *document.tex*, the externs should be extracted by +**memoize-extract** *document.mmz*. + +*document.mmz* also records the expected width and height of each extern. In +case of a mismatch, **memoize-extract** refuses to extract the page and removes +the extern file if it already exist, and prints a warning message to the +standard error. The script furthermore refuses to extract the page if a +(c)c-memo associated to the extern does not exist, and to write to any file +whose absolute path does not occur under the current directory or the directory +set by TEXMFOUTPUT (in *texmf.cnf* or as an environment variable); TEXMFOUTPUT +is also not allowed to point to the root directory, except on Windows, where it +can only point to a drive root. + +The Perl (.pl) and the Python (.py) version of the script are functionally +equivalent. The Perl script requires library +[PDF::API2](https://metacpan.org/pod/PDF::API2), and the Python script requires +library [pdfrw2](https://pypi.org/project/pdfrw2). + +# OPTIONS + +**-P, \--pdf** *filename.pdf* +: The externs will be extracted from *filename.pdf*. By default, + they are extracted from *document.pdf*. + +**-p, \--prune** +: Remove the extern pages from the PDF after extraction. + +**-k, \--keep** +: Do not modify the *document.mmz* to mark the externs as extracted. By + default, they are commented out to prevent double extraction. + +**-f, \--force** +: Extract the extern even if the size-check fails. + +**-l, \--log** *filename* +: Log size mismatches to *filename* rather than to the standard error. + +**-w, \--warning-template** *string* +: Wrap the size mismatch warning text into the given template: \\warningtext in + the template will be replaced by the warning text. + +**-q, \--quiet** +: Don't describe what's happening. + +**-e, \--embedded** +: Prefix all messages to the standard output with the script name. + +**-m, \--mkdir** +: A paranoid *mkdir -p*. (No extraction occurs, *document.mmz* is interpreted as a directory name.) + +**-h, \--help** +: Show help and exit. + +**-V, \--version** +: Show the Memoize version number and exit. + +# SEE ALSO + +[Memoize manual](https://ctan.org/pkg/memoize), section 6.6.1. diff --git a/doc/memoize.mst b/doc/memoize.mst new file mode 100644 index 0000000..68a1128 --- /dev/null +++ b/doc/memoize.mst @@ -0,0 +1 @@ +encap '`' diff --git a/doc/memoize.tex b/doc/memoize.tex new file mode 100644 index 0000000..8bc647f --- /dev/null +++ b/doc/memoize.tex @@ -0,0 +1,9094 @@ +\documentclass[a4paper,11pt]{article} +\usepackage[margin=2cm,top=1cm,bottom=1cm,nohead,includefoot]{geometry} + +\usepackage{nomemoize} +\usepackage{memoize-doc} +\mmzset{ + % recompile, + % readonly, + % disable, + % inverse search=false, + % include context in ccmemo, + % direct ccmemo input, + % trace, +} +\def\exampledir{examples/} + +\title{\pkg[white]{Memoize}} +\author{SaÅ¡o Živanović\\[2mm] + \emailsymbol~\url(mailto:){saso.zivanovic@guest.arnes.si}\\ + \homepagesymbol~\url(http://){spj.ff.uni-lj.si/zivanovic}\\ + \faGithub~\url(https://){github.com/sasozivanovic}} +\datefrompackageversion{memoize} +\preto\packagever{v} + +\hypersetup{ + pdftitle={Memoize}, + pdfauthor={SaÅ¡o Živanović}, + pdfsubject={externalization}, + pdfkeywords={LaTeX, externalization, memoization} +} + +\usepackage{makeidx} +\pdfsystem{makeindex -s memoize.mst \jobname.idx} +\makeindex +\usepackage[hangindent=1em,justific=raggedright,font=small]{idxlayout} +\appto\indexfont{\def\pkgcolor{gray}} + +\AddToHook{begindocument}{% so that the region compilation takes these in + \docForeign{ + scope={ + after/.style={index annotation/.prefix={\hologo{LaTeX}\space}}, + cmd={name=begin}, cmd={name=end}, + cmd={name=label}, cmd={name=@currentlabel}, + cmd={name=ref}, cmd={name=pageref}, + cmd={name=index}, + cmd={name=NewDocumentCommand}, cmd={name=GetDocumentCommandArgSpec}, + env={name=verbatim}, + cmd={name=ReadonlyShipoutCounter}, + hook={name=begindocument}, + cmd={name=usepackage}, + }, + scope={ + before/.style={index annotation=\hologo{TeX} primitive}, + cmd={name=shipout}, + cmd={name=hbox}, cmd={name=vbox}, + cmd={name=ignorespaces}, cmd={name=unskip}, + cmd={name=errmessage}, + cmd={name=catcode}, + cmd={name=mag}, + }, + scope={ + before/.style={index annotation=\hologo{eTeX} primitive}, + cmd={name=scantokens}, + cmd={name=currentgrouplevel}, + }, + scope={ + before/.style={index annotation=\hologo{pdfTeX} primitive}, + cmd={name=quitvmode}, + }, + scope={ + before/.style={index annotation=\hologo{LuaTeX} primitive}, + pdfcmd={name=savepos}, + cmd={name=pdfvariable}, + }, + pdfvariable={name=compresslevel}, + pdfvariable={name=horigin}, + pdfvariable={name=vorigin}, + scope={ + after/.style={index annotation/.prefix={\hologo{ConTeXt}\space}}, + cmd={name=realpageno}, + }, + pdfcmd={name=primitive, index annotation=\hologo{LuaTeX}/\hologo{XeTeX} primitive}, + register={name=pdfmajorversion}, + register={name=pdfminorversion}, + scope={ + after/.style={index annotation/.prefix={\hologo{plainTeX}\space}}, + cmd={name=llap}, cmd={name=rlap}, + }, + scope={ + pkg=forest, + env={name=forest}, + cmd={name=Forest}, + }, + scope={ + pkg=tikz, keypath=/tikz, + cmd={name=tikz}, + env={name=tikzpicture}, + key={name=remember picture}, + key={name=overlay}, + cmd={name=tikzexternalize}, + cmd={name=pgfsys@getposition}, + }, + file={name=texmf.cnf}, + env={name=tcblisting, pkg=tcolorbox}, + cmd={name=vref, pkg=varioref}, + cmd={name=cref, pkg=cleveref}, + cmd={name=crefrange, pkg=cleveref}, + xparse type={name=l, index annotation/.append={\ (up to begin-group)}}, + xparse type={name=u, index annotation/.append={\ (until tokens)}}, + xparse type={name=r, index annotation/.append={\ (required delimited)}}, + xparse type={name=R, index annotation/.append={\ (required delimited with default)}}, + xparse type={name=d, index annotation/.append={\ (optional delimited)}}, + xparse type={name=D, index annotation/.append={\ (optional delimited with default)}}, + xparse type={name=o, index annotation/.append={\ (standard optional)}}, + xparse type={name=O, index annotation/.append={\ (standard optional with default)}}, + xparse type={name=t, index annotation/.append={\ (optional token)}}, + xparse type={name=s, index annotation/.append={\ (optional star)}}, + xparse type={name=m, index annotation/.append={\ (mandatory)}}, + xparse type={name=g, index annotation/.append={\ (optional group)}}, + xparse type={name=G, index annotation/.append={\ (optional group with default)}}, + xparse type={name=v, index annotation/.append={\ (verbatim)}}, + xparse type={name=e, index annotation/.append={\ (embellishments)}}, + xparse type={name=E, index annotation/.append={\ (embellishments with defaults)}}, + xparse modifier={name=+, index annotation/.append={\ (long)}}, + xparse modifier={name=!, index annotation/.append={\ (don't ignore spaces)}}, + xparse modifier={name=>, index annotation/.append={\ (argument processor)}}, + generic={name=shell-escape, name prefix=-, label prefix:=-, + index annotation=option of \hologo{TeX} binaries}, + generic={name=enable-write18, name prefix=--, label prefix:=--, + index annotation=option of \hologo{TeX} binaries}, + generic={name=TEXMFOUTPUT, index annotation={variable in + \reffile[into index=false]{texmf.cnf}}}, + }% + \docindex{% + cmd={name=pdfprimitive, see={\refcmd[into index=false,short]{primitive}}}, + cmd={name=pdfsavepos, see={\refcmd[into index=false,short]{savepos}}}, + cmd={name=pdfhorigin, see={\docref[into index=false]{pdfvar:horigin}}}, + cmd={name=pdfvorigin, see={\docref[into index=false]{pdfvar:vorigin}}}, + cmd={name=pdfcompresslevel, see={\docref[into index=false]{pdfvar:compresslevel}}}, + pdfvariable={name=majorversion, see={\docref[into index=false,long]{reg:pdfmajorversion}}}, + pdfvariable={name=minorversion, see={\docref[into index=false,long]{reg:pdfminorversion}}}, + }% +} + +\begin{document} + + +\maketitle +\thispagestyle{empty} + +\begin{abstract} + Memoize is a package for externalization of graphics and memoization of + compilation results in general, allowing the author to reuse the results of + compilation-intensive code. + Memoize + \begin{enumerate*}[(i)] + \item induces very little overhead, as all externalized graphics is produced + in a single compilation. It features + \item automatic recompilation upon the change of code or user-adjustable + context, and + \item automatic externalization of \TikZ pictures and Forest trees, easily + extensible to other commands and environments. Furthermore, Memoize + \item supports cross-referencing, \TikZ overlays and Beamer, + \item works with all major engines and formats, and + \item is adaptable to any workflow. + \end{enumerate*} +\end{abstract} + +\bigskip + +\ExampleName{titlepage} +\makeexample{\examplename.pdf N=2} % N=2, because we show the .mmz file later +\begingroup +\tcbset{page box/.style={ + box align=center,boxsep=2mm,top=0pt,bottom=0pt,left=0pt,right=0pt, + enhanced, remember as=#1, + }}% +\begin{tcboxedraster} + [raster columns=1] + {title=The two steps of externalization of graphics in Memoize} + \tcbinputexample{ + title=\tt doc.tex, + listing only, + remember as=tex, + } + \begin{tcolorbox}[example title=doc.pdf, no attachment, remember as=pdf1] + \includeexamplepdf[page box=extern1]{page=1,trim=1in 1in 1in 1in}\hfill + \includeexamplepdf[page box=extern2]{page=2,trim=1in 1in 1in 1in}\hfill + \includeexamplepdf[page box=extern3]{page=3,trim=1in 1in 1in 1in}\hfill + \includeexamplepdf[page box=docpage]{page=4}% + \end{tcolorbox} + \vspace{10mm} + \begin{tcboxedraster}[raster columns=3, raster column skip=1cm]{blankest} + \begin{tcolorbox}[example title=.pdf]\centering + \includeexamplepdf[page box=externfile1]{page=1,trim=1in 1in 1in 1in}\hfill + \end{tcolorbox} + \begin{tcolorbox}[example title=.pdf]\centering + \includeexamplepdf[page box=externfile2]{page=2,trim=1in 1in 1in 1in}\hfill + \end{tcolorbox} + \begin{tcolorbox}[example title=.pdf]\centering + \includeexamplepdf[page box=externfile3]{page=3,trim=1in 1in 1in 1in}\hfill + \end{tcolorbox} + \end{tcboxedraster} +\end{tcboxedraster} + +\medskip + +\begin{tcolorbox}[title=Using the externalized graphics] + \begin{tcolorbox}[example title=doc.pdf, + halign=center, remember as=pdf2] + \tcbox[remember, enhanced]{\footnotesize + We all love Ti\emph{k}Zlings! + \def\mytikzling#1#2{% + \tcbox[blankest, baseline=1mm, remember as=used extern #1] + {\tikz[x=0.3cm,y=0.3cm]{#2;}}}% + \mytikzling1{\penguin} is a penguin, + \mytikzling2{\koala} is a koala, and + \mytikzling3{\owl} is an owl. + } + \end{tcolorbox} +\end{tcolorbox} + +\begin{tikzpicture}[remember picture, overlay] + \draw[->, snake arrow, thick, red] (tex.west) to[out=-90-60, in=90+60] (pdf1.west); + \draw[->, snake arrow, thick, red] (tex.east) to[out=-90+19, in=90-19] (pdf2.east); + \draw[->, thick, red] (extern1.south) to[out=south, in=north] (externfile1); + \draw[->, thick, red] (extern2.south) to[out=south, out looseness=1.1, in=north, in looseness=0.9] (externfile2); + \draw[->, thick, red] (extern3.south) to[out=south, out looseness=0.7, in=north, in looseness=0.9] (externfile3); + \draw[->, thick,blue] (externfile1) to[out=south, in=north] ([yshift=0.8mm]used extern 1.north); + \draw[->, thick,blue] (externfile2) to[out=south, in=north] (used extern 2.north); + \draw[->, thick,blue] (externfile3) to[out=south, in=north] ([yshift=0.3mm]used extern 3.north); +\end{tikzpicture} +\endgroup + +\begin{tcolorbox}[colback=emphcolor, fontupper=\footnotesize] + This manual also documents packages Advice + ({\datefrompackageversion{advice}v\packagever}) and CollArgs + ({\datefrompackageversion{collargs}v\packagever}). These are auxiliary + packages which were developed alongside Memoize, but are distributed as + independent packages as they might be useful outside the context of Memoize, + as well. See sections~\ref{sec:advice} and \ref{sec:ref:advice} for Advice, and + sections~\ref{sec:collargs} and \ref{sec:ref:collargs} for CollArgs. +\end{tcolorbox} + + + +\section*{Introduction} +\label{sec:intro} + +\begin{tcolorbox}[ + title={\introboxtitle{What} is externalization and why you might want it?}, + ] + If you have ever worked on a long document full of \TikZ pictures and maybe + Forest trees, you have probably had some compilation-enforced coffee breaks + --- even on modern computers, compiling pictures, trees and such takes a lot + of time. And you might have wondered, why do I need to compile these + pictures over and over again? --- after all, I'm not changing them anymore! + Enter \emph{externalization}, a mechanism designed to deal precisely with + your issue, by saving the produced pictures into separate PDFs and including + those PDFs in subsequent compilations --- in no time at all! +\end{tcolorbox} + +\begin{tcolorbox}[ + title={\introboxtitle{Why} yet another externalization package?}, + ] + \TikZ, the popular and all-powerful graphics language for \TeX, ships + including an externalization library (described in \PGFmanual{53}). \TikZ's + library does an excellent job, but with one caveat. Assume you're using it + for the first time (or after a clean-up) on that long document full of \TikZ + pictures and Forest trees. It will take ages to produce all the externalized + graphics. Why? Because to get you up to speed, your document has to be + compiled many many times --- once for each and every externalized picture. + Even with \TikZ's advanced mechanism for skipping the parts of the document + irrelevant for the picture at hand, the first externalization can be a + daunting task. +\end{tcolorbox} + +\begin{tcolorbox}[ + title={\introboxtitle{How} does Memoize save your time?}, + ] + There is a reason why \TikZ uses an entire compilation cycle to produce a + single externalized picture: \TeX\ itself can only produce a single PDF per + compilation (at least at the moment). Memoize evades this limitation by + dumping the externalized pictures right in the middle of the document + (ouch!). More precisely, an externalized picture occurs in the PDF twice, + first on a special page of its own and then on a regular page, where you + intended it to be. The daring dump obviously necessitates a second step of + the procedure, when those special pages are \emph{extracted} into separate + PDFs, called \emph{externs}, which are then included into the document in + subsequent compilations. + + This two-step procedure, illustrated on the cover page of this manual, is + very fast. The first step, which externalizes \emph{all} the pictures into + the document itself (the squiggly red arrow), takes virtually no more time + than a regular compilation. The time needed for the second step, extraction + (the normal red arrows), depends on the system setup, but it ranges from + little to almost none. +\end{tcolorbox} + +\begin{tcolorbox}[ + title={\introboxtitle{When} should I use Memoize?}, + ] + In short, whenever you are writing a document containing lots of \TikZ + pictures, Forest trees, or other time-consuming constructs, and you are bored + waiting for the compilation to finish. + + Using Memoize on a paper containing a single picture does not make much of a + difference. But with more complex documents, the speed-up can be immense. + For example, the compilation time of my 400-page book containing about 160 + Forest trees was reduced by more than half, and the compilation time of a + 260-page Beamer presentation with a hundred complex dynamic trees went from + four minutes to a mere half minute! +\end{tcolorbox} + + +\begin{tcolorbox}[ + title={\introboxtitle{How} much extra work does Memoize require?}, + ] + In principle, none. + + For one, while allowing for manual memoization of selected document chunks + (\S\ref{sec:tut:memoize}), Memoize features a system which automatically + triggers memoization at each invocation of selected commands and + environments. Out of the box, Memoize \emph{automemoizes} \TikZ + pictures\noprint{\refenv{tikzpicture}} and Forest + trees\noprint{\refenv{forest}}, but the author can easily submit (almost) any + command or environment to automemoization (\S\ref{sec:tut:automemoization}). + Memoize also does its best to automatically prevent memoization of code that + cannot be externalized, like \TikZ pictures with \refkey{/tikz/remember + picture}, and to abort memoization in case the memoized code yields any + errors. +\end{tcolorbox} + + +\begin{tcolorbox}[ + title={\introboxtitle{Why} is Memoize not called Externalize?}, + ] + Fundamentally, Memoize is about producing and utilizing \emph{memos} --- + pieces of \hologo{TeX} code replicating the effect of the compilation of a + document chunk in a computationally less intensive manner. Typically, each + memo has an associated extern, which is where the effect of + \emph{typesetting} is stored, but conceptually, memos come first. For + example, the extern is included back into the document by the memo, and a + memo may be associated with any number of externs, including zero. + + Memos solve several externalization-related problems in a generic fashion, + allowing for a multitude of applications. For example, they store the + information about the associated externs, so that an extern can be integrated + back into the document as a box with the original orientation, width, height + and depth. They solve the problem of cross-referencing from and into the + memoized code by storing its \emph{context} (\S\ref{sec:cross-referencing}) + and replicating any \cs{label}s which occur in it. They are also crucial for + externalizing pictures in Beamer frames overlay by overlay. + + Incidentally, the term ``memoization'' is used with some programming + languages to refer to the process of remembering the result of the function, + along with the given arguments, so that on subsequent invocations of the + function with the same arguments, the result can be returned from memory + rather than recomputing it. I would say that, give or take the functions, + what Memoize does fits the bill. +\end{tcolorbox} + + +\begin{tcolorbox}[ + title={\introboxtitle{How} can I make my command (auto)memoizable?}, + ] + Any command which interacts with the rest of the document, like a command + which produces a float, must receive special treatment. Some issues can be + resolved from within Memoize. Other issues require a memoization-compatible + (re)implementation of the command. It is in the hope that package writers + will adapt their ``difficult'' commands to Memoize that this package offers a + documented interface to the memoization process, fully described in + sections~\ref{sec:tut:package}, \ref{sec:memoization-drivers} + and~\ref{sec:tut:automemoization-details}. + + An advanced user might also want to know that Memoize ships with two + auxiliary packages, which form the base of Memoize's automemoization feature. + Package Advice implements a generic framework for extending the functionality + of selected commands and environments, while package CollArgs provides a + command which can determine the argument scope of any command whose argument + structure conforms to \pkg{xparse}'s argument specification. +\end{tcolorbox} + +\begin{tcolorbox}[ + title={\introboxtitle{What else} is out there?}, + ] + Not long before submitting Memoize to CTAN, I became aware of another new + externalization package, \pkg{robust-externalize}, and it seems that the same + happened to the author of that package \Smiley, who found the + proof-of-concept version of Memoize, which was available + at \href{https://github.com/sasozivanovic/memoize}{GitHub} for a while. + + The key idea behind \pkg{robust-externalize} seems to be to extract the code + submitted to externalization into separate files, and add the necessary + preamble. While a compilation from scratch takes more time than with Memoize + (but less than with \TikZ library), the approach allows for parallel + compilation of externs --- nice! +\end{tcolorbox} + +\newpage +\tableofcontents + + +\section{Before you start} +\label{sec:setup} + +\subsection{Installing the extern extraction software} +\label{sec:install} + +Good news: using Memoize can be as easy as writing +\EmphVerbatim{\usepackage{memoize}} in the preamble. + +Bad news: Memoize won't work out of the box. The culprit is the extern +extraction --- the process which ships the externalized graphics from the main +document into separate extern files; for details, see the title page +illustration and the ``How'' box in the Introduction. For the extraction to +work, you will probably have to install some additional software, and you might +also have to allow your \hologo{TeX} to execute the extraction script. But +there's a silver lining: once Memoize is set up, it is set up for good. + +\begin{tcolorbox}[title=What do I have to do?] + + In principle, all you have to do for Memoize to work \emph{under the default + configuration} is install Perl libraries + \hreftt{https://metacpan.org/pod/PDF::API2}{PDF::API2} and + \hreftt{https://metacpan.org/pod/Path::Class}{Path::Class}; see the Perl + section below for the installation guideline. + +\end{tcolorbox} + +Consult section~\ref{sec:extraction} if you want to use an extraction method +other than the default \refmmz{extract=perl}-based method or adapt Memoize to +your particular workflow (for example, if you're compiling via a Makefile). + +If you installed Memoize through the package manager of your \hologo{TeX} +distribution, your system should be already set up to allow the execution of +Memoize's extraction scripts. If this is not the case, please contact either +me or the maintainer of your distribution; until the issue is resolved, you +have to either +\begin{enumerate}[(a)] +\item compile documents loading Memoize with command-line option + \docref{-shell-escape} (on \hologo{TeX}Live) or + \docref{--enable-write18} (on MiK\hologo{TeX}), or +\item set up the restricted shell escape mode to allow for the execution of + \refscript{memoize-extract.pl}.\footnote{\label{fn:shell-escape-commands}On + \hologo{TeX}Live, execute \code{tlmgr conf texmf shell\_escape\_commands} + to get the list of currently allowed commands \meta{current}, then add the + script by executing \code{tlmgr conf texmf shell\_escape\_commands + \meta{current},memoize-extract.pl}. On MiK\hologo{TeX}, you get the + \meta{current} list by \code{initexmf + --show-config-value=[Core]AllowedShellCommands[]}, and add to it by + \code{initexmf + --set-config-value=[Core]AllowedShellCommands[]=\meta{current};memoize-extract.pl}.} +\end{enumerate} + +Once you have set up your system, I advise you to follow the instructions in +section~\ref{sec:tut:test} to test if the setup was successful. + + +\begingroup +\setlength\intextsep{0pt} + +\paragraph{Perl} If you're running GNU/Linux or macOS, Perl is most likely +already installed on your system. On Windows, you might have to install it. I +tested Memoize with Strawberry Perl, available +at \url(https://){strawberryperl.com}; see \url(https://){www.perl.org} for +other options. + +\begin{wrapfigure}[3]{r}{0.25\linewidth} + \raisebox{0.5mm}[\dimexpr\height-0.5mm][\depth]{% + \mmznext{no verbatim} + \begin{tcolorbox}[ + % example title=Installing the required libraries in Perl, + % attach shifted boxed title to top right, + % top=2.5mm, + fontupper=\small, + left=2mm, + force nobeforeafter, + ] + |cpan PDF::API2| + + |cpan Path::Class| + \end{tcolorbox}% + }% +\end{wrapfigure} +Once Perl is installed on your system, you will need to install two Perl +libraries as well: the PDF processing library +\hreftt{https://metacpan.org/pod/PDF::API2}{PDF::API2}, and the cross-platform +path specification manipulation library +\hreftt{https://metacpan.org/pod/Path::Class}{Path::Class}. On some GNU/Linux +distributions, these libraries are included as packages --- just use your +package manager to install them. Otherwise, install them from +\hreftt{https://www.cpan.org}{CPAN} using +\hreftt{https://metacpan.org/pod/CPAN}{cpan} tool, as shown in the box. + + +\paragraph{Python} Installing (Python and) the required Python library is only +necessary if you decide to use the Python-based extraction script; see +section~\ref{sec:extraction}. + +If you're running GNU/Linux, install Python using your package manager. +Otherwise, download the installer from \url(https://){www.python.org}. You can +install Python even if you don't have administrator privileges: simply uncheck +the ``Install launcher for all users'' when running the installer. + +\begin{wrapfigure}[2]{r}{0.25\linewidth} + \raisebox{0.2mm}[\dimexpr\height-0.2mm][\depth]{% + \mmznext{no verbatim} + \begin{tcolorbox}[ + % example title=Installing the required library in Python, + % attach shifted boxed title to top right, + % top=2.5mm, + fontupper=\small, + left=2mm, + nobeforeafter, + ] + |pip install pdfrw2| + \end{tcolorbox}% + }% +\end{wrapfigure} + +Once Python is installed on your system, you will also need to install the +|pdfrw2| library (or its predecessor, |pdfrw|, which will work just as well). +Some GNU/Linux distributions offer this library as a package; if this is not +the case, and on other operating systems, install it +from \href{https://pypi.org}{The Python Package Index} +using \href{https://pip.pypa.io}{pip} tool (if you +run \href{https://pip.pypa.io}{pip} as a superuser, it will install the library +system-wide, otherwise locally), as shown in the box. + +\endgroup % \intextsep + + +\subsection{The configuration commands} +\label{sec:mmzset} + +Memoize can be configured using command \Emph{\refcmd{mmzset}\marg{keylist}} +(and friends). The \meta{keylist} argument is a comma-separated list of +configuration settings, each setting having the form \meta{key}|=|\meta{value}, +or sometimes just \meta{key}. The \meta{keylist} argument is processed by package +\pkg{pgfkeys} (see \PGFmanual{88}), so you can use all the bells and whistles +of that fantastic PGF utility (like easily defining your own styles). + +Here's some examples of \refcmd{mmzset}. For one, to whet your appetite to learn +about the various keys in the \refkeypath{/mmz} path, but more importantly now, to show +you that white-space is irrelevant in the \meta{keylist} argument, so you can +format the keylist as you wish --- as long as it does not contain an empty +line.\footnote{I like to add a comma after the final key as well, as shown in + the bottom left example, because if I don't, I often forget to insert it when + I add more keys.} + +\begin{tcbraster}[raster columns=4, raster valign=bottom] + \begin{tcboxedraster}[raster columns=1]{blankest, raster multicolumn=3, valign=bottom} + \begin{tcblisting}{listing only} +~\mmzset~{memo dir,recompile,memoize=circuitikz} + \end{tcblisting} + \begin{tcblisting}{listing only} +~\mmzset~{memo dir, recompile, memoize=circuitikz} + \end{tcblisting} + \end{tcboxedraster} + \begin{tcblisting}{listing only} +~\mmzset~{ + memo dir, + recompile, + padding=2in} + \end{tcblisting} +\end{tcbraster}\par +\begin{tcbraster}[raster columns=4, raster valign=top] + \begin{tcblisting}{listing only, raster multicolumn=2} +~\mmzset~{ + memo dir, readonly, + memoize=\qrcode{om}, + deactivate=\label, + disable, +} + \end{tcblisting} + \begin{tcblisting}{listing only} +~\mmzset~{ + memo dir, + recompile, + % comment + padding=2in +} + \end{tcblisting} + \begin{tcblisting}{listing only, bad} +~\mmzset~{ + memo dir, + recompile, + + padding=2in +} + \end{tcblisting} +\end{tcbraster} + +Command \refcmd{mmzset} can be used any time after loading the package. It is +very common in the preamble, but also useful in the document body, where its +effect is local to the \hologo{TeX} group.\footnote{Any keys with a non-local + effect are explicitly marked as such in the reference section.} For example, +you can use the idiom on the left below to force recompilation of a single +Forest tree somewhere in the middle of the document (in the code listings +below, highlighting marks the resulting scope of the \refmmz{recompile} +directive). However, as applying some setting to a single piece of +automatically memoized code is common, Memoize provides a special command for +the occasion: the keys given as the argument of \Emph{\refcmd{mmznext}} will be +applied only at the next instance of automemoization, overriding any keys set +by \refcmd{mmzset} in case of a conflict. If the command is given more than +once, only the final invocation takes effect. + +\begin{tcbraster}[raster columns=2, raster equal height=rows, raster force size=false] +\begin{tcblisting}{listing only, mark region={3}{6}} +~{~ + ~\mmzset~{recompile} + \begin{forest} + [VP[V][DP]] + \end{forest} + % ... +~}~ +\end{tcblisting} +\begin{tcblisting}{listing only, add to width=-1em, mark region={3}{5}} +% ... +~\mmznext~{recompile} +\begin{forest} + [VP[V][DP]] +\end{forest} +% ... + +\end{tcblisting} +\end{tcbraster} + +I like to follow |\usepackage{memoize}| by \refcmd{mmzset}, but if you prefer, you +can also provide the document-wide configuration as \Emph{package options.} +Note, however, that \hologo{LaTeX} removes spaces from package +options, so keys such as \refmmz{memo dir} won't work. That said, the following are +equivalent --- both will force re-externalization of all the externs in the +document. + +\begin{tcbraster}[raster columns=2, raster equal height=rows] + \begin{tcblisting}{listing only} +\usepackage{memoize} +\mmzset{recompile} + \end{tcblisting} + \begin{tcblisting}{listing only} +\usepackage[recompile]{memoize} + \end{tcblisting} +\end{tcbraster} + + +\subsection{The configuration file} +\label{sec:memoize.cfg} + +Memoize allows you to configure settings which apply to more than just one +document. It does that by attempting to load file \Emph{\reffile{memoize.cfg}} +just before executing package options. Given how \hologo{TeX} searches for +files, the location of this file determines whether it applies system-wide, +user-wide or directory-wide. The directory-wide location is clearly the +directory itself. The user-wide and system-wide location depend on the +\hologo{TeX} distribution and which format(s) you want to use +\reffile{memoize.cfg} with:\footnote{The |memoize| subfolder is not + obligatory.} + +\begin{center} + \meta{the relevant texmf tree root}|/tex/|\meta{format}|/memoize/memoize.cfg| +\end{center} + +You can say |generic| for \meta{format} if you want the configuration file to +be accessible by all formats, otherwise \meta{format} should be one of the +formats supported by Memoize: |plain|, |latex| or |context|. The texmf root +directory depends on the distribution, here's how to figure out what it is: + +\begin{tcboxedraster} + [raster columns=1, raster valign=top, raster force size=false] + {title=The roots of TEXMF trees} +\begin{tcolorbox}[title={\hologo{TeX} Live\hfill\url[white](https://){tug.org/texlive}}] + \begin{description}[itemsep=0pt] + \item[user-wide] + |tlmgr conf texmf TEXMFHOME| + or |kpsewhich -var-value TEXMFHOME|\\ + the default (on Linux): |/home/|\meta{username}|/texmf| + \item[system-wide] + |tlmgr conf texmf TEXMFLOCAL| + or |kpsewhich -var-value TEXMFLOCAL|\\ + the default (on Linux): |/usr/local/texlive/texmf-local| + \end{description} + + \smallskip + Don't forget to run |texhash| or |mktexlsr| after creating \reffile{memoize.cfg}. +\end{tcolorbox} +\begin{tcolorbox}[title={MiK\hologo{TeX}\hfill\url[white](https://){miktex.org}}, before upper={\parskip0.3\baselineskip plus 2pt\relax},] + Open the MiK\hologo{TeX} Console, select the ``Settings'' page and then the + ``Directories'' tab. + + If there is a folder marked with the ``Generic'' purpose with attribute + ``User'' (for a user-wide \reffile{memoize.cfg}) or ``Common'' (for a system-wide + \reffile{memoize.cfg}), that's the folder you are looking for. Otherwise, create a + folder following MiK\hologo{TeX}'s instructions and add it to the list. + + Don't forget to click ``Refresh file name database'' (in the ``Tools'' menu + of the MiK\hologo{TeX} Console) after creating \reffile{memoize.cfg}. +\end{tcolorbox} +\end{tcboxedraster} + +Note that a directory config file will override the user config, and the user +config will in turn override the system-wide one. This should not concern you +too much, because you will probably only want to use the user-wide config +anyway,\cprotect\footnote{If you want to have a directory-wide configuration + based on (rather than overriding) the user-wide configuration, your could + write down the real user-wide config in, say, |memoize.user.cfg| (located + user-wide), and then |\input| this file by both the user-wide and the + directory-wide \reffile{memoize.cfg}. Of course, the same logic can be used to base + a user-wide config on the system-wide one.} which might look something like +this: + +\ExampleName{memoize} +\makeexample{\examplename.cfg.c1} +\tcbinputexample[.cfg]{listing only} + +I recommend including \refmmz{memo dir} in your \reffile{memoize.cfg}, +as shown in the first line. It reduces the clutter in the document +directories; see section~\ref{sec:tut:memodir} for details. + +The \refmmz{extract} line concludes the story on ``permanently'' selecting the +extraction method, started in chapter~\ref{sec:setup}. As the final note, +observe that key \refmmz{extract} only makes sense as a package option or as a +\refcmd{mmzset} key in \reffile{memoize.cfg}. It will have no effect as a +\refcmd{mmzset} key in the document, because the extraction happens while the +package is loaded. + + + +\section{Your first memoized documents} +\label{sec:tut} + +\subsection{Let's see if it works!} +\label{sec:tut:test} + +\ExampleName{test} +\noprint{\refcmd{tikz}\refenv{tikzpicture}\refenv{forest}}% + +Take example file \texttt{\examplename.tex},\footnote{Where can you find + the example files? For one, they are integrated into this manual, so if your + PDF viewer supports attachments, you can simply click on the paperclip icon + on the top right of the example box (even if you're offline). Otherwise, + visit the |examples| subdirectory of wherever you found this document + \Smiley. Online, the Memoize documentation can be found at CTAN: + \url{https://ctan.org/pkg/memoize}; and if your \hologo{TeX} installation + includes the documentation, you should also find it in directory \meta{the + root of your \hologo{TeX} installation}|/doc/generic/memoize|. + + Incidentally, while we present a full example document in this section, many + code listings will only present the parts of the file relevant for the + discussion, for brevity. The example \emph{files}, however, will remain + full, compilable documents, including the document preamble etc.} or some +simple document containing a \TikZ picture or a Forest tree, add +\EmphVerbatim{\usepackage{memoize}} to the preamble,\footnote{Memoize likes to + be loaded early. If you get the error \texttt{Extern extraction from + document \meta{jobname}.pdf was unsuccessful}, move + \cs{usepackage}\bracestt{memoize} up the preamble; see + section~\ref{sec:loading-order} for details.} and compile it twice. + +\begin{itemize} +\item The first compilation of the example should produce a three-page PDF. + The first two pages are the \emph{extern pages} holding the externalized + graphics, while the final page is the (sole page of the) real document. Note + that you can see each extern twice: first on a page of its own, and then + wherever it belongs to in the real document. +\item At the second compilation, the extern pages should have disappeared from + the PDF, meaning they were successfully extracted into extern files, which + are now embedded into the main document. +\end{itemize} + +\makeexample{\examplename.pdf} +\tcbinputexample{ + sidebyside, + comment={\centering + \includeexamplepdf[extern page,left=2mm,right=2mm]{page=1,trim=1in 1in 1in 1in}\quad + \includeexamplepdf[extern page,left=2mm,right=2mm]{page=2,trim=1in 1in 1in 1in}\\[2ex] + \includeexamplepdf[document page]{page=3} + }, +} + +You might want to play with this example a bit now. +For example, if you reverse the order of the \TikZ picture and the Forest +tree, you should notice that the externs don't get recompiled. You won't see +any extern pages again until you change the actual code of the picture or the +tree --- or until you add some other picture or tree, of course. + +If you \emph{don't} want to automatically memoize \TikZ pictures and/or Forest +trees, you can switch off their \emph{automemoization} using key +\Emph{\refmmz{deactivate}}. This key takes a list of command and environment +names. As you can see below, the command and the environment must be +deactivated separately. + +\begin{tcblisting}{listing only} +\mmzset{ + deactivate={\tikz, tikzpicture}, % deactivate automemoization of all TikZ pictures + deactivate=\tikz, % deactivate only the command + deactivate=tikzpicture, % deactivate only the environment +} +\end{tcblisting} + + +\subsection{Memoizing by hand} +\label{sec:tut:memoize} + +In the previous section, we have compiled our very first document which used +Memoize. In that document, we only had to load the package, as Memoize knows +how to externalize \TikZ pictures and Forest trees without any help from the +author. But what if you want to externalize some other code? The manual way of +doing this is by surrounding the code by a \Emph{\refenv{memoize}} environment, +or by making it the argument of the \Emph{\refcmd{mmz}} command. The only +difference between the two is that the environment, but not the command, +ignores any spaces surrounding the given code. + +\ExampleName{manual} +\makeexample{\examplename.pdf} +\tcbinputexample{ + sidebyside, lefthand ratio=0.528, + comment={\centering + \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}\hfill + \includeexamplepdf[extern page]{page=2,trim=1in 1in 1in 1in} + }, +} + +Both the \refenv{memoize} environment and the \refcmd{mmz} command take a +configuration keylist as the optional argument, so their full syntax is +\cs{begin}\marg{\refenv{memoize}}\oarg{keylist}\meta{code to be + externalized}\cs{end}\marg{\refenv{memoize}} and and +\refcmd{mmz}\oarg{keylist}\marg{code to be externalized}. The keys given in +this optional argument take precedence over the keys set by \refcmd{mmzset}. +Note that \refcmd{mmznext} does not apply to manual memoization. + +Manual memoization is great for one-shot memoizations, but you can use it +within your own macros as well. For example, assume that you don't want to +externalize \TikZ pictures in general (so you have \refmmz{deactivate}d +automemoization of the \cs{tikz} command, as explained at the end of +section~\ref{sec:tut:test}), but that you want to easily memoize selected +pictures. You could define a memoized variant of the \cs{tikz} command, as shown +below (and similary for the environment). (Note the |%| comment characters in +the definition of |\mmztikz|. The definition was intentionally broken into +several lines to remind you that the spaces around the argument of \refcmd{mmz} +matter.) + +\ExampleName{mmztikz} +\makeexample{\examplename.pdf} +\tcbinputexample{ + comment={\centering + \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in} + \quad + \includeexamplepdf[document page]{page=2} + }, +} + +\clearpage +\subsection{Memoizing automatically} +\label{sec:tut:automemoization} + +Out of the box, Memoize automatically externalizes \TikZ pictures and Forest +trees. Let us see how other commands and environments can be submitted to this +\emph{automemoization} process. + +We start with the simpler case of environments (fortunately, externalizing +environments also makes sense more often than externalizing commands). You can +submit an environment to automemoization by writing +\EmphTT{\refmmz{auto}=\marg{environment name}\braces{\refmmzauto{memoize}}} (as +a key in \refcmd{mmzset}). The natural (but not the only possible) location +for this instruction is the preamble. Below, we automemoize environment +\env{circuitikz} of package \pkg{circuitikz}, used for drawing electronic +circuits.\footnote{In section~\ref{sec:tut:test}, we learned that + automemoization can be switched off using key \refmmz{deactivate}. Memoize + also offers key \refmmz{activate}, but you probably won't have to use it, as + an \refmmz{auto} declaration automatically activates the submitted command.} + +\ExampleName{automemoize-environment} +\makeexample{\examplename.pdf} +\tcbinputexample{ + sidebyside, lefthand ratio=0.6, + comment={\centering + \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in,scale=0.8} + }, +} + +Commands are a bit harder to automemoize, because Memoize cannot possibly know +how far the arguments of a command extend (in contrast, the end of an +environment is clearly marked). With commands, we must inform Memoize about +their argument structure, which we achieve using key \refmmzauto{args} in the +second argument of key \refmmz{auto}: +\EmphTT{\refmmz{auto}=\meta{command}\braces{\refmmzauto{memoize}, + \refmmzauto{args}=\marg{argument specification}}}. We can only leave out +\refmmzauto{args} if the command was defined by \refcmd{NewDocumentCommand} or +similar; in this case, Memoize can retrieve the argument specification on its +own. + +And how does the \meta{argument specification} look like? It is a sequence of +letters, each letter determining an argument type. Memoize recognizes the same +argument types and their letters as package \pkg{xparse} (which defines +\refcmd{NewDocumentCommand} and friends), so you should look at (section 1 of) +the documentation of that package for details, if and when you need them. +Here, we focus on the two most commonly used types, \docref{xparse:m} and \docref{xparse:o}, and add the +optional star for good measure: +\begin{center} + \begin{tabular}{lll} + \toprule + letter & argument type & example\\ + \midrule + \docref{xparse:m} & mandatory argument \\ + & --- either surrounded with braces & |\foo{arg}|\\ + & --- or a single token & |\foo a|\\ + \docref{xparse:o} & optional argument, surrounded with brackets & |\foo[arg]|\\ + \docref{xparse:s} & optional star & |\foo*|\\ + \bottomrule + \end{tabular} +\end{center} + +Below, we write |args=om| because command \cs{qrcode} (of package \pkg{qrcode}) +takes two arguments: a bracketed optional argument, followed by a mandatory +argument (in braces). + +\ExampleName{automemoize-command} +\makeexample{\examplename.pdf} +\tcbinputexample{ + sidebyside, lefthand ratio=0.603, top=0mm, + comment={\centering + \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}\quad + \includeexamplepdf[extern page]{page=2,trim=1in 1in 1in 1in} + }, +} + +This should get you started with automemoization. We'll provide some further +basic information in sections~\ref{sec:tut:working-on-a-picture} +and~\ref{sec:tut:verbatim} of the tutorial, but only package writers will +probably ever need the gory details from +section~\ref{sec:tut:automemoization-details}. It is my sincere hope that they +will support Memoize in their packages, where necessary, so that you don't even +have to write the \refmmz{auto} declarations, but there is one thing you should +know if you encounter a package supporting Memoize: you should load it +\emph{after} Memoize! + + + +\subsection{Working on a picture} +\label{sec:tut:working-on-a-picture} + + +Memoize automatically recompiles a picture when the code producing the picture +changes. However, sometimes we can modify a picture without changing its code, +like when we modify the definition of a command used in the code. In the +example below, a predefined style |emph| is applied to the node, producing a +node with a red background. Let's say we compile the document (with +memoization) and then change this style to set the yellow background. +Curiously, the node will remain red. + +\ExampleName{recompile} +\makeexample{\examplename.pdf N=3} +\begin{tcbraster}[raster columns=2, raster valign=top, raster column skip=4mm] + \tcbinputexample{ + after title pre={\ (version~1)}, + comment={\centering + \includeexamplepdf[document page]{page=2} + }, + } + \tcbinputexample[.tex][.c2]{ + no attachment, + after title pre={\ (version~2)}, + comment={\centering + \includeexamplepdf[document page]{page=1} + }, + } +\end{tcbraster} + +The curious thing happens (or rather, doesn't happen) because Memoize doesn't +keep track of how commands and styles are defined; it just uses the extern file +it created when the old style was in effect. To get a yellow node, we must ask +Memoize to reexternalize the picture. The simplest way to do that is by using +the \Emph{\refmmz{recompile}} key; below, we write +\refcmd{mmznext}\bracestt{\refmmz{recompile}} just before the picture and +compile the document again (remember from section~\ref{sec:mmzset} that +whatever keys we provide through \refcmd{mmznext} only apply to the instance of +automemoization). After the compilation, we may (and should) remove the +\refmmz{recompile} directive (otherwise, Memoize will produce the extern page +again and again). + +\tcbinputexample[.tex][.c3]{ + no attachment, + after title pre={\ (version~3)}, + sidebyside, lefthand ratio=0.6, + comment={\centering + \includeexamplepdf[document page]{page=2} + }, +} + +It is also common to put (again, for the space of a single compilation) +\refcmd{mmzset}\braces{\refmmz{recompile}} in the preamble, or to use +\refmmz{recompile} as the package option. Either will remake all the +externalized graphics in the document, so you can be sure all of them use the +latest version of your macros and styles. + +We'll revisit the issue of memoized code depending on macros and styles defined +elsewhere in section~\ref{sec:tut:redefinitions}. In this section, we will +learn how the issue can be \emph{avoided}, at least to some extent. One idea +is to turn off memoization for the picture(s) we are currently working on; +another idea is to let Memoize know which definitions the picture relies on. +The simplest way to achieve the former is by using key \Emph{\refmmz{disable}}; +by putting it into a \hologo{TeX} group, we can localize its effect to the +selected pictures. + +\ExampleName{disable} +\makeexample{\examplename.pdf} +\tcbinputexample{ + sidebyside, + lefthand ratio=0.6, + top=0mm, % manual top, bottoms and \\[...] to fit the page + comment={\centering + \includeexamplepdf[extern page,bottom=0.8mm]{page=1,trim=1in 1in 1in 1in}\\[0.5mm] + \includeexamplepdf[extern page,bottom=0.8mm]{page=2,trim=1in 1in 1in 1in}\\[0.5mm] + \includeexamplepdf[document page,bottom=0.8mm]{page=3} + }, +} + +\begin{tcolorbox}[warning] + As you can imagine, key \refmmz{disable} is complemented by \refmmz{enable}, + but it is perhaps worth mentioning a problem that can arise if you disable + memoization for a part of your document by enclosing it in a pair of + \refcmd{mmzset}\braces{\refmmz{disable}} and + \refcmd{mmzset}\braces{\refmmz{enable}}. Yes, it might work at the moment, + but say you later (e.g.\ when you are preparing the final version of the + document) decide to disable memoization for the entire document, and say you + try to do this by writing \refcmd{mmzset}\braces{\refmmz{disable}} in the + preamble. As shown below on the left, you're in for a surprise: memoization + will still be enabled in the part of the document following + \refcmd{mmzset}\braces{\refmmz{enable}}! The solution is to always disable + memoization for a part of the document by using + \refcmd{mmzset}\braces{\refmmz{disable}} in a \hologo{TeX} group (i.e.\ the + braces), as shown on the right. (In the examples below, the shaded areas + mark the parts of the document where memoization is \emph{disabled}.) +\end{tcolorbox} + +\makeexample{disable-bad.tex.c1} +\makeexample{disable-good.tex.c1} +\makeexample{disable-nomemoize.tex.c1} +\makeexample{disable-nommz.tex.c1} +\makeexample{disable-auto-cmd.tex.c1} +\makeexample{disable-auto-env.tex.c1} + +\begin{tcbraster}[raster columns=2, raster equal height=rows] + \tcbinputexample(disable-bad){ + listing and comment, bad, mark region={4}{7}, + comment={\raggedright The upper \refcmd{mmzset}\braces{\refmmz{disable}} + does not have the intended effect, + i.e.\ it doesn't apply to the whole document!}} + \tcbinputexample(disable-good){ + listing and comment, mark region={4}{10}, + comment={\raggedright The upper \refcmd{mmzset}\braces{\refmmz{disable}} applies + to the entire document, as expected.}} +\end{tcbraster} + +In fact, it might be better to disable memoization using environment +\Emph{\refenv{nomemoize}} or macro \Emph{\refcmd{nommz}}. I also like these +commands because it is easy to add and remove prefix |no| to switch manual +memoization (triggered using environment \refenv{memoize} or macro +\refcmd{mmz}) off and on. + +\begin{tcbraster}[raster columns=2, raster equal height=rows] + \tcbinputexample(disable-nomemoize){listing and comment, mark region={2}{2}, + comment=\raggedright Disable using the dedicated environment.} + \tcbinputexample(disable-nommz){listing and comment, mark region={2}{2}, + comment=\raggedright Disable using the dedicated command.} +\end{tcbraster} + +It is also possible to disable memoization for all occurrences of a selected +command or environment. In fact, we're already familiar with the procedure +from section \ref{sec:tut:automemoization}, where we used key +\refmmzauto{memoize} inside the second argument of \refmmz{auto} to +automatically memoize all instances of the command or environment given as the +first argument. All we have to do to auto-disable rather than auto-memoize, is +substitute \refmmzauto{nomemoize} for \refmmzauto{memoize}. Note that this +prevents memoization of not only the given command or environment, but also of +any (manual or automatic) memoization which would otherwise occur during its +execution; for example, if |\foo| executes \cs{tikz} under the hood, +autodisabling |\foo| prevents memoization of the inner \cs{tikz}, even though +that command is normally automemoized. + +\begin{tcbraster}[raster columns=2, raster equal height=rows] + \tcbinputexample(disable-auto-cmd){ + listing and comment, + mark region={3}{3}, mark region={5}{5}, + comment=\raggedright Autodisable within a command., + } + \tcbinputexample(disable-auto-env){ + listing and comment, + mark region={3}{5}, + comment=\raggedright Autodisable within an environment., + } +\end{tcbraster} + +All that said, Memoize actually offers a neater way to switch off the +externalization for the picture I'm currently working on. The +\Emph{\refmmz{readonly}} key instructs Memoize to use whatever externs it had +already produced (thereby reducing the document compilation time), but to +abstain from producing any new externs. In effect, the stuff we are currently +working on does not undergo memoization and therefore does not produce the +clutter which can potentially lead to trouble described in the \refmmz{recompile} +examples above. + +What I like to do is load the package using |\usepackage[readonly]{memoize}|, +work on stuff, and once I'm happy with the most recent pictures, remove +\refmmz{readonly} from the package options for one compilation. + +\ExampleName{readonly} +\makeexample{\examplename.pdf N=2} + +\begin{tcbraster}[raster columns=5, raster valign=top, raster column skip=4mm] + \tcbinputexample{ + raster multicolumn=2, + after title pre={\ (work in progress)}, + comment={\centering + \includeexamplepdf[document page]{page=1} + }, + } + \tcbinputexample[.tex][.c2]{ + raster multicolumn=3, + no attachment, + title={\tt readonly.tex} (the final version), + comment={\centering + \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}\quad + \includeexamplepdf[document page]{page=2} + }, + } +\end{tcbraster} + +We're now ready to tackle a completely different way of avoiding the issue, by +informing Memoize which definitions the externalized picture depends on. We do +this by appending these definitions to \emph{context} --- when the context of a +picture changes, Memoize recompiles the picture, same as if the code of the +picture itself was changed. (We will talk about context in more detail in +section~\ref{sec:cross-referencing}.) + +A command can be added as a dependency using key \Emph{\refmmz{meaning to + context}}. Below, we make the following externalized picture depend on the +definition of macro \cs{answer}; changing this definition will result in the +recompilation of the extern. In general, \refmmz{meaning to context} accepts a +comma-separated list of command and environment names, e.g.\ +\code{\refmmz{meaning to context}=\bracestt{\cs{foo},bar}} (note the braces). + +Memoize offers several variants of \refmmz{meaning to context}, applicable to +various types of commands. For example, the easiest way of making the picture +depend on the definition of a \pkg{pgfkeys} style is to use handler +\Emph{\refkey{/handlers/.meaning to context}} --- note the dot in the name, and +observe that \code{emph/.meaning to context} below is executed within +\cs{tikzset}, not \refcmd{mmzset}; see \PGFmanual{87} to learn about key +handlers. + +\ExampleName{meaning-to-context} +\makeexample{\examplename.pdf N=2} +\tcbinputexample{ + after title pre={\ (version~1)}, + sidebyside, + comment={\centering + \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in} + }, +} + +\tcbinputexample[.tex][.c2]{ + after title pre={\ (version~2)}, + sidebyside, + comment={\centering + \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in} + }, + no attachment, +} + +All variants of \refmmz{meaning to context} (see reference +section~\ref{sec:ref:memoization:basic} for the full list) may be used within +the externalized picture itself, e.g.\ \code{\cs{node}[emph, + emph/\refkey{/handlers/.meaning to context}]\bracestt{...}} is perfectly +valid --- and also handy when you want to limit the effect of the handler to a +single picture, as \refkey{/handlers/.meaning to context} cannot be used within +\refcmd{mmznext}. + + + +\subsection{Keeping a clean house} +\label{sec:tut:memodir} + +Memoize produces lots of auxiliary files. For each piece of memoized code, it +produces two \emph{memo} files (we will learn more about these in +section~\ref{sec:memos}), which will be joined by the extern PDF upon the next +compilation.\footnote{If you're using the \hologo{TeX}-based extraction, each + extern (|.pdf|) is also accompanied by a log file (|.log|) produced during + the compilation that extracted the extern.} You can recognize these files +easily: their names start with the name of your document and include one or two +long hexadecimal numbers. + +\ExampleName{dirty-house} +\makeexample{\examplename.pdf} +{ + \relaxmmzcommands + \edef\marshal{% + \noexpand\def\noexpand\mynewextern.//\examplename + }\marshal.#1-#2.pdf\relax{% + \forestset{ + append={[\examplename.#1.memo\vphantom{p},pointcolor]}, + append={[\examplename.#1-#2.memo\vphantom{p},pointcolor]}, + append={[\examplename.#1-#2.pdf,pointcolor]}, + }% + } + \tcbinputexample{ + comment={% + \begin{tcolorbox}[reset, left=2mm, bottom=0mm, + my boxed title=the folder contents (after two compilations), + attach shifted boxed title to top right, + ] + \begin{forest} + before typesetting nodes={for tree={ + font=\scriptsize\tt, grow'=0, folder, s sep=0}}, + [\meta{the document folder}, inner xsep=0, + TeX={% + \def\mmzNewExtern##1##2##3##4##5{\mynewextern##1\relax}% + \input{\examplepath.mmz}% + }, + [\examplename.tex] + [\examplename.pdf] + [\normalsize\dots, no edge] + [\examplename.mmz, tikz={\draw[dotted](.east)--+(5em,0ex) node [anchor=south west, yshift=-1ex, align=justify, text width=14em, font=\footnotesize]{This is another auxiliary file produced by Memoize. We will mention it at the end of the section.};}] + ] + \end{forest} + \end{tcolorbox} + }, + } +} + +To top it off, changing the memoized code will produce new memo (and extern) +files, with the old files staying in place. This is all by design --- the +first hexadecimal number in these filenames is the MD5 sum of the memoized code +and that's how Memoize knows which memo belongs to which piece of +code\footnote{The second hexadecimal number in the memo and extern filenames is + the MD5 sum of the \emph{context}. The context is crucial for properly + externalizing code containing cross-references, see + section~\ref{sec:cross-referencing} for details.} --- but it has the downside +that the folder containing your document can get quite cluttered (imagine the +directory listing as above, but for a document with a hundred externalized +pictures which you have been working on for a month). + +\ExampleName{clean-house} + +I like to keep a clean house by instructing Memoize to put memos and friends +into their own directory. This can be achieved by writing +\refcmd{mmzset}\braces{\Emph{\refmmz{memo dir}}} into the preamble (anytime +after loading the package).\footnote{The \refmmz{memo dir} key is in fact + merely an abbreviation for a sequence of \refmmzpath{dir} and + \refmmzpath{prefix} within \refmmz{path}; use these keys if you need more + control over the name and location of the auxiliary files. Furthermore, there + is also the \refmmz{no memo dir} key, which reverts the configuration back to + the dirty default.} This will put the memo and the extern files into folder +\meta{document name}|.memo.dir| (and it will also omit the \meta{document name} +prefix in their filenames, because it makes no sense to repeat it there). + +\makeexample{\examplename.pdf} +{% + \relaxmmzcommands + \edef\marshal{% + \noexpand\def\noexpand\mynewextern./\examplename + }\marshal.memo.dir/#1-#2.pdf\relax{% + \forestset{ + append={[#1.memo\vphantom{p},pointcolor]}, + append={[#1-#2.memo\vphantom{p},pointcolor]}, + append={[#1-#2.pdf,pointcolor]}, + }% + } + \tcbinputexample{ + comment={% + \begin{tcolorbox}[reset, left=2mm, bottom=0mm, + my boxed title=the folder contents (after two compilations), + attach shifted boxed title to top right, + ] + \begin{forest} + before typesetting nodes={for tree={ + font=\scriptsize\tt, grow'=0, folder, s sep=0}}, + [\meta{the document folder}, inner xsep=0 + [\examplename.tex] + [\examplename.pdf] + [\normalsize\dots, no edge] + [\examplename.mmz] + [\examplename.memo.dir,pointcolor, + % tikz={\draw[dotted](.east)--+(9em,0ex) node [anchor=south west, yshift=-1ex, font=\footnotesize, emphshade=black!5!white, text width=15em, align=justify]{You need to create this directory by hand, or allow Memoize to create it by adding |mkdir| to the list of restricted shell escape commands.};}, + tikz={\draw[dotted](.east)--+(9em,0ex) node [anchor=west, font=\footnotesize, emphshade=black!5!white]{This directory must be created, somehow.};}, + TeX={% + \def\mmzNewExtern##1##2##3##4##5{\mynewextern##1\relax}% + \input{\examplepath.mmz}% + }, + ] + ] + \end{forest} + \end{tcolorbox} + }, + } +} + +\begin{tcolorbox}[title={Why is \refmmz[link color=white]{memo dir} not the default?}] + The \code{clean-house} example most likely compiled just fine, and you are + wondering why \refmmz{memo dir} is not in effect by default. Well, out of + the box, \hologo{TeX} cannot create directories, so it is the fact that + Memoize \emph{can} create them (at least under the default settings) which + requires explanation. By default, Memoize triggers extraction by executing + the Perl extraction script \refscript{memoize-extract.pl}, and it is this + script which actually creates the memo directory. However, not everybody + will necessarily use this script \dots\ so \refmmz{memo dir} should not be + the default. + + The Python extraction script \refscript{memoize-extract.pl}, used when + \refmmz{extract}|=|\refmmz{extract=python}, works the same as the Perl + variant. With \hologo{TeX}-based extraction + \refmmz{extract}|=|\refmmz{extract=tex}, things are different. If you are + compiling the document with a full shell escape mode + (\docref{-shell-escape}), Memoize successfully creates the directory with the + system command |mkdir|.\footnote{|mkdir| is the default value of key + \refmmz{mkdir command}, but executing the extraction method + \refmmz{extract=perl} or \refmmz{extract=python} overrides this default.} + However, if you're using the restricted shell escape mode, the attempt to + create the directory won't succeed unless you include |mkdir| among the + restricted shell escape commands (see footnote~\ref{fn:shell-escape-commands} + on page~\pageref{fn:shell-escape-commands} for how to do this, but note that + it is not recommended). + + If you are using external extraction, you have to create directory + \texttt{\examplename.memo.dir} by hand, prior to the first compilation of the + document (with Memoize). This is the case even if you are performing the + extraction using one of the shipped extraction methods, and it is due to the + fact that Memoize needs the memo directory to be present even before extern + extraction, because it writes the |.memo| files into the same directory. + (When Memoize uses the extraction script to create the memo directory, it + does so completely independently of extraction, and prior to creating any + |.memo| files.) +\end{tcolorbox} + +I actually suggest adding \refcmd{mmzset}\braces{\refmmz{memo dir}} into your +user-wide \reffile{memoize.cfg} (see section~\ref{sec:memoize.cfg} for details +on this file). This will keep all your houses clean --- without work! --- as +Memoize will automatically use the memo directory for any document your create. + +It is always safe to delete memos (|.memo|) and externs (|.pdf|s residing next +to memos), in the sense that you cannot lose data this way.\footnote{The same + goes for the extern |.log| files produced by the \hologo{TeX}-based + extraction.} + +\begin{itemize} + +\item Many memos and externs are typically stale anyway, i.e.\ they reflect + some previous state of your document and are not needed anymore. These files + can be deleted without any repercussions whatsoever (unless you later revert + to a previous version of the document, of course). In fact, you might + \emph{want} to delete them periodically, or at least once you finish writing + the document. As it is hard to figure out which memos/externs are stale, + Memoize ships with a clean-up script: writing \refscript{memoize-clean.pl} + \meta{document name}\dmmz (replace |.pl| with |.py| if you use Python rather + than Perl) into the command line will delete all the \emph{stale} auxiliary + files belonging to the document. + +\item If you delete a memo or an extern currently in use, you will trigger + recompilation of their code --- so deleting a memo or an extern is actually a + perfectly legal alternative to using the \refmmz{recompile} key!\footnote{For the + users of the \hologo{TeX}-based extraction: deleting the |.log| file does + \emph{not} trigger recompilation.} + +\end{itemize} + +It is also safe to delete the \dmmz file (or any other kind of record file, see +section~\ref{sec:record-files}) residing next to your document's |.pdf|. The +\dmmz file contains the information about which externs should be extracted +from the |.pdf|. Deleting it before this is done (by default, before compiling +the document again) will prevent the extraction (same as if providing the +package option \code{\refmmz{extract}=\refmmz{extract=no}}) and ultimately +result in the recompilation of the externs produced in the previous run. +Deleting it after the extraction will have almost no effect: it will only only +prevent the clean-up script from working (the \dmmz file also lists the +currently active memos and externs, and thereby indirectly informs the clean-up +script which files are stale). For further information on the \dmmz file, see +section~\ref{sec:.mmz}. + + + +\subsection{Writing a book?} +\label{sec:tut:multifile} + +Books and other long documents are usually produced from sources which reside +in more than a single file, and to speed up the editing process, authors +usually use some system which allows them to compile each chapter separately. +Can Memoize --- designed for virtually the same task of speeding up the editing +process --- work sensibly in this kind of situation? More precisely, can the +book and the individual chapters share the memos and the externs? Yes they +can! If we instruct Memoize to use the same memo directory for both the book +job and the chapter jobs, then we can externalize graphics when compiling a +chapter and have the externs included when compiling the book (and vice +versa).\footnote{Package \pkg{docmute} makes \hologo{LaTeX} ignore the preamble of + the chapter file when including this file into the main document.} All we +need to do is use our old friend \refmmz{memo dir} from section~\ref{sec:tut:memodir} +--- we see now that this setting is good for more than just keeping a clean +house! + +\ExampleName{book} +\makeexample{\examplename.tex.c1} +\makeexample{chapters/chapter1.tex.c1} + +\begin{tcbraster}[raster columns=2, raster valign=top] + \tcbinputexample{listing only} + \tcbinputexample(chapters/chapter1){listing only} +\end{tcbraster} + +In the above example, the individual chapters reside in files stored in the +|chapters| subdirectory, and that's why the |book.tex| preamble uses +\code{\refmmz{memo dir}=chapters/book} (rather than \code{\refmmz{memo + dir}=book} or just \refmmz{memo dir}). However, Memoize has no trouble +with a situation where the main file and the chapters reside in the same +folder; the setup is even simpler, as we then say \code{\refmmz{memo dir}=book} +in both the book and the chapter preamble. The more complicated situation was +chosen to point out the following potential problem with the setup where the +chapters reside in a subdirectory. + +If you're anything like me, you would first go for having a memo directory +immediately contained in the project directory (so |examples/book.memo.dir| +above) and set up \refmmz{memo dir} as shown below. Well, this won't work, or +at least it won't work with the vanilla \hologo{TeX} Live, because \hologo{TeX} +will refuse to \emph{write} into (memo) files outside the directory where it +was executed,\cprotect\footnote{In \hologo{TeX} Live, the \reffile{texmf.cnf} + option controlling this behaviour is called |openout_any|. By default, it is + set to |p| (paranoid), which ``disallow[s] opening dot files [and] + \emph{going to parent directories}, and restrict[s] absolute paths to be + under \texttt{\$TEXMFOUTPUT}'' (emphasis mine).} and this is precisely what +the chapter compilation is asked to do below. + +\begin{tcboxedraster}[raster columns=2, raster valign=top]{blankest, bad} + \begin{tcblisting}{example title, title=the main file, listing only} +\mmzset{~memo dir=book~} +% ... +\input{chapters/chapter1.tex} + \end{tcblisting} + \begin{tcblisting}{example title, title=a chapter file, listing only} +\mmzset{~memo dir=../book~} + \end{tcblisting} +\end{tcboxedraster} + +\pagebreak % manual + +Section~\ref{sec:tut:working-on-a-picture} presented some ideas on how to work +on a single picture. Those ideas can be all easily applied to the multi-file +situation. For example, you could use \refmmz{readonly} on the chapter that you're +working on (and that chapter only). This way, the preview of the chapter will +not be tarnished by the extern pages, and if you periodically compile it +without \refmmz{readonly}, or compile the book (which does not have the \refmmz{readonly} +set), you will have a reasonably up-to-date set of externs. + +\begin{tcboxedraster}[raster columns=2, raster valign=top]{blankest} + \begin{tcblisting}{example title, title=the main file, listing only} +\mmzset{memo dir=chapters/book} +% ... +\input{chapters/chapter1.tex} + \end{tcblisting} + \begin{tcblisting}{example title, title=the current chapter file, listing only} +\mmzset{memo dir=book, ~readonly~} + \end{tcblisting} +\end{tcboxedraster} + +\ExampleName{memoize.cfg._region_} +\makeexample{\examplename.tex.c1} +\begin{tcolorbox}[title=For \Emacs users] + I often use this \refmmz{readonly} trick myself, but with a twist. As an Emacs user, + I don't use a \hologo{TeX}-based mechanism (such as the \pkg{docmute} package) to + compile a chapter, but rely on the region compilation feature of Emacs' + AUC\hologo{TeX} package. AUC\hologo{TeX} offers a way to compile the current + buffer (if you don't know what an Emacs buffer is, read ``file'') or region + (roughly speaking, the selected text). It does that by putting the buffer or + the region into a file called |_region_.tex| while dressing it up in the + preamble of the original document (when I'm working on a multi-file document, + it correctly pulls the preamble from the main document). This results in a + compilable region file. My trick is to detect whether I'm compiling a region + (this is the job of |\ifregion|), and if so, put Memoize into the \refmmz{readonly} + mode (an alternative trick would be to \refmmz{disable} it). + + This is the trick in a nutshell, but to make it really work we have to + address one further issue: the original document and the region have to share + memos and externs. This happens automatically if the original document sets + \refmmz{memo dir} explicitly (e.g.\ if a document called |doc.tex| contains + \code{\refmmz{memo dir}=doc} in the preamble), but I'm lazy and don't want to + write this in every document --- if I have to do that, what's the point of + \refmmz{memo dir} I put into my \reffile{memoize.cfg} in + section~\ref{sec:tut:memodir}? Fortunately, the region file starts with + |\message{ !name(|\meta{original document name}|.tex)}| to indicate the + origin. The complicated part of the code below (everything following + \refcmd{mmzset}\braces{\refmmz{readonly}} parses this header to extract the + \meta{original document name}, which is then fed to \refmmz{memo dir}. Now, + the trick works automatically for any document.\footnote{The assumption here + is that \refmmz{memo dir} is in effect for the original document. If not, + the trick can be adapted to use (\refmmzpath{dir} and) \refmmzpath{prefix} + within \refmmz{path}.} + + \tcbinputexample{ + title=\tt memoize.cfg, + attachment name=memoize-region.cfg, + listing only, + } +\end{tcolorbox} + + +\subsection{Writing a presentation?} +\label{sec:tut:beamer} + +Memoize ships with built-in support for the most widespread \hologo{LaTeX} +presentation class, Beamer, in the sense that it can externalize a picture +which changes from overlay to overlay. Before we learn how to use that +functionality, however, there's a peculiarity about loading Memoize in Beamer +to address. + +\ExampleName{beamer} +\makeexample{\examplename.pdf} + +\tcbinputexample{ + comment and listing, + listing options app={lastline=2}, + warning, no attachment, title=, + % + comment={Beamer opens the document PDF while loading the class, while + Memoize requires the PDF from the previous compilation intact in order to + extract the externs (when extraction is triggered internally, which is the + default setting). The solution is to load Memoize (a package) before + Beamer (a class), which can be done by using \cs{RequirePackage} instead of + the usual \cs{usepackage}. Easy, if hacky.}, + % +} + +To memoize a piece of code which produces different results on different +overlays --- by virtue of containing |\pause|, |\only|, and\slash or related +commands --- apply key \Emph{\refmmz{per overlay}}. Without this key, +externalization of the picture will end badly, with a single extern (the final +one) appearing on all overlays. The key may be invoked either from a prior +\refcmd{mmznext} command,\footnote{Of course, \refmmz{per overlay} may also be + invoked from \refcmd{mmzset}, but I guess this won't make sense often. For + example, if you set it for the entire presentation, and the presentation + contains static memoized pictures as well, you will compile those pictures + more times than necessary: once for each overlay, whereas once per frame + would suffice. It might occasionally make sense, however, to use \refmmz{per + overlay} as an \refmmz{auto} option --- consult + section~\ref{sec:tut:verbatim} to learn what that is.} or executed in the +memoized code itself. The example below illustrates the latter option, and +also shows that we may invoke it via its full path, +\refkeypath{/mmz}|/|\refmmz{per overlay}, when listed among options processed by +\pkg{pgfkeys}.\footnote{Read section~\ref{sec:per-overlay} to learn how the + Beamer support is implemented. The implementation only uses Memoize's public + interface, so understanding it should help if you need to support some other + presentation package.} + +\tcbinputexample{ + listing options app={firstline=3}, + middle=1mm, + comment={\def\dpwidth{0.27\linewidth}\def\epwidth{0.15\linewidth}% + \raisebox{-\height}{\includeexamplepdf[extern page,left=0mm,right=0mm]{width=\epwidth,page=1,trim=1in 1in 0.4in 0.6in}}\hfill + \raisebox{-\height}{\includeexamplepdf[document page,left=1mm,right=1mm]{page=2,width=\dpwidth}}\hfill + \raisebox{-\height}{\includeexamplepdf[extern page,left=0mm,right=0mm]{width=\epwidth,page=3,trim=1in 1in 0.4in 0.6in}}\hfill + \raisebox{-\height}{\includeexamplepdf[document page,left=1mm,right=1mm]{page=4,width=\dpwidth}}% + }, +} + +\begin{tcolorbox}[warning] + If the memoized code changes the value of Beamer's pause counter + |beamerpauses|, e.g.\ by issuing a |\pause|, take care that (i) \refmmz{per + overlay} is executed prior to any changes of |beamerpauses|, and that (ii) + the final value of this counter in the memoized code is the same for all + overlays. +\end{tcolorbox} + + +\subsection{When stuff sticks out} +\label{sec:tut:padding} + +Some constructs --- like plain \hologo{TeX}'s \refcmd{llap} and \refcmd{rlap}, +and, notably, \TikZ overlays --- fool \hologo{TeX} into thinking that the +``size'' of the typeset material is different than what it actually is. This +can cause trouble for externalization: a piece of your picture might disappear! +In a sentence, the solution is to manually set the \emph{padding} of the +externs, but let's slow down a bit. + +The \TikZ picture in the following example consists of node with a pin on the +right, but let's say we want to horizontally center this picture so that only +the node rather than the entire picture (including the pin) will be centered. +This can be achieved by adding key \refkey{/tikz/overlay} to the pin (actually, +we need to add it to both the pin and its edge). \TikZ normally updates the +extents (called the bounding box) of the picture every time it puts something +in it; when \refkey{/tikz/overlay} is in effect, however, these updates are +temporarily disabled. In effect, the \refkey{/tikz/overlay} key on the pin +below will fool \hologo{TeX} into thinking that the node is all there is to the +picture, so centering will work as desired. + +\ExampleName{overlay} +\makeexample{\examplename.pdf N=4} +\tcbinputexample{ + after title pre={\ (no memoization)}, + comment={\centering + % \includeexamplepdf[document page]{page=1,trim=1.8in 7.4in 1.8in 1.7in} + \includeexamplepdf[document page]{page=1} + }, +} + +What happens when we try to externalize this picture? The example below shows +what would happen if Memoize had no concept of \emph{padding} --- which we +simulate by setting \code{\refmmz{padding}=0pt}.\footnote{Unlike in the rest of + the manual, the extern pages in this section are shown without trimming the + whitespace.} Along with the rest of \hologo{TeX}, Memoize would be fooled +into thinking that the picture comprises of the node only, so the pin would +never make it into the extern. You would end up with a document missing the +pin!\footnote{On the first compilation, the document page containing the figure + without padding looks fine, as it uses the result of the compilation rather + than the extern file. But on the second compilation, when Memoize actually + uses the extern, the pin disappears.} + +\tcbinputexample[.tex][.c2]{ + after title pre={\ (memoization without padding)}, + attachment name=\examplename-no-padding.tex, + sidebyside, lefthand ratio=0.3, + comment={\centering + \includeexamplepdf[size=minimal,boxrule=0.5mm,extern page, + attach boxed title to top right={xshift=1.5mm,yshift=-1mm}, + ]{page=1} + }, +} + + +By default, Memoize puts an inch of space around (what it thinks is) the +externalized picture, and if the overlayed parts of the picture fit into this +inch of space, you will find them in the extern and therefore also in the +document. In our example, however, the default padding is not enough --- the +pin is only partially visible.\footnote{You might wonder why I didn't make the + default padding much bigger, like 10 inches. \hologo{TeX} wouldn't be + bothered (unless the resulting extern size exceeded its maximum dimension), + but you might be, because with such a large default padding, all the externs + would be huge, most often bigger than the document pages, and remember that + the externs are first dumped into the document, where they can bother you.} + +\tcbinputexample[.tex][.c3]{ + after title pre={\ (memoization with default padding)}, + attachment name=\examplename-default-padding.tex, + listing and comment, + middle=0.9mm, + comment={\centering + \includeexamplepdf[extern page,size=minimal,boxrule=0.5mm]{page=1} + }, +} + +The solution is to set the padding manually. Below, I used \refmmz{padding + right} to only increase the padding on the right side (clearly, we also have +\refmmz{padding left}, \refmmz{padding top} and \refmmz{padding bottom}), but +if you're not bothered by a large extern, you can just use +\Emph{\refmmz{padding}}, which sets all four sides at once. By the way, having +too much padding (almost) never hurts, and as you see, you can use (simple) +arithmetics in the value of these keys. + +\tcbinputexample[.tex][.c4]{ + after title pre={\ (memoization with extra padding)}, + attachment name=\examplename-extra-padding.tex, + listing and comment, + middle=0.9mm, + comment={\centering + \includeexamplepdf[extern page,size=minimal,boxrule=0.5mm]{page=1} + }, +} + +\enlargethispage{1ex} % manual +Incidentally, the \refmmz{padding} keys only change how +the externalized picture is \emph{stored}. Memoize remembers the size of the +extern as seen by \hologo{TeX} (e.g.\ the bounding box of the picture as +reported by \TikZ, with overlayed parts of the picture protruding out of it), +and it uses that size when integrating the extern into the document --- so +everything works as it should! + + + +\subsection{The verbatim mode} +\label{sec:tut:verbatim} + +Not all code will peacefully submit to memoization. In particular, this is the +case for environments which process the environment body verbatim (or perform +some other kind of \refcmd{catcode} magic). A simple environment of this kind is the +standard \hologo{LaTeX} \refenv{verbatim}, but let us illustrate the issue with +\refenv{tcblisting}, which typesets a code listing alongside its compiled effect. +(This environment is defined by the |listings| library of package \pkg{tcolorbox} +and was used extensively during the production of this manual.) To manually +memoize a \refenv{tcblisting} environment, we enclose it in a \refenv{memoize} +environment with a \Emph{\refmmz{verbatim}} key in the optional argument --- +without this key, the example below would produce nothing but +errors.\footnote{Memoize also offers a \emph{partial} verbatim mode, triggered + by key \refmmz{verb}; in this mode, the braces retain their usual category + codes. Also note that the effect of \refmmz{verbatim} can be ``undone'' by + key \refmmz{no verbatim}.} + +\ExampleName{verbatim-manual} +\makeexample{\examplename.pdf} +\tcbinputexample{ + sidebyside, + comment={\centering + \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}\\[1ex] + \footnotesize + (The document page is the same as for the \texttt{verbatim-auto} example below.) + }, +} + +Using \refmmz{verbatim} from \refcmd{mmzset} or \refcmd{mmznext} works just as +well, and the latter can be very useful with automemoization, when some +environment (say, \env{tcolorbox}) generally does not require the verbatim mode, +but a specific occurrence does (say, because it contains some verbatim +construction such as \verb!|!\meta{verbatim text}\verb!|! of the \pkg{ltxdoc} +class). + +However, for an environment such as |tcblisting|, it makes the most sense to +declare it verbatim in general, so that all instances of the environment will +be processed in the verbatim mode. This is simple to do: add \refmmz{verbatim} +to the \refmmz{auto} keylist. + +\ExampleName{verbatim-auto} +\makeexample{\examplename.pdf} +\tcbinputexample{ + sidebyside, % lefthand ratio=0.62, + comment={\centering + \footnotesize + (The extern page is the same as for the \texttt{verbatim-manual} example above.)\\[1ex] + \includeexamplepdf[document page]{page=2}\\ + }, +} + +In fact, you can add any \refkeypath{/mmz} key to the \refmmz{auto} keylist, +and the key will be applied to all occurrences of the command or the +environment. For example, adding \refmmz{recompile} to the declaration of +|tcblisting| above would recompile all and only the |tcblisting| environments; +and as an \refmmz{auto} declaration only updates (rather than completely +replaces) a previous declaration, you can also say things like +\code{\refmmz{auto}=\refcmd{tikz}\braces{\refmmz{recompile}}} to recompile all +\TikZ pictures produced by the \cs{tikz} command (handy, as you don't know how +automemoization for \cs{tikz} was declared unless you've read +section~\ref{sec:tut:automemoization-details} or looked at the Memoize's source +code). + + +\subsection{The final version of your document} +\label{sec:tut:final} + +Bluntly put, you might want to disable Memoize when compiling the final version +of your document, at least if you intend to distribute it in electronic form, +for two reasons: +\begin{itemize} +\item An externalized picture cannot contain hyperlinks. Any hyperlinks (or + hyperlink anchors) contained in the original picture will silently disappear + during the production of the extern. +\item When the document contains many externs, the size of the resulting PDF + can be several times the size of the PDF compiled without externalization. +\end{itemize} + +Below, we list several ways of fully disabling Memoize. You're of course +already familar with the first two ways, but what's this \refpkg{nomemoize} +package? The rationale behind this package is that if you want to be +absolutely sure that there is no trace of memoization in your document (for +example, see the \refmmz{disable} -- \refmmz{enable} pitfall in +section~\ref{sec:tut:working-on-a-picture}), the best thing to do is to not +load the package at all. However, you have all those \refcmd{mmzset}s etc.\ in +your source, so the document won't compile without +\cs{usepackage}\braces{\refpkg{memoize}}, right? Right, but wrong. Enter +\Emph{\refpkg{nomemoize}}, a dummy package which accepts all the commands that +Memoize does, but does nothing. In effect, your document will compile, but you +can be sure that not a single memo or extern was loaded or produced. + +\begin{tcbraster}[raster columns=3, raster force size=false, raster valign=top] + \begin{tcblisting}{listing only, add to width=2.4em, enhanced} +\usepackage[~disable~]{memoize} + \end{tcblisting} + \begin{tcblisting}{listing only, add to width=-1.6em, enhanced} +\usepackage{memoize} +\mmzset{~disable~} + \end{tcblisting} + \begin{tcblisting}{listing only, add to width=-0.8em, enhanced} +\usepackage{~no~memoize} + \end{tcblisting} +\end{tcbraster} + +There is one issue you might need to resolve manually before package +\refpkg{nomemoize} works as intended, though. If you have used any +\refkeypath{/mmz} keys outside \refcmd{mmzset}, you need to list them in +\refcmd{nommzkeys}. For example, if you used \refmmz{per overlay} in the manner +illustrated in section~\ref{sec:tut:beamer}, i.e.\ as +\refkeypath{/mmz}|/|\refmmz{per overlay} among the \TikZ keys, you need to +write \refcmd{nommzkeys}\braces{\refmmz{per overlay}} into the document +preamble. + +Another thing you might want to do once you have produced the final version of +the document (in fact, just before you disable Memoize for good) is clean up. +As we saw in sections~\ref{sec:tut:memodir} and~\ref{sec:tut:redefinitions}, +Memoize produces a lot of auxiliary files (memos and externs) and it keeps the +old versions around! Once your document is prepared, you can reduce the +clutter (and save some disk space) by deleting memos and externs belonging to +the work-in-progress versions of your document, and keep only those used in the +final version. + +You could achieve this by deleting all the memos and externs (if you're using +the \refmmz{memo dir} directive, this amounts to the entire contents of the +memo directory) and compiling your document for the final couple of times. +However, there is an easier (but \hologo{TeX}-external) way: on the command +line, change into the directory containing your (main) document and write +\EmphTT{\refscript{memoize-clean.pl}} \meta{document name}\dmmz (substitute +|.py| for |.pl| to use Python rather than Perl). The script will inspect the +contents of the \dmmz record file to see which memos and externs were used in +the final compilation, and delete all other memos and externs belonging to the +given document. + +\begin{tcolorbox}[warning] + Deleting memos and externs is never an irreversible operation, as you can + always recreate them, but it is still wise to be cautious when cleaning up. + For one, avoid cleaning up after a compilation which produced errors; a + failed compilation can lead to an incomplete \dmmz file, which can in turn + lead to over-deletion. Another bad idea is cleaning up after disabling + Memoize for a part of a document, for the same reason. + + All that said, Memoize takes some precautions itself. It will cowardly + refuse to perform the clean-up when the \dmmz file is missing the + end-of-file marker (|\endinput|), assuming that this indicates a fatal error + in the previous compilation. It will do the same in case the \dmmz file is + absent or empty. The latter is assumed to be a result of a globally + \refmmz{disable}d memoization, but note that clean-up will be performed if + memoization was disabled using package \refpkg{nomemoize}: that package does not + touch the \dmmz file, so cleaning up should work as intended. +\end{tcolorbox} + +As the final note, memos and externs (cleaned-up or not) may be copied (along +the document source) to another directory or machine, where they should be +picked up by Memoize. There is no need to copy the \dmmz file (assuming that +the document PDF contains no extern pages waiting for extraction). + + +\section{Digging deeper} +\label{sec:potential-pitfalls} + + + +\subsection{Good to know} +\label{sec:tut:good-to-know} + + +\paragraph{Line- and page-breaking} An extern can't be broken across lines or +pages. + +Externalization of a chunk of code produces a PDF, which is included into the +document at subsequent compilations as a picture --- an unbreakable object (a +horizontal box) with fixed width and height. Therefore, the original code +should produce an unbreakable object as well. For example, this means that you +cannot externalize some text and expect \hologo{TeX} to break it across lines +or pages on subsequent compilations. If you try, the compilation will succeed +--- without an error! --- but your externalized text will end up in a single +line, as shown below. + +\ExampleName{no-linebreaking} +\makeexample{\examplename.pdf N=2} +\tcbinputexample{ + bad, + comment={\centering + \includeexamplepdf[extern page,to be continued on right] + {page=1,trim=1in 1in 14in 1in}\\[1ex] + \includeexamplepdf[document page]{page=2}\\[1ex] + \includeexamplepdf[document page,title=the expected document page] + [\examplepath.c2.pdf]{page=1} + }, +} + +That said, you \emph{can} externalize a paragraph or some other vertical mode +material using \refmmz{capture}|=|\refmmz{capture=vbox}, but beware that the +vertical spacing between the memoized material and its surroundings might +change. + + +\paragraph{\env{remember picture}} +\TikZ pictures using this key cannot be externalized. + +Memoize will silently refuse to externalize any \TikZ picture using +\refkey{/tikz/remember picture} (see \PGFmanual{17.13}). Such pictures +interact with the outside world --- they either reference or are referenced by +other pictures --- and are as such unsuitable for externalization. For +example, while the colored boxes in this manual are generally externalized --- +out of principle \Smiley\ --- the title page illustration is not, and it cannot +be, because of the arrows connecting the various \TikZ pictures composing that +illustration. Some packages use the \refkey{/tikz/remember picture} mechanism +under the hood, and are thus subject to this limitation; one example is package +\pkg{todonotes}, but in general, any package dealing with absolute positions on the +page will be limited in this way. + +How does Memoize deal with this situation? Well, by cowardly refusing to +externalize any code which uses \refkey{/tikz/remember picture} or a similar +mechanism for dealing with absolute positions. Luckily, any such mechanism +eventually boils down to the \hologo{TeX} primitive \refcmd{savepos}, so +Memoize hacks --- or as we will say in this manual, \emph{advises} --- this +primitive to abort any ongoing memoization. Initializing and then aborting the +memoization takes some time, to be sure, but the overhead is negligible, +especially in the light of the fact that \emph{not} aborting wreaks real havoc. + +Memoize actually provides a user interface for aborting memoization. +Memoization can be aborted either manually, by executing \refcmd{mmzAbort}, or +automatically. The latter is a generalization of the automemoization idea: a +command such as \refcmd{savepos} can be advised to abort memoization by +\refmmz{auto}|=|\refcmd{savepos}\bracestt{\refmmzauto{abort}}. In Memoize, +commands take your advice seriously, so memoization will be aborted whenever +the advised command or environment is encountered. + + +\paragraph{Indirectly embedded environments} Such environments cannot be +memoized. + +Read this if you got an error message such as |Environment "tikzpicture" ended +as "foo"|. + +Some environments are defined so that they embed another environment using the +idiom shown on the left: the begin-code of the outer environment opens the +inner environment, and the end-code of the outer environment closes the inner +environment. While this is a fine, and common, idiom, it messes up the +memoization of the inner environment. In the example on the right, trying to +\emph{auto}memoize a \env{minipage} environment (not recommended at all!) causes +trouble with package \pkg{sectionbox}.\footnote{This is a \texttt{Package + collargs Error} because Memoize outsources the actual work of collecting + the environment body to the auxiliary package CollArgs, described in + section~\ref{sec:collargs}.}\fncomma\cprotect\footnote{Why does this happen? + As mentioned in section~\ref{sec:tut:memodir}, Memoize keeps track of memos + and externs by the MD5 sum of the memoized code. But to compute that sum for + an environment, Memoize has to \emph{grab} the environment body, meaning it + has to collect the body in advance. This presents no problem when + \refcmd{end}\meta{environment name} is already present in the input stream at the +time \refcmd{begin}\meta{environment name} is executed, like when you use the + environment normally in your document, or when some macro expands so that it + produces both \cs{begin}\meta{environment name} and \cs{end}\meta{environment + name} simultaneously --- so there would be no problem above if + |\end{minipage}| occured in the beginning code of \env{sectionbox}. The idiom +presented above is problematic for memoization because at the time \hologo{TeX} +executes |\begin{sectionbox}|, putting |\begin{minipage}| into the input + stream, |\end{sectionbox}| is not yet executed and remains as it is. The + input stream therefore contains a pair of |\begin{minipage}| and + |\end{sectionbox}|. In the normal, non-memoizing course of events this + would not be a problem, because |\end{sectionbox}| would eventually expand to +|\end{minipage}|. During memoization, however, this \emph{is} a problem, +because, as we said, Memoize needs to grab the environment body: upon +encountering |\begin{minipage}|, it looks in the input stream for + |\end{minipage}| --- but there is no |\end{minipage}| in the input stream, +there is only |\end{sectionbox}|, and this results in the |Environment +"minipage" ended as "sectionbox"| error.} + +\begingroup +\ExampleName{sectionbox} +\makeexample{\examplename.tex.c1} +\mmzset{disable} +\begin{tcbraster}[raster equal height] +\begin{tcblisting}{listing only, bad, valign=center} +\newenvironment{foo}% ... args +{% the begin-code of foo + % ... + \begin{tikzpicture} + % ... +} +{% the end-code of foo + % ... + \end{tikzpicture} + % ... +} +\end{tcblisting} +\tcbinputexample{ + bad, + comment={\small\tt + ! Package collargs Error: Environment\\"minipage" ended as "sectionbox". + }, + } +\end{tcbraster} +\endgroup + +What are your options in this kind of a situation? +\begin{enumerate} +\item The only way to perform any memoization here is to memoize the + \emph{outer} environment --- if that makes sense.\footnote{This avoids the + error because Memoize grabs and memoizes the outer environment, and while + it is memoizing it, further memoization is switched off.} You can do this + either on a case-by-case basis, by enclosing it in the \refenv{memoize} + environment, or automemoize it: \code{\refmmz{auto}=\marg{outer + environment}\braces{\refmmzauto{memoize}}}. +\item But what if memoizing the outer environment is out of the question? + Then, the only way to avoid the error is to prevent the automemoization of + the inner environment. + \begin{enumerate} + \item If you are facing a single occurrence of the problem, it is perhaps + easiest to use key \refmmz{disable} just before the start of the outer + environment. + \item Otherwise, you can automatically disable memoization for the span of + each occurrence of the outer environment: \code{\refmmz{auto}=\marg{outer + environment}% + \braces{\refmmzauto{nomemoize}}}. + \item To deactivate the automemoization of the inner environment for the span + of the outer environment, but otherwise allow for memoization inside the + outer environment: \code{\refmmz{auto}=\marg{outer environment}% + \braces{\refmmzauto{noop}, \refmmz{deactivate}=\meta{inner + environment}}}. Key \refmmzauto{noop} does nothing but apply the + given options (in this case, \refmmz{deactivate}=\meta{inner environment}) + to the advised command or environment. + \end{enumerate} +\end{enumerate} + +\subsection{Extraction methods and modes} +\label{sec:extraction} + +Remember that in Memoize, externalization is a two-step process. First, +externs are typeset on separate pages of the main document, called extern +pages. Then, these extern pages are extracted out of the main document PDF +into extern files. The process is illustrated on the title page. + +Memoize is flexible in terms of which piece of software is used to perform +extern extraction. It ships with three \emph{extraction methods}: + +\begin{description} +\item[\refmmz{extract=perl}] A Perl script, \refscript{memoize-extract.pl}. + This method is the default because it is fast and because Perl is usually + already installed on a system running \hologo{TeX}. However, you will most + likely still need to install two pieces of software that the script depends + on: Perl libraries \hreftt{https://metacpan.org/pod/PDF::API2}{PDF::API2} and + the \hreftt{https://metacpan.org/pod/Path::Class}{Path::Class}, the + installation guidelines can be found in section~\ref{sec:install}. +\item[\refmmz{extract=python}] A Python script, \refscript{memoize-extract.py}. + This method is even faster than the Perl script, though not by much. Try it + out if you have problems installing Perl or the required libraries, or if the + Perl script chokes on your document (see section~\ref{sec:troubleshooting} + for the list of known issues). Besides Python ($\geq 3.8$), you will also + need the Python library \hreftt{https://pypi.org/project/pdfrw/}{pdfrw} or + \hreftt{https://pypi.org/project/pdfrw2/}{pdfrw2}. For the installation + guidelines, see section~\ref{sec:install}. +\item[\refmmz{extract=tex}] \hologo{TeX}-based extraction requires no + additional software, but it is much slower than the scripts. As \hologo{TeX} + can only produce a single PDF per compilation, an instance of \hologo{TeX} + (loading the entire document PDF) has to be invoked for each extern, and this + takes time (although the entire process is still much faster than the + venerable \TikZ externalization library). +\end{description} + +Memoize is also flexible in terms of how extern extraction is triggered, +providing two \emph{extraction modes}: + +\begin{description} +\item[internal]\label{item:setup:who} By default, extern extraction is + triggered internally, i.e.\ by Memoize during the compilation of the + document; more precisely, any externs produced in a compilation are extracted + during the next compilation. To choose an extraction method other than the + default Perl script, load Memoize with the package option + \EmphTT{\refmmz{extract}=\meta{extraction method}}. + +\item[external] Loading Memoize with with package option + \EmphTT{\refmmz{extract}=\refmmz{extract=no}} instructs Memoize to \emph{not} + trigger the (internal) extraction. When instructed to use extraction + ``method'' \refmmz{extract=no}, Memoize expects you to trigger the extraction + yourself, in any way that is convenient to you: manually from the command + line, or automatically through your editor, a Makefile, etc. --- all Memoize + cares about is that the extraction takes place before the next compilation of + the document. +\end{description} + +Summing up, the extraction mode and method are selected by providing the +appropriate value to package option key \refmmz{extract}; the possible values +are listed in the table below. Note that this key can only be used as a +package option, or in \refcmd{mmzset} within \reffile{memoize.cfg}. In +particular, it is disabled in the document preamble, because Memoize performs +extraction while it is loaded. + +\medskip +\begin{center} + \begin{tabular}{lll} + \toprule + extraction method&external program&Memoize invocation\\ + \midrule + \refmmz{extract=perl}&\refscript{memoize-extract.pl}&\refcmd{usepackage}\braces{\refpkg{memoize}}\footnotemark\\ + \refmmz{extract=python}&\refscript{memoize-extract.py}&\refcmd{usepackage}\bracketstt{\refmmz{extract}=\refmmz{extract=python}}\braces{\refpkg{memoize}}\\ + \refmmz{extract=tex}&|pdftex|&\refcmd{usepackage}\bracketstt{\refmmz{extract}=\refmmz{extract=tex}}\braces{\refpkg{memoize}}\\ + \refmmz{extract=no}&none (external extraction)&\refcmd{usepackage}\bracketstt{\refmmz{extract}=\refmmz{extract=no}}\braces{\refpkg{memoize}}\\ + \bottomrule + \end{tabular}% + \footnotetext{Or + \refcmd{usepackage}\bracketstt{\refmmz{extract}=\refmmz{extract=perl}}% + \braces{\refpkg{memoize}}. This is useful if you have changed the default + using \reffile{memoize.cfg}.}% +\end{center} +\smallskip + +For internal extraction, \hologo{TeX} must be allowed to execute the external +program implementing the chosen extraction method. Both |memoize-extract| +scripts should be listed among restricted shell escape mode commands in your +\hologo{TeX} distribution; their execution should therefore be allowed under +the default, restricted shell escape mode. However, the |pdftex| program, +executed by extraction method \refmmz{extract=tex}, is not listed there, nor +should it be. If you are forced to use this fallback method, I suggest you +compile documents loading Memoize under the full shell escape mode, by adding +command-line option \docref{-shell-escape} (on \hologo{TeX}Live) or +\docref{--enable-write18} (on MiK\hologo{TeX}) to the invocation of the +\hologo{TeX} program. The answers linked from question +``\href{https://tex.stackexchange.com/q/598818/16819}{How can I enable + shell-escape?}'' on \href{https://tex.stackexchange.com}{\hologo{TeX} + StackExchange} will tell you how you can ask your editor to do this for you. + +You may use any extraction method to perform external extraction. The simplest +option is to use the Perl or the Python script. Supposing you are doing this +manually from the command line, change into the directory containing your +document, which should contain the auxiliary \dmmz file produced by Memoize, +and execute: + +\begin{enumerate}[(a)] +\item \refscript{memoize-extract.pl} \meta{document name}\dmmz \hfill (for + the Perl script) +\item \refscript{memoize-extract.py} \meta{document name}\dmmz \hfill (for + the Python script) +\end{enumerate} + +See sections~\ref{sec:.mmz} and \ref{sec:ref:extraction-perl-python} for +further details on the \dmmz file and the extraction scripts. + +Things are a bit more complicated if you want to use the \hologo{TeX}-based +extraction method externally, because an instance of |pdftex| needs to be +invoked for each extern (and these have unwieldy names and can be many in +number), but Memoize can help you here by producing a shell script or a +makefile, executing which will extract all the externs at once. To have Memoize +produce a shell script, use package option +\code{\refmmz{record}=\refmmz{record=sh}} (or +\code{\refmmz{record}=\refmmz{record=bat}} on Windows); package option +\code{\refmmz{record}=\refmmz{record=makefile}} will make a makefile. By +default, these files are named |memoize-extract.|\meta{document name} plus the +|.sh|, |.bat| or |.makefile| suffix. If neither a shell script nor a makefile +works for you, you can also define your own kind of \emph{record file}, to be +processed by the external tool of your choice (and implementation) in order to +extract the externs; see section~\ref{sec:new-record-file} to learn how to do +this. + + +\subsection{From cross-references to the context} +\label{sec:cross-referencing} + +Cross-referencing presents a challenge to externalization, because without +special provisions, the ``communication channel'' between the \cs{label} and the +\cs{ref} is broken once we start utilizing the extern. + +One direction of the issue occurs when a \refcmd{label} within the memoized +code is referenced by a \cs{ref} on the outside. Without the (built-in) +workaround, the \cs{label} command would only be executed when the extern is +being produced, but not on subsequent compilations of the document, when it is +merely included. Memoize addresses this problem by generalizing +externalization (which can only produce a picture, the extern) to memoization +(which can additionally produce arbitrary code). When Memoize is externalizing +code which contains a \cs{label}, it automatically replicates it into the +\emph{memo}, which is input into the document on subsequent compilations. In +effect, the memo--extern team will continue to produce the label even when it +is utilized rather than compiled. As far as the author is concerned, \cs{label}s +in memoized code ``just work,'' without any observable differences to the +situation without memoization. This is why we will not discuss this direction +of the issue here; a reader interested in how precisely the system works is +invited to read section~\ref{sec:memos}. + +The other direction of the issue occurs when a \refcmd{ref} within the memoized +code references \cs{label} on the outside. In this situation, the extern +should be recompiled when the value of the label it refers to changes. Again, +Memoize addresses this problem in full generality, by associating with each +extern a \emph{context}, and recompiling the extern whenever the value of the +context changes.\footnote{The dependency of an extern upon prior definitions + and such can also be addressed in a more \emph{ad hoc} manner, by recompiling + manually; we have already touched upon this subject in + section~\ref{sec:tut:working-on-a-picture}, and will revisit it in + section~\ref{sec:tut:redefinitions}.} All that needs to be done for \cs{ref} +and friends, specifically, is to advise them to add their reference keys to the +context. + +As we shall see presently, for the author, the only difference between a +non-memoized and a memoized \cs{ref} is that the latter will take one more +compilation cycle to ``stabilize'' the resulting document. (More precisely, +the memoized situation will take one more cycle if the reference is undefined +on the first compilation.) Then, we will show how we can teach Memoize about +cross-referencing commands other than \cs{ref} and \cs{pageref}. Finally, we will +learn about key \refmmz{context}, the backbone of the cross-referencing support +in Memoize. (The inner workings of the context are further explained in +section~\ref{sec:c-memos}.) + +\ExampleName{ref} +\makeexample{\examplename.pdf N=7} + +When the memoized code contains a \cs{ref} referring to a label given in another +part of the document, the code is recompiled when (and only when) the reference +changes. Let us look at the following example, jumping in at the point where +it was already compiled enough times that the resulting PDF had stabilized into +a single (document) page with correct references. (Environment +\refenv{nomemoize} disables memoization +of \href{https://ctan.org/pkg/tikzlings}{Ti\emph{k}Zlings}, so that their +externs don't disturb us, and we can focus on the \cs{tikz} command, which does +get externalized and contains a \cs{ref}.) + +\tcbinputexample[.tex][.c3]{ + after title pre={\ (with stable output after three compilations)}, + middle=1mm, + comment={\centering + \includeexamplepdf[document page]{page=1} + } +} + +Let us add an owl in front of the penguin. In the next compilation, neither +the ``normal'' nor the memoized reference is yet updated, as expected --- in +this compilation, the new value of the penguin label only makes it into the +|.aux| file. + +\tcbinputexample[.tex][.c4]{ + after title pre={\ (after the first compilation with the added owl)}, + no attachment, + comment={\centering + \includeexamplepdf[document page]{page=1} + } +} + +During the following compilation, the \refcmd{ref}s pick up the new value of the +penguin label, and the \cs{ref} inside the automemoized \cs{tikz} command +forces recompilation of the extern (\emph{how} this is done will be explained +later). + +\tcbinputexample[.tex][.c5]{ + after title pre={\ (after the second compilation with the added owl)}, + comment only, no attachment, + comment={\centering + \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in}\quad + \includeexamplepdf[document page]{page=2} + } +} + +In the next compilation, the resulting PDF is finally stabilized, as the +updated extern is (extracted and) included into the document. + +\tcbinputexample[.tex][.c6]{ + after title pre={\ (after the third compilation with the added owl)}, + comment only, no attachment, + comment={\centering + \includeexamplepdf[document page]{page=1} + } +} + +The message to take home? When some memoized code contains a reference and +that reference changes, it will take three compilation cycles (so, one more +cycle than without memoization) for the resulting document to ``stabilize.'' + +Out of the box, Memoize supports the standard \hologo{LaTeX} cross-referencing +commands \cs{ref} and \refcmd{pageref}. To automatically recompile code +containing some other cross-referencing command, like \refcmd{vref} of package +\pkg{varioref}, we use the advising framework implemented by package Advice. +This framework is a generalization of automemoization: we use the familiar +\refmmz{auto}, but with advice offered by \Emph{\refmmzauto{ref}} rather than +\refmmzauto{memoize}. + +{\ExampleName{vref} +\makeexample{\examplename.tex.c1} +\tcbinputexample{listing only}} + +Key \refmmzauto{ref} only works for commands which operate on a single +reference key. However, that single key (which must be enclosed in braces) may +be preceded by optional argumen(s) of any kind. Extensions to \refcmd{ref}, +e.g.\ the \pkg{hyperref}'s variant, which accepts an optional |*|, work out of +the box. Furthermore, Memoize offers support for cross-referencing commands +which work on multireferences and reference ranges, such as \pkg{cleveref}'s +\refcmd{cref} and \refcmd{crefrange}. Those commands should be advised by +\refmmz{auto} keys \refmmzauto{multiref} and \refmmzauto{refrange}, +respectively. + +We have jumped into first example of this section with the assumption that it +had already been compiled several times, allowing the resulting PDF to +stabilize. Let us now take a look at what happens at the very first, fresh +compilation of our original example (the one without the owl). (Removing the +|.aux| file before compiling the example again will start afresh.) The curious +thing is that we don't get the extern page containing +\tikz[baseline]\node[draw=red,thick,fill=yellow,anchor=base,font=\bf]{??};. +This is so because by default, Memoize aborts a memoization containing an +undefined reference. + +\tcbinputexample[.tex][.c1]{ + after title pre={\ (after the fresh compilation of the original example)}, + comment only, no attachment, + comment={\centering + \includeexamplepdf[document page]{page=2} + } +} + +Now sometimes you might want to produce an extern even if it contains an +undefined reference --- for example, you might intend to write the code +containing the \cs{label} much later but enjoy the speed-up offered by Memoize +until then. In that case, apply the \refmmz{auto} key \Emph{\refmmzauto{force + ref}} to \cs{ref}. + +\tcbinputexample[.tex][.c7]{ + after title pre={\ (after the fresh compilation with \refmmzauto{force ref})}, + attachment name=\examplename-force.tex, + comment={\centering + \includeexamplepdf[extern page][\examplepath.c1.pdf]{page=1,trim=1in 1in 1in 1in}\quad + \includeexamplepdf[document page][\examplepath.c1.pdf]{page=2} + } +} + +However, note that when you use \refmmzauto{force ref}, \hologo{LaTeX} will +\emph{not} complain about the undefined reference once the extern containing it +is included (unless that reference also occurs in some non-memoized piece of +code). Using \refmmzauto{force ref} is therefore a tiny bit dangerous, and +this is why \refmmzauto{ref}, with the abortion mechanism, is the default +handler for \cs{ref} and \refcmd{pageref}. + +As already noted in the previous section, \refcmd{ref} works by appending the +cross-reference to the \emph{context}, the change of which triggers +recompilation. Memoize initializes the context to contain the four +\refmmz{padding}s --- as a result, an extern recompiles if we change the +padding --- but we can append stuff to the context by ourselves, as well. +Below, we use key \Emph{\refmmz{context}} to append the font size (we'll talk +about the value given to this key a bit later); as a result, the picture is +recompiled whenever the font size changes. Below, we change the font size +using command |\small|; changing the default size with a class option such as +|12pt| works as well. + +\ExampleName{fontsize} +\makeexample{\examplename.pdf N=2} +\tcbinputexample{ + sidebyside, lefthand ratio=0.7, after title pre={\ (the first version)}, + comment={ + \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in} + } +} + +\tcbinputexample[.tex][.c2]{ + sidebyside, lefthand ratio=0.7, after title pre={\ (the second version)}, + no attachment, + comment={ + \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in} + } +} + +How does this work? Key \refmmz{context} appends the given tokens to the +\emph{context expression}. When creating an extern or trying to use it, +Memoize (fully) expands this expression and computes the MD5 sum of the +expansion. This \emph{context MD5 sum} then serves as a part of the extern's +filename (see sections~\ref{sec:tut:memodir} and~\ref{sec:memos}). In effect, +Memoize will only find (and utilize) the extern if \emph{the context MD5 sum + computed during (attempted) utilization matches the one computed during + memoization}. + +As revealed by looking at the \hologo{LaTeX} source code, \hologo{LaTeX} holds +the current font size in macro |\f@size|, and above, we have effectively added +the contents of this macro to the context. Now, why didn't we simply write +\refmmz{context}|=\f@size|? First, we used |\csname ... \endcsname| because we +were under the normal \hologo{LaTeX} catcode regime, where |@| cannot be a part +of the command name. Of course, we could have temporarily changed the catcode +of |@| using |\makeatletter| and |\makeatother|, but I would advise against +that, because the approach does not work in general: it fails when key +\refmmz{context} is used \emph{within} memoized code (we will explain why in +section~\ref{sec:memos}). Another reason why I recommend the |\csname +... \endcsname| approach is that it does not result in an error when the +control sequence is not defined (|\csname ... \endcsname| will expand to +|\relax| then); this behaviour is handy for undefined cross-references, for +example. Second, why did I write |fsize={...}| around the control sequence? +Well, because I'm being paranoid, really. Writing \refmmz{context}|={\csname + f@size\endcsname}| would work just as well, but I like to explicitly +``announce'' the value to prevent any possibility of a conflict with an +alternative context. Imagine that we don't use the ``announcements'' and we +decide to add some other dimension instead of the font size to the context. +Now if that dimension happened to have the same value as the font size, Memoize +would incorrectly pick up the ``font size extern'' instead of producing a new +one. + +It bears emphasizing that whatever you add to the context expression must be +fully expandable, and also not merely declared as robust. So writing +\code{\refmmz{context}=\cs{ref}\marg{key}}, for example, would be unwise, since +it would not work as intended when package \pkg{hyperref} is loaded. (This +package declares \refcmd{ref} as robust, so it won't expand to the +cross-reference value.) You have to look up where the cross-references are +stored internally; the cross-reference for \meta{key} turns out to be stored in +the internal control sequence |\r@|\meta{key}, so it is |\csname +r@|\meta{key}|\endcsname| that the \refmmzauto{ref} handler actually appends to +the context. + +The padding and font-size contexts are useful quite generally. However, the +context can be pretty command-specific, as well. Consider the \pkg{skak} +package used for typesetting chess games. The board is drawn using command +|\showboard|, but this command has no arguments, because it draws the state of +the board that is reached by the moves given by command |\mainline|. Memoizing +|\showboard| as such will therefore yield the wrong result --- all the boards +will be one and the same board! The solution is to provide the correct +context: we dig into the \pkg{skak} sources and realize that the current +board is stored in macro |\csname chessgame.skak.mainline\endcsname|. + +\ExampleName{skak} +\makeexample{\examplename.pdf} +\tcbinputexample{ + sidebyside, lefthand ratio=0.48, + comment={ + \includeexamplepdf[extern page]{page=1,trim=1in 1in 1in 1in,scale=0.45}\quad + \includeexamplepdf[extern page]{page=2,trim=1in 1in 1in 1in,scale=0.45} + } +} + +If you remove \code{\refmmz{context}=\bracestt{...}} from the code above, you +will end up with a document where the final board drawn takes place of all the +boards. This is so because in that case, all externs are written into the same +file, so the final extern overwrites the previous ones, but note that you will +only observe this after the second compilation, when the externs are actually +used. + + + +\subsection{More on redefinitions and stale externs} +\label{sec:tut:redefinitions} + +In this subsection, we elaborate on an issue touched upon at the beginning of +section~\ref{sec:tut:working-on-a-picture}: what happens if the memoized code +depends on some macro or style which gets redefined? The answer was +``nothing,'' and one solution was to \refmmz{recompile} the code. Let us take +the example from that section a bit further. We will propose no new solution +or workaround, but deepen our understanding of the issue. + +\ExampleName{redefinitions} +\makeexample{\examplename.pdf N=6} +\tcbset{ + recompile step/.style={ + sidebyside, lefthand ratio=0.74, title=, + comment={\includeexamplepdf[blankest][\examplepath.c\theenumi.pdf]{#1}}, + /utils/exec={\addtocounter{enumi}{1}}, + enhanced, overlay app={\node[at=(frame.north west), font=\scriptsize, circle, fill=black!80!white, text=white, inner sep=1pt]{\theenumi};}, + }, +} +\begin{tcboxedraster}[raster columns=1]{% + title=Working on \texttt{\examplename.tex}, enhanced, breakable} + \setcounter{enumi}{0}% + \tcbox[blankest]{I like red. My emphasized nodes will have red background.} + \tcbinputexample[.tex][.c1]{recompile step={page=2}} + \tcbox[blankest]{Hmm, this particular node is really important, + let me put the text in italics as well!} + \tcbinputexample[.tex][.c2]{recompile step={page=2}, no attachment} + \tcbox[blankest]{You know what? Perhaps yellow background would work better + --- in general.} + \tcbinputexample[.tex][.c3]{recompile step={page=1}, bad, no attachment} + \tcbox[blankest]{How come my node is still red?! Oh yes, I changed the + style, so I have to recompile the extern!} + \tcbinputexample[.tex][.c4]{recompile step={page=2}, no attachment} + \tcbox[blankest]{Ahh, yellow background, that's much better. But you know + what, this double emphasis won't do after all, let me go back to the + upright shape.} + \tcbinputexample[.tex][.c5]{recompile step={page=1}, bad, no attachment} + \tcbox[blankest]{Red???!???!? Ok, I know that recompiling will help, but what + happened here?} + \tcbinputexample[.tex][.c6]{recompile step={page=2}, no attachment} +\end{tcboxedraster} + +What happened is that the externs from steps~1 and~5 share the very same code. +In step~1, this code was compiled when the red |emph| style was in effect, and +that extern lingered and was eventually picked up again in step~5, Memoize +having no idea that it is including an extern produced with the obsolete +definition of the style. + +There are two points to this story. First (and forgetting for a moment about +the context, which we started discussing in +section~\ref{sec:cross-referencing}), Memoize identifies externs (and memos) by +the code that produced them --- or more precisely, by the MD5 sum of the code, +as each piece of code has a unique (well, unique enough) MD5 sum. Each extern +is saved in a file whose name contains this MD5 sum; see +section~\ref{sec:tut:memodir} for illustration. Generally, this is a very +useful feature. You can move your picture to another location in the document, +insert some other (externalized) picture in front of it, and so on, all without +triggering recompilation of the extern(s). (None of this is possible with +\TikZ's externalization library, which identifies the externs by the order in +which they appear in the document.) + +The downside of the MD5 sum approach is the potential pitfall illustrated +above, and the downside comes about because of the second point of the story: +Memoize does not attempt to delete the ``old'' externs. (However, as described +in section~\ref{sec:tut:memodir}, stale memos and externs can be easily removed +using the \refscript{memoize-clean.pl} script.) That would be not only +dangerous (as any deletion inherently is) but also potentially wasteful: what +if you have only temporarily removed some code, or compiled only a portion of +the document --- you surely wouldn't want your hard-won externs to disappear in +such a situation! + +The pitfall described above applies to any command which depends on parameters +which can be set prior to the invocation of the command, like \TikZ pictures, +which depend on the settings given in \cs{tikzset}. After customizing the +settings, you will have to recompile the externs: +\refcmd{mmznext}\braces{\refmmz{recompile}} is useful when you only have to +recompile a single extern; use \refcmd{mmzset}\braces{\refmmz{recompile}}, or +the package option \refmmz{recompile}, to recompile all externs in the +document; and there is also the middle road: if you have changed only Forest's +settings, you can write +\code{\refmmz{auto}=\braces{forest}\braces{\refmmz{recompile}}} to recompile +all and only the Forest trees. + +Above, we have seen the ``same code, same extern'' issue manifested ``through +time,'' i.e.\ Memoize was (incorrectly) reusing externs produced in previous +compilations, but the issue can also manifest ``through space.'' This can +happen if the same code appears twice in the same document --- but, crucially, +with some parameters which it depends on changed from one occurrence to the +next. Observe what happens in the following example, where the settings for +|\progressbar| are changed by |\progressbarchange|. After the first +compilation, everything looks fine. But as both extern pages were produced by +the same code, they will be stored into the same file, the second one +overwriting the first one. The second compilation pulls in the externs --- or +rather, the single extern --- resulting in the document containing the second +progressbar in the place of the first one as well. + +\ExampleName{progressbar} +\makeexample{\examplename.pdf N=2} +\tcbinputexample{ + bad, float, + comment={ + \begin{tcbitemize}[raster columns=3,raster equal height,halign=center,valign=center] + \tcbitem[title=After 1\textsuperscript{st} compilation] + \includeexamplepdf[extern page,remember as=extern1]{page=1,trim=1in 1in 1in 1in}\\ + \includeexamplepdf[extern page,remember as=extern2]{page=2,trim=1in 1in 1in 1in}\\ + \includeexamplepdf[document page]{page=3} + \tcbitem[title=After extern extraction\vphantom{p\textsuperscript{nd}}] + \includeexamplepdf[my boxed title=the extern file,attach shifted boxed title to top right,remember as=externfile]{page=2,trim=1in 1in 1in 1in} + \tcbitem[title=After 2\textsuperscript{nd} compilation] + \includeexamplepdf[document page,remember as=doc][\examplepath.c2.pdf]{page=1} + \end{tcbitemize} + \begin{tikzpicture}[remember picture,overlay] + \draw[->, thick, red] (extern1.east) to[out=east, in=west] ([yshift=0.5ex]externfile.west); + \draw[->, thick, red] (extern2.east) to[out=east, in=west] ([yshift=-0.5ex]externfile.west); + \draw[->, thick, blue] (externfile.east) to[out=east, in=west] (doc.west); + \end{tikzpicture} + }, +} + +The same ``extern duplication'' can arise due to how a particular command is +implemented. Say we deactivate automemoization of Forest trees +(\code{\refmmz{deactivate}=forest}), but keep on automemoizing \TikZ pictures. +Forest uses \refenv{tikzpicture}\noprint{\refenv{forest}} under the hood (a +lot); in particular, the tree itself is typeset as a \env{tikzpicture} +environment. But the code that typesets it is the same for all trees, +regardless of their content (the actual content of the tree is hidden in +various macros and boxes, rather than ``pasted'' into the \env{tikzpicture}). +Consequently, the final tree of the document will overwrite all other trees in +the document, just as the second (and thus final) progress bar overwrote the +first one above.\footnote{That is assuming that \hologo{TeX} doesn't simply + spew a bunch of errors. This can happen as well. In the interest of full + disclosure, compiling a Forest tree in the situation described above would + actually also produce --- but only in the first compilation --- a number of + small empty extern pages, one for each node of the tree. A promise: Forest + will soon fully support Memoize and (among other things) avoid this pitfall. + But the principle will remain.} Ouch! + +Generally speaking, this final sort of extern duplication issue can arise +whenever we have an ``outer'' command that we don't want to (auto)memoize which +uses an ``inner'' command that we \emph{do} want to automemoize. The solution +is to use the \refmmz{auto} key \refmmzauto{nomemoize} on the outer command; +remember that this key disables memoization for the space of the command or +environment. For example, the correct way to ``deactivate'' automemoization of +\env{forest} environments (but keep automemoizing \TikZ pictures) is +\code{\refmmz{auto}=\bracestt{forest}\braces{\refmmzauto{nomemoize}}}. + + + + +\subsection{Supporting Memoize in your package} +\label{sec:tut:package} + +\subsubsection{Loading Memoize?} +\label{sec:loading-memoize} + +So you want to support Memoize in your package? That's great! + +What form precisely this support will take of course depends on your package. +For some commands, a simple \refmmz{auto} declaration will suffice; for other +commands, you might need to write a dedicated \emph{memoization driver}, as +explained in section~\ref{sec:memoization-drivers}. However, one thing is +clear: you \emph{don't} want to require Memoize's presence by +\cs{RequirePackage}\braces{\refpkg{memoize}} in your package. That would +trigger memoization, but triggering memoization should be left at the sole +discretion of the author. The question is, if you're not allowed to load +Memoize, how can you even issue the \refmmz{auto} declaration? + +Well, it's not that you really want to \emph{memoize} anything; you want to +make the commands of your package \emph{memoizable}. So: +\cs{RequirePackage}\braces{\Emph{\refpkg{memoizable}}} --- and note that in +`memoizable', the final `e' of `memoize' is dropped, apparently this is the +correct way to spell it. + +Loading \refpkg{memoizable} does nothing if Memoize is already loaded, and +behaves like package \refpkg{nomemoize} otherwise --- remember from +section~\ref{sec:tut:final} that \refpkg{nomemoize} is a dummy package which +accepts all the commands that Memoize does, but does nothing. + +I have decided to require that Memoize must be loaded before any package that +supports it. Allowing for an arbitrary loading order would complicate the +implementation (and possibly even turn out to be problematic), and furthermore, +Memoize likes to be loaded early anyaway, because it needs to be loaded before +the document PDF is opened if it is to perform the embedded extern extraction. +I don't think the ordering requirement will cause any problems --- let me know +if it does! --- but perhaps it is wise to inform the author about it in the +documentation of your package (I did so at the end of +section~\ref{sec:tut:automemoization}). Anyway, I have enforced the +requirement by raising an error and refusing to load the package in case +Memoize detects \refpkg{memoizable} to be loaded. + +Note that the loading order requirement implies that you can use +|\@ifpackageloaded{memoize}| to specifically react to the presence Memoize, if +necessary. + + +\subsubsection{Memoizable design} +\label{sec:memoizable-design} + +Many commands and environments can be submitted to externalization with a +single-line \refmmz{auto} declaration, as illustrated in +section~\ref{sec:tut:automemoization}, perhaps requiring an addition to the +context (section~\ref{sec:cross-referencing}), or some pre- or post-memoization +code (section~\ref{sec:tut:beamer}). In some situations, however, these simple +approaches won't work. Most often, this will happen when the extern must be +integrated into the document in some special way. For example, a command might +internally create floating material, or surround the core typeset material with +some stretchable space.\footnote{Commands and environments of package + \pkg{tcolorbox} exhibit both these issues (see \pkg{tcolorbox} options |float|, + |before| and |after|), and were in fact the inspiration for several technical + details of Memoize.} None of these behaviours can be replicated by merely +including the extern; with respect to the stretchable space, remember that an +extern, being a picture, has fixed size, so if our extra space ended up in the +extern, it would lose the stretchability. + +The key to successful memoization of problematic commands is their design. In +a nutshell, the idea is to \emph{break up the command's definition into two + parts, the outer command and the inner command, and only submit the inner + command to automemoization}. We will illustrate this with a simple +environment --- |poormansbox| --- which produces a potentially framed box of +the given width, and surrounds this box with some configurable material --- by +default, this material will be stretchable vertical space, and this will be the +source of our memoization problem. (In terms of user experience, the solution +in this section will leave something to be desired, but we will revisit the +example in section~\ref{sec:memoization-complex-single-driver} and make things +right.) + +Let us first take a look at a document using our to-be-developed box +environment. The |poormansbox| environment takes one optional argument, a +keylist of options, which can also be set with the |\pmbset| command. This +being a \textbf{p}oor \textbf{m}an's \textbf{b}ox, it doesn't recognize many +options. One can set the |width| of the box, or request that it occurs in a +|frame|, and the surrounding material can be configured using keys |before| and +|after|. As we will see later in the listing of the package, the box is +|\linewidth| wide by default, has no frame, and is surrounded by vertical glue +|\vskip 2ex plus 1ex minus 1ex| (|2ex| of natural vertical space which may both +stretch and shrink for |1ex|); furthermore, the default value of |before| +contains |\centering| to center the box horizontally (centering is of course +only observable when we change the width of the box). + +\ExampleName{poormansbox} +\makeexample{\examplename.sty} +\makeexample{\examplename.pdf} +\tcbinputexample{ + sidebyside, lefthand ratio=0.482, + comment={\centering + \includeexamplepdf[document page,left=0pt,right=0pt] + {page=1,scale=0.5,trim=0mm 3mm 0mm 3mm} + }, +} + +You might want to play with the example to see that the surrounding vertical +space is indeed stretchable. The example is set up so that the surrounding +space is shrunk a bit to fit all the material onto one page. But if you remove +the final |\lipsum[144]|, the natural amount of all vertical space can be +accommodated on the page, so you should observe an increase of vertical +spacing. + +You might have noticed that the example contains nested |poormansbox|es: the +second box (the one which contains |\lipsum[66]|) is nested within the first +one (between |\lipsum[101]| and |\lipsum[75]|). This is intentional: when we +will revisit the |poormansbox| example in +section~\ref{sec:memoization-complex-single-driver}, the implementation will +have to pay special attention to nesting (which presents no problem to the +implementation in this section). + +As you can see in the package listing below (\texttt{\examplename.sty}), the +implementation of our environment is straightforward. We first define the +configuration command |\pmbset| and the option keys (we're using +\pkg{pgfkeys}), and set the option defaults. Then, we move on to the +environment itself: we apply the given options, execute the pre-code, typeset +the box (which is a |minipage| of the given width, potentially wrapped in a +|\fbox|), and execute the post-code. + +\tcbinputexample[.sty]{listing only, float} + +\ExampleName{poormansbox-memoizable} +Now let's make our |poormansbox| externalizable (\texttt{\examplename.sty}). As +announced above, the idea is to split the definition of the environment into +the outer part (below, the user-level environment |poormansbox|), which +(applies the options and) executes the pre- and the post-code, and the inner +part (below, the macro |\@poormansbox|), which typesets the actual box. If we +then then submit |\@poormansbox|, rather than |poormansbox|, to +automemoization, the outer part will be executed at every compilation (giving +us stretchable space if we request it), while the inner command will be +executed (and memoized) at the first compilation, and substituted for the +extern (the fixed-size box) at subsequent compilations.\cprotect\footnote{You + might have wondered why our definition of the |poormansbox| environment grabs + the body into an argument (|+b|, yielding |#2|), necessitating the use of + |\NewDocumentEnvironment| over the venerable |\newenvironment|. One reason + was that having the environment body as an argument simplifies wrapping the + |\fbox| around the |minipage|, but there is a more important reason. If we + did not grab the environment body, we would have to implement the internal + part of the definition as an environment (|@poormansbox|) as well, and embed + it into the user-level environment using the following idiom: + |\newenvironment{poormansbox}[2][]{...\begin{@poormansbox}}{\end{@poormansbox}...}|. + However, as illustrated in section~\ref{sec:tut:good-to-know}, automemoizing + an environment indirectly embedded in such a way produces an error, because + Memoize is prevented from collecting the environment body.} + +\makeexample{\examplename.sty} +\makeexample{\examplename.pdf}% just to know if it compiles fine +\tcbinputexample[.sty]{listing only, float} + +Looking at the definition of the internal |\@poormansbox| command, it might +strike you as weird that we have equipped this command with an optional +argument (|#1|) it never uses. However, this optional argument is crucial for +memoization. It will become a part of the memoized code (note +\code{\refmmzauto{args}=om} in the \refmmz{auto} declaration) and thereby +ensure that Memoize will produce separate externs for invocations of +|\@poormansbox| with the same environment body but different options; or in +other words, it will ensure that changing the options recompiles the +extern.\cprotect\footnote{Of course, this only holds for options given in the + optional arguments; if the user changes an option value using a prior + \cs{pmbset} (and that option does not occur in the optional argument), + Memoize won't detect the change. But the end-user knows about this issue, as + it was addressed in sections~\ref{sec:tut:working-on-a-picture} + and~\ref{sec:tut:redefinitions}, and she is also aware of two workarounds: + manual recompilation, or setting the context + (section~\ref{sec:cross-referencing}). + + While we're on the subject of the context, note that it is also possible to + deploy context to trigger recompilation of the inner command upon change of + parameters it depends on. We could simply omit the optional argument of + \cs{@poormansbox} and add + \refmmz{context}|={width=\pmb@width,frame=\ifpmb@frame true\else false\fi}|, + to the \refmmz{auto} declaration. The advantage of such an approach is that + Memoize reacts to the change of parameters regardless of whether they are set + using the optional argument or \cs{pmbset}. However, the approach is + unfeasible for commands depending on many parameters: can you imagine listing + all the \TikZ options in the context? Not to mention that a particular + picture usually only depends on a small subset of these options --- by and + large, \TikZ externs would get recompiled too often if the context contained + all \TikZ options.}\footnote{I have toyed with the idea of + splitting (using \pkg{pgfkeys} key filtering) the given options into outer + options, relevant for the outer command, and inner options, relevant for the + inner command, and only passing the inner options to the inner command. The + thought was that would (i) avoid recompiling the extern when only outer + options change, as these options don't affect the inner command, and (ii) + avoid applying the inner options when utilizing the extern, as these options + don't affect the outer command. However, it then hit me that the end-user + might define a style which incorporated both inner and outer options --- I + know I do this with my |tcolorbox|es.} + +The downside to automemoizing an internal command is that this might be +counter-intuitive for the author. For example, to deactivate automemoization +of |poormansbox|, the author will have to write +\refcmd{mmzset}\bracestt{\refmmz{deactivate}=\cs{@poormansbox}} (note the +|\@|), but they will have no clue they have to do this unless they have +carefully read |poormansbox|'s documentation. Even worse, the above +\refcmd{mmzset} command will not work unless surrounded by |\makeatletter| and +|\makeatother|, as it refers to an internal control sequence containing |@|. +Well, Memoize offers \refmmz{auto csname}, \refmmz{activate csname} and +\refmmz{deactivate csname}, so that |@| catagory code manipulations can be +omitted by writing \refcmd{mmzset}\bracestt{\refmmz{deactivate + csname}|=@poormansbox|}, but still. + +Another downside could occur when you use the same (automemoized) internal +command in service of several user interface commands. For the sake of +illustration, assume we have also defined an UI-macro |\pmb| which again relies +on |\@poormansbox|. How is the author to deactivate automemoization of |\pmb| +but leave the |poormansbox| environment intact? This is how: +\refcmd{mmzset}\bracestt{\refmmz{auto}=\cs{pmb}\bracestt{\refmmzauto{args}=m, + \refmmzauto{nomemoize}}}. Again, counter-intuitive; the author expects +\refcmd{mmzset}\bracestt{\refmmz{deactivate}=\cs{pmb}} to work. + +One other consequence of this approach is that the code included in the c-memo +(if \refmmz{include source in cmemo} is in effect) will not faithfully reflect +the source: as shown in the c-memo listing below, it will contain +|\@poormansbox{...}| instead of |\begin{poormansbox}...\end{poormansbox}| --- +even if this might actually count as an advantage, as the discrepancy will at +least inform the author who refuses to read the fine material accompanying our +|poormansbox| that something funky is going on. + +\begingroup +\relaxmmzcommands +\def\mmzNewCMemo#1{% fetch the last c-memo filename + \def\mycmemo{#1}% +} +\input{\examplepath.mmz.c1} +\sed{% + s/[]]\lbrace/]\n\space\space\space\space\space\space\space + \space\space\space\space\space\space\space\lbrace/; +}{\exampledir\mycmemo} +\tcbinputlisting{ + listing only, + listing file=\exampledir\mycmemo, + example title, + title=the c-memo of the last \texttt{poormansbox} environment, + left=0.5em, right=0em, +} +\endgroup + +In a nutshell, automemoizing an internal command might be counter-intuitive for +the author. But the core idea --- to support memoization of a resistant +command by splitting its definition into the outer and the inner command --- is +sound, and we will elaborate on this idea in +section~\ref{sec:memoization-complex-single-driver}, where we will revisit our +|poormansbox| example and develop a variant of this environment which is both +memoizable and user-friendly. + + +\section{Under the hood} +\label{sec:under-the-hood} + +This chapter is written for three audiences: a curious user who wants to +know how Memoize does what it does; a package writer who wants to support +Memoize in a tricky situation; and myself, lest I forget why I made the design +decisions that I made. + +\subsection{The entry point} +\label{sec:Memoize} + + +From the author's perspective, the functionality of this package is entered +either through the manual memoization commands (macro \refcmd{mmz} and +environment \refenv{memoize}), or via automemoization. And while that is +correct, those user interface entry points merely determine what code is +submitted to memoization, and set any options specific to the upcoming +memoization. The real fun starts with command \Emph{\refcmd{Memoize}}, which +is eventually executed by both manual and automatic memoization. + +Not every call to \refcmd{Memoize} results in memoization. Calling this macro +has three possible outcomes. It can result in \emph{memoization}, which +produces the memos and externs; in \emph{utilization} of the result of an +earlier memoization (which boils down to inputting the memos); or in +\emph{regular compilation}, whereby the code is compiled +(almost)\footnote{\label{fn:regular-compilation-almost}This is absolutely true + for memoized code which is ``contained'' in the sense of not peeking into the + input stream following the memoized code. In general, code which fails to + satisfy this containment requirement is most likely simply not memoizable; + but there are borderline cases. For example, \refcmd{ignorespaces} at the + end of some code will have the expected effect in the absence of Memoize, but + no effect when executed either during memoization or regular compilation + under Memoize, simply because it will hit some code belonging to Memoize + rather than the continuation of the document. Memoize offers the + \refmmz{ignore spaces} provision to work around this specific problem.} as if +Memoize was not there. Which outcome obtains depends on several factors. The +decision logic is depicted below, and note that you can \refmmz{trace} the +action on the terminal. + +\begin{center} + \begin{forest} + yes/.style={edge=->,edge label={node[font=\scriptsize,pos=0.4,left,#1]{yes}}}, + no/.style={edge=->,edge label={node[font=\scriptsize,pos=0.4,right,#1]{no}}}, + use/.style={content=utilization\\(of the cc-memo)\vphantom{dj},fill=orange,align=center}, + memoize/.style={content=memoization\vphantom{dj},fill=green}, + compile/.style={content=regular compilation\vphantom{dj},fill=emphcolor}, + for tree={ + l sep*=1.5, + if n children={0}{}{align=center}, + child anchor=north, + }, + [Is Memoize enabled?\\(\refcmd{ifmemoize}), + [Are we currently undergoing memoization?\\(\refcmd{ifmemoizing}), yes + [,compile, yes] + [Is the\\\refmmz{recompile}\\mode in effect?, no + [,memoize, yes] + [Do the relevant\\memos and externs exist?, no + [,use, yes] + [Is the\\\refmmz{readonly}\\mode in effect?,no + [,compile, yes] + [,memoize, no] + ] + ] + ] + ] + [,compile, no] + ] + \end{forest} +\end{center} + +As the memoization options were already set by the user interface entry points, +you might expect, quite reasonably, that \refcmd{Memoize} takes a single +argument, the code submitted to memoization. After all, what more does it +need? Clearly, executing this code is what produces the typeset material, and +to detect whether the code has ``changed'' (in order to recompile the memos and +externs), we compute the MD5 sum of this very code, don't we? Well, the +reality is a bit more complicated. When it comes to automemoized commands, the +code which the MD5 sum is computed off of (and which is displayed in the c-memo +if \refmmz{include source in cmemo} is in effect) is not exactly the same as +the code we compile (during either memoization or regular compilation). We'll +see what the difference is in section~\ref{sec:tut:automemoization-details}; +what matters here is that we must provide \refcmd{Memoize} with both and that +this macro therefore takes two arguments: the \emph{identification code}, which +the MD5 sum is computed off of, and the \emph{executable code}, which, well, is +the code that gets executed during memoization (or regular compilation). + +Let's illustrate this with an example which is probably entirely useless (but +don't worry, we'll get to a realistic example in +section~\ref{sec:tut:automemoization-details}). We first memoize some text +manually, using command \refcmd{mmz}, and then do something very stupid: we use +this very text as the identification code for the following \refcmd{Memoize}, +even if the executable code of that command is completely different. The +second line of the typeset output should convince you that the first argument +to that command was really used to produce the extern; and one further +compilation should convince you that the first argument was indeed used to +identify the extern: the extern produced by \refcmd{mmz} was overwritten by the +extern produced by \refcmd{Memoize}, in the fashion of the |progressbar| +example from section~\ref{sec:tut:redefinitions}. + +\ExampleName{memoize-internal} +\makeexample{\examplename.pdf N=2} +\tcbinputexample{ + comment={% + \includeexamplepdf[document page, + after title pre={\ (after the first compilation)} + ]{page=3}\hfill + \includeexamplepdf[document page, + after title pre={\ (after the second compilation)} + ][\examplepath.c2.pdf]{page=1} + }, +} + +The example above also illustrates a(nother) peculiar feature of +\refcmd{Memoize}. \refcmd{Memoize} does not open a new \hologo{TeX} group, but +it \emph{expects a group to be opened prior to calling it}, as it will issue an +|\endgroup| at some point. Specifically, the memoization group will be closed +before regular compilation or utilization, but after memoization. If you want +to know why, read the boxed text below. + +\begin{tcolorbox}[title=\string\Memoize\ and grouping, enhanced, breakable] + One important desideratum behind the design of Memoize was that using the + package should disrupt the original, Memoize-less compilation as little as + possible. In particular, if the memoized code contains local assignments + whose effect (in the original compilation) persists into the rest of the + document (until the end of the surrounding \hologo{TeX} group, of course), + wouldn't one want these local effects to persist when Memoize is around, as + well? Fortunately, most memoized code does not have persistent local effects + (at least for me, it is usually environments, like \env{tikzpicture}s, that I + want to memoize, and environments introduce a group anyway) --- fortunately, + because there are design reasons for enclosing memoization in a \hologo{TeX} + group (or two), and this enclosure will of course cancel the effect of local + assignments in the memoized code. + + For one, the user interface memoization commands, such as \refcmd{mmz} and + automemoized commands, allow for options specific to a particular piece of + memoized code (the options given as the optional argument to manual + memoization, the next-options and the auto-options), and to delimit their + effect, it makes most sense to apply them in a group. I have toyed with the + idea of working around the introduction of a group by manually saving and + restoring all the options, but I quickly gave up on this line of thought. + For one, manually saving and restoring the options would be cumbersome and + error-prone, and probably also slower than using the group. But even worse, + all that work would not really solve the problem of the persistence of local + effects, because memoization itself introduces a group, as well: during + memoization, the typeset material is collected into a box, and opening a box + introduces a group. In some particular situations, this could be avoided by + typesetting the memoized code as-is and collecting the resulting material + using |\lastbox|, but this approach cannot work in general. In general, + memoization will take place in a group, so the issue of local effects must be + addressed in some other way. Memoize offers the following workaround: during + memoization, the memoized code can (globally) add code to the \refmmz{after + memoization} hook, which gets executed immediately after closing the + memoization group. + + Does this mean it would be best if the user interface memoization commands + straightforwardly surrounded \refcmd{Memoize} by |\begingroup| and + |\endgroup|? For example, \refcmd{mmz} would open the memoization group, let + \refcmd{Memoize} do its work, and then close the group. Not really. + Remember that memoization is not the only possible outcome of calling + \refcmd{Memoize}. Perhaps we can at least retain the local effects of a + regular compilation, and of utilization? + + We can, by finely tuning the timing of the memoization group closure within + \refcmd{Memoize}. This command is designed to close the memoization group + after memoization, but before regular compilation and utilization. Closing + the group after memoization makes sure that the given options are in effect + during this process. By closing the group prior to regular compilation, + regular compilation of the memoized code (which takes place when Memoize is + disabled, for example) is guaranteed to have (almost, see + footnote~\ref{fn:regular-compilation-almost}) exactly the same effect as the + compilation of that code in absence of Memoize; in particular, the effect of + any local assignments will persist into the rest of the document. Finally, + closing the group before utilization simplifies the construction of the memo + in the cases where we need to replicate local effects of the memoized code + --- the group closed, there is no need to smuggle local assignments out of a + memo. +\end{tcolorbox} + +\subsection{Memos} +\label{sec:memos} + +Up until now, we have pretended that there is a single kind of a memo file. In +truth, there's two kinds: \emph{code memos}, or \emph{c-memos} for short; and +\emph{code--context memos}, or \emph{cc-memos} for short. In this section, we +will learn what they are for, and how they look like --- and also a bit on how +they are produced, even if the details on that will have to wait until +section~\ref{sec:memoization-drivers}. + +We will see that when Memoize utilizes memos, c-memos are processed first. But +conceptually, cc-memos are more important, so we will start the discussion with +these. + +\subsubsection{Cc-memos (and extern inclusion)} +\label{sec:cc-memos} + +When it is input, a cc-memo replicates the effect of the memoized code. This +includes the reproduction of its visual output, which takes the form of +inclusion of any externs produced by memoization. And yes, you got the +implication right: a cc-memo can have any number of associated externs, +including zero, even if the most common case is that of exactly one extern per +cc-memo. The number of externs mostly depends on the memoization driver (see +section~\ref{sec:memoization-drivers}); the default driver always produces +exactly one extern. + +A cc-memo is located in the directory given via subkey \refmmzpath{dir} (and +\refmmzpath{relative}) of key \refmmz{path}. You can recognize it by its filename, +which has the following form (\meta{prefix} is set via subkey \refmmzpath{prefix}): +\begin{center} + \code{\meta{prefix}\meta{code md5sum}-\meta{context md5sum}.memo} +\end{center} + +In fact, this is how Memoize recognizes --- or rather, searches for --- a +cc-memo as well: Memoize will utilize a cc-memo when the code and the context +MD5 sum computed during an attempted utilization match the code and the context +MD5 sum computed during some previous memoization (for details on the context +MD5 sum, see section~\ref{sec:c-memos}). In detail, a cc-memo is created at +the end of memoization, at which point Memoize computes the MD5 sum of the +memoized code and the MD5 sum of the context, and writes the results of +memoization into the cc-memo identified by (the prefix and) these two MD5 sums. +And when Memoize, on a subsequent compilation, encounters a piece of memoized +code, it again computes the MD5 sum of that code and the MD5 sum of the +context, and tries to input the cc-memo identified by (the prefix and) these +two MD5 sums. If the inputting is successful, we have utilized the cc-memo +(which in the typical case amounts to including the one associated extern); if +the cc-memo cannot be found, Memoize starts the memoization process, which +creates the memos and the externs. + +Let us take a look at the contents of a cc-memo in detail. Here's a typical +cc-memo (it belongs to the titlepage penguin): + +\begingroup +\relaxmmzcommands +\def\mmzNewCCMemo#1{% fetch the first cc-memo filename + \def\myccmemo{#1}% + \endinput +} +\input{\exampledir titlepage.mmz.c1} +\sed{% + s/\cmd{quitvmode} \cmd{mmzIncludeExtern}/\cmd{quitvmode}\n\cmd{mmzIncludeExtern}/; + s/\(\marg\marg\marg\)\(\marg\marg\marg\marg\marg\)/\1\space\2/; +}{\exampledir\myccmemo} +\tcbinputlisting{ + listing only, + listing file=\exampledir\myccmemo, + example title=\myccmemo, +} +\endgroup + +A cc-memo begins by listing the externs which the memo will (actually, might) +attempt to include into the document. When the cc-memo is input, each +\refcmd{mmzResource} command checks if the given extern exists. If some +existence check fails, Memoize enters the memoization mode, same as if the +cc-memo itself did not exist. If all the resources pass the existence check, +Memoize inputs the core of the cc-memo, i.e.\ everything following the +\refcmd{mmzMemo} marker. + +The core might contain arbitrary code, but most often, it will consist of only +two commands. The first one is \refcmd{quitvmode} and it is included if the +extern was \refmmz{capture}d into a horizontal box (which is the usual +situation). The second one is \refcmd{mmzIncludeExtern}, and it is this +command which actually includes the extern into the document upon inputting the +cc-memo. The core code is executed without introducing any groups, i.e.\ the +effect of any local assignments in the cc-memo will persist into the code +following the memoized code. + +Command \refcmd{mmzIncludeExtern} takes nine parameters. The first is the +sequential number of the extern associated with the cc-memo, starting with 0; +usually, this is simply 0 as most memos are associated with a single extern. +The second one is a \refcmd{hbox} or \refcmd{vbox}, noting the type of the box +the memoized code was externalized into. The next three numbers are the +expected width, height and the depth of the extern. Finally, we have the four +\refmmz{padding} amounts (left, bottom, right and top). We should arrive at +the expected size after trimming the extern PDF by the +padding amounts; Memoize will complain if we don't. + +Let's look at a more interesting cc-memo. Using the advising framework, +described in section~\ref{sec:tut:automemoization-details}, Memoize hacks +\refcmd{label} to support \cs{label}s inside memoized code --- the following +code ``just works.'' + +\ExampleName{label} +\makeexample{\examplename.pdf N=3} +\tcbinputexample{ + comment={\centering + \includeexamplepdf[document page, after title pre={\ (compilation 1)}, + left=1.5mm, right=1mm]{page=2}\quad + \includeexamplepdf[document page, after title pre={\ (compilation 2)}, + left=1.5mm, right=1mm][\examplepath.c2.pdf]{page=1}\quad + \includeexamplepdf[document page, after title pre={\ (compilation 3)}, + left=1.5mm, right=1mm][\examplepath.c3.pdf]{page=1} + }, +} + +Everything seems normal --- after the first compilation, we get ``\textbf{??}'' +because the label has not made it into the |.aux| file yet, but in subsequent +compilations, we learn where the penguin lives --- but it is far from normal +under the hood. If we de-hacked \cs{label} by writing +\refcmd{mmzset}\bracestt{\refmmz{deactivate}=\cs{label}}, the third compilation +(and subsequent compilations) would revert to ``\textbf{??}''. Why would that +happen? The memoized code containing the \cs{label}s is only executed in the +first compilation; in the subsequent compilations, we're simply inputting the +cc-memo, so the memoized code, including any \cs{label}s in contains, is not +compiled, and the labels don't get into the |.aux| file anymore. + +The \cs{label} hack deploys Memoize's ability to put arbitrary code into the +cc-memo. During memoization, the memoized code may add arbitrary code to +register \refcmd{mmzCCMemo}, and the contents of this register at the end of +the memoization form the free-form part of the cc-memo.\footnote{This is also + how the above-described code containing \refcmd{mmzIncludeExtern} gets into + the cc-memo. The code is produced by \refcmd{mmzExternalizeBox} and appended + to \refcmd{mmzCCMemo} by the default memoization driver + \refcmd{mmzSingleExternDriver}; see section~\ref{sec:memoization-drivers} for + details.} When the hacked \cs{label} is encountered during memoization, it +appends \refcmd{mmzLabel}\marg{label name}\marg{current label value} to +\refcmd{mmzCCMemo}, so this command winds up in the cc-memo. It is then a +simple job for \refcmd{mmzLabel}, executed when the cc-memo is input at +subsequent compilations, to temporarily store \meta{current label value} (i.e.\ +the contents of \refcmd{@currentlabel} at the time the \cs{label} was invoked) back +into \cs{@currentlabel} and to execute \cs{label}\marg{label name}. In effect, any +\cs{label} command contained within the memoized code is executed at every +compilation, even if the memoized code itself is not compiled. + +\begingroup +\relaxmmzcommands +\def\mmzNewCCMemo#1{% fetch the first cc-memo filename + \def\myccmemo{#1}% + \endinput +} +\input{\examplepath.mmz.c1} +\sed{% + s/~//g; + s/\cmd{quitvmode} \cmd{mmzLabel}/\cmd{quitvmode}\n\cmd{mmzLabel}/; + s/\(\marg\)\cmd{mmzIncludeExtern}/\1\n\cmd{mmzIncludeExtern}/; + s/\(\cmd{mmzLabel}\) *\(\marg\marg\) */~\1\2~\space/g; + s/\(\marg\marg\marg\)\(\marg\marg\marg\marg\marg\)/\1\space\2/; +}{\exampledir\myccmemo} +\tcbinputlisting{float, + listing only, right=1.5mm, + listing file=\exampledir\myccmemo, + example title=\myccmemo, +} +\endgroup + +We will continue the discussion of \refcmd{label} in section~\ref{sec:label+} using +a funkier example. + + +\subsubsection{C-memos (and context)} +\label{sec:c-memos} + +As explained in the previous section, a cc-memo belonging to a piece of +memoized code is identified by two MD5 sums: the MD5 sum of the memoized code, +and the MD5 sum of the associated context. However, when Memoize encounters +some code submitted to memoization, the context expression is not yet fully +known, as it may be adjusted by the memoized code itself during memoization --- +and this potential adjustment is crucial for \cs{ref} and friends to work as +advertised (see section~\ref{sec:cross-referencing}). Upon being invoked, +Memoize therefore cannot immediately attempt to input the cc-memo; it needs to +first learn about the context adjustments. Here's where c-memos enter the +picture: \emph{the primary job of a c-memo is to store the context adjustments + made by the memoized code}. Let's see how this works in detail. + +Same as cc-memos, c-memos are located in the directory given via subkey +\refmmzpath{dir} (and \refmmzpath{relative}) of key \refmmz{path}. However, a c-memo +belonging to some memoized code is identified by the MD5 sum of that code +alone; its filename has the following form, where \meta{prefix} is again set +via subkey \refmmzpath{prefix}: +\begin{center} + \code{\meta{prefix}\meta{code md5sum}.memo} +\end{center} + +The c-memo is created at the end of the memoization process. At that time, the +context expression is fully known, as the memoized code was already processed. +Even more, Memoize keeps track of both the state of the context expression +prior to memoization, stored in token register \refcmd{mmzContext}, and of the +\emph{additions} to the context expression made by the memoized code, which are +stored in token register \refcmd{mmzContextExtra}. (Incidentally, key +\refmmz{context} automatically adapts to the situation by appending to +\refcmd{mmzContext} outside memoization and to \refcmd{mmzContextExtra} during +memoization.) The complete context expression is the concatenation of the +contents of these two registers, but it is only the context expression +additions, i.e.\ the contents of \refcmd{mmzContextExtra}, which Memoize stores +into the c-memo, with the idea that during subsequent compilations, the initial +context (\refcmd{mmzContext}) will be set up again via ``normal'' compilation, +while inputting the c-memo will restore the additions, jointly reconstructing +the complete context expression associated with a piece of memoized code to +what it was at the end of memoization. + +We can now complete the picture of a utilization attempt started in +section~\ref{sec:cc-memos}. Memoize begins by trying to input the c-memo; this +can be done as the c-memo can be identified based solely on (the MD5 sum of) +the memoized code. If the c-memo does not exist, Memoize starts the +memoization process, which will produce the memos and the externs. But if it +does exist, inputting it reconstructs the context expression to the state at +the end of memoization. Therefore, as the MD5 sum of the \emph{expansion} of +the context expression \emph{at the end of memoization} is baked into the +cc-memo filename, trying to load the cc-memo identified by (the prefix, the +code MD5 sum and) the MD5 sum of the \emph{expansion} of the context expression +\emph{at attempted utilization} will succeed precisely when the context +remained unchanged from memoization to attempted utilization. + +All this might have sounded very complicated, but in the end, most c-memos are +quite boring, the titlepage penguin's c-memo shown below being no exception. A +c-memo starts with the \refcmd{mmzMemo} marker, which is always followed by a +(global) assignment to token register \refcmd{mmzContextExtra}, holding the +context expression additions. As promised, the c-memo below is boring: it +assigns an empty token list to this register, leaving the context expression +as-is. Next comes the free-form part of the memo. Below, it is boringly empty +as well (just the percent sign), but in principle, it will contain any code +gathered in register \refcmd{mmzCMemo} during memoization; see +\ref{sec:per-overlay} for an example. A c-memo is concluded by an optional +part consisting of the \refcmd{mmzSource} marker, followed by the memoized +code. The source code section is not used by Memoize in any way and can be +switched off by \code{\refmmz{include source in cmemo}=false}; it is included +by default so that an interested user can know which code produced which memo, +which can be useful if one wants to trigger recompilation of an extern by +deleting the corresponding memo. Incidentally, any newlines in the source code +are lost in the c-memo replica (unless \refmmz{verbatim} is in effect), but we +will only see this once we arrive at the \pkg{beamer} example below. + +\begingroup +\relaxmmzcommands +\def\mmzNewCMemo#1{% fetch the first c-memo filename + \def\mycmemo{#1}% + \endinput +} +\input{\exampledir titlepage.mmz.c1} +\tcbinputlisting{ + listing only, + listing file=\exampledir\mycmemo, + example title=\mycmemo, +} +\endgroup + +A c-memo of code containing a cross-reference will prove more interesting. The +following c-memo was produced by the |ref| example from section +\ref{sec:cross-referencing}. As we know from that section, when a \refcmd{ref} (as +hacked by Memoize's \refmmzauto{ref} key) occurs in some memoized code, it +appends the cross-reference to the context. In the c-memo below, this is +reflected by the (global) assignment of an expression containing the +cross-reference macro to token register \refcmd{mmzContextExtra}, holding +the context expression additions. + +\begingroup +\relaxmmzcommands +\def\mmzNewCMemo#1{% fetch the first c-memo filename + \def\mycmemo{#1}% + \endinput +} +\input{\exampledir ref.mmz.c1} +\sed{% + s/~//g; + s/\cmd{global}.*\marg/~\0~/; +}{\exampledir\mycmemo} +\tcbinputlisting{ + listing only, + listing file=\exampledir\mycmemo, + example title=\mycmemo, +} +\endgroup + + +\subsubsection{More on \texorpdfstring{\cs{label}}{\textbackslash label}} +\label{sec:label+} + +A \refcmd{label} inside memoized code works out of the box in the usual situation +when label value is fully determined by the memoized code, as in the example in +section~\ref{sec:cc-memos}, where the memoized code contained the outermost +(and only) \env{enumerate} environment. However, the out of the box approach does +not work if the label value is (fully or partially) determined outside the +memoized code. To illustrate the problem, and some potential solutions, we +define two very simple enumeration environments, |listi| and |listii|, which +use counters |counti| and |countii|, and which are intended as the outer and +the inner environment, respectively. Our interest here is in the inner +environment, |listii|. While it prefixes each item by an indented +|\thecountii)|, the label is a composite of both counters: +|\thecounti\thecountii|. The label is stored into \refcmd{@currentlabel}, so +referencing works as usual. However, problems arise when we automemoize the +inner environment. + +\ExampleName{label+} +\makeexample{\examplename.tex.c1 N=6} +\makeexample{\examplename.pdf N=2} +\tcbinputexample{ + sidebyside, lefthand ratio=0.53, + comment={\centering\includeexamplepdf[document page][\examplepath.c2.pdf]{page=1}}, +} + +While the result looks fine at first, changing the order of |listii| +environments, for example by moving ``pets'' below ``domestic'', will result in a +problem: the reference at the bottom will remain unchanged. This is so because +the reference text is baked into the cc-memo, as shown below. + +\begingroup +\relaxmmzcommands +\def\mmzNewCCMemo#1{% fetch the first cc-memo filename + \def\myccmemo{#1}% + \endinput +} +\input{\examplepath.mmz.c1} +\sed{% + s/~//g; + s/\cmd{mmzLabel} \marg\marg/~\0~/; + s/\(\marg\)\(\cmd{mmzIncludeExtern}\)/\1 \2/; + s/\(\marg\marg\marg\)\(\marg\marg\marg\marg\marg\)/\1\space\2/; +}{\exampledir\myccmemo} +\tcbinputlisting{ + listing only, + listing file=\exampledir\myccmemo, + example title=\myccmemo, +} +\endgroup + +How can we remedy this? The manual option is to force the recompilation of the +extern by putting an (invisible) reference to the outer item into the inner +item: add |\label{item:pets}| to item ``pets'' and refer to it at ``dog'' by +\refcmd{mmzNoRef}|{item:pets}|.% +\attachexample[\examplename mmzNoRef.tex][\examplepath.tex.c3.attachment] + +An automatic variant of the recompilation solution is to add \cs{@currentlabel} +to the context upon memoizing |listii|. This can be achieved by adding +\refmmz{context}|={@currentlabel={\csuse{@currentlabel}}}| to the \refmmz{auto} +declaration for |listii|. The downside of this approach is that every |listii| +will get reexternalized upon movement, whether it actually contains a label or +not.\attachexample[\examplename context.tex][\examplepath.tex.c4.attachment] + +In fact, given that the externs produced by the inner environment do not +contain the value of the outer counter, it seems wasteful to recompile any +extern just to change the reference. And indeed, it is possible to avoid this, +but the approach unfortunately requires adapting the inner environment code +(and this is why I have not illustrated the problem using an environment of an +elaborate package like \pkg{enumitem}). The idea is to ``unbake'' the +reference to the outer item in the cc-memo. We can achieve this by changing +|listii| to define \cs{@currentlabel} to be |\unexpanded{\thecounti}\thecountii|. +Under this definition, the cc-memo will contain |\mmzLabel +{item:dog}{\thecounti a}|, and rearranging |listii| environments will produce +(upon two compilations, of course) the correct reference without recompiling +the extern. Note again, however, that this solution can only work when the +value of the outer counter does not appear in the extern, i.e.\ it would not +work the ``dog'' item was prefixed by |1a)| rather than simply |a)|. In those +cases, one should deploy one of the other solutions.% +\attachexample[\examplename listii.tex][\examplepath.tex.c5.attachment] + +The final solution, presented below, is an elaboration on the second one. +Rather than append \cs{@currentlabel} to the context immediately upon beginning +to memoize environment |listii|, we will at that point redefine \cs{label} to do +that. In effect, changing the location of |listii| will only recompile it if +it contains a \cs{label}. + +At announced, we redefine \cs{label} once the memoization of |listii| begins, +so within \refmmz{at begin memoization}.\footnote{Another generally good + location for such redefinitions is among the auto-options of |listii|. We + could include an \refmmz{auto}\cs{label}\marg{...} there, or a |/utils/exec| + with \refcmd{AdviceSetup}. However, in this particular case this would be + wasteful, as it would be applied regardless of whether memoization will take + place or not, whereas we only need the redefined \cs{label} when memoizing.} +However, we do not redefine \cs{label} directly, as Memoize advises this +control sequence out of the box (see +section~\ref{sec:tut:automemoization-details} for details). What we redefine +is the command which the advising framework executes instead of \cs{label} --- +its so-called \refmmzauto{outer handler} --- and we do this by calling +\refcmd{AdviceSetup}, the low-level variant of the familiar key +\refmmz{auto}.\footnote{We could have also used \refmmz{auto}, but we don't, + because (a) \refcmd{AdviceSetup} is faster, (b) it is easier to prepend + material to a handler using the low-level interface, and (c) I wanted to + showcase \refcmd{AdviceSetup}.} The first argument of \refcmd{AdviceSetup} +is the installation path (|/mmz|), the second one the command or environment we +are submitting to the framework (\cs{label}), and the third one the setup +\emph{code} --- here lies the biggest difference between \refmmz{auto} and +\refcmd{AdviceSetup}: the former expects a keylist, and the latter \hologo{TeX} +code which directly manipulates settings macros like +\refcmd{AdviceOuterHandler} (for the full list, see +section~\ref{sec:tut:automemoization-details} or~\ref{sec:ref:advice}). + +\tcbinputexample[.tex][.c6]{listing only, float, + attachment name=\examplename auto.tex, +} + +Within \refcmd{AdviceSetup}, we prefix (using macro \cs{preto} of package +\pkg{etoolbox}) the original outer handler \refcmd{AdviceOuterHandler} by code +which causes \cs{outerlabeltocontext} to be executed at the end of memoization +(by globally appending this macro to \refcmd{mmzAtEndMemoizationExtra}; +``Extra'' because we're appending during memoization). It is +\cs{outerlabeltocontext} which then appends \refcmd{@currentlabel} to the +context (\refcmd{mmzContextExtra}; again, ``Extra'' because we're appending +during memoization),\footnote{As a courtesy, we clear out macro + \cs{outerlabeltocontext} once it did it's job, so that multiple \cs{label}s + do not include multiple \cs{@currentlabel}s into the context. But the code + would work even without this addendum, can you see why?} and it is crucial +that this happens at the end of memoization rather than when \cs{label} is +executed. When \cs{label} is executed, we're inside an inner item, and +\cs{@currentlabel} refers to that item, while at the end of memoization, the +value of this macro equals the value at the beginning of memoization, namely +the label of the outer item. While the outer list remains unshuffled, the +value of \refcmd{@currentlabel} that contributes to the context MD5 sum during +the utilization attempt will therefore match the value which contributed to the +context MD5 sum during memoization, resulting in matching MD5 sums and +therefore in actual utilization of the extern; once the outer list is shuffled, +this will cease to be the case and the extern will be recompiled. + + +\subsubsection{The Beamer support explained} +\label{sec:per-overlay} + +The implementation of \refmmz{per overlay}, which makes memoization sensitive +to Beamer overlays, provides an example of a complex interaction between +various components of memoization. At the core, the Beamer support works by +adjusting the context, but we will also have the occasion to observe the +free-form part of the c-memo, add a bit of extra code to the cc-memo, and +deploy several memoization hooks. We will show the complete Beamer support +code later on; let us build our understanding of that code step by step. +(Before you read on, you might want to refresh your memory about the \pkg{beamer} +example from section~\ref{sec:tut:beamer}, as we will refer to it in the +present section.) + +The core idea behind \refmmz{per overlay} is to append the current beamer +overlay number to the context:\cprotect\footnote{As we saw in + section~\ref{sec:tut:beamer}, it is convenient to execute \refmmz{per + overlay} inside memoized code. But remember, from + section~\ref{sec:cross-referencing}, that when \refmmz{context} is executed + from within the memoized code, its argument winds up in the c-memo. As the + c-memo is processed under the normal category code regime, where |@| is not a + letter, we have to access |\beamer@overlaynumber| using the |\csname + ... \endcsname| construct.} \refmmz{context}|={overlay=\csname + beamer@overlaynumber\endcsname}|. This makes Memoize produce a separate +extern for each overlay. However, only the first of these externs will get +utilized on subsequent compilations, in general at least. Even worse, we will +lose each frame whose creation is driven solely by the memoized code. We will +lose the second overlay in our example (i.e.\ in the \pkg{beamer} example from +section~\ref{sec:tut:beamer}) as the second overlay was only created because +Beamer encountered |only={2}{...}| (resolving to |\only<2>{...}| under the +hood) inside the picture code; once we utilize the extern instead of compiling +the picture on the first overlay, the |\only| command is not executed anymore, +so Beamer thinks it is done with the frame. + +As the compilation of our picture is substituted by utilization of its +cc-memos, we have to somehow drive the creation of the necessary overlays from +these files. An easy way to achieve this is to furnish them with a dummy +|\only<|\meta{final overlay number}|>{}|,\footnote{`The final overlay' here + should be understood as relative to our memoized picture, i.e.\ as the final + overlay containing the memoized picture.}\footnote{Actually, putting this + \cs{only} command only into the first cc-memo would suffice, but would be + harder to implement.} but there is a problem: the final overlay number is +unknown when we're memoizing our picture --- it is unknown even when we're +memoizing the picture on final overlay itself (we simply don't know yet that +this overlay will end up being the final one), let alone during the memoization +on the first overlay. + +The solution exploits the fact that \emph{the c-memo is rewritten at each + memoization}: at each memoization of our picture, we store the the +\emph{current} overlay number to the c-memo; after all memoizations, the c-memo +will thus contain the number of the \emph{final} overlay containing our +memoized picture. To access this number from the cc-memo, we store it as a +macro definition, and then use the defined macro, |\mmzBeamerOverlays|, in the +overlay specification of the dummy |\only|. Below, you can see all this in +code, as the argument to \refmmz{at begin memoization}. + +\ExampleName{per-overlay-v1} +\makeexample{\examplename.sty} +\tcbinputexample[.sty]{ + listing only, + title={The implementation of \refmmz{per overlay} (first attempt)}, +} + +A couple of remarks are in order here. First, the definition of +|\mmzBeamerOverlays| in the c-memo is global, because it will be accessed from +the cc-memo, but the cc-memo is input after closing the memoize group (which +the c-memo \emph{is} processed in). Second, using \refmmz{at begin + memoization} makes it possible to use \refmmz{per overlay} both outside and +during memoization: if \refmmz{at begin memoization} is executed outside +memoization, its argument is (locally) stored into hook +\refcmd{mmzAtBeginMemoization}, to be called at the beginning of each +memoization; if the key executed outside memoization, the argument is executed +immediately. Third, the Memoize keys in the definition of \refmmz{per overlay} +are prefixed with \code{\refkeypath{/mmz}/}, so that this key can be called from +\pkg{pgfkeys} option lists of other packages, for example the option list of +the \env{tikzpicture} environment, as shown in the example in +section~\ref{sec:tut:beamer}. + +I used the above version of \refmmz{per overlay} for quite a while. In +general, it worked as I expected, but there were glitches. Occasionally, the +picture would appear on the wrong overlay, or I would get an extra overlay, or +perhaps lose an overlay. Eventually, I figured out this happens when I play +with the overlay structure of the frame: when I add or remove a \cs{pause} or +similar. In hindsight, it is easy to see what was happening. Once the picture +is memoized, it is fixed, forever, which extern will appear on which overlay. +I cannot expect the extern--overlay correlation to change just because I added +a \cs{pause} in front of the picture. Furthermore, the number of overlays the +memos will drive to be created is fixed as well. If I memoize the picture +while it follows a \cs{pause}, and the picture creates 10 overlays, the c-memo +will define |\mmzBeamerOverlays| to 11. So what, if I then remove that +\cs{pause}! The c-memo will still define |\mmzBeamerOverlays| to 11, and drive +the creation of 11 overlays --- one too many. + +By now, the road ahead is probably clear --- we put the |beamerpauses| counter +into the context --- but we will see there are still obstacles on the way. The +issue is that the context is evaluated at the \emph{end} of memoization (so +that those cross-references from section~\ref{sec:cross-referencing} actually +get into it). However, the memoized code might contain a \cs{pause} or similar +itself, and change the value of |beamerpauses|. For one, this means that we +have to write down the changed value of |beamerpauses| into the cc-memo; below, +we do this using key \refmmz{at end memoization} (the code given code to this +key is executed after the driver but before Memoize writes down the memos and +ships out the extern pages; the key itself may be executed either before or +during memoization). Furthermore, if the memoized code changes the value of +|beamerpauses|, the value of |beamerpauses| at the attempted utilization, which +would nicely match the value from the start of memoization, will never match +the changed, final value from the end of memoization, in effect preventing our +hard-won externs from ever getting utilized. + +We therefore have to invent a way to get the memoization-\emph{initial} value +of |beamerpauses| into the context.\footnote{This imposes a requirement on the + in-code usage of \refmmz{per overlay}, namely, that it should be executed + prior to any changes of |beamerpauses|.} Fine, we store it in a +macro,\footnote{We must define \cs{mmzBeamerPauses} globally, because + \refmmz{per overlay} can be arbitrarily deeply embedded in the memoized + code.} |\mmzBeamerPauses|, when we start the memoization (\refmmz{at begin + memoization}), and put |\mmzBeamerPauses| rather than |beamerpauses| into the +context. Will this work? Not yet, because |\mmzBeamerPauses| is undefined at +utilization. We need to set up the context expression so that it will expand +to the value of |\mmzBeamerPauses| at (the end of) memoization, and to the +value of |beamerpauses| at utilization. This leads to the +|pauses=\ifmemoizing...| part of the context expression in (the final version + of) the Beamer support code below. + +\medskip % manual, to avoid an orphan + +\ExampleName{per-overlay} +\makeexcerpt{per-overlay} +\tcbinputexample[.tex][.excerpt]{% + listing only, one file, + left=0pt, % manual indentation gobble + title={The implementation of \refmmz{per overlay}}, +} + +Are we done? Almost. The final issue is that once we have introduced support +for pauses, we have to relativize |\mmzBeamerOverlays| (the final overlay +number) to |beamerpause|. So instead of a simple |\gdef\mmzBeamerOverlays| in +the first version, we define |\mmzSetBeamerOverlays|\nohyphen\marg{beamer + pauses}\marg{final overlay number}, which sets |\mmzBeamerOverlays| only if +\meta{beamer pauses} argument matches the value of |beamerpauses| (at its +invocation in the c-memo). Well, the macro has some other housekeeping to do +as well: it is self-replicating, so that during potential memoization, the +|\mmzBeamerOverlays| values belonging to non-current |beamerpauses| values get +rewritten into the c-memo.\footnote{As replication should only occur during + memoization (actually, it \emph{can} only occur then, anyway), the + instruction to append to the c-memo is appended to the + \cs{mmzAtBeginMemoization} hook (the low-level interface to \refmmz{at begin + memoization}). Note that the assignment to this hook must be local (once + local, always local), and it \emph{can} be local because of a little + implementation detail: while the c-memo is processed in the memoize + \hologo{TeX} group, we don't open an additional group to process it; so the + local effects from c-memo will persist into memoization (but not into + utilization, because remember that the memoize group is closed before + inputting the cc-memo).} (Fine, there is another fine detail, regarding +anti-pollution: the macro also ensures that, relative to \marg{beamer pauses}, +only the instance with the greatest \meta{final overlay number} is replicated.) + +We are now truly done, and we can look at the final result, the c-memo and the +cc-memo belonging to the extern on the first overlay of the example from +section~\ref{sec:tut:beamer}. Specifically, look at the |\mmzSetBeamerOverlays +{1}{2}|, which says that the extern chain started when |beamerpauses| equals 1 +should continue up to overlay 2, and at the (expanded) context included at the +end of the cc-memo, courtesy of \refmmz{include context in ccmemo}, where you +can see that the cc-memo will be used when on the first overlay (|overlay=1|) +when preceded by no \cs{pause} command (|pauses=1|). + +\begingroup +\relaxmmzcommands +\def\mmzNewCMemo#1{% fetch the first c-memo filename + \def\mycmemo{#1}% +} +\def\mmzNewCCMemo#1{% fetch the first cc-memo filename + \def\myccmemo{#1}% + \endinput +} +\input{\exampledir beamer.mmz.c1} +\sed{% + s/~//g; + s/\cmd{mmzSetBeamerOverlays} \marg\marg/~\0~/; +}{\exampledir\mycmemo} +\sed{% + s/~//g; + s/overlay=[0-9]*/~\0~/; + s/pauses=[0-9]*/~\0~/; + s/\(\cmd{quitvmode}\) \(\cmd{only}\)/\1\n\2/; + s/\rbrace\(\cmd{mmzIncludeExtern}\)/\rbrace\percentchar\n\1/; + s/\rbrace\(\cmd{setcounter}\)/\rbrace\percentchar\n\1/; + s/\(\marg\marg\marg\)\(\marg\marg\marg\marg\marg\)/\1\space\2/; +}{\exampledir\myccmemo} + +\tcbinputlisting{ + listing only, + listing file=\exampledir\mycmemo, + example title=\mycmemo, +} + +\tcbinputlisting{ + listing only, + listing file=\exampledir\myccmemo, + example title=\myccmemo, +} +\endgroup + + +\subsection{Record files} +\label{sec:record-files} + +We have seen that externalization is a two-step process in Memoize: as it is +impossible for \hologo{TeX} to create multiple PDFs during a single +compilation, the externs are first dumped into the document PDF as special +extern pages, and only later extracted from the main document into separate PDF +files. But extraction requires a complete PDF, which is unavailable even at +the very end of the compilation which produces the externs. The externs can +therefore only be extracted \emph{after} that compilation (either before or at +the beginning of the next one), and this necessitates some form of +communication whereby the memoization step informs the extraction step which +pages should be extracted from the document PDF and into which (PDF) files they +should be stored. This communication is implemented through auxiliary files +called \emph{record files}. + +\subsubsection{The \texttt{.mmz} file} +\label{sec:.mmz} + +By default, Memoize records the information needed for the extraction in a file +named \meta{document name}\dmmz,\footnote{For \hologo{TeX}perts: the + \meta{document name} is of course the expansion of \cs{jobname}.} henceforth +a \dmmz file. In fact, this file contains more than information on externs +created during the last compilation: it records which memos and externs were +either used or created during the compilation. The full information contained +in the \dmmz file is used by the clean-up script \refscript{memoize-clean.pl} +to safely remove stale memos and externs. Let us take a look at the \dmmz file +produced by the titlepage illustration. In fact, we have two versions of this +file, as it changes upon the second compilation. + +\ExampleName{titlepage} +\makeexample{\examplename.pdf N=2} +\sed{% + s/~//g; + s/\cmd{mmzNewExtern}/~\0~/; +}{\examplepath.mmz.c1} +\tcbinputexample[.mmz][.c1]{ + listing only, one file, no attachment, float, + after title pre={\ (after the first compilation)}, + listing options app={breakatwhitespace=false,prebreak=\coloredpercentchar}, +} +\tcbinputexample[.mmz][.c2]{ + listing only, one file, no attachment, float, + after title pre={\ (after subsequent compilations)}, + listing options app={breakatwhitespace=false,prebreak=\coloredpercentchar}, +} + +As you can see, the \dmmz file takes the form of a \hologo{TeX} script (the +format was chosen because it facilitated the implementation of the internally +triggered \hologo{TeX}-based extraction). The crucial lines in this file, and +the only lines used by the extraction script, occur in the first version of the +file: they contain command \refcmd{mmzNewExtern}, which informs the extraction +script that it should extract the document page given by the second argument +into the extern file given by the first argument.\footnote{If you look at the + \dmmz file after extracting the externs using \refscript{memoize-extract.pl} + without the \refscript{memoize-extract.pl--keep} option, you will find that + the \refcmd{mmzNewExtern} commands are commented out; this is to prevent + multiple extractions (even if they are harmless).} (The following two +arguments provide the expected width and height of the extern; the +extraction script may check whether the extern size conforms to these +expectations, but this is not crucial, as the extern size is checked every time +it is included anyway.) + +A \dmmz file also contains a record of the memos (both c-memos and cc-memos) +created in the last compilation; this information is provided by the sole +argument of commands \refcmd{mmzNewCMemo} and \refcmd{mmzNewCCMemo}. And once +memos and externs get used in subsequent compilations, the \dmmz file will +reflect this with \refcmd{mmzUsedCMemo}, \refcmd{mmzUsedCCMemo} and +\refcmd{mmzUsedExtern}, as shown in the second version of the file above. + +Finally, both versions illustrate that a \dmmz file always begins with command +\refcmd{mmzPrefix} and ends with the |\endinput| marker. The argument of +\refcmd{mmzPrefix} is the path prefix to the memo and extern files, as +determined by the invocation of key \refmmz{path} (and its subkeys +\refmmzpath{relative}, \refmmzpath{dir} and \refmmzpath{prefix}). The initial +\refcmd{mmzPrefix} line is written to the \dmmz file at the beginning of the +document, but an additional \refcmd{mmzPrefix} line will occur for every +invocation of \refmmz{path} in the document body. Finally, the |\endinput| +marker signals that the \dmmz file is complete. + +As mentioned above, the full contingent of \dmmz file commands is only used by +the clean-up script \refscript{memoize-clean.pl}. By default, this script +removes all memos and externs with the prefix given by \refcmd{mmzPrefix} +(relative to the directory hosting the \dmmz file) but those listed by any of +\refcmd{mmzNewCMemo}, \refcmd{mmzNewCCMemo}, \refcmd{mmzNewExtern}, +\refcmd{mmzUsedCMemo}, \refcmd{mmzUsedCCMemo} and \refcmd{mmzUsedExtern}. +Furthermore, the clean-up script will cowardly refuse to delete anything if the +\dmmz file does not end with |\endinput|, as this means that the compilation +ended prematurely and that the \dmmz file might not mention all memos and +externs actually used in the document. If given option +\refscript{memoize-clean.pl--all}, the clean-up script removes even the memos +and externs mentioned in the \dmmz file, and as this option is intended to +bring Memoize to a clean slate after any ``disasters,'' the +\refscript{memoize-clean.pl--all} mode also ignores the potential absence of +the |\endinput| marker. Incidentally, the \refscript{memoize-clean.pl--all} +mode is also the raison d'être for \refcmd{mmzPrefix}: while the prefix is +usually recognizable from \refcmd{mmzNewCMemo} and friends, these commands +might not make it into the \dmmz file in a fatally failed compilation, but it +is precisely such compilations that could occasionally require the full +clean-up. + +\subsubsection{Defining a new record type} +\label{sec:new-record-file} + +The \dmmz file is not the only kind of a record file that can be produced by +Memoize. Out of the box, it can also write down the extraction instructions +into a makefile or a shell script. These are useful on systems which have to +employ the \hologo{TeX}-based extraction but cannot trigger it internally. +Running the \hologo{TeX}-based extraction manually would be painful, as it must +be done on extern-by-extern basis, so Memoize offers to automate the extraction +by a makefile or a shell script; here, the record file is named +\code{memoize-extract.\meta{document name}.\meta{record type}} by default, +where \meta{record type} is either \refmmz{record=makefile}, +\refmmz{record=sh} (for shell scripts on Linux), or \refmmz{record=bat} (for +shell scripts on Windows). + +To turn on recording of an alternate record type, use key +\refmmz{record}|=|\meta{record type}. Memoize can record any number of files +simultaneously, so saying \code{\refmmz{record}=\refmmz{record=sh}} will +produce the shell script alongside \dmmz (Memoize internally executes +\code{\refmmz{record}=\refmmz{record=mmz}} to start recording the \dmmz file); +this should not be a problem, but if you really want to disable the \dmmz file +production, you can say \refmmz{no record}. + +The predefined record types are defined through a generic system open to the +user. To define an additional record type, one needs to define, using +\pkg{pgfkeys}, the relevant hooks of the form \refkeypath{/mmz/record/record + type}|/|\meta{hook}. The following \meta{hook}s can be defined (the hooks +not needed for the record file type may be left undefined): +\begin{itemize} +\item Key \refmmz{record/record type/begin} will be executed at the beginning + of the document; it will receive no argument. Use it to open the record + file. +\item Key \refmmz{record/record type/end} will be executed at the end of the + document; it will receive no argument. Use it to close the record file. +\item Key \refmmz{record/record type/prefix} will be executed at the end of the + document and at every invocation of key \refmmz{path} in the document body; + it will receive a single argument, the path prefix determined by key + \refmmz{path}. +\item Keys \refmmz{record/record type/new cmemo}, \refmmz{record/record + type/used cmemo}, \refmmz{record/record type/new ccmemo} and + \refmmz{record/record type/used ccmemo} will be executed after creating or + inputting a memo; they will receive a single argument, the full path to the + memo. +\item Key \refmmz{record/record type/used extern} will be executed after an + extern was included into the document; it will receive a single argument, the + full path to the extern. +\item Key \refmmz{record/record type/new extern} will be executed after + creating creating an extern, more precisely at the end of memoization, right + after shipping out the extern page. It will receive a single argument, the + full path to the extern, but additionally, Memoize prepares the following + macros: + \begin{itemize} + \item \refcmd{ne:externbasepath} holds the full path to the extern, but (unlike |#1|) + without the |.pdf| suffix; + \item \refcmd{ne:pagenumber} holds the ``physical'' page number of the extern page in + the document (the numbering starts by $1$); + \item \refcmd{ne:expectedwidth} and \refcmd{ne:expectedheight} hold the width and + the height (total height, i.e.\ the sum of \hologo{TeX}'s height and depth) + of the extern page. + \end{itemize} +\end{itemize} + +Below, we present two simple examples of a record file. The first type simply +records the names of all memos and externs used or created by Memoize; the +resulting file could be included by |.gitignore| to have +\hreftt{https://git-scm.com}{git} automatically ignore all files produced by +Memoize. The second type lists the new externs, each preceded by its page +number in the |.pdf|; this file could be fed to a custom extern extraction +tool. + +\ExampleName{record-files} +\makeexample{\examplename.tex.c1} +\tcbinputexample{listing only} + +\ExampleName{record-extern-pages} +\makeexample{\examplename.tex.c1} +\tcbinputexample{listing only} + +Finally, note that (unlike memos and externs) record files are auxiliary files +and may be deleted at any time after the extraction of the externs produced in +the final compilation --- actually, even if these externs were not yet +extracted, deleting the record file(s) will merely force their recompilation. + + +\subsection{The memoization process} +\label{sec:memoization-drivers} + +We now turn to the memoization process itself. The job of memoization is to, +while compiling the given code in a regular fashion, prepare the cc-memo +(which, when it is input, will replicate the effect of the given code), +alongside any externs that the cc-memo will include (these hold the typeset +material to be replicated). Clearly, merely compiling the code cannot have +this effect (unless that code was written specifically to support memoization; +more on this later), and this is why the memoized code is typically wrapped by +a \emph{memoization driver}, which can be set using key \Emph{\refmmz{driver}}. +We'll inspect the default memoization driver, \refcmd{mmzSingleExternDriver}, +in the first subsection, and we will learn how to write specialized drivers in +the remaining subsections. But first, let us say some words about a +grouping-related \hologo{TeX}nical detail we need to take care about during +memoization. + +During memoization, we have to collect certain information, like build the +contents of the cc-memo. Some of that information might be contributed by the +memoized code itself. For example, a \cs{label} ``adds itself'' to the cc-memo +(by appending to token register \refcmd{mmzCCMemo}); a +\refkey{/tikz/remember picture} aborts memoization (by issuing +\refcmd{mmzAbort}); etc. The issue is that the memoized code might open any +number of \hologo{TeX} groups; we have no idea how deeply embedded the +\cs{label} or \refkey{/tikz/remember picture} might be. Therefore, we have +to collect all the information about the ongoing memoization \emph{globally}: +all assignments to \refcmd{mmzCCMemo} must be global; \refcmd{mmzAbort} sets +the underlying conditional globally; etc. (Clearly, all these global variables +are initialized at the start of memoization.) + +This was the easy part. An additional complication arises with some options +which may be set either outside memoization, or during this process. For +example, you can append the font size to the context expression in the preamble +(see section~\ref{sec:cross-referencing}), so that the externs will be +automatically recompiled when the font size changes, and clearly, this context +adjustment should respect \hologo{TeX} grouping; but a \cs{ref} or some other +cross-referencing command in the memoized code needs to append to the context +as well, and as this \cs{ref} occurs \emph{within} the memoized code, the +assignment must be global, as explained above. + +Mixing the local and global assignments to the token register +\refcmd{mmzContext}, which holds the (in the actual implementation, local) +context expression, will not do. For one, we \emph{do} want to restore the +pre-memoization context expression after we have memoized the code, and +furthermore, mixing local and global assignments to the same variable is not +recommended for save stack reasons anyway. + +Memoize addresses this issue by having \emph{two} context registers, +\refcmd{mmzContext} and \refcmd{mmzContextExtra} --- when computing the context +MD5 sum (which happens at the end of memoization), the two registers are +concatenated (the local one comes first). A package writer should know when to +use which register, and how. Outside memoization, one should assign to +\refcmd{mmzContext} --- \emph{locally}. During memoization, one should assign +to \refcmd{mmzContextExtra} --- \emph{globally}. The user interface key +\refmmz{context} respects this requirement automatically: it locally appends to +\refcmd{mmzContext} outside memoization, and it globally appends to +\refcmd{mmzContextExtra} during memoization. (The same idea is applied to the +post-memoization hooks \refmmz{at end memoization} and \refmmz{after + memoization}.) + + +\subsubsection{The default memoization driver} +\label{sec:memoization-driver-default} + +The default memoization driver, \refcmd{mmzSingleExternDriver}, produces +exactly one extern, which contains whatever is typeset by the code submitted to +memoization. The driver compiles the code into a horizontal or vertical box +depending on the value of key \refmmz{capture}. Let us look at the definition +of the driver line by line: + +\makeexcerpt{single-extern-driver} +\tcbinputexample[.tex][.excerpt]{% + listing only, one file, + listing options app={numbers=left, numberstyle=\tiny, numbersep=0.5em}, + title=The default memoization driver, + float, +} + +\begin{enumerate} +\item Macro \refcmd{mmzSingleExternDriver} (and in fact any memoization + driver) takes a single argument, the code to compile. Memoize will call the + driver with the code given as the second argument to \refcmd{Memoize}, but + wrapped in a macro which re-reads it using \refcmd{scantokens} when + \refmmz{verbatim} is in effect. +\item If we're capturing into a horizontal box + (\refmmz{capture}|=|\refmmz{capture=hbox}), we put \refcmd{quitvmode} into + the cc-memo --- putting it to the very beginning should make sure that any + replicated \cs{label} and \cs{index} commands refer to the correct page. +\item We compile the given code, storing the typeset material into a box + (above, a temporary box called |\mmz@box|). |\mmz@capture| resolves into a + box construction command, depending on the value \refmmz{capture}. +\item Macro \refcmd{mmzExternalizeBox} instructs Memoize to externalize the box + given as its first argument. However, this macro does not directly produce + an extern page or write any instructions into the cc-memo; the road to this + final destination is indirect. \refcmd{mmzExternalizeBox} has two effects. + First, it adds the contents of the given box (above, |\mmz@box|) to an + internal box dedicated to holding all the externs produced in this + memoization (the contents of |\mmz@box| remain as they are) --- it is only at + the end of memoization that the contents of this internal box are shipped off + to extern pages. Second, \refcmd{mmzExternalizeBox} produces the code which + will include the extern into the document on subsequent compilations (this + will be a call to \refcmd{mmzIncludeExtern}, potentially prefixed by + \refcmd{quitvmode}; see section~\ref{sec:cc-memos} for details). This code + is stored into the token register gives as the second argument (above, + |\mmz@temptoks|), and it is the responsibility of the driver to include it + into the cc-memo. (In the interest of full disclosure, + \refcmd{mmzExternalizeBox} also updates the list of externs produced in this + memoization. At the end of memoization, this list is written to the + beginning of the cc-memo, resulting in the \refcmd{mmzResource} lines + preceding the \refcmd{mmzMemo} marker.) +\item The construction of the cc-memo is indirect as well. In the third line + of the definition, we globally append the extern-inclusion code residing in + |\mmz@temptoks| to token register \refcmd{mmzCCMemo}. At the end of + memoization, the contents of \refcmd{mmzCCMemo} are written into the cc-memo, + preceded by the \refcmd{mmzMemo} marker. +\item We put the typeset material into the document, again preceded by + \refcmd{quitvmode} when capturing in a horizontal box. +\end{enumerate} + +You might wonder why the construction of the extern pages and the cc-memo (and +actually, of the c-memo as well) is indirect, as described above. +\begin{itemize} +\item For one, the indirect construction facilitates potential abortion of + memoization (see section~\ref{sec:tut:good-to-know}). With the indirect route, + aborting is easy --- as nothing was permanently written anywhere yet, Memoize + simply skips the final part of the process, where extern boxes are shipped + into extern pages and the memo registers written into memo files --- and also + clean: if \refcmd{mmzExternalizeBox} immediately shipped out the extern + pages, these pages would remain in the document even in the case of abortion. +\item Even more importantly, the cc-memo filename contains the \meta{context + md5sum} (see section~\ref{sec:cc-memos}), but the context expression is not + yet fully known when memoization starts --- remember (from + section~\ref{sec:cross-referencing}) that a \cs{ref} in the memoized code will + update the context! The cc-memo can therefore only be opened at the end of + memoization, which necessitates a buffer (i.e.\ the \refcmd{mmzCCMemo} + register) for storing its contents during memoization. +\end{itemize} + + +\subsubsection{Pure memoization} +\label{sec:pure-memoization} + +The default memoization driver discussed above is really an externalization +driver: it produces a single extern. We now move to examples of drivers with +other functions, starting with a pure memoization driver, which does not +externalize any typeset output --- simply because it does not call +\refcmd{mmzExternalizeBox} at any point --- but rather remembers the result +of a (pgfmath) computation (let's pretend that the computation is +time-consuming). + +\ExampleName{pgfmathparse} +\makeexample{\examplename.pdf} +\begingroup +\relaxmmzcommands +\def\mmzNewCCMemo#1{% fetch the first cc-memo filename + \def\myccmemo{#1}% + \endinput +} +\input{\examplepath.mmz.c1} +\tcbinputexample{% + comment={% + \tcbinputlisting{ + listing only, width=.4\linewidth, nobeforeafter, + listing file=\exampledir\myccmemo, + example title, title=the cc-memo, + }\quad + \includeexamplepdf[document page]{page=1} + }, +} +\endgroup + +Command \refcmd{mmz} above memoizes its mandatory argument with the memoization +\refmmz{driver} set to the previously defined macro \cs{mmzPgfmathDriver}. +Just as the default driver above, \cs{mmzPgfmathDriver} first executes the +given code. However, there is no need to do this in the context of a +|\setbox|, as the memoized code, which is obviously expected to consist of a +single \cs{pgfmathparse} call, does not typeset anything: \cs{pgfmathparse} +evaluates the given expression and stores the result into macro +\cs{pgfmathresult}. The driver has two jobs: first, it must store this result +into the cc-memo, to be utilized in subsequent compilations; second, because +the assignment to \cs{pgfmathresult} (within \cs{pgfmathparse}) is local, the +driver also needs to somehow smuggle the result out of the \cs{endgroup} issued +by \refcmd{Memoize} and thereby make it into the following code (the final line +of the example, which typesets the equation). Both jobs are easy enough: the +expansion of |\def\noexpand\pgfmathresult{\pgfmathresult}| (in this case, +|\def\pgfmathresult{42.0}|) is (globally) appended both to the token register +\refcmd{mmzCCMemo}, which Memoize later writes into the cc-memo, and to the +macro underlying the \refmmz{after memoization} hook, whose contents are +executed \emph{after} closing the memoization group. + +Let us consider an alternative implementation of the same goal of memoizing the +result of a pgfmath computation, showcasing a couple of useful tricks. + +\ExampleName{pgfmathparse-embellished} +\makeexample{\examplename.pdf} +\tcbinputexample{listing only} + +For one, this ``embellished'' example reminds us that we can list the +\refmmz{driver} key among the auto-options (even if I don't really recommend +automemoizing \cs{pgfmathparse}). But even more importantly, the example shows +that the driver consist of more than a single control sequence; the only +requirement is that the given driver code will consume the memoized code. In +this example, we have developed a generic smuggling driver and applied it to +\cs{pgfmathresult} in particular --- \cs{pgfmathresult} will become the first +argument of \cs{mmzSmuggleOneDriver}, and the memoized code will become its +second argument. + +In the first version of the example, we have appended the same code to macro +\refcmd{mmzCCMemo} and to macro \refcmd{mmzAfterMemoizationExtra} --- no +surprise here, as we want the effect of memoization and utilization to be the +same. In the embellished version, we advertise another way to achieve the same +effect, a way which might be useful for complicated drivers: we simply smuggle +out the entire cc-memo. The idea works even when memoization procudes externs; +in that case, however, the driver also has to say \cs{mmzkeepexternstrue} --- +conditional \refcmd{ifmmzkeepexterns} decides whether Memoize keeps the externs +around, in memory, even after shipping them out (but they are always gone at +the start of the next memoization). + +Finally, remember that the default context expression contains the +\refmmz{padding} values. However, these really have no place in the context +expression of some purely memoized code. We have therefore emptied out the +context expression using \refmmz{clear context}. + + +\subsubsection{Multiple externs per memo} +\label{sec:memoization-multiple-externs} + +In the next example, we show how to produce multiple externs for a single piece +of memoized code. The usage case I find most appealing is breaking the typeset +material, like a table, across pages --- but of course, table-breaking is too +complicated an example, so we illustrate the idea by defining command +|\countdown|, which counts down from the given number, typesetting each number +into its own line. Clearly, if we were to externalize a call to this command +using the default memoization driver, page breaking would stop working, as the +entire countdown would be seen as a single, unbreakable box. To externalize it +properly, the chunks of the countdown that should appear on separate pages must +be externalized into separate externs, as shown below. + +\ExampleName{countdown} +\makeexample{\examplename.sty N=2} +\makeexample{\examplename.pdf} +\tcbinputexample{% + listing options app={ + basicstyle=\ttfamily\footnotesize, + }, + middle=1mm, bottom=0mm, + comment={\centering + \relaxmmzcommands + \def\mmzUsedExtern##1{% + \saveexpandmode\fullexpandarg + \StrGobbleRight{##1}{4}[\mytemp]% + \StrRight{\mytemp}{5}[\mytemp]% + \restoreexpandmode + \relaxmmzcommands + }% + \def\mmzNewExtern##1##2##3##4##5{\mmzUsedExtern{##1}} + \def\myexternname##1{extern \dots\texttt{\mytemp##1.pdf}}% + \input{\examplepath.mmz}% + \begin{tabular}{ccc} + \includeexamplepdf[extern page,title/.expand once=\myexternname{}] + {page=2,trim=1in 1in 1in 1in,scale=0.333}& + \includeexamplepdf[extern page,title/.expand once=\myexternname{-1}] + {page=3,trim=1in 1in 1in 1in,scale=0.333}& + \includeexamplepdf[extern page,title/.expand once=\myexternname{-2}] + {page=4,trim=1in 1in 1in 1in,scale=0.333}\\ + \includeexamplepdf[document page]{page=1,scale=0.333}& + \includeexamplepdf[document page]{page=5,scale=0.333}& + \includeexamplepdf[document page]{page=6,scale=0.333} + \end{tabular} + }, +} + +To achieve this, we will have to integrate the memoization driver into the very +code of |\countdown|. This approach contrasts sharply with the standard +memoization driver, which is simply wrapped around the memoized code. Let's +say we have implemented a non-memoization-aware variant of |\countdown| as a +loop which gathers the countdown lines into a vertical box, and periodically, +when this box holds all the material that will fit onto the page, places it +into the main vertical list (i.e.\ on the page).\footnote{Of course, + implementing \cs{countdown} this way would be idiotic; a sane implementation + would simply spit out the countdown lines one by one, and let \hologo{TeX} + deal with page-breaking. However, remember that we are pretending that we + are typesetting (and page-breaking) some complex material, like a table; in + such a case, the loop outlined in the main text would make perfect sense.} +To have this command support memoization, we have to externalize our box every +time we're placing it into the main vertical list. This is precisely what we +do in the definition of |\countdowntypeset| below:\footnote{We omit the + definition of the core algorithm of \cs{countdown} in the listing, because it + is mostly irrelevant for our discussion, and only show the + memoization-related code.} the final line of this macro adds the material to +the main vertical list, and the preceding lines externalize it (the two lines +inside \cs{ifmemoizingcountdown} should be familiar from the definition of the +standard memoization driver; we'll explain about the conditional below); note +that Memoize automatically deals with the fact that our box is vertical. As a +result of having our memoization driver integrated into the loop of the core +command, we can create as many externs as necessary, complete with the code in +the cc-memo for including each and every one of them on subsequent +compilations. Each extern eventually makes it into its own extern file, and +note that the filenames of the non-first externs have their sequential number +(we start counting at $0$) appended to the basename, as shown in the +example.\cprotect\footnote{The \refmmz{auto} declaration of |\countdown| adds + some relevant parameters to the context (see + section~\ref{sec:cross-referencing}). The countdown will be recompiled upon + change of either the font size (|f@size|), the text height (|\textheight|), + or the height of the material in the main vertical list collected so far + (|\pagetotal|). The |\pagetotal| parameter is especially important; + including it makes sure that the countdown will be recompiled when it is + pushed up or down the page. Also note that we want the context to record the + value of |\pagetotal| when the (automemoized) |\countdown| is encountered + (rather than at the end of memoization), so we expand it when applying the + auto-options.} + +\tcbinputexample[.sty]{listing only, after title pre={\ (version 1)}} + +Of course, the chunks of the countdown should only be externalized when the +code is actually being memoized, and not, say, when Memoize is disabled or +performing regular compilation. (Note that this is a problem that only affects +integrated drivers and not wrapped drivers such as the default driver.) The +first thought is to detect whether we're undergoing memoization using +conditional \refcmd{ifmemoizing}, which Memoize sets to true at the start of +every memoization. This conditional is used in the run conditions of advice +for \cs{ref} and \cs{label}, the idea being that they should add stuff to the +context (\cs{ref}) and the cc-memo (\cs{label}) only when undergoing +memoization. However, deploying \refcmd{ifmemoizing} in the current example +would not be exactly right. It would work well with the main document as it +is, but it would fail if |\countdown| was called from a piece of code that was +independently submitted to memoization, e.g.\ +\refcmd{mmz}|{\countdown{30}}|.\footnote{Such embedding occurs more often than + you might think. For example, \env{forest} calls \env{tikzpicture} under the + hood, and both environments are automemoized.} In that case, both the +\refcmd{mmz} driver and the |\countdown| integrated driver would get executed, +resulting in the creation (and in subsequent compilations, utilization) of four +externs: first, the |\countdown| driver would externalize each countdown chunk +separately, and then, the \refcmd{mmz} driver would externalize them, all +together, yet again. You can try this out by replacing +\cs{ifmemoizingcountdown} in \cs{countdowntypeset} by \refcmd{ifmemoizing} (and +wrapping the \cs{countdown} call in \cs{mmz}). + +The solution to the \refcmd{ifmemoizing} problem deployed in the example is to +declare a new, \cs{countdown}-specific memoization conditional, and set it to +true in \cs{countdown}'s formal driver, i.e.\ the macro set as the +\refmmz{driver} in the \refmmz{auto} declaration for \cs{countdown}. In fact, +Memoize can do most of this for you: when we write \refmmzauto{integrated + driver}|=countdown|, Memoize creates the countdown-specific memoization +conditional and declares the formal driver which sets this conditional to true; +you only have to access this conditional in your code, and you should do this +using the \hologo{LaTeX}-style conditional \refcmd{IfMemoizing}, as shown +below.\footnote{You shouldn't directly use the plain \hologo{TeX} + countdown-specific conditional created by \refmmzauto{integrated driver} --- + to prevent accidental access, Memoize doesn't actually name it + \cs{ifmemoizingcountdown} --- because this conditional is undefined when + Memoize is not loaded, i.e.\ when only package \refpkg{memoizable} is in + effect. Furthermore, \refcmd{IfMemoizing} addresses a problem faced by + integrated drivers of potentially recursive commands; we will talk about this + in section~\ref{sec:memoization-complex-single-driver}.} + +\tcbinputexample[.sty][.c2]{listing only, after title pre={\ (version 2)}, + attachment name=\examplename-integrated-driver.sty, +} + + +\subsubsection{Driver-based memoizable design} +\label{sec:memoization-complex-single-driver} + +In the previous section, we used the integrated driver approach to produce +memos including multiple externs, but the approach can be useful for one-extern +memos as well, when the extern must be integrated into the document in some +special way. We already discussed such situations in +section~\ref{sec:memoizable-design}, where we suggested to split a +``difficult'' command into the outer command and the inner command, and only +submit the inner command to automemoization. However, the vanilla flavour of +this approach had a negative impact on the user interface to automemoization. +In this section, we will deploy the memoization driver to overcome the issue. + +\ExampleName{poormansbox-driver} +\makeexample{\examplename.sty} +\makeexample{\examplename.pdf N=2} + +Let us revisit the |poormansbox| example from +section~\ref{sec:memoizable-design}. Remember that that environment produced +a potentially framed box of a certain width, surrounded by some pre- and +post-code, and that the issue was that the pre- and the post-code should not be +memoized, but rather executed at every invocation of the command, as it was +primarily intended to put some stretchable vertical space around the box. + +The document source\attachexample\ and the resulting PDF of the example are the +same as in section~\ref{sec:memoizable-design}, so we will not repeat them +here, but jump directly into a revised definition of the environment. We will +retain the core idea from the original implementation: the outer command will +execute the pre- and the post-code, and the inner command will typeset the box. +But unlike in the original implementation, we will not automemoize the inner, +internal command (this was the source of the author's discomfort) but the outer, +user-level command --- and we will equip it with a custom memoization driver. +The major idea here is to have the driver compose a cc-memo which not only +includes the extern, but also executes the outer command. + +\tcbinputexample[.sty]{listing only, float} + +In detail, the implementation (partially shown in the |.sty| listing) is as +follows. The outer command (|\poormansbox@outer|) first applies the options +(|#1|) and then wraps the pre-code (|\pmb@before|) and the post-code +(|\pmb@after|) around some arbitrary code (|#2|). During memoization or +regular compilation, the outer command is invoked through the |poormansbox| +environment, and you can see that in the definition of that environment, the +second argument to |\poormansbox@outer| is a call to the inner command +(|\poormansbox@inner|; this command takes two arguments, the options and the +environment body). During utilization, the outer command is invoked from the +cc-memo,\cprotect\footnote{As you can see, in the cc-memo the outer command is invoked + by |\csuse{poormansbox@outer}|. A straight |\poormansbox@outer| would not + work because we're in the middle of the document where |@| is not a letter, + and including a |\makeatletter| in front of it (and in a group) only works if + \refmmz{direct ccmemo input} was in effect. Under the default, indirect + cc-memo input regime, the core cc-memo is tokenized before |\makeatletter| can + take effect.} and as you can see in the cc-memo listing below, the second +argument to |\poormansbox@outer| there is a call to \refcmd{mmzIncludeExtern}. + +\begingroup +\relaxmmzcommands +\def\mmzNewCCMemo#1{% + \def\mmzNewCCMemo##1{% fetch the second cc-memo filename + \def\myccmemo{##1}% + \endinput + }% +} +\input{\examplepath.mmz.c1} +\sed{% + s/~//g; + s/\(\cmd{csuse} *{poormansbox@outer}\) *\({\nobrace*\marg\nobrace*}\)\({.*}\rbrace\)/~\1~\2~\3~/; + s/\(\marg\marg\marg\)\(\marg\marg\marg\marg\marg\)/\1\space\2/; +}{\exampledir\myccmemo} +\tcbinputlisting{ + listing only, left=1.5mm, right=1mm, + listing options app={basicstyle=\tt\small}, + listing file=\exampledir\myccmemo, + example title, title=the second poor man's box's cc-memo, +}% +\endgroup + +And how does |\poormansbox@outer| get into the cc-memo, which normally only +includes a call to \refcmd{mmzIncludeExtern}, you ask? This is the job of the +memoization driver, which is in this case integrated into the inner command. +The overall shape of the driver is the same as the shape of the standard +driver, discussed in section~\ref{sec:memoization-driver-default}: typeset the +extern material into a box, externalize this box, append the extern-inclusion +code to the cc-memo, and put the extern box into the document. It is the +cc-memo part which interests us right now: unlike the standard driver, we don't +simply append the contents of |\mmz@temptoks|, i.e.\ a +\refcmd{mmzIncludeExtern} call; we rather append a call to +|\poormansbox@outer|, which gets the \refcmd{mmzIncludeExtern} call as its +second argument (and the options as its first argument). + +The core part of the driver, which externalizes the box and appends to the +cc-memo, is embedded inside the true branch of conditional +\refcmd{IfMemoizing}|[1]{pmb}|. We already used this conditional in +section~\ref{sec:memoization-multiple-externs}, but without the optional +argument. Such usage will not work here, because it is not recursion-safe. +Unlike in the \cs{countdown} situation, one |poormansbox| environment can be +embedded in another one (and, in our example, it is). If we deployed +\refcmd{IfMemoizing}|{pmb}| in the inner command, the driver would be executed for +\emph{both} the outer and the inner instance of the environment, whereas it +should really be executed only for the outer instance. + +When used in a recursion-safe way, i.e.\ with the optional argument, +\refcmd{IfMemoizing} first tests whether the auxiliary command-specific +conditional from the previous section is true, and then proceeds to compare the +current group level (\hologo{eTeX}'s \refcmd{currentgrouplevel}) to the group +level at the start of memoization (which Memoize stored in +\refcmd{memoizinggrouplevel}). Only if these group levels match do we know +that we're working on the outer instance of the environment, and that we should +therefore execute the memoization driver. Importantly, though, the two group +levels are compared modulo the offset, given as the optional parameter to +\refcmd{IfMemoizing}: in our example, the offset is 1, because the driver is +located inside the |poormansbox| environment, which opens a group --- note that +0 zero (no offset) is not the default optional parameter; the absence of the +optional parameter indicates that the non-recursion safe method should be +used.\footnote{Even this approach is not completely bullet-proof. It will only + work when the inner instance of the command is guaranteed to occur in an + additional group, i.e.\ when our command opens up a group for any free-form + code. I will assume that situations which require externalization of a + potentially recursive command which, for some reason, cannot open the group + before processing a free-form argument, are rare enough to not warrant a + generic solution here.} + + +\FloatBarrier + + +\subsubsection{Shipout} + +Memoize is a hypocrite: when it is creating extern pages, it uses +\refcmd{primitive}\refcmd{shipout} to bypass the regular shipout routine of the +format, but it is offended if anyone else does that. + +Memoize bypasses the regular shipout because the extern pages should really not +be modified or discarded by a foreign package. But using the primitive +\refcmd{shipout} means that extern shipouts can't be detected by another +package, at all. To facilitate peaceful coexistence with a potential package +which needs to know about our extern pages, we offer public counter +\refcmd{mmzExternPages} holding the number of externs shipped out so far. And +if anyone really needs to \emph{do} something at every extern shipout, they can +always (ab)use \refmmz[show keypath]{record/record type/new extern} as a +post-extern-shipout hook. + +The other side of the story is about Memoize needing to know the ``physical'' +page numbers of its externs in the document PDF --- how else are we to extract +them? Memoize computes these page numbers by adding the values of several +counters: \refcmd{mmzRegularPages}, which holds the number of regular shipouts; +the above-mentioned \refcmd{mmzExternPages}, which holds the number of extern +shipouts; and \refcmd{mmzExtraPages}, which holds the number of other shipouts. +The latter counter should be advanced by a package which, like Memoize, +bypasses the regular shipout routine. + +\hologo{LaTeX} and \hologo{ConTeXt} kindly provide the number of regular +shipouts as publicly a accessible counter, so we define +\refcmd{mmzRegularPages} as synonymous with their +\refcmd{ReadonlyShipoutCounter} and \refcmd{realpageno}. In \hologo{plainTeX}, we +have to hijack the \refcmd{shipout} control sequence and count regular shipouts +ourselves; as we have to hijack it while it still refers to the +\refcmd{shipout} primitive, this format provides another reason for preferring +Memoize to be loaded early. + + +\subsection{Automemoization} +\label{sec:tut:automemoization-details} + +Automemoization is a mechanism that automatically memoizes the result of the +compilation of certain commands and environments. Writing Memoize, I went to +great lengths to make it flexible, yet easy to use. This resulted in +automemoization deploying two specifically developed auxiliary packages: +package Advice, which provides a generic framework for extending the +functionality of selected commands and environments, and package CollArgs, +which provides a command for collection of the arguments conforming to the +given (slightly extended) \pkg{xparse} argument specification. + +This section lists the considerations which went into designing the system, +followed by short tutorials on both auxiliary packages, which include several +examples of how Memoize uses the underlying advising framework. + +\paragraph{(De)activation} +Ideally, all commands and environments where memoization makes sense would +support Memoize (or Memoize would support them) and nothing would ever go +wrong. In this dream world, memoization would be completely transparent to the +author. However, things will go wrong, so at the very least, we need to +offer the author a \emph{simple} way to \emph{selectively} switch automemoization +on and off. This is achieved by keys \refmmz{activate} and +\refmmz{deactivate}. + +\paragraph{Submission} +Of course, there will be commands without official support by either Memoize or +the package which defines them; clearly, at the moment when I write this, all +commands but \cs{tikz}, \env{tikzpicture} and \env{forest} are such. Or, the +author might want to automemoize his or her own command. Ideally, submitting a +new command to automemoization would be as simple as +|memoize=|{\meta{command}}, and for environments, this is in fact achievable, +although the actual interface is +\refmmz{auto}|=|\braces{\meta{environment}}\braces{\refmmzauto{memoize}}. But +simply submitting the name cannot work for commands, because commands are where +we encounter the major \hologo{TeX}nical problem with automemoization: we need +to somehow collect the arguments of the command --- without executing the +command itself. + +\paragraph{Argument collection using CollArgs} +\hologo{TeX} being \hologo{TeX}, automatically determining the scope of a +command in general is just plain impossible. Note that inspecting the +|\meaning| is not enough in general, because the ``real'' and the formal +arguments of a command can, and quite often do, differ wildly. The author (or the +package writer) will need to tell Memoize about the argument structure of the +command. And as there is already a nice and general argument specification on +the market --- I'm obviously referring to the argument specification of package +\pkg{xparse}, which was recently even integrated into the core \hologo{LaTeX} +--- why not use that? Memoize comes with an auxiliary package CollArgs, which +(given the slightly extended \pkg{xparse}-style argument specification) +collects the arguments of a command into a single entity. All the user needs +to write to enable automemoization for a command is thus +\refmmz{auto}|=|\meta{command}\braces{\refmmzauto{memoize}, + \refmmzauto{args}|=|\braces{\meta{argument specification}}}. Even simpler, +when it comes to commands defined by \pkg{xparse}'s \refcmd{NewDocumentCommand} +or friends, writing \refmmz{auto}|=|\meta{command}\braces{\refmmzauto{memoize}} +will suffice, as the argument specification of these commands can be retrieved +by \refcmd{GetDocumentCommandArgSpec}. + +\paragraph{Weird commands} +Not every argument structure can be described using \pkg{xparse}'s argument +specification, a case in point being \refcmd{tikz} with its totally +idiosyncratic syntax --- and if Memoize won't support \cs{tikz}, why have it at +all? The interface to automemoization must be flexible enough to cover even +the craziest commands, and this is why Memoize allows for arbitrary argument +collectors. These are defined by the advanced user or package writer and then +declared to be used for parsing the argument structure of a command by writing +\code{\refmmz{auto}=\marg{command}\bracestt{...,\refmmzauto{collector}=\meta{argument + collector}}}. + +\paragraph{Over and above automemoization: handlers} +The framework facilitating automemoization must cover more than just that. For +one, it sometimes makes sense to automatically \emph{prevent} memoization +during the execution of certain commands (as in the \refmmzauto{nomemoize} +example in section~\ref{sec:tut:redefinitions}). It follows that the action +performed to an invocation of a command should not be fixed. In the advising +framework, implemented by the auxiliary package Advice, we assign each +advised command a handler --- a command which does the real work of +memoizing or whatever. Crucially, the handler and the collector are +independent of each other, allowing a single memoization handler to handle +commands with both standard and non-standard argument structure, and allowing a +single collector to serve either the memoization or the no-memoization handler. + +\paragraph{Over and above automemoization: the outer and the inner handler} +Second, unlike the memoization handler set by \refmmzauto{memoize}, not all +handlers work with the entire argument list of the advised command. Some +handlers don't care about the arguments of the advised command at all: +\refmmzauto{abort} simply aborts memoization whenever the advised command is +executed. Other handlers are only intended to advise a single command or a +small family of commands, and need to inspect specific arguments of the advised +command: for example, \refmmzauto{ref} needs to append the internal +cross-reference macro to the context, and it of course constructs the name of +this macro from the reference key. For all such handlers, it would be plain +wasteful to first collect the arguments and then tear them apart to inspect +them (or not). The advising framework therefore recognizes two kinds of +handlers. The abortion and the cross-reference handler are examples of an +\emph{outer} handler, which is simply placed in front of the arguments of the +handled command as they are, without invoking the collector. The memoization +handler, on the other hand, is an example of an \emph{inner} handler, which +receives the entire argument list from the collector (as a single argument) --- +or more precisely, even \refmmzauto{memoize} sets up an outer handler, but this +outer handler doesn't do much more than invoke the collector, which in turn +invokes the inner handler. + +\paragraph*{Run conditions} are another, if minor, lego piece of the +advising framework. Using key \refmmzauto{run conditions}, the user can set the +conditions under which the (outer) handler is executed; for example, +cross-reference commands are only advised when memoization is underway. And +the same goes for \refcmd{label}, and for the \refmmzauto{replicate}d +\refcmd{index}, and for \refcmd{savepos}, upon which memoization must be +aborted. The bottom-line is that run conditions repeat across handlers, so +it makes sense to separate them out as an independent component of the +framework, with the added bonus that the system can make sure that an +invocation of a advised command which does not satisfy the run conditions +will incur as litte overhead as possible. + +\paragraph{Bailout handler} +An automemoized command applies the next-options (set by \refcmd{mmznext}), but +what happens when the run conditions are not satisfied? If nothing happened, +the existing next-options might apply to the next instance of +(auto)memoization, which would not be what the author intended. This is why +Advice introduces the bailout handler, a piece of code executed before the +original command when the run conditions are not met. Obviously, the bailout +handler for memoization clears out the next-options (and does not process +them). + +\paragraph{The structure of advice} +Together, the components mentioned above form a piece of \emph{advice}: + +\begin{center} + \begin{forest} + /tikz/edge node/.style={midway, font=\scriptsize, yshift=0.5ex}, + for tree={l sep=5ex, % manual, to avoid a page break + child anchor=north, s sep+=2em}, + [activated? + [\refmmzauto{run conditions}?, + edge=dashed, edge label={node[edge node, left]{yes}} + [\refmmzauto{outer handler}\meta{args}, + edge=->, edge label={node[edge node, left]{yes}}, + [default:, + edge=dashed, + [\refmmzauto{collector}\meta{args}, edge=->, + [\refmmzauto{inner handler} + \textcolor{red}{\bracestt{\textcolor{black}{\meta{args}}}}, + edge=-> + ] + ] + ] + [other:\\whatever\rlap\footnotemark, + align=center, edge=dashed] + ] + [\refmmzauto{bailout handler}, + edge=->, edge label={node[edge node, right]{no}}, + [\meta{original command}\meta{args}, edge=->] + ] + ] + [\meta{original command}\meta{args}, + edge=dashed, edge label={node[edge node, right]{no}}, + ] + ] + \end{forest}% + \footnotetext{The handler may do whatever as long as it consumes all and + only the arguments of the original command.} +\end{center} + + + +\paragraph{Deferred activation} +Memoize needs to be loaded early, but activation should take place late, so +that it can surely override the submitted commands; a case in point, +\pkg{hyperref} redefines \refcmd{ref} very late. To address the issue, the +advising framework implements the deferred \refmmz{activation} regime, under +which (de)activation commands are not executed but collected in a special +style, \refmmz{activate deferred}. Memoize deploys the deferred activation +regime throughout the preamble, and executes \refmmz{activate deferred} at the +latest possible \docref{hook:begindocument} hook; as a bonus, it also offers +the author a way to avoid automatic activation completely by invoking key +\refmmz{manual}. + + +\paragraph{Install anywhere} +Once all this machinery is developed, why not offer it to others as well? + +Once I decided to offer Advice (at the time, still called Auto) as a standalone +package (and I freely admit that the framework got much cleaner once I +separated its code out of Memoize) it became immediately clear that if it is +to serve as a generic framework, it should be possible for multiple packages to +use it without interfering with each other. The package thus allows any number +of installations into different namespaces, each namespace a \pkg{pgfkeys} +keypath. The installation is a breeze: +\cs{pgfkeys}\bracestt{\meta{namespace}/\refkey{/handlers/.install advice}}. + + +\subsubsection{Using package Advice} +\label{sec:advice} + +In this section, we will provide some examples of handler declarations, mainly +based on how Memoize deploys the advising framework. + +\paragraph{\refmmzauto[show keypath]{memoize}} + +In section~\ref{sec:tut:automemoization}, the author was instructed to submit a +command to automemoization by writing +\code{\refmmz{auto}=\meta{command}\bracestt{\refmmzauto{memoize},...}}. The +auto-key \refmmzauto{memoize} is a style (defined by Memoize rather than +Advice) which sets the appropriate components of the automemoization advice. +Residing in keypath \refkeypath{/mmz/auto}, it is effectively defined as +follows: + +\begin{tcblisting}{listing only} +\mmzset{ + auto/memoize/.style={ + run if memoization is possible, + bailout handler=\mmz@auto@bailout, + outer handler=\mmz@auto@outer, + inner handler=\mmz@auto@memoize + } +} +\end{tcblisting} + +The heart of this advice is its inner handler, which actually triggers +memoization by executing \refcmd{Memoize}. Remember that the first argument of +\refcmd{Memoize} is the code which the md5sum is computed off of. This +argument must therefore be identical to the author's invocation of the +automemoized command or environment. Given what Advice offers, this is easy to +construct: \refcmd{AdviceReplaced} holds the code replaced by the advice, and +the \meta{arguments} of the automemoized command are waiting for us in |#1|. +The second argument of \refcmd{Memoize} will be similar, but as this is the +code which will get compiled, we have to execute the original definition of the +command, followed by the (unbraced!) \meta{arguments} as |#1|; this is a job +for \refcmd{AdviceOriginal}. (Note that \emph{executing} +\refcmd{AdviceReplaced} would run the auto-handler again, resulting in an +infinite loop! Or at least a pile of errors.) + +However, the overly simplistic approach shown below won't necessarily work. +The issue is that the arguments of \refcmd{Memoize} contain +\refcmd{AdviceReplaced} and \refcmd{AdviceOriginal} themselves, instead of their +contents, i.e.\ (first) expansions. + +\begin{tcblisting}{listing only, bad} +\long\def\mmz@auto@memoize#1{% + \Memoize{\AdviceReplaced#1}{\AdviceOriginal#1}% +} +\end{tcblisting} + +Regarding the first argument, the problem is that the code md5sum will be +computed off of the token list \refcmd{AdviceReplaced}\meta{arguments} --- +exactly as you see it.\footnote{If you inspected a c-memo, you would find + \refcmd{AdviceReplaced}\meta{arguments} in the \refcmd{mmzSource} section.} +This implies that two commands sharing exactly the same \meta{arguments} will +receive the same (c-)memo. For example, if you automemoized first +|\textit{foo}| and then |\textbf{foo}|, both would come out as a bold ``foo'' +upon utilization. + +The second argument illustrates a general issue about the lifespan of +\refcmd{AdviceOriginal} and other |\Advice...| commands.\footnote{The list of + all commands available only within the handler can be found in the + documentation of key \refmmzauto{outer handler} in + section~\ref{sec:ref:advice}.} By executing \refcmd{Memoize}, we leave the +advice and thereby cannot be sure that when expanded, \refcmd{AdviceOriginal} +will mean what it means at the moment. In general, another piece of advice might be +triggered until its expansion, or the group might be closed, etc. For example, +the author may have issued \refcmd{mmznext}\bracestt{\refmmz{at begin + memoization}=\cs{label}\marg{key}}, and as the pre-memoization code is +executed before the memoization driver, the \cs{label}, which is submitted to +Advice so that any \cs{label}s inside the memoized code ``just work'', would +execute another piece of advice, redefining \refcmd{AdviceOriginal} and friends. +Effectively, you'd end up memoizing an invocation of the \cs{label} command. + +The bottom line is that while the code following the above template +\emph{might} sometimes work, Advice offers no guarantees that it will, so I +advise against using it. The actual definition of the memoization inner +handler is shown below. In this definition, we expand \refcmd{AdviceReplaced} +and \refcmd{AdviceOriginal} --- exactly once! --- into the respective arguments +of \refcmd{Memoize}; of course, as the entire invocation of \refcmd{Memoize} is +expanded, we have to guard against expanding the collected arguments (|#1|) and +\refcmd{Memoize} itself.\footnote{As the final touch, the handler also contains + \refcmd{ignorespaces} after the invocation of \refcmd{Memoize}, if this was + requested using \refmmz{ignore spaces}. Note that this could not be done + without pre-expanding the \cs{ifmmz@ignorespaces} conditional, as + \refcmd{Memoize} closes the group in which the auto- and the next-options are + applied.} The result of the expansion is shown under the code: the first and +the second line assume we are automemoizing command |\foo| and environment +|bar|, respectively. Note that \refcmd{AdviceOriginal} expands into an +invocation of \refcmd{AdviceGetOriginal}, a command which may be safely used +outside the advice; the first argument of this command is the auto-namespace +(in our case, \refkeypath{/mmz}), and the second argument is the advised +command. For a \hologo{LaTeX} environment, the advised command is actually +\refcmd{begin}, and this is why the call of \refcmd{AdviceGetOriginal} is of +course followed by the environment name. + +\makeexcerpt{_auto-memoize-inner} +\tcbinputexample[.tex][.excerpt]{% + listing and comment, one file, no attachment, + title={The implementation of the \refmmzauto{inner handler} + for automemoization}, + comment={% + $\rightarrow$ \refcmd{Memoize}\braces{\cs{foo}\Arg1}% + \braces{\refcmd{AdviceGetOriginal}\bracestt{/mmz}\bracestt{\cs{foo}}\Arg1}\\ + $\rightarrow$ \refcmd{Memoize}\braces{\cs{begin}\bracestt{bar}\Arg1}% + \braces{\refcmd{AdviceGetOriginal}% + \bracestt{/mmz}\bracestt{\cs{begin}}\bracestt{bar}\Arg1} + } +} + +Let us now move backwards in time and look at the outer handler installed by +\refmmzauto{memoize}. It is very simple, but performs an important function of +applying the auto- and the next-options (in this order), which also +necessitates opening a group (closed by \refcmd{Memoize}). The final line +invokes the argument collector, which then calls the inner handler; remember +that the invocation of \refcmd{AdviceCollector} is the sole function of the +default outer handler. + +\makeexcerpt{_auto-memoize-outer} +\tcbinputexample[.tex][.excerpt]{% + listing only, one file, no attachment, + title={The implementation of the \refmmzauto{outer handler} + for automemoization}, +} + +Moving even further back in time, we arrive at the run conditions. The +\refmmzauto{memoize} style invokes \refmmzauto{run if memoization is possible}, +defined as \code{run conditions=\cs{mmz@auto@rc@if@memoization@possible}}, with +the installed macro as shown below. Indeed, memoization only makes when +Memoize is \refmmz{enable}d (which we test using \refcmd{ifmemoize}), but we're +not already ``inside \refcmd{Memoize}'' (which we test using +\refcmd{ifinmemoize}). The latter condition is true when we're either +memoizing or regularly compiling some code submitted to memoization (see the +diagram in section~\ref{sec:Memoize}). Note that it is not necessary to invoke +\refcmd{AdviceRunfalse} in branches where the run conditions are not satisfied. + +\makeexcerpt{_auto-run-if-memoization-is-possible} +\tcbinputexample[.tex][.excerpt]{% + listing only, one file, no attachment, + title={The implementation of + \refmmzauto{run if memoization is possible}}, +} + +While it is clear that double memoization is a no-no, why should we avoid +memoizing inside a regular compilation? Imagine that Memoize decides not to +memoize a Forest tree, perhaps because \refmmz{readonly} is in effect. Under +the hood, Forest creates many \env{tikzpicture}s. Should all of them be +(auto)memoized now? Certainly not. + +Finally, what happens when the run conditions are not met? Not much, but +something important nevertheless: by consuming the next-options, the +\refmmzauto{bailout handler} makes sure they will not erroneously apply to the +next instance of (auto)memoization. + +\makeexcerpt{_auto-memoize-bailout} +\tcbinputexample[.tex][.excerpt]{% + listing only, one file, no attachment, + title={The implementation of the \refmmzauto{bailout handler} + for automemoization}, +} + +The only component of the automemoization advice not determined by style +\refmmzauto{memoize} is the argument collector, which allows the user to submit +a command with a weird argument structure to automemoization simply by setting +key \refmmzauto{collector} in addition to executing \refmmzauto{memoize}. For +example, Memoize submits \refcmd{tikz} to automemoization by loading +\reffile{advice-tikz.code.tex}, which contains Advice's definition of the +\cs{tikz} collector \refcmd{AdviceCollectTikZArguments}, and issuing the +following declaration. + +\makeexcerpt{_auto-tikz-collector} +\tcbinputexample[.tex][.excerpt]{% + listing only, one file, no attachment, + title={Declaring automemoization of command \cs{tikz}}, +} + +\paragraph{\refmmzauto[show keypath]{ref}} + +The cross-reference advice presents an example of an outer handler radically +different from the default outer handler. This outer handler does not invoke +the collector at all. As shown below, it grabs the argument of \refcmd{ref} (or +whichever cross-referencing command) on its own --- remember that the outer +handler receives the arguments of the handled command ``as they are,'' i.e.\ +uncollected. It then asks \refcmd{mmzNoRef} to do the real job of getting the +reference key into the context, and finally executes the original \cs{ref}. + +\ExampleName{_auto-ref} +\makeexample{\examplename.tex.c1} +\tcbinputexample{% + listing only, no attachment, + title={\hypercolor{link}{white}A simplified\footnotemark{} definition + of \refmmzauto{ref}}, + % This only works if there is a single footnote in the memoized code. + /mmz/context/.expanded={footnote=\numexpr\thefootnote-1}, +}\footnotetext{The real outer handler allows for arbitrary optional arguments of + the cross-referencing command, and shares code with \refmmzauto{force + ref}.} + +The run conditions of this style are agonizingly simple: \refmmzauto{run if + memoizing} sets \refmmzauto{run conditions} to a macro defined as +\refcmd{ifmemoizing}\hyp\refcmd{AdviceRuntrue}\hyp\cs{fi}. + +\paragraph{\refmmzauto[show keypath]{abort}} + +The advice for aborting memoization is very simple --- it merely executes +\refcmd{mmzAbort} --- but also very sneaky. Here, the \refmmzauto{run + conditions} do the real work of aborting memoization, while the ``real,'' +i.e.\ outer handler, never even gets executed; note the absence of +\refcmd{AdviceRuntrue}, which implies \refcmd{AdviceRunfalse}, which triggers +the execution of the original command after the run conditions are ``checked.'' + +\makeexcerpt{_auto-abort} +\tcbinputexample[.tex][.excerpt]{% + listing only, one file, no attachment, + title={The definition of \refmmzauto{abort}}, +} + +The point here is that executing \refcmd{mmzAbort} (itself a single-liner +setting an internal conditional) is cheaper than testing for the real run +conditions (\refmmzauto{run if memoizing}) and aborting only if they are +satisfied. Of course, the trick only works because (i) the advice doesn't +need to inspect any arguments of advised command, and because (ii) setting the +internal abortion conditional outside memoization does no damage. + +\paragraph{Advice in chains} + +A command may be submitted to several instances of the advising framework, +i.e.\ instances installed under different keypaths. In the example below, we +submit |\foo| both to the instance of Advice installed in keypath |/one| and to +the one installed in keypath |/two|. Under |/one|, the result of |\foo{...}| +will be boxed (|\fboxWrap|); under |/two|, in will be parenthesized +(|\parenWrap|). The order in which this happens depends on the order in which +|\foo| was activated under different keypaths. If we first activate it under +|/one| with the boxing effect and then under two with the parenthesizing +effect, the box will appear within parenthesis; if we reverse the activation +order, the parenthesis will appear inside the box. + +\ExampleName{chained-advice} +\makeexample{\examplename.tex.c1 N=2} +\tcbinputexample{comment=\input{\examplepath.tex.c2}} + +First of all, looking at the code above, you have probably noticed the absence +of key \refmmz{auto}. This is because by default, \refkey{/handlers/.install + advice} defines the \emph{setup key} to be |advice| --- Memoize overrides +this default by installing the framework with \refkey{/handlers/.install + advice}|=|\bracestt{\refkey{/advice/install/setup key}=auto, ...}. + +Next, |advice'| is a variant of |advice| which prevents automatic activation +upon setup (and the same holds for |auto'| vs.\ |auto| in Memoize). We have +used the bar variant above to make it clear that it is the order of activation, +rather than declaration by |advice|\slash \refmmz{auto}, which matters in +determining which handler is applied first. + +Finally, note that the deactivation order must be the reverse of the activation +order. So if we activate |\foo| first in |/one| and then in |/two|, we should +deactivate it in |/two| first and in |/one| next, otherwise Advice will +complain. + + +\paragraph{A simple collector} + +Let us implement a collector for a command which accepts one (standard +\hologo{LaTeX}) optional argument and one mandatory argument; in \pkg{xparse} +terms, a command with argument specification |om|. + +Using \cs{NewDocumentCommand}, such a collector is very easy to implement. We +simply define a command with signature |om| and distinguish two possibilities +regarding the presence of the optional argument, which we test using +\cs{IfValueTF}. If the true branch, we pass a \emph{braced} |[#1]{#2}| to the +inner handler, which we invoke by \refcmd{AdviceInnerHandler}; in the false +branch, we omit the optional argument, passing it an (additionally) braced +|{#2}|. + +\ExampleName{om-collector-NewDocumentCommand} +\makeexample{\examplename.tex.c1} +\tcbinputexample{listing only} + +Defining a functionally equivalent collector using \cs{newcommand} would be a +bit more involved, as \hologo{LaTeX2e} does not offer a standardized way to +test for the \emph{presence} of the optional argument. Consider the following +collector, whose optional argument has the same default value as the advised +command. Is it functionally equivalent to the one above? + +\ExampleName{om-collector-newcommand} +\makeexample{\examplename.tex.c1} +\tcbinputexample{listing only} + +While there will be no visual difference, there is a difference under the hood. +If you compile both documents, you will see that the first one creates three +memos\slash externs, while the second one only creates two: |\foo{...}| does +not have its own memo anymore, but creates and uses the same memo as +|\foo[green]{...}|. + +While the second version might sometimes be preferred, perhaps even in the +context of memoization, the initial collector, which deploys command +\refcmd{CollectArguments}, behaves like the \cs{NewDocumentCommand}-defined +collector above,\footnote{In fact, there is a slight difference after all. + While the above-defined collector won't distinguish between the single-token + mandatory argument given with or without braces, \refcmd{CollectArguments} + will again faithfully replicate the original argument tokens.} as it attempts +to perfectly replicate the command invocation. Furthermore, this behaviour +makes it unnecessary for the author to provide the default values of optional +arguments (and even allows them to replace |O{default}| in the argument +specification by \docref{xparse:o}). + +We now turn to the package CollArgs, which implements the actual argument +collection; we'll revisit the initial collector of Advice at the end of the +following subsection. + + + +\subsubsection{Using package CollArgs} +\label{sec:collargs} + +Automemoization is implemented on top of the framework offered by package +Advice, and that package in turn couldn't really work as intended without +package CollArgs. A regular user of Memoize shouldn't need to know anything +about CollArgs, but a package writer wanting to support Memoize might have to. + +The package provides two public commands, \refcmd{CollectArguments} and +\refcmd{CollectArgumentsRaw}; we'll focus on the former first. +\refcmd{CollectArguments} takes three arguments: optional \meta{options} in the +form of a \pkg{pgfkeys} keylist; a mandatory \meta{argument specification} in a +(slightly extended) \pkg{xparse} format; and the \meta{next-code}: +\begin{center} + \refcmd{CollectArguments}\oarg{options}\marg{argument specification}\marg{next-code}% + \textcolor{gray}{\meta{tokens}} +\end{center} +Following the three formal arguments of \refcmd{CollectArguments} are some +\meta{tokens} --- the rest of the document, really --- and the job of +\refcmd{CollectArguments} is to figure out the extent to which these +\meta{tokens} conform to the given \meta{argument specification}. In other +words, \refcmd{CollectArguments} will consume as many of the \meta{tokens} as a +\meta{command} defined by \refcmd{NewDocumentCommand}\meta{command}\marg{argument + specification}\bracestt{...} would. Once these \meta{argument tokens} are +collected, \refcmd{CollectArguments} executes the \meta{next-code} with the +\meta{argument tokens} given as a single, braced argument (clearly, the +\meta{rest} of the \meta{tokens}, i.e.\ the non-consumed tokens, will follow): +\begin{center} + \meta{next-code}\marg{argument tokens}\textcolor{gray}{\meta{rest}} +\end{center} + +In the example below, we define macro |\PrintAndDo|, which takes two arguments, +a command and the collected arguments of that command, prints out which command +we're about to execute and with what arguments, and then executes that command +with those arguments --- |#1#2| at the end of the definition. Note that |#2| +immediately following |#1| is not braced, so +|\PrintAndDo\makebox{[5em][r]{text}}| executes |\makebox[5em][r]{text}|. + +{\tolerance 1000 Executing |\PrintAndDo\makebox{[5em][r]{text}}| directly would + thus yield the first line of the result below --- and in fact, this is + precisely what gets executed to yield that line, but in a roundabout fashion. + Given the argument specification |oom| (two optional arguments followed by a + mandatory argument), \refcmd{CollectArguments} figures out how many tokens + following its formal arguments conform to this argument specification --- + below, these would be |[5em][r]{text}| following + \refcmd{CollectArguments}\hyp|{oom}{\PrintAndDo\makebox}|--- and puts them, + braced, behind its \meta{next-code} argument, |\PrintAndDo\makebox|, yielding + |\PrintAndDo|\hyp|\makebox{[5em][r]{text}}|.\par} + +\ExampleName{collargs-makebox} +\makeexample{\examplename.tex.c1} +\tcbinputexample{listing and compile} + +Seeing the arguments of |\makebox| without the immediately preceding |\makebox| +might seem strange, but remember that \refcmd{CollectArguments} is about the +arguments of a command, not about the command's control sequence. It doesn't +know or care which command the argument tokens ``belong'' to, as long as they +conform to the given specification. In the example above, it is only in |#1#2| +of |\PrintAndDo| that |\makebox| is ``reunited'' with its arguments, but note +that the reunion is far from obligatory. + +CollArgs supports all the argument types (and modifiers) that \pkg{xparse} +does, including the environment type \docref{xparse:b}, as exemplified below. +Again, the code below might seem strange, as it features an |\end{minipage}| +without the matching |\begin{minipage}|, but the logic is similar as for + commands: just as \refcmd{CollectArguments} occurs in front of the command + arguments, without the command itself, so it occurs in front of the + environment body, without the opening of that body. However, while + \refcmd{CollectArguments} never needs to know the command name, we need to + inform it of the environment name, so that it can find the end of the + environment. This can be achieved as shown below, using key + \refcollargs{environment} in the optional argument of the command, or by our + extension to the \pkg{xparse} argument specification, where the environment + argument type \docref{xparse:b} may be followed by a braced environment name. + In the example below, we could therefore also invoke argument collection by + \refcmd{CollectArguments}\braces + {\docref{xparse:+}\docref{xparse:b}\braces{\env{minipage}}} (we have preceded + \docref{xparse:b} with a \docref{xparse:+} to allow for an environment body + containing paragraph tokens).\footnote{CollArgs automatically adapts to the + format, i.e.\ it knows that environments are tagged by \cs{}\meta{name} and + \cs{end}\meta{name} in \hologo{plainTeX} and by \cs{start}\meta{name} and + \cs{stop}\meta{name} in \hologo{ConTeXt}.} + +\ExampleName{collargs-minipage} +\makeexample{\examplename.tex.c1} +\tcbinputexample{comment=\input{\examplepath.tex.c1}} + +You might wonder why didn't we provide \refcmd{CollectArguments} in the +previous example with argument specification |omb| --- after all, the +\env{minipage} environment takes an optional and a mandatory argument. While that +would work, and produce the same result,\footnote{Unless argument processing + was in effect; see section~\ref{sec:ref:collargs} for details.} note that +\refcmd{CollectArguments} is only interested in finding the scope of the +arguments, and grabbing everything until |\end{minipage}| is the same as first +grabbing the optional argument, maybe, then the mandatory argument, and finally +the argument body. + +\refcmd{CollectArguments} not only supports \pkg{xparse}'s verbatim argument +type \docref{xparse:v}, it can grab an argument of \emph{any} type in the +verbatim mode, triggered by option \refcollargs{verbatim}.\footnote{We refer to + the verbatim mode triggered by \refcollargs{verbatim} as the full verbatim + mode, where all characters are of category ``other''. There is also the + partial verbatim mode, triggered by \refcollargs{verb}, where braces retain + their normal category codes.} We illustrate this key below, where we also use +option \refcollargs{tags}, which makes CollArgs automatically surround the +grabbed environment body with the begin tag \refcmd{begin}\marg{environment + name} and the end tag \cs{end}\marg{environment name}, and use +\refcmd{scantokens} to execute the grabbed environment. Consult +section~\ref{sec:ref:collargs} for the full reference on the verbatim mode and +its limitations. + +% A harmless warning: +% Missing character: There is no ^M (U+000D) in font [lmmono10-regular]:! +% because \texttt in the example is fed a (verbatim) carriage return +\ExampleName{collargs-verbatim} +\makeexample{\examplename.tex.c1} +\tcbinputexample{listing and compile} + +Finally, CollArgs extends the \pkg{xparse} specification by modifier +\docref{xparse:amp}, which allows the user to specify options which apply only +to the following argument, as opposed to the options given as the optional +argument of \refcmd{CollectArguments}, which apply to all the arguments. A +third way to invoke the environment body collection in the above example is +thus \refcmd{CollectArguments}% +\bracestt{\docref{xparse:amp}\bracestt{\refcollargs{environment}=minipage}+b}. + +Both the single-argument and the common options can be given not only as +\pkg{pgfkeys} keys, but also in the raw, ``programmer's interface'' format. +Every option key has a corresponding macro; for example, key +\refcollargs{environment} is matched by macro \refcmd{collargsEnvironment}. +The macros are listed alongside their corresponding keys in the reference +section~\ref{sec:ref:collargs}; here, we merely learn how to use them. + +To use raw options for a single argument, double the ampersand in the argument +specification. Therefore, the fourth way to specify the environment name is +\code{\docref{xparse:amp}\docref{xparse:amp}\bracestt{% + \refcmd{collargsEnvironment}\bracestt{minipage}}\docref{xparse:+}\docref{xparse:b}}. + +To set the raw options for all arguments, use \refcmd{CollectArgumentsRaw}, the +second public command of the package. This command is exactly like +\refcmd{CollectArguments}, excepts that it expects the options in the raw +format and as a \emph{mandatory} argument: + +\begin{center} + \refcmd{CollectArgumentsRaw}\marg{raw options}\marg{argument specification}% + \marg{next-code}\textcolor{gray}{\meta{tokens}} +\end{center} + +This leads us to the fifth way to set the environment name (an overkill, I +know): \refcmd{CollectArgumentsRaw}\hyp +\bracestt{\refcmd{collargsEnvironment}\bracestt{minipage}}\bracestt{+b}\marg{next-code}. +Furthermore, you can use a mixture of raw and key--value options: the raw +option commands include \refcmd{collargsSet}, which applies the given option +keylist. The idea here (incarnated by both Auto and Memoize) is that the +package will provide CollArgs with the raw options, for speed, while the +author can supplement them in the friendly keylist format --- and this leads +us to the sixth, and thankfully final way to set the environment name: +\refcmd{CollectArgumentsRaw}\bracestt{\refcmd{collargsSet}% + \bracestt{\refcollargs{environment}=minipage}}\bracestt{+b}\marg{next-code}. + + +\paragraph{The initial collector} + +As the final example, let us study Advice's initial collector; this is a macro +which is used as the collector when key \refmmzauto{collector} is not given. +This macro is not really \refcmd{CollectArguments}, as we sometimes state to +simplify matters, but a macro which acts as the ``bridge'' between Advice and +CollArgs, by compiling an invocation of \refcmd{CollectArgumentsRaw} from the +given advice setup, and executing it. + +The bridge macro is shown below in its full glory, but it is really less +complicated than it might appear at first sight. In line~2, we use +\refcmd{AdviceIfArgs} to see whether the argument structure of the handled +command was given by the user. If it wasn't, we assume that the handled +command was defined using \cs{NewDocumentCommand} or similar, and use +\refcmd{GetDocumentCommandArgSpec} to retrieve it (line~3; note that +\refcmd{AdviceName} holds the handled control sequence) and store it into +\refcmd{AdviceArgs} (line~4), which also receives the argument specification +when given by the user via key \refmmzauto{args}. + +\makeexcerpt{_advice-CollectArgumentsRaw}(../../advice.edtx) +\tcbinputexample[.tex][.excerpt]{% + listing only, one file, no attachment, + listing options app={numbers=left, numberstyle=\tiny, numbersep=0.5em}, + title={The definition of the initial collector}, +} + +Lines~6--17 are somewhat of an expansion mess, because we have to construct the +invocation of the CollArgs' collector from the advice setup stored in various +macros. But once we think away all the (non-)expansion commands, we're left +with \refcmd{CollectArgumentsRaw} plus the following three arguments: +\begin{enumerate} +\item The raw options (lines 8--11): + \begin{enumerate} + \item In line 8, the advised command's control sequence is designated as the + \refcollargs{caller}. The effect is that if the given arguments don't + conform to the specification, the error thrown seems to come from the + advised command rather than some internal CollArgs macro. The author will + be grateful for this little detail. + \item In line 9, we add any \refmmzauto{raw collector options} set by Advice + (plus the package deploying Advice, like Memoize); user-given options are of + course possible, but not really expected here, because: + \item In lines 10--11, we add the user-given \refmmzauto{collector options}, + if there are any, embedded under \refcmd{collargsSet}. + \end{enumerate} +\item The argument specification (line 14). +\item The \refmmzauto{inner handler} (line 15). +\end{enumerate} + + + +\section{Reference} +\label{sec:reference} + +In this section, the extra information about keys, offered at the right of a +key in parenthesis, may contain the initial value of a key, and also a default +value of a key. In this context, the terms ``initial'' and ``default'' have +the meaning employed by the \pkg{pgfkeys} utility. Initial value refers to the +value that is set by the package. More often, we would call this the default +or the package-default value, but in the \pkg{pgfkeys} parlance, the default value +refers to the value that is passed to the key in the absence of the argument. +Honestly, I only kept to this convention in the reference section; elsewhere, +I often say ``default'' or ``package-default'' and mean the initial value. + +Another convention I kept to in this section is the color-coding of the keys +and commands. Green background indicates a basic key or command, which any +user might want to know about. Red background indicates other, more or less +advanced keys and commands. + + +\subsection{Loading} +\label{sec:ref:loading} +\paragraph{\hologo{LaTeX}} + +Load Memoize by \cs{usepackage}\braces{\docaux{package}{memoize}} or +\cs{usepackage}\oarg{options}\bracestt{memoize}. The latter form functions +almost identically to the former followed by +\refcmd{mmzset}\bracestt{\meta{options}}, with two exceptions. + +First, the \meta{options} as package options may not contain spaces. This is a +constraint imposed by \hologo{LaTeX} itself. To avoid it for a particular key, +define a spaceless variant of the key in \reffile{memoize.cfg}. For example, +to use \refmmz{memo dir} as a package option, put +\refcmd{mmzset}|{memodir/.style={|\refmmz{memo dir}|={#1}}}| into that file. + +Second, key \refmmz{extract} only make senses as a package option, or within +\reffile{memoize.cfg}. Internal extern extraction can only be performed before +the output PDF is opened, and to maximize chances of that, Memoize is designed +to extract as soon as it can: while it is being loaded. Consequently, changing +the extraction method in the document preamble has no effect. + +The necessity of performing extraction before the output PDF is opened is also +why Memoize prefers to be loaded early with respect to other packages. In +particular, it must be loaded before \PGF library |fadings| (see +section~\ref{sec:fadings-problem}) and before the \pkg{beamer} class (see +section~\ref{sec:tut:beamer}). + +If you're familiar with the \TikZ externalization library, you might wonder +whether Memoize has an equivalent of the \refcmd{tikzexternalize} command. It +doesn't. Memoize assumes that if you loaded it, you want to use it --- but you +can always disable it using key \refmmz{disable}, or even by loading package +\refpkg{nomemoize} in its stead. + +In \hologo{LaTeX}, initialization and finalization are completely automatic. +Memoize defines several initialization and finalization styles --- +\docaux{key}{begindocument/before}, \docaux{key}{begindocument}, +\docaux{key}{begindocument/end} and \docaux{key}{enddocument/afterlastpage} +---and executes them at the cognominal \hologo{LaTeX} hooks. + +\paragraph{\hologo{plainTeX}}{} + +Load Memoize by |\input memoize|. As package options cannot be provided in +\hologo{plainTeX}, the author must trigger extraction from \refcmd{mmzset} +using key \refmmz{extract}; I recommend doing this immediately after loading +the package. This key may be invoked with or without a value. In the latter +case, Memoize will extract using the package default method +\refmmz{extract=perl}, unless its has been overriden from +\reffile{memoize.cfg}. + +Furthermore, as \hologo{plainTeX} has no concept of a document body, the text +must be manually enclosed in \refcmd{mmzset}\bracestt{\docaux{key}{begin + document}} and \refcmd{mmzset}\bracestt{\docaux{key}{end document}}; this +is where the initialization and finalization hooks described above will be +executed. Note that \refmmz{extract}, when used, must precede this enclosure. + +Finally, \hologo{plainTeX} has another reason for preferring the early loading +of the package. In this format, Memoize must redefine \refcmd{shipout}, at a +time the meaning of this control sequence is still primitive. In particular, +this means that Memoize must be loaded before \pkg{atbegshi}. + +\begin{tcboxedraster}[raster column skip=1cm]{blankest} + \ExampleName{plainTeX}% + \makeexample{\examplename.tex.c1}% + \tcbinputexample{listing only, title=A minimal \hologo{plainTeX} example} + % + \ExampleName{ConTeXt}% + \makeexample{\examplename.tex.c1}% + \tcbinputexample{listing only, title=A minimal \hologo{ConTeXt} example} +\end{tcboxedraster} + +\paragraph{\hologo{ConTeXt}}{} + +Load Memoize by \cs{usemodule}\bracketstt{memoize} or +\cs{usemodule}\bracketstt{memoize}\oarg{options}. Unlike in \hologo{LaTeX}, +spaces are allowed in \meta{options}; the remarks on key \refmmz{extract} and +loading order are the same as for \hologo{LaTeX}. + +In \hologo{LaTeX}, Memoize automatically executes its initialization and +finalization code when at the beginning and the end of the document body. Due +to my very limited experience with \hologo{ConTeXt}, and its project structure +in particular, I don't know what the appropriate place for initialization and +finalization would be in \hologo{ConTeXt}. I therefore provisionally leave it +to the author to execute \refcmd{mmzset}\bracestt{\refmmz{begin document}} and +\refcmd{mmzset}\bracestt{\refmmz{end document}} manually, and hope for advice +on how to handle this properly. + + +\paragraph{Auxiliary packages} + +\begin{doc}{package={name=nomemoize}} + Loading this package instead of Memoize completely disables memoization, but + does not require removing any Memoize commands from the document (they all + become no-ops). +\end{doc} + +\begin{doc}{package={name=memoizable}} + This package is a programmer's stub: if Memoize is loaded, it does nothing; + otherwise, it provides the no-op variants Memoize commands. See + section~\ref{sec:loading-memoize} for details. +\end{doc} + + +\subsection{Configuration} +\label{sec:ref:configuration} + + +\begin{doc}{easy,cmd={name=mmzset, par=\marg{options}}} + + Update the Memoize configuration. + + The \meta{options} are a comma-separated list of \meta{key}|=|\meta{value} + pairs. They are processed using the \pkg{pgfkeys} utility of PGF/\TikZ (see + \PGFmanual{87}), with the default path set to \docaux{key path}{mmz}. + + The changes are local to the current \hologo{TeX} group, except for keys + where explicitly noted otherwise. +\end{doc} + +\begin{doc}{easy, + cmd={name=mmznext, par=\marg{options}}, + } + + This command accepts the same \meta{options} as \refcmd{mmzset}, but + interprets them as \emph{next-options} --- options which will be applied to + the next, and only the next, \emph{auto}memoized command or environment. + (Remember that a command or environment is submitted to automemoization by + \refmmz{auto}|=|\marg{command or + environment}\bracestt{\refmmzauto{memoize},...}; see + sections~\ref{sec:tut:automemoization}, \ref{sec:tut:working-on-a-picture} + and \ref{sec:ref:advicememoization} for details.) + + Remarks for the author: + + \begin{itemize} + \item Key \refmmz{enable} has no effect inside \refcmd{mmznext}. + \item If \refcmd{mmznext} is used more than once preceding an automemoized + command, only the final invocation takes effect. + \item The next-options also apply to commands and environments for which + memoization is autodisabled via \refmmz{auto}|=|\marg{command or + environment}\bracestt{\refmmzauto{nomemoize},...}. + \item It is safe to set the next-options in front of a command submitted to + automemoization which does not actually undergo memoization in this + particular instance. In other words, the absence of memoization will not + cause the next-options to ``leak'' to the next automemoized command. + \item Only the linear (execution) order of \refcmd{mmznext} and the + automemoized command matters. Key \refcmd{mmznext} will correctly apply to + a single following automemoized command even if it occurs outside the group + which that command is executed from; and it will apply to the following + automemoized command even if it is called within a group closed before that + command is executed. + \end{itemize} + + Remarks for the programmer: + \begin{itemize} + \item The next-options are set globally. + \item The effect of \refcmd{mmznext} is \emph{not} cumulative. Consequently, + \refcmd{mmznext}\braces{} clears the next-options. + \item The next-options are applied by executing \refcmd{mmzAutoInit} within + the advice. Any piece of advice applying the next options should also clear them + when the \refmmzauto{run conditions} are not met. This is streamlined by + style \refmmzauto{apply options}, intended for use within \refmmz{auto} + declarations. Out of the box, this style is deployed by + \refmmzauto{memoize}, \refmmzauto{nomemoize} and \refmmzauto{noop}, but it + may be used by any piece of advice. Note that the \refmmzauto{outer handler} + declared by this style opens a group (to apply the options in) but leaves + it to the (undeclared) \refmmzauto{inner handler} to close that group. + \item Key \refmmz{enable} has no effect inside \refcmd{mmznext} because when + Memoize is disabled upon encountering an automemoized command, the advice + bails out without ever applying the next-options. More generally, this + applies to any advised command whose run conditions require + \refcmd{ifmemoize} to be true. Key \refmmz{disable}, on the other hand, + takes effect, because \refcmd{ifmemoize} is checked within \refcmd{Memoize} + as well. + \end{itemize} +\end{doc} + +\begin{doc}{easy,file={name=memoize.cfg, desc=file}} + The configuration file, loaded just before processing the package options. + It will typically contain a \refcmd{mmzset} command, but it may contain any + \hologo{TeX} code. + + As for any other file loaded by \hologo{TeX}, the location of the file + determines whether it applies system-wide, user-wide or directory-wide. + + This file is also loaded by package \refpkg{nomemoize}, on the off chance it + defines some commands other than \refkeypath{/mmz} keys. (It is not loaded + by package \refpkg{memoizable}, though). +\end{doc} + +\begin{doc}{cmd={name=nommzkeys, par=\marg{key}}} + In package \refpkg{memoize}, this command is a no-op; in packages + \refpkg{nomemoize} and \refpkg{memoizable}, it defines key + \refkeypath{/mmz}|/|\meta{key} as a no-op. + + As explained in section~\ref{sec:tut:final}, use this command to declare any + \refkeypath{/mmz} keys you have used outside \refcmd{mmzset} when switching + to package \refpkg{nomemoize}. +\end{doc} + + +\subsection{Memoization} +\label{sec:ref:memoization} + +\subsubsection{Manual memoization commands} +\label{sec:ref:memoization:manual} + +\begin{doc}{easy, + cmd={name=mmz, par=\oarg{options}\marg{code}}, + env={name=memoize, par=\oarg{options}}, + } + Submit \meta{code} or \meta{environment body} to memoization. + + Prior to memoization, the configuration is locally updated by executing + \meta{options} given as the optional argument to this command, i.e.\ the + given options take precedence to options previously set via \refcmd{mmzset}. + Note that next-options, set by \refcmd{mmznext}, are not applied. + + The effect of the macro and of the environment version of this command is the + same, except that the command version memoizes \meta{code} exactly as-is, + while the environment version trims away any spaces at the beginning and the + end of the code.\footnote{What actually happens is that at the beginning of + the environment body, all space tokens will be discarded. At the end of + the body, no spaces are actually discarded; Memoize simply issues an + \refcmd{unskip}. This should not matter to a regular user who simply + writes down the environment.} The space-trimming feature of the environment + ensures that you can write |\begin{memoize}| and |\end{memoize}| in separate + lines (as shown above), but no extra space will creep into the extern. + + The space-trimming feature of the environment, which trims spaces at the + beginning and at the end of the \meta{environment body}, should not be + confused with the effect of \refmmz{ignore spaces}, which ignores spaces + following the environment end-tag (in \hologo{LaTeX}, |\end{...}|) --- and + which does not apply to manual memoization at all! + + The argument of \refcmd{mmz} \emph{must} be enclosed in braces. +\end{doc} + +\begin{doc}{easy, + cmd={name=nommz, par=\oarg{options}\marg{code}}, + env={name=nomemoize, par=\oarg{options}}, + } + Disable Memoize for the span of the compilation of \meta{code} or + \meta{environment body}. + + This command consumes the \meta{options} in the same way as + \refcmd{mmz}\slash \refenv{memoize} described above. The macro and the + environment version of the command exhibit the same space-trimming behaviour + as their \refcmd{mmz}\slash \refenv{memoize} counterparts, and the argument + of \refcmd{nommz} \emph{must} be enclosed in braces. +\end{doc} + + +\subsubsection{Basic configuration} +\label{sec:ref:memoization:basic} + +\begin{doc}{easy, + key={name=enable}, + key={name=disable}, + } + Enable or disable the functionality of the package. + + What happens when Memoize is enabled depends on the memoization mode + (\refmmz{normal}, \refmmz{readonly}, \refmmz{recompile}) and many other + factors. When the package is disabled, it neither creates new memos and + externs, nor uses the existing ones; this applies to both manual and + automatic memoization. The effect is close to not having Memoize loaded, or + to loading NoMemoize, but it is not completely the same; for example, the + record file (\dmmz) \emph{is} updated while Memoize is disabled, reflecting + the fact that nothing was memoized (or utilized) in the disabled + state.\footnote{Cleaning the folder (\S\ref{sec:cleanup-scripts}) after + disabling the package for the entire document is thus a bad idea.} + + If these keys are used in the preamble, their effect is delayed until the + beginning of the document, to ensure that Memoize is never enabled in the + preamble. Other than that, all these keys do is set the \hologo{TeX} + conditional \refcmd{ifmemoize}, which you may use in your code to test + whether Memoize is enabled. You may also use \refcmd{memoizetrue} and + \refcmd{memoizefalse}, as long as you never enable the package in the + preamble. + + Key \refmmz{enable} cannot be applied to automemoized commands via + \refcmd{mmznext}. It will take effect for manual memoization, though, and + key \refmmz{disable} will work for both, as expected. +\end{doc} + +\begin{doc}{easy, + key={name=normal, desc=the default mode}, + key={name=readonly}, + key={name=recompile}, + } + + Select the memoization mode. + + Each piece of code submitted to (either manual or automatic) memoization is + associated to several files: one c-memo, one cc-memo, and some externs (zero + or more, typically one). When Memoize encounters a piece of code submitted + to memoization, it takes one of the following actions: + + \begin{description} + \item[memoization] The code is compiled in a special way which produces the + associated memos and externs. + \item[utilization] The code is not compiled. Its effect is replicated by + processing the cc-memo; typically, this includes the single extern into the + document. + \item[regular compilation] The code is compiled as if Memoize was absent or + disabled (the memos and externs are neither utilized nor produced). + \end{description} + + \begin{minipage}[t]{0.48\linewidth} + The action taken depends on the memoization mode and on whether all the + memos and externs associated with the code exist, as shown in the table on + the right. Note that a single missing memo or extern implies the ``no'' + column of the table, and that memoization will create \emph{all} the + associated memos and externs, even those which already exist. + \end{minipage} + \hfill + \begin{tabular}[t]{@{}lll@{}} + \toprule + &\multicolumn{2}{c}{Do the memos and externs exist?}\\ + \cmidrule{2-3} + mode&yes&no\\ + \midrule + normal&utilization&memoization\\ + readonly&utilization®ular compilation\\ + recompile&memoization&memoization\\ + \bottomrule + \end{tabular} + + The memoization mode only has effect when Memoize is \refmmz{enable}d. Mode + selection is orthogonal to enabling\slash disabling the package; for example, + if you switch to a new mode while the package is disabled, the new mode will + be in effect once the package is enabled. +\end{doc} + + +\begin{doc}{easy, + desc={style}, + key={name=verbatim}, + key={name=verb}, + key={name=no verbatim}, + } + When \refmmz{verbatim} or \refmmz{verb} is in effect, the code submitted to + memoization is read verbatim; \refmmz{no verbatim} reverts to the normal, + non-verbatim collection of the code. This applies to both manual and + automatic memoization. + + The long version, \refmmz{verbatim}, switches to the full verbatim mode, + where all characters are assigned category code 12 (other). With the short + version, \refmmz{verb}, the braces, |{| and |}|, retain category codes 1 and + 2, which can be useful for verbatim collection of optional arguments. For + details, see the documentation of CollArgs' \refcollargs{verbatim} in + section~\ref{sec:ref:collargs}. + + Under the hood, these keys have two effects. First, they are passed on to the + argument collector (typically, \refcmd{CollectArguments} of the auxiliary + package CollArgs; for details, see section~\ref{sec:ref:advicememoization}), + instructing it to collect the code in the specified fashion, as described + above. Second, if the collected verbatim code is eventually compiled (either + regularly, or memoized), Memoize first rescans it using \refcmd{scantokens}. +\end{doc} + +\begin{doc}{easy, + key={name=padding left, par=\meta{dimension}, + desc={no default, initially |1| |in|}}, + key={name=padding right, par=\meta{dimension}, + desc={no default, initially |1| |in|}}, + key={name=padding top, par=\meta{dimension}, + desc={no default, initially |1| |in|}}, + key={name=padding bottom, par=\meta{dimension}, + desc={no default, initially |1| |in|}}, + } + Set the left/right/top/bottom padding of the extern in the extern PDF. + + Without padding, the (PDF) page holding the extern would tightly fit the + bounding box of the extern. These keys enlarge the extern page by the given + amounts, so that any parts of the extern lying outside the bounding box will + be correctly included when using the extern. See + section~\ref{sec:tut:padding} for details. + + \meta{dimension} is evaluated with \hologo{eTeX}'s |\dimexpr|, and may + contain control sequences \docaux{cmd}{width}, \docaux{cmd}{height} and + \docaux{cmd}{depth}, which will refer to the dimensions of the extern. + \refcmd{width} and friends behave like dimension registers, so it is ok to write + e.g.\ \refmmz{padding right}|=0.5\width|. + + The default padding is what \hologo{pdfTeX} puts around the page anyway, 1 + inch, but we use |1 in| rather than |1 true in|, which is the true default + value of PDF registers \docref{pdfvar:horigin} and \docref{pdfvar:vorigin}, + as we want the padding to adjust with \refcmd{mag}nification. +\end{doc} + +\begin{doc}{easy,key={name=padding, par=\meta{dimension}, desc={style, no default}}} + Set all the above |padding| keys to the given value. +\end{doc} + +\begin{doc}{ + easy, + key={name=context, par=\meta{tokens}, desc={cumulative, no default, + initially set by \refmmz{padding to context}}}, + key={name=clear context}, + } + These keys append the given \meta{tokens} to the \emph{context expression}, + or clear this expression. Memoized code gets recompiled whenever the + expansion of the context expression changes. + + The \meta{tokens} must be fully expandable (modulo protection); in + \hologo{LaTeX}, they will be expanded by |\protected@edef| when calculating + the md5sum of the context. + + The context expression is evaluated at the end of the memoization, and at + utilization attempts after inputting the c-memo (note that the c-memo + contains any additions to the context expression accumulated during + memoization). At evaluation, the given context expression is fully expanded, + yielding the \emph{context value}, whose md5 sum forms the \meta{context md5 + sum} part of the filename of the cc-memo and the extern. + + These keys may be used both prior to the memoization process, or during + memoization. In the former case, their effect is local to the current group; + in the latter case, the effect is global, so that the changes surely survive + until the end of memoization, when the c-memo, where the context expression + is stored, is written into a file. + + Under the hood, these keys manipulate token registers + \docaux{cmd}{mmzContext} and \docaux{cmd}{mmzContextExtra}, changing the + contents of the former while not memoizing, and the contents of the latter + during memoization. These token registers may also be manipulated directly + by the user, as long as one keeps to the convention of adjusting + \refcmd{mmzContext} locally and only while not memoizing, and adjusting + \refcmd{mmzContextExtra} globally and only during memoization. +\end{doc} + +\begin{doc}{ + key={easy, name=meaning to context, + par=\marg{comma-separated list of commands and environment names}}, + key={name=csname meaning to context, par=\marg{control sequence name}}, + key={name=key meaning to context, + par=\marg{full path to a pgfkeys command key}}, + key={name=key value to context, + par=\marg{full path to a pgfkeys value key}}, + } + These keys append the definition of the given construct to the context. + + Essentially, the ``meaning'' keys append \cs{meaning}\meta{control sequence} + to the context, for the appropriate \meta{control sequence}. For example, + \refmmz{meaning to context} appends \cs{meaning}\cs{foo} when given \cs{foo} + as in item in the list, and it appends the internal environment macros + appropriate to the format when given an environment name. Similarly, + \refmmz{key meaning to context} resolves \meta{control sequence} to the + internal macro holding the key command. + + Key \refmmz{key value to context} should be used on keys which store values, + e.g.\ keys initialized by \pkg{pgfkeys} handler \code{.initial}; see + \PGFmanual{87.3.4 and \S87.4.5}. + + All the keys prefix the meaning\slash value by the name of the command\slash + environment\slash key, in order to prevent ambiguous contexts, see + section~\ref{sec:cross-referencing} for details. Furthermore, they all + operate through \code{\cs{csname}...\cs{endcsname}} construct, allowing one + to safely add internal commands to the context. +\end{doc} + +\begin{doc}{ + keypath={/handlers}, + key={easy, name=.meaning to context}, + key={name=.value to context}, + } + These are the handler variants of \refmmz{key meaning to context} and + \refmmz{key value to context}. +\end{doc} + + +\begin{doc}{key={name=padding to context,desc=style}} + This key appends the values of the \refmmz{padding} keys to the context, + causing the memoized code to be recompiled whenever the padding values are + changed. This key is used to initialize \refmmz{context}, so the author + normally shouldn't have to use this key. +\end{doc} + +\begin{doc}{ + cmd={name=mmzNoRef, par=\marg{reference key}, desc=\hologo{LaTeX} only}, + cmd={name=mmzForceNoRef, par=\marg{reference key}, desc=\hologo{LaTeX} only}, + } + These macros append the current value of the \meta{reference key} to the + context,\footnote{More precisely, it is \meta{reference key}|=|\marg{current + value} which is appended.} causing the memoized code to be recompiled + when the reference changes. + + If the reference key is undefined, \refcmd{mmzNoRef} aborts memoization, + while \refcmd{mmzForceNoRef} uses \cs{relax} as the reference string. + + These commands are deployed in the implementation of \refmmzauto[show + keypath]{ref}, \refmmzauto{force ref} and friends. If the + cross-referencing commands you are using are advised by these keys, you most + likely have no need of these macros. +\end{doc} + +\begin{doc}{easy, key={name=per overlay,desc=style}} + This key is only defined in the Beamer class. When in effect, the memoized + code will produce a cc-memo (and extern) for each overlay of the frame. For + implementation, see section~\ref{sec:per-overlay}. +\end{doc} + +\begin{doc}{ + key={name=capture, par=\docAux{of=key:/mmz/capture, value={name=hbox}, text=\alt, + value={name=vbox,of=key:/mmz/capture}}, + desc={no default, initially \refmmz{capture=hbox}}} + } + Select the capture mode. This setting only applies to the default + memoization \refmmz{driver}. + + By default, it is assumed that the memoized code should be executed in the + horizontal mode, so the default memoization driver captures the output of the + memoized code in a \refcmd{hbox} --- and also issues a \refcmd{quitvmode} + (both in the document and in the cc-memo), just in case the memoized code + occurs at the start of the paragraph. + + Use \refmmz{capture}|=|\refmmz{capture=vbox} to execute the memoized code in + the vertical mode: Memoize will capture the output of the memoized code in a + \refcmd{vbox}, and avoid issuing \refcmd{quitvmode}. For example, this + capture mode is necessary to memoize a \refenv{verbatim} environment. +\end{doc} + + +\subsubsection{Inside the memoization process} +\label{sec:ref:memoization:process} + +\begin{doc}{easy, cmd={name=mmzAbort}} + This command aborts the ongoing memoization. + + The memoization will proceed as usual (i.e.\ the extern boxes and the cc-memo + code will be produced), but at the end of this process, no memos will be + produced, no externs shipped out to extern pages, and no record files + updated. +\end{doc} + +\begin{doc}{easy, cmd={name=mmzUnmemoizable}} + This command aborts the ongoing memoization, and marks the submitted code as + unmemoizable. + + The ongoing memoization produces a c-memo setting conditional + \docaux{cmd}{ifmmzUnmemoizable} to true. Upon utilizing this c-memo, the + system switches to regular compilation. + + For example, if you are automemoizing |tcolorbox|es of package + \pkg{tcolorbox}, you will want to refrain from memoizing boxes marked as + |breakable| or |float|ing. Simply aborting the memoization cannot do the + trick here, as memoization compiles the submitted code in a \hologo{TeX} box. + Marking a |breakable| or |float|ing |tcolorbox| as unmemoizable (either + manually using this macro, or automatically using \refmmz{auto key}) makes + sure that after the first compilation when memoization is attempted, the box + will be compiled regularly, and will have the intended ability to break + across pages, or float. +\end{doc} + + +\begin{doc}{ + cmd={name=Memoize, par=\marg{key}\marg{code}}, + } + Depending on various factors, this command either memoizes \meta{code} under + key \meta{key}, utilizes the results of a previous memoization, or performs a + regular compilation of \meta{code}. + + The outcome of executing this command --- memoization, utilization or regular + compilation --- depends upon the Memoize's state (\refcmd{ifmemoize}, + \refcmd{ifmemoizing}) and mode (\refmmz{normal}, \refmmz{readonly}, + \refmmz{recompile}), and the existence of the relevant memos and externs. + The decision process is depicted in section~\ref{sec:Memoize}. + + This command expects to be executed in a dedicated group, which it will close + itself. + + Invoking memoization through \refcmd{Memoize} might be useful for packages + which want to save the results of intensive computations, regardless of + whether the author loads (and enables) memoization or not. However, this + usage is not yet officially allowed, because there is currently no way to + load the core memoization routines without loading the entire package, + thereby forcing the author to use Memoize. +\end{doc} + +\begin{doc}{ + key={ + name=driver, par=\marg{code}, + desc={no default, initially \refcmd{mmzSingleExternDriver}} + }, + } + This key sets \meta{code} as the memoization driver. + + Given some code submitted to memoization, the memoization driver should + produce the memos and externs which will replicate the effect of that code + (while retaining its regular effect). For details, see + section~\ref{sec:memoization-drivers}. + + Typically, the \meta{code} argument of this key will consist of a single + control sequence (the driver control sequence), but any amount of tokens is + allowed. Memoize executes the driver followed by the code which it is + supposed to memoize, in braces, and only cares that the driver consumes that + code. +\end{doc} + + +\begin{doc}{ + key={name=at begin memoization, par=\meta{code}, desc={cumulative, initially empty}}, + key={name=at end memoization, par=\meta{code}, desc={cumulative, initially empty}}, + key={name=after memoization, par=\meta{code}, desc={cumulative, initially empty}}, + } + Use these keys to set up memoization hooks. + + These keys may be used both prior to the memoization process, or during + memoization. In the former case, their effect is local to the current group; + in the latter case, the code given to \refmmz{at begin memoization} is + executed immediately, while the assignment performed by the other two keys is + global, so that the changes surely survive until the end of memoization. + + The code given to hook \refmmz{at begin memoization} is kept in macro + \docaux{cmd}{mmzAtBeginMemoization}, while the content of the other two hooks + resides in two macros per hook: \docaux{cmd}{mmzAtEndMemoization} and + \docaux{cmd}{mmzAtEndMemoizationExtra}, and \docaux{cmd}{mmzAfterMemoization} + and \docaux{cmd}{mmzAfterMemoizationExtra}. All these macros may be + manipulated directly by the user,\footnote{Use \cs{appto}, \cs{eappto}, + \cs{gappto} and \cs{xappto} of package \pkg{etoolbox} (loaded by Memoize) + to easily append code to these macros.} as long as one keeps to the + convention of adjusting the macros without ``\texttt{Extra}'' locally and + only while not memoizing, and adjusting the macros with ``\texttt{Extra}'' + globally and only during memoization. The ``\texttt{Extra}'' macros require + global assignments as they might be manipulated by code residing within a + \hologo{TeX} group of any depth. + + These complications explained, let us take a look at how memoization proceeds + to learn when the hooks are used: + \begin{enumerate} + \item Initialize various conditionals, macros and token registers. (Here is + where the ``\texttt{Extra}'' hooks are cleared.) Remember that at this + point, we're inside a group opened by \refcmd{Memoize}. + \item Execute \refmmz{at begin memoization} hook, i.e.\ the contents of + macro \refcmd{mmzAtBeginMemoization}. + \item Execute the memoization \refmmz{driver}. + \item Execute \refmmz{at end memoization} hook, i.e.\ the contents of macros + \refcmd{mmzAtEndMemoization} and \refcmd{mmzAtEndMemoizationExtra} (in this + order). + \item Write out the memos and ship out the externs to extern pages (unless + memoization was aborted). + \item Close the memoization group. + \item Execute \refmmz{after memoization} hook, i.e.\ the contents of + macros \refcmd{mmzAfterMemoization} and \refcmd{mmzAfterMemoizationExtra} + (in this order). + \end{enumerate} +\end{doc} + +\begin{doc}{ + cmd={name=mmzCMemo, desc={token register, global, empty at the start of memoization}}, + } + This token register mediates the construction of the c-memo. During + memoization (and only during memoization), arbitrary code may be added to + this register; at the end of memoization, Memoize writes out its contents to + the free-form part of the c-memo. + + All assignments to this register should be global. Use \refcmd{gtoksapp} and + \refcmd{xtoksapp} to easily append tokens to the register. +\end{doc} + + +\begin{doc}{ + cmd={name=mmzCCMemo, desc={token register, global, empty at the start of memoization}}, + } + This token register mediates the construction of the cc-memo. During + memoization, the memoization driver should append cc-memo code to + \refcmd{mmzCCMemo}; at the end of memoization, Memoize writes out its + contents to the cc-memo (preceded by the list of produced externs). + + All assignments to this register should be global. Local assignments would + not work, because the memoized code may contain commands, like \cs{label} and + \cs{ref}, which contribute content to cc-memo as well, but these commands may + appear within a \hologo{TeX} group of any depth. + + Use \refcmd{gtoksapp} and \refcmd{xtoksapp} to easily append tokens to the + register. +\end{doc} + +\begin{doc}{ + par=\meta{token register}\marg{tokens}, + cmd={name=toksapp}, + cmd={name=gtoksapp}, + cmd={name=etoksapp}, + cmd={name=xtoksapp}, + } + These commands append the given \meta{tokens} to the \meta{token register}. + \refcmd{etoksapp} and \refcmd{xtoksapp} expand the \meta{tokens} before + appending them; \refcmd{gtoksapp} and \refcmd{xtoksapp} perform a global + assignment. + + These commands are actually provided by CollArgs, and they are defined only + if they don't already exist; in particular, note that \hologo{LuaTeX} + provides them as primitives. + + Unlike the \hologo{LuaTeX} primitive variant, these commands require the + \meta{token register} to be given by a (|\toksdef|fed) control sequence; it + cannot be given as |\toks|\meta{number}. +\end{doc} + +\begin{doc}{ + cmd={name=ifmemoize}, + cmd={name=memoizetrue}, + cmd={name=memoizefalse}, + } + Use the \hologo{TeX}-style conditional \refcmd{ifmemoize} to test whether + Memoize is currently enabled. Within the document body, the conditional may + be set using \refcmd{memoizetrue} and \refcmd{memoizefalse}, which are then + functionally equivalent to \refmmz{enable} and \refmmz{disable}. Do not set + the conditional in the preamble of the document (unless you really know what + you are doing). +\end{doc} + +\begin{doc}{ + cmd={name=ifmemoizing,desc={readonly}}, + } + Use this \hologo{TeX}-style conditional to test whether Memoize is currently + memoizing. It may be only inspected; you should \emph{never} set this + conditional yourself. +\end{doc} + +\begin{doc}{ + cmd={name=ifinmemoize,desc={readonly}}, + } + Use this \hologo{TeX}-style conditional to test whether Memoize is currently + active, in the sense of either memoizing or regularly compiling some code --- + so inside a call to \refcmd{Memoize}. The conditional may be only inspected; + you should \emph{never} set it yourself. +\end{doc} + +\begin{doc}{ + cmd={name=mmzSingleExternDriver, par=\marg{code}}, + } + This is the default memoization \refmmz{driver}, producing exactly one extern + containing whatever is typeset by the submitted \meta{code}. + + The \meta{code} is compiled either within a horizontal or vertical box, + depending on the value of key \refmmz{capture}. In the case of a horizontal + capture, the driver makes sure that the horizontal mode is entered prior to + both typesetting the resulting box in the document, or utilizing the extern. + + For the implementational details, see + section~\ref{sec:memoization-driver-default}. +\end{doc} + +\begin{doc}{ + cmd={name=mmzExternalizeBox, par=\marg{box}\marg{token register}}, + } + This macro is indended to be called by memoization drivers to produce an + extern page. The given \meta{box} is dumped into the document as a separate + extern page, while the \meta{token register} receives the cc-memo extern + inclusion code. + + The \meta{box} may be given either as a control sequence (declared via + |\newbox|), or as box number. The resulting extern page will contain a + \emph{copy} of the given box, padded by the \refmmz{padding} values in effect + at the time of invocation of \refcmd{mmzExternalizeBox}. + + An implementation detail is that \refcmd{mmzExternalizeBox} does not ship out + the extern page immediately. This action is delayed until the end of the + memoization process; more precisely, it is carried out (in tandem with + writing out the c-memo and the cc-memo) between execution of hooks \refmmz{at + end memoization} and \refmmz{after memoization}. This delay guarantees + that no extern pages are produced in the event of aborting memoization, even + if the abortion is triggered after executing \refcmd{mmzExternalizeBox}. + + The \meta{token register} may be given either as a control sequence (declared + via |\newtoks|) or as control sequence |\toks| followed by the register + number. The register will receive the code, which, when executed from the + cc-memo, includes the extern file into the main document. This code consists + of a single invocation of \refcmd{mmzIncludeExtern}. It is the + responsibility of the driver to include the code received by \meta{token + register} in the register \refcmd{mmzMemo}, whose contents are, unless + memoization is aborted, written into the cc-memo. (See + \refcmd{ifmmzkeepexterns} and \refmmz{after memoization} to learn about + another way to use the code received by \meta{token register}.) + + The invocation of \refcmd{mmzIncludeExtern} in the produced extern-inclusion + code is adapted to the type of the box (horizontal or vertical), which is + detected automatically --- the memoization driver does not need to inform + \refcmd{mmzExternalizeBox} about this type explicitly.\footnote{This does not + negate the need for key \refmmz{capture}, which applies to the default --- + and therefore generic --- memoization driver. This driver cannot know + whether the memoized code would prefer to be compiled in a horizontal or + vertical box. It is precisely key \refmmz{capture} which gives the user an + opportunity to inform Memoize about this preference. Only once the + memoized code is compiled into a box of the appropriate type, it is trivial + to detect the type of that box.} +\end{doc} + +\begin{doc}{ + cmd={name=ifmmzkeepexterns, desc={initially \cs{iffalse}}}, + cmd={name=mmzkeepexternstrue}, + cmd={name=mmzkeepexternsfalse}, + } + Setting this conditional to true makes Memoize keep the extern boxes in the + global temporary storage even after shipping them out as extern pages. (The + temporary storage is emptied at the start of the next memoization.) + + The extern inclusion code received by the \refcmd{mmzCCMemo} when executing + \refcmd{mmzExternalizeBox} is primarily meant to be executed by inputting the + cc-memo file; i.e.\ when the cc-memo is input, \refcmd{mmzIncludeExtern} is + defined to include the extern file into the document. However, it sometimes + makes sense to execute the cc-memo contents immediately after memoization; + for example, if memoization produces several externs, intricately integrated + into the surrouding environment, it might be cumbersome to replicate their + typesetting both in the memoizing compilation and in the cc-memo code --- + easier to build up the cc-memo code and execute it right after memoization. + This is why Memoize, just before executing the contents of \refmmz{after + memoization} hook, redefines \refcmd{mmzIncludeExtern} to include externs + from the temporary storage rather than from (at that point still + non-existing) extern files. However, as this mechanism requires Memoize to + keep the externs around even after memoization, it is not enabled by default: + it must be enabled by setting conditional \refcmd{ifmmzkeepexterns} to true. +\end{doc} + +\begin{doc}{ + key={keypath=/mmz/auto, name=integrated driver, par=\marg{name}} + } + Use this key to easily setup a memoization driver which is integrated into + the command itself. + + \begin{tcolorbox}[warning] + This is an auto-key residing in keypath \refkeypath{/mmz/auto}. + \end{tcolorbox} + + An integrated driver must have a way of telling whether it is memoizing or + regularly compiling the code. This key declares a driver-specific + conditional which may be inspected, using \refcmd{IfMemoizing}, to determine + this. The conditional is set to true by the formal driver of the command + (set up by the invocation of this key), executed at the start of memoization; + it should never be set elsewhere. See + section~\ref{sec:memoization-multiple-externs} for details and an example. +\end{doc} + +\begin{doc}{ + cmd={name=IfMemoizing, par=\oarg{offset}\marg{name}\marg{true code}\marg{false code}} + } + This \hologo{LaTeX}-style conditional is meant to be used by the + \refmmzauto{integrated driver} with the given \meta{name}. It tests whether + this particular driver is currently memoizing some code. + + Potentially recursive commands are supported via the optional argument + \meta{offset}. If given, the conditional will only execute the \meta{true + code} when the current \hologo{TeX} group level matches the \hologo{TeX} + group level at the time of the invocation of the formal driver (held in + \refcmd{memoizinggrouplevel}), plus the \meta{offset}. In effect, the inner + invocation of the integrated driver will perform a regular compilation. For + details, see section~\ref{sec:memoization-complex-single-driver}. +\end{doc} + +\begin{doc}{ + cmd={name=memoizinggrouplevel,desc={readonly}}, + } + During memoization, this macro holds the \hologo{TeX} group level in effect + at the start of the memoization. +\end{doc} + +\begin{doc}{ + cmd={name=mmzRegularPages, desc=readonly counter}, + } + This counter holds the number of pages shipped out (so far) by the format's + regular shipout routine. \emph{Do not change its value!} + + In \hologo{LaTeX}, this counter is synonymous with + \refcmd{ReadonlyShipoutCounter}, and in \hologo{ConTeXt}, it is synonymous + with \refcmd{realpageno}. Memoize does not touch its value. + + In \hologo{plainTeX}, Memoize hijacks the \refcmd{shipout} control sequence + to count (and only to count) regular shipouts. In order for its value to be + realistic, Memoize should be loaded before other packages which hack + \cs{shipout} --- in particular, before \pkg{atbegshi}. +\end{doc} + +\begin{doc}{ + cmd={name=mmzExternPages, desc=readonly counter}, + } + This counter holds the number of extern pages Memoize has shipped out (so + far). \emph{Do not change its value!} + + A third-party tool may inspect this counter to have a realistic count of + shipped-out pages. +\end{doc} + +\begin{doc}{ + cmd={name=mmzExtraPages, desc=counter}, + } + This counter holds the number of pages shipped out (so far) in a way not + tracked by either \refcmd{mmzRegularPages} or \refcmd{mmzExternPages}. It + \emph{should} be advanced by any code which performs such shipouts, or + Memoize won't work correctly. +\end{doc} + + +\subsubsection{Tracing} +\label{sec:ref:memoization:tracing} + +\begin{doc}{ + key={name=trace, conditional=false}, + } + When tracing is on, Memoize shows information about its decision processes on + the terminal. You can learn whether the memoized code is being memoized, + utilized or regularly compiled; find out the md5sum of the code and which + input line it comes from; etc. + + This key has the syntax of a conditional, but there is no underlying + \hologo{TeX} conditional. The low-level interface for switching the tracing + on and off consists of macros \docaux{cmd}{mmzTracingOn} and + \docaux{cmd}{mmzTracingOff}. + + To learn about tracing the ``auto'' part of the automemoization process, also + \refcmd{AdviceTracingOn}. +\end{doc} + +\begin{doc}{ + key={name=include source in cmemo, conditional=true}, + } + + As a courtesy towards a curious user and a debugging aid, Memoize can include + a copy of the memo source in the c-memo. This feature is switched on by + default, but as the package itself never uses that information, it can be + safely switched off at any time. +\end{doc} + +\begin{doc}{ + key={name=include context in ccmemo, conditional=false}, + } + When this key is in effect, the expanded context expression is appended to + the cc-memo, behind the \docaux{cmd}{mmzThisContext} marker. + + Memoize never uses the context information from the cc-memo; this information + is only for tracing purposes. +\end{doc} + +\begin{doc}{ + key={name=direct ccmemo input, conditional=false}, + } + When this key is set to false, a cc-memo is processed indirectly: it is first + read into a token register, and it is the contents of this register which are + executed. When the key is set to true, the cc-memo is simply |\input|ted. + + The indirect execution is implemented to facilitate inverse search. Under + the direct cc-memo input, inverse search pointed at an included extern will + visit the cc-memo, which is not practical; under the indirect regime, the + inverse search will work as expected, and this is why the indirect cc-memo + input is the default. + + The overhead produced by the default indirect input method seems negligible, + but there are other factors which might make the user switch to the direct + input. For one, a cc-memo changing some category codes will require direct + input (no such cc-memos are ever produced out of the box). Less crucially, + sometimes one would like to use the inverse search to figure whether a part + of the document was produced by regular compilation or utilization, and which + memos\slash externs were utilized if the latter. Figuring this out under the + indirect input regime is harder: (i) reading the tracing information shown by + \refmmz{trace} is the surest way to learn what's going on, although (ii) + visual inspection of the externs and (iii) grepping through the |.memo.dir| + folder for particular code often help, as well. + + Both input methods use the same cc-memos; there is no need to + \refmmz{recompile} the memos when switching the cc-memo input method. Note + that the default indirect input method crucially relies on cc-memos ending + with \refcmd{mmzEndMemo}; this macro should not appear in the cc-memo itself. +\end{doc} + + + +\subsubsection{Internal memo commands} +\label{sec:ref:memoization:internal} + +The end-user should never have to use these commands. They are not formally +marked as internal by a |@| in their name only because doing so would +complicate |\input|ting the memos due to the category code changes it would +require. + +\begin{doc}{ + cmd={name=mmzMemo}, + } + This macro marks the beginning of a c-memo and a cc-memo core. Without it, + utilization of a memo will not work. +\end{doc} + +\begin{doc}{cmd={name=mmzSource}} + This macro marks the beginning of the memoized source in the c-memo. That + source is not used by Memoize in any way. It's inclusion into the c-memo may + be switched off by \refmmz{include source in cmemo}|=false|. +\end{doc} + +\begin{doc}{ + cmd={name=mmzResource, par=\marg{filename}}, + } + This is an internal command, which only occurs in a cc-memo. It checks + whether file \meta{filename} exists and is non-empty, and triggers + recompilation of the memoized code if the check fails. +\end{doc} + +\begin{doc}{ + cmd={ + name=mmzIncludeExtern, + par=\marg{seq}\braces{\refcmd{hbox}\alt\refcmd{vbox}}% + \marg{expected width}\marg{expected height}\marg{expected depth}% + \marg{padding left}\marg{padding bottom}\marg{padding right}\marg{padding top}, + } + } + + This is an internal command, which only occurs in a cc-memo. It includes the + extern identified by the sequential number \meta{seq} into the document as a + box of the specified type (horizontal or vertical). The extern is trimmed by + the given padding values. After trimming, the command checks whether the + size of the resulting box matches the given expectations; if it doesn't, a + warning is yielded. + + Before this command is executed, the externs should be listed by a sequence + of \refcmd{mmzResource} commands; \meta{seq} refers to the sequential number + of an extern in this sequence. + + This command may also be executed by executing the entire contents of + \refcmd{mmzCCMemo} after memoization. +\end{doc} + +\begin{doc}{ + cmd={name=mmzLabel, par=\marg{label key}\marg{label value}} + } + This is an internal command written into the cc-memo by the auto-handler of + \refcmd{label}. It temporarily stores \meta{label value} into + \refcmd{@currentlabel} and then executes \cs{label}\marg{label name}. +\end{doc} + +\begin{doc}{ + cmd={name=mmzEndMemo}, + } + This macro marks the end of a cc-memo. It is used to grab the cc-memo core + (everything between \refcmd{mmzMemo} and \refcmd{mmzEndMemo}) under the + indirect cc-memo input regime, i.e.\ when \refmmz{direct ccmemo input} is not + in effect. +\end{doc} + + +\subsection{Location of memos and externs} +\label{sec:ref:dirs} + +\begin{doc}{easy, + key={name=memo dir,par=\meta{name}, desc={style, default \texttt{\string\jobname}}}, + } + A convenient way to store memos and externs in a dedicated directory (and + create this directory in case it does not exist). Without an argument, this + key places these files in subdirectory \meta{document name}|.memo.dir| of the + current directory. See section~\ref{sec:tut:memodir} for the tutorial. + + This key sets \refmmzpath{relative} to |false|, \refmmzpath{dir} to + \meta{name}|.memo.dir|, \refmmzpath{prefix} to empty and \refmmz{mkdir} to + |true|. In effect, memos and externs are placed in the subdirectory + \meta{name}|.memo.dir| of the directory containing the document; their + filenames contain no \meta{name} prefix, as \meta{name} already occurs in the + directory name. The latter feature also makes it easy for projects (or parts + of a project) to share memos and externs; see section~\ref{sec:tut:multifile} + for a typical usage case. +\end{doc} + +\begin{doc}{easy,key={name=no memo dir,desc=style}} + A convenient way to undo the effect of \refmmz{memo dir} and revert to the + initial settings where memos and externs are located in the current + directory. See section~\ref{sec:tut:memodir} for the tutorial. + + This key resets the subkeys of \refmmz{path} to their initial values, and + sets \refmmz{mkdir} to |false|. +\end{doc} + +\begin{doc}{ + key={name=path, par=\meta{keylist}, desc=style}, + } + + Set the \emph{path prefix} to memo and extern files by executing the given + \meta{keylist} in keypath \docaux{key path}{mmz/path}. + + The path prefix contains both the location of the memo\slash extern files + (set by \refmmzpath{relative} and \refmmzpath{dir}) and the initial, + fixed part of their filenames (set by \refmmzpath{prefix}): + \begin{center} + \meta{path prefix}=[|./|]\meta{directory}|/|\meta{prefix} + \end{center} + where ``|./|'' is only present when \refmmzpath{relative} is in effect. + Given the \meta{path prefix}, this is how the paths to memos and externs are + constructed: + \begin{center} + \begin{tabular}{r@{ }l} + c-memo:&\meta{path prefix}\meta{code md5 sum}|.memo|\\ + cc-memo:&\meta{path prefix}\meta{code md5 sum}|-|\meta{context md5 sum}|.memo|\\ + extern:&\meta{path prefix}\meta{code md5 sum}|-|\meta{context md5 sum}-$N$|.pdf|\\ + &(where ``-$N$'' is only present when $N\neq 0$, i.e.\ for non-first externs)\\ + \end{tabular} + \end{center} + + For example, the default \refmmz{no memo dir} \meta{path prefix} equals + \meta{jobname}|.| (note the dot), and after issuing \refmmz{memo dir}, the + \meta{path prefix} is \meta{jobname}|.memo.dir|. Executing + \refmmz{path}|=|\bracestt{\refmmzpath{dir}=project-memo-dir, + \refmmzpath{prefix}=\string\jobname.} would set the memo prefix to + |./project-memo-dir/|\meta{jobname}|.|, allowing the author to keep the memo + files of all documents compiled from the project directory in the same place. + + The following keys may occur in the \meta{keylist}: + \yadocset{keypath=/mmz/path} + + \begin{doc}{ + key={name=relative, conditional=true}, + } + + This key determines whether the location is relative to the current + directory, i.e.\ the directory where \hologo{TeX} is executed from; + usually, this will be the directory where the compiled |.tex| file resides. + When set to |true| (the default), the directory set by \refmmzpath{dir} + is prefixed by ``|./|''. + + You will probably need to set |openout_any=a| in \reffile{texmf.cnf} + to allow writing to an arbitrary directory --- but remember, this might be + dangerous! + \end{doc} + + \begin{doc}{ + key={name=dir, par=\meta{name}, desc={no default, initially empty}}, + } + + Set the \meta{directory} where Memoize will search for memos and externs + and\slash or create them in. + + Unless \refmmzpath{relative} is set to |false|, this location is + relative to the current directory. Given the empty default, memos and + externs are therefore created in the directory holding the source file by + default. + + In principle, the given memo directory must already exist, but see + \refmmz{mkdir}. + \end{doc} + + \begin{doc}{ + key={name=prefix, par=\meta{name}, + desc={no default, initially \texttt{\string\jobname.}}}, + } + + Set the \meta{prefix}, i.e.\ the initial part of the memo\slash extern + filename. Initially, it is set to the document name. + \end{doc} + + After processing the \meta{keylist}, \refmmz{path} records the new path + prefix by invoking \refmmz{record/record type/prefix}, which typically results + in a \refcmd{mmzPrefix} entry in the \dmmz file, and attempts to create the + \meta{directory} is \refmmz{mkdir} is in effect --- except when \refmmz{path} + is executed in the document preamble: then, these actions are only carried + out at the beginning of the document, for the final value of the keys. +\end{doc} + +\begin{doc}{key={name=mkdir, conditional=false}} + When this key is set to true, Memoize will attempt to create the directory + set by \refmmz{path} if it does not yet exist. The directory creation takes + place at the beginning of the document and at every subsequent invocation of + key \refmmz{path}, using the system command specified by \refmmz{mkdir + command}. +\end{doc} + +\begin{doc}{ + key={name=mkdir command, par=\meta{system command invocation}, + desc={no default, initially |mkdir "\#1"|}}, + } + Sets the command used to create \refmmzpath{dir} when \refmmz{mkdir} is in effect. + + This is a system command, so an appropriate shell escape mode must be in + effect to execute it successfully. + + The default should work on Linux, MacOS and Windows. On Linux systems, it + makes sense to change the default (using \reffile{memoize.cfg}) to |mkdir + -p "#1"|, which can create parent folders as necessary. + + Note that extraction methods \refmmz{extract=perl} and + \refmmz{extract=python} set \refmmz{mkdir command} to + \refscript{memoize-extract.pl} \refscript{memoize-extract.pl--mkdir} and + \refscript{memoize-extract.py} \refscript{memoize-extract.pl--mkdir}, + respectively. Unlike system |mkdir|, these commands are safe in the sense + that they conform to the paranoid openout regime (|openout_any=p|). +\end{doc} + +\begin{doc}{ + key={name=output-directory, par=\meta{directory}, + desc={no default, initially undefined, as package option only}}, + cmd={name=mmzOutputDirectory, par=\meta{directory}, desc={pre-defineable}} + } + If the \hologo{TeX} binary was invoked with option |-output-directory|, one + should use this key or define this macro to inform Memoize this, as there is + no way to learn about it automatically. + + The given \meta{directory} must end with a slash (|/|). + + The key is only allowed as a package option. But I imagine that defining the + macro from the command line, prior to inputting the document source, will be + more common: + \begin{center} + |pdftex -output-directory somedir '\def\mmzOutputDirectory{somedir/}\input doc'| + \end{center} +\end{doc} + + +\subsection{Extern extraction} +\label{sec:ref:externs} + +\begin{doc}{easy, + key={name=extract,par=\marg{extraction method}, + desc={preamble-only, initially \refmmz{extract=perl}, default: see below}}, + } + This key selects or executes the extern \meta{extraction method}, i.e. the + method which Memoize will use to extract the extern pages out of the document + PDF. + + Out of the box, Memoize recognizes the following \meta{extraction method} + keywords: \docAux{easy, of=key:/mmz/extract, value={name=perl}, comma, + value={name=python}, comma, value={name=tex}, and, value={name=no}}. The final + keyword (not available in \hologo{plainTeX}) instructs Memoize to \emph{not} + perform to extraction; it should be used when extraction is performed + externally (for details, see section~\ref{sec:setup}). Additional methods + may be installed by defining key \docaux{key + path}{mmz/extract}|/|\meta{extraction method}. + + When invoked from \reffile{memoize.cfg} or used as a package option, this key + \emph{selects} the extraction method. In this case, the key has no default + value, i.e.\ it is illegal to use it without an argument. The method + selected by the package option overrides the method selected in + \reffile{memoize.cfg}, which in turn overrides the package-initial value + \refmmz{extract=perl}. + + In \hologo{LaTeX} and \hologo{ConTeXt}, the selected method is executed at + the end of loading the package. Afterwards, the key is disabled. If you + really need to invoke extraction in the preamble, or again, write + \refmmz{extract}|/|\meta{method}. + + When invoked from a \refcmd{mmzset} in the document preamble, this key + immediately \emph{executes} the given extraction method. In the preamble + incarnation, the key may be invoked without a value to execute the previously + selected method. + + As we want to allow a \hologo{plainTeX} author to override the extraction + method specified by the package (\refmmz{extract=perl}) or in + \reffile{memoize.cfg}, Memoize does \emph{not} perform extern extraction + while loading the package in this format. In \hologo{plainTeX}, internal + extraction can only be triggered by an explicit invocation of + \refmmz{extract} in the ``document preamble'' --- i.e.\ between |\input + memoize| and \refcmd{mmzset}\braces{\refmmz{begin document}}. In this case, + the key does not require an argument; invoking it without the argument will + execute either the package-default, \refmmz{extract=perl}, or whatever the + user had selected in \reffile{memoize.cfg}. + + Executing extraction method \refmmz{extract=perl} or \refmmz{extract=python} + has an additional effect of setting the \refmmz{mkdir command} to the + extraction script with option \refscript{memoize-extract.pl--mkdir}. This + obviates the need to include |mkdir| among the restricted shell commands if + one is using the restricted shell mode. +\end{doc} + +\subsubsection{Perl- and Python-based extraction} +\label{sec:ref:extraction-perl-python} + +\begin{doc}{ + key={name=perl extraction command, par=\meta{system command}, + desc={no default, initially \refscript{memoize-extract.pl}}}, + key={name=perl extraction options, par=\meta{options}, + desc={no default, initially: see below}}, + key={name=python extraction command, par=\meta{system command}, + desc={no default, initially \refscript{memoize-extract.py}}}, + key={name=python extraction options, par=\meta{options}, + desc={no default, initially: see below}}, + } + These keys determine the system calls used for invoking the extraction + scripts \refscript{memoize-extract.pl} and \refscript{memoize-extract.py}. + All the details below apply both to the Perl and the Python version. + + Use |perl|\slash|python extraction command| to set the name of the extraction + script. If necessary, include the full path to the scrip, or |perl|\slash + |python| plus the path to the script. Whatever you set here must be allowed + by the shell escape mode. + + Use |perl|\slash|python extraction options| to set the options that the + script will receive; consult the documentation of + \refscript{memoize-extract.pl} for their meaning. + + The initial value of \refmmz{perl extraction options}, shown below, (i) sets + embedded mode, which prefixes each output line with the script name, (ii) + requests a log file named \meta{jobname}|.mmz.log| (|-l|; |\input|ting the + log after extraction informs Memoize, and the author, whether extraction was + successful), and (iii) sets the warning template suitable for the format + (|-w|; this way, any warning messages issued by the script can be reissued by + the compilation of the document). + + These keys were initialized using \pkg{pgfkeys} handler |.initial|, so their + values may be modified by handlers |.prefix|, |.append|, etc. During the + execution of the system call, their values are fully expanded --- thus the + |\string|s in the initial options value below. The guards + (|%| etc.) make sure that + each format asks for a warning message it understands (the code shown below + is an excerpt from the |.dtx| file; ultimately, each format receives a single + of the three guarded lines). + + \makeexcerpt{perl-extraction-options} + \tcbinputexample[.tex][.excerpt]{listing only, one file, no attachment, + title={The initial value of \refmmz{perl extraction + options}}, full width, left=-2mm, right=0mm, listing options app={ + morecomment={[s]{\%<}>} }, } +\end{doc} + +\begin{doc}{ + script={name=memoize-extract.pl, par=[\meta{options}] \meta{name}\texttt{.mmz}}, + script={name=memoize-extract.py, par=[\meta{options}] \meta{name}\texttt{.mmz}}, + } + These scripts extract the new externs recorded in \meta{name}\dmmz from + \meta{name}|.pdf|. Memoize invokes them when loaded with package option + \refmmz{extract}|=|\refmmz{extract=perl} (the default) or + \refmmz{extract}|=|\refmmz{extract=python}. + + The script inspects the given record file, \meta{name}\dmmz, for lines of + form \refcmd{mmzNewExtern}\marg{extern filename}\marg{extern page + number}\braces{\meta{expected width}\texttt{pt}}\braces{\meta{expected + height}\texttt{pt}}. For each such line, page number + \meta{extern page number} is extracted from \meta{name}|.pdf| into + \meta{extern filename}. Other lines are ignored (and so are commented + invocations of \refcmd{mmzNewExtern}). + + The \meta{extern filename} may contain a (relative or absolute) path to the + new extern file. The relative paths are relative to the location of the + \dmmz file, even when the script is invoked from some other directory. + + To guard against extracting a wrong page, the script checks whether the size + of each extracted page matches the \meta{expected width} and \meta{expected + height}.\footnote{\label{fn:tolerance}To avoid false positives, the match + need not be exact, a difference up to |0.01pt| is tolerated. Some PDF + tools, notably the |PDF::API2| library deployed by the Perl version of the + script, round the dimensions of a PDF page, recorded in |/MediaBox|, to two + digits.} If it does not, the script refuses to extract the page, yields a + warning and even removes the extern file if it exist. + + The extraction script's paranoia extends further. It will refuse to extract + the page, yielding a warning, if a (c)c-memo associated to the extern does + not exist. And it will refuse (yielding a runtime error) to write to any + file whose absolute path does not occur under the current directory or the + directory set by \docref{TEXMFOUTPUT} (in \reffile{texmf.cnf} or as an + environment variable); \docref{TEXMFOUTPUT} is also not allowed to point to + the root directory, except on Windows, where it can only point to a drive + root. + + \yadocset{ + of=script:memoize-extract.pl, + override/.style={ + index annotation={option of {% + \hypercolor{link}{gray}% + \hyperref[script:memoize-extract.pl]{\texttt{memoize-extract}}% + }}, + }, + } + \begin{doc}{ + option={name=pdf, short name=P, par=\meta{pdf}} + } + Extract the externs from the given \meta{pdf} instead of the default + \meta{name}\texttt{.mmz}. Note that file \meta{pdf}, despite the different + name, should be produced by the same compilation that produced + \meta{name}\dmmz, otherwise wrong pages might be extracted. + \end{doc} + \begin{doc}{ + option={name=prune, short name=p} + } + After extraction, remove the extracted extern pages from the document PDF. + \end{doc} + \begin{doc}{ + option={name=keep, short name=k} + } + By default, the script comments out the \refcmd{mmzNewExtern} lines in the + \dmmz file, to prevent multiple extractions. Specifying this option + prevents this behaviour. + \end{doc} + \begin{doc}{ + option={name=log, short name=l, parameters=\meta{filename}} + } + When given this option, the script creates a log file with the given name. + The log will receive any warnings yielded by the script, see also + \refscript{memoize-extract.pl--warning-template}. A well-formed log ends + with |\endinput|, indicating that the \dmmz file was completely processed. + + In absence of this option, the warnings are printed to the standard error. + \end{doc} + \begin{doc}{ + option={name=warning-template, short name=w, parameters=\meta{template}}, + } + When this option is given, a warning message is not logged (or printed to + standard error) as-is; it is wrapped by the template given as the argument + of this option. More precisely, the script will log the given + \meta{template}, with all occurrences of \docaux{cmd}{warningtext} + substituted by the actual warning message. + + The option can be used to propagate warnings to the upstream compilation, + simply by setting this option appropriately (see the initial value of + \refmmz{python extraction options}) and |\input|ting the log after + extraction. + \end{doc} + \begin{doc}{ + option={name=force, short name=f} + } + Force extern extraction even if the size-check fails. The failure will + still be logged. + \end{doc} + \begin{doc}{ + option={name=quiet, short name=q} + } + Normally, the script prints what it is doing to the standard output; in + particular, it prints out the page number and the filename of each extern + it is extracting. This option disables this behaviour. + \end{doc} + \begin{doc}{ + option={name=embedded, short name=e} + } + When given this option, everything printed to the standard output is + prefixed by the script name. The idea is to use this option when calling + the script from the \hologo{TeX} compilation, as it makes it easy to + identify the output of the script. + \end{doc} + \begin{doc}{ + option={name=mkdir, short name=m} + } + When given this option, the extraction script transforms into a paranoid + |mkdir| (|-p|). Argument \meta{name}|.mmz| is interpreted as a path to the + directory to create; all other options are ignored. + + The ancestors of the directory are created as needed. The script will + refuse to create any directory whose absolute path does not occur under the + current directory or a directory listed in \docref{TEXMFOUTPUT} (set in + \reffile{texmf.cnf} or as an environment variable). + + This option exists so that the author using the restricted shell mode does + not have to list |mkdir| among the restricted shell mode commands (and it + is also safer than a plain |mkdir|). + + Memoize automatically uses this script to create the memo directory when + option \refmmz{extract} is given value \refmmz{extract=perl} or + \refmmz{extract=python}. + \end{doc} + \begin{doc}{ + option={name=help, short name=h} + } + Show help. + \end{doc} + \begin{doc}{ + option={name=version, short name=V} + } + Show Memoize version. + \end{doc} + + Functionally, the Perl (|.pl|) and the Python (|.py|) version of the script + are almost equivalent. The minor differences, listed below, are mostly due + to the underlying PDF-processing library: + \hreftt{https://metacpan.org/pod/PDF::API2}{PDF::API2} in Perl, and + \hreftt{https://pypi.org/project/pdfrw2/}{pdfrw2} in Python. + \begin{itemize} + \item The Python script is about twice as fast as the Perl script. However, + both scripts are very fast compared to the \hologo{TeX}-based extraction. + On my computer, extracting 160 externs out of a 400-page book takes 1.4s + with Python, 3.7s with Perl, and 65s with \hologo{TeX}. But even when + using \hologo{TeX}-based extraction, externalization using Memoize is + extremely fast compared to the \TikZ's externalization library. Adding + the regular compilation time of one minute to the above numbers, we arrive + at the maximum externalization time of about two minues, whereas my + estimate for the production of all 160 externs using \TikZ's + externalization would be an \emph{hour} or more. + \item The Python script cannot extract externs out of PDFs created without + stream compression, i.e.\ with \refcmd{pdfvariable} + \docref{pdfvar:compresslevel} set to |0|. + \item Occasionally, the Perl script crashes during extraction externs; see + section~\ref{sec:troubleshooting} for details. + \end{itemize} +\end{doc} + +\subsubsection{\texorpdfstring{\hologo{TeX}}{TeX}-based extraction} +\label{sec:ref:extraction-tex} + +\begin{doc}{ + key={name=tex extraction command, par=\meta{system command}, + desc={no default, initially |pdftex|}}, + key={name=tex extraction options, par=\meta{options}, + desc={no default, initially: see below}}, + key={name=tex extraction script, par=\meta{\hologo{TeX} code}, + desc={no default, initially: see below}}, + } + \yadocset{ + before/.style={label prefix=cmd:te}, + index annotation={defined at \hologo{TeX} extraction}, + } + + Together, these keys determine the system call used for invoking the + \hologo{TeX}-based extraction script, \refscript{memoize-extract-one.tex}. + (They were initialized using \pkg{pgfkeys} handler |.initial|, so their + values may be modified by handlers |.prefix|, |.append|, etc.) + + Memoize uses the resulting system call string at the following occasions. + First, it executes it, once for each new extern in the \dmmz file, during the + internal extraction, i.e.\ when it is loaded with package option + \refmmz{extract}|=|\refmmz{extract=tex}. Second, it uses it to construct + record files of types \refmmz{record=sh}, \refmmz{record=bat} and + \refmmz{record=makefile} when recording of these types is requested. + + Key \refmmz{tex extraction command} sets the \hologo{TeX} binary used for + \hologo{TeX}-based internal extraction. By default, the \hologo{pdfTeX} + engine |pdftex| is used; other sensible values for this key are |luatex| and + |xetex|, or the program name including the path. Note that shell escape mode + must be configured appropriately, and that + \refscript{memoize-extract-one.tex} must be compiled with the + \hologo{plainTeX} format. + + The value of key \refmmz{tex extraction options} is passed as options to the + \hologo{plainTeX} binary. As shown in the initial value in the frame below, + it may use the temporary macro \docaux{cmd}{externbasepath}, which expands to + the path to the extern without the |.pdf| suffix. This macro is available + during internal \hologo{TeX}-based extraction and during the execution of + \refmmz[show keypath]{record/record type/new extern} key for and \meta{record + type}. + + \makeexcerpt{tex-extraction-options} + \tcbinputexample[.tex][.excerpt]{% + listing only, one file, no attachment, title={The initial value of + \refmmz{tex extraction options}}, + } + + Key \refmmz{tex extraction script} defines the command-line script executed + to extract the extern. The default value, shown in the frame below, invokes + \refscript{memoize-extract-one.tex} after setting its parameter macros. + Temporary macros \docAux{cmd={name=pagenumber}, comma, cmd={name=expectedwidth}, + and, cmd={name={expectedheight}}} are defined at the same occasions as + \refcmd{te:externbasepath} above, i.e.\ during internal \hologo{TeX}-based + extraction and during the execution of a \refmmz{record/record type/new + extern} key. The initial value requests the extern to be of the same version as + the main document, if possible;\footnote{As far as I know, it is impossible + to access the version of the PDF being produced in \hologo{XeTeX}, i.e.\ + there are no registers \docref{reg:pdfmajorversion} and + \docref{reg:pdfminorversion}. To request production of a specific version of + PDF, \hologo{XeTeX} must be invoked by with command-line option + \code{-output-driver 'xdvipdfmx -V $N$'}.} note that Memoize defines + \docref{reg:pdfmajorversion} and \docref{reg:pdfminorversion} in \hologo{LuaTeX}. + + \makeexcerpt{tex-extraction-script} + \tcbinputexample[.tex][.excerpt]{% + listing only, one file, title=The initial value of \refmmz{tex extraction + script}, no attachment} + + As the value of \refmmz{tex extraction script} is fully expanded when used, + the initial value shown above must prevent the expansion of much code. + Furthermore, the initial value varies with the \hologo{TeX} format, as + indicated by the |.dtx| guards in the definition of + \refcmd{meo:warningtemplate}. +\end{doc} + +\begin{doc}{ + script={ + head prefix={% + (\texttt{pdf}\alt\texttt{lua}\alt\texttt{xe})\texttt{tex -jobname} + \meta{extern filename} + \texttt{"}\meta{parameters} + \cs{input}\texttt{\textbraceleft} + }, + name=memoize-extract-one.tex, + head infix=\texttt{\textbraceright"}, + }, + } + Compiling \refscript{memoize-extract-one.tex} with \hologo{plainTeX} + produces an extern file containing a single (extern) page extracted from the + document PDF. + + Memoize invokes this script, once for each new extern appearing in the \dmmz + file, when loaded with package option + \refmmz{extract}|=|\refmmz{extract=tex}. + + The desired \meta{extern filename} is given as the value of option |-jobname| + of the \hologo{TeX} binary. To set the extraction \meta{parameters}, define + the following macros before |\input|ting the file: + \yadocset{ + index annotation=option of \texttt{memoize-extract-one.tex}, + before/.style={head prefix=\cs{def}, label prefix=cmd:meo}, + } + \begin{doc}{cmd={name=fromdocument, parameters=\marg{document pdf filename}}} + Defining this macro sets the filename of the PDF which the externs will be + extracted from. The filename is relative to the working directory. + \end{doc} + \begin{doc}{cmd={name=pagenumber, parameters=\marg{number}}} + Defining this macro sets the number of the page to extract. The first page + has number 1. + \end{doc} + \begin{doc}{ + cmd={name=expectedwidth, parameters=\marg{dimension}, desc=optional}, + cmd={name=expectedheight, parameters=\marg{dimension}, desc=optional}, + } + Defining these macros sets the expected width and height of the extracted + page. + + To guard against extracting a wrong page, the dimensions of the extracted + page are compared against the expected width and height. If the size check + fails,\footnote{The match need not be exact, see + footnote~\ref{fn:tolerance}.} the resulting extern PDF is empty (which + counts as non-existent when Memoize checks for its presence when it + attempts to utilize it), and a warning message (formatted via + \refcmd{meo:warningtemplate}) is printed to the log file, if logging was + requested via \refcmd{meo:logfile}. + + If any of these macros is undefined, the size check will be skipped. + \end{doc} + \begin{doc}{cmd={name=logfile, parameters=\marg{filename}, desc=optional}} + Defining this macro sets the name of the log file. If not defined, no log + file will be produced. + + The log file is intended to be used when the script is invoked from an + outer \hologo{TeX} compilation. In particular, it is intended to be + |\input| by that compilation to see whether the extraction was successful. + Upon a failed size check, it will contain a warning (formatted by + \refcmd{meo:warningtemplate}, if that macro is defined). The log file ends + with |\endinput| to signal that extraction actually took place. + \end{doc} + \begin{doc}{cmd={name=warningtemplate, parameters=\marg{code}, desc=optional}} + Defining this macro determines how to log the warning message in the case + of a failed size check. The macro should expand to a \hologo{TeX} + format-specific warning message code containing the warning text given in + \docAux{cmd={name=warningtext, label prefix=cmd:meo, into + index=false}}.\footnote{Macro \refcmd{meo:warningtemplate} is passed + the warning text by a macro rather than a formal parameter to avoid + category code problems with the parameter character when setting key + \refmmz{tex extraction script}.} + + While the script formats the warning message \emph{text} on its own (``I + refuse to extract page \dots''), the warning message is not written into + the log unadorned. The log file is intended to be \cs{input} by the outer + \hologo{TeX} compilation, and the idea is that inputting it should yield a + warning in that compilation (in the case of a failed size + check). Therefore, the content of the log file must contain an invocation + of the command used to produce warning messages in the \hologo{TeX} format + used by the outer compilation. + + For example, when this script is invoked from within a \hologo{LaTeX} + compilation, it makes sense to define something like + |\def\warningtemplate{\PackageWarning{memoize}{\warningtext}}|. + \end{doc} + \begin{doc}{cmd={name=force, + parameters=\bracestt{\texttt{true}\Alt\texttt{false}}, desc=optional}} + If this macro is defined to |true|, extern extraction will be carried out + even if the size-check fails. The failure will still be logged. + \end{doc} + \begin{doc}{ + cmd={name=mmzpdfmajorversion, parameters=\marg{number}, desc=optional}, + cmd={name=mmzpdfminorversion, parameters=\marg{number}, desc=optional}, + } + Defining (one or both of) these macros requests that the extern PDF be + produced with the given major\slash minor PDF version, i.e.\ the extraction + script will set registers \docref{reg:pdfmajorversion} and + \docref{reg:pdfminorversion}. + \end{doc} + + After extracting the extern, the script will end the compilation, i.e.\ + intentionally, only one page documents can be produced. +\end{doc} + +\subsubsection{The clean-up scripts} +\label{sec:cleanup-scripts} + +\begin{doc}{ + script={name=memoize-clean.pl, par=[\meta{options}] [\meta{name}\texttt{.mmz} \dots]}, + script={name=memoize-clean.py, par=[\meta{options}] [\meta{name}\texttt{.mmz} \dots]}, + } + This script removes memo and extern files whose filenames start with + \meta{path prefix}es mentioned in the given \dmmz files or by the + \refscript{memoize-clean.pl--prefix} option. Unless option + \refscript{memoize-clean.pl--all} is given, the script only deletes the + \emph{stale} files, i.e.\ the files not mentioned in any of the given \dmmz + files. + + A \meta{path prefix} of a memo or an extern is what was set by key + \refmmz{path}, or more commonly, one of the shortcut keys \refmmz{memo dir} + and \refmmz{no memo dir}; see section~\ref{sec:ref:dirs} for details on the + form of a memo/extern filename. + + In detail, the script scans the given \dmmz files for occurrences of + \refcmd{mmzPrefix}, and adds their \meta{path prefix} arguments to the list + of prefixes given on the command line by option + \refscript{memoize-clean.pl--prefix}; a \meta{path prefix} occurring in some + \dmmz file is interpreted relatively to the location of the \dmmz file. The + script removes all files whose full pathname (relative to the current + directory) matches pattern \meta{path + prefix}\meta{md5sum}(|-|\meta{md5sum})(|.memo|\alt(|-|$N$)|.pdf|\alt|.log|),% + \footnote{The |.log| files are produced by the \hologo{TeX}-based extraction + script.} except those which occur as the \meta{filename} argument to one + of \refcmd{mmzUsedCMemo}, \refcmd{mmzUsedCCMemo}, \refcmd{mmzUsedExtern}, + \refcmd{mmzNewCMemo}, \refcmd{mmzNewCCMemo} and \refcmd{mmzNewExtern} in one + of the \dmmz files. + + The script is fairly paranoid. It refuses to delete anything if a \dmmz file + is malformed in any way (but not if it doesn't exist or is completely empty, + which facilitates its usage in clean-up scripts), or if it would remove a + file not residing under the current directory. Before removing the files, it + lists the files to be removed and asks for confirmation. + + Functionally, the Perl (|.pl|) and the Python (|.py|) version are completely + equivalent. + + \yadocset{ + of=script:memoize-clean.pl, + override/.style={ + index annotation={option of {% + \hypercolor{link}{gray}% + \hyperref[script:memoize-clean.pl]{\texttt{memoize-clean}}% + }}, + }, + } + \begin{doc}{ + option={name=prefix, short name=p, par=\meta{path prefix}} + } + Add \meta{path prefix} to the list of prefixes; the given prefix is + relative to the current directory. This option may be given multiple + times. + \end{doc} + \begin{doc}{ + option={name=all, short name=a} + } + When given this option, the script removes \emph{all} memos and externs + belonging to the document, not just the stale ones, i.e.\ it effectively + ignores the occurences of \refcmd{mmzUsedCMemo} and friends in the \dmmz + file. + \end{doc} + \begin{doc}{ + option={name=yes, short name=y} + } + When given this option, the script does not ask for confirmation before + removing the files. + \end{doc} + \begin{doc}{ + option={name=quiet, short name=q} + } + Normally, the script prints what it is doing to the standard output; in + particular, it prints out the filename of each file as it is deleting it. + This option disables this behaviour. + \end{doc} + \begin{doc}{ + option={name=help, short name=h} + } + Show help. + \end{doc} + \begin{doc}{ + option={name=version, short name=V} + } + Show Memoize version. + \end{doc} +\end{doc} + +\subsubsection{Record files} +\label{sec:ref:record-files} + +\begin{doc}{ + key={name=record, par=\marg{record type}, + desc={cumulative, initially \refmmz{record=mmz}, no default}}, + key={name=no record}, + } + Memoize records which externs were produced and used in the compilation, + producing a record file of every type found in the record-type list. These + keys add \meta{record type} to the record-type list, or clear this list. See + section~\ref{sec:record-files} for details. + + Note that passing an undefined \meta{record type} to this key will not yield + an error. + + Out of the box, the following \meta{record type}s are recognized: + \yadocset{of=key:/mmz/record} + \begin{doc}{value={name=mmz}} + This record type produces a \dmmz file recording new/used + externs/c-memos/cc-memos and changes in the \refmmz{path} prefix to these + files; see section~\ref{sec:.mmz} for details. + + The produced file is named \docAux{file={name=mmz, + name prefix=\meta{jobname}., + ref prefix=., + index prefix=., + }}. This name cannot be changed. + + The \dmmz file is a \hologo{TeX} file, but uses only a simple subset of + the \hologo{TeX} syntax, to be easily parsable by the external scripts such + as \refscript{memoize-extract.pl}. Each line of the file consists of a + (possibly commented) invocation of one of the commands listed below; the + final line is |\endinput|. The \meta{path prefix} below consists of the + path to memos/externs and the immutable \refmmzpath{prefix} of their filename. + \begin{doc}{ + cmd={name=mmzUsedCMemo, par=\marg{filename}}, + cmd={name=mmzUsedCCMemo, par=\marg{filename}}, + cmd={name=mmzUsedExtern, par=\marg{filename}}, + } + Record that the (c)c-memo or extern residing in file \meta{filename} was + utilized. + \end{doc} + \begin{doc}{ + cmd={name=mmzNewCMemo, par=\marg{filename}}, + cmd={name=mmzNewCCMemo, par=\marg{filename}}, + } + Record that a new (c)c-memo residing in file \meta{filename} was + produced. + \end{doc} + \begin{doc}{cmd={name=mmzNewExtern, par=\marg{filename}\marg{page number}% + \marg{expected width}\marg{expected height}}} + Record that a new extern was produced and dumped as page \meta{page + number} into the document, that it should be extracted into file + \meta{filename}, and that it should be \meta{expected width} wide and + \meta{expected height} high (modulo tolerance of |0.01pt|, see + footnote~\ref{fn:tolerance}), where the height is the total height + comprising both \hologo{TeX} height and depth. + \end{doc} + \begin{doc}{cmd={name=mmzPrefix, par=\marg{path prefix}}} + Record that the \refmmz{path} prefix of memo and extern files was + changed. + \end{doc} + \end{doc} + \begin{doc}{value={name=makefile}} + This record type produces a makefile which, when processed by the |make| + utility, triggers \hologo{TeX}-based extraction of the new externs. + \begin{doc}{ + key={name=makefile, par=\marg{filename}, desc={no default, + initially \texttt{memoize-extract.\jobname.makefile}}} + } + Use this key to change the filename of the produced makefile. + \end{doc} + \end{doc} + \begin{doc}{value={name=sh}, value={name=bat}} + These record types produce a shell script which, when executed, triggers + \hologo{TeX}-based extraction of the new externs. + + Use \refmmz{record=sh} on Unix-like systems, and \refmmz{record=bat} on + Windows. + + \begin{doc}{ + key={name=sh, par=\marg{filename}, desc={no default, + initially \texttt{memoize-extract.\jobname.sh}}}, + key={name=bat, par=\marg{filename}, desc={no default, + initially \texttt{memoize-extract.\jobname.bat}}} + } + Use these keys to change the filename of the produced shell script. + \end{doc} + \end{doc} +\end{doc} + +\begin{doc}{ + desc=definable, + keypath=/mmz/record/\meta{record type}, + keypath label=/mmz/record/record type, + name prefix={\meta{record type}/}, ref prefix=, + index annotation={key in \texttt{/mmz/\meta{record type}}}, + key={name=begin}, + key={name=prefix, par=\marg{path prefix}}, + key={name=new extern, par=\marg{filename}}, + key={name=new cmemo, par=\marg{filename}}, + key={name=new ccmemo, par=\marg{filename}}, + key={name=used extern, par=\marg{filename}}, + key={name=used cmemo, par=\marg{filename}}, + key={name=used ccmemo, par=\marg{filename}}, + key={name=end}, + } + A new record type can be implemented by defining these keys in keypath + \docAux{key path={name=mmz/record/\meta{record type}, label=mmz/record/record + type}} (using the standard \pkg{pgfkeys} handlers such as |.code| and + |.style|). The keys are invoked by Memoize where appropriate if recording + for the defined type is activated by \refmmz{record}|=|\meta{record type}, + just as for the predefined types. Only those keys which are required for + implementing the desired functionality need to be defined. + + The following macros are available during the execution of key + \refmmz{record/record type/new extern}: + \yadocset{before/.style={label prefix=cmd:ne}, + index annotation=defined at \refmmz{record/record type/new extern}} + \begin{doc}{cmd={name=pagenumber}} + This macro holds the number of the extern page. + \end{doc} + \begin{doc}{ + cmd={name=expectedwidth}, + cmd={name=expectedheight}, + } + These macros hold the width and the height of the extern page. + \end{doc} + \begin{doc}{cmd={name=externbasepath}} + This macro holds the filename of the extern, minus the |.pdf| suffix (but + including the path leading to the extern). + \end{doc} +\end{doc} + + + +\subsection{Automemoization} +\label{sec:ref:advicememoization} + + +\subsubsection{Package Advice} +\label{sec:ref:advice} + +Package Advice is a namesake of \Emacs's Advice. As such, it implements a +generic framework for extending the functionality of selected commands and +environments. Each \emph{advised} command and environment is assigned a piece +of \emph{advice} --- a command which is executed instead of the advised command +and environment, and which may, or may not, invoke the original command or +environment during its execution. The package offers an elegant way of +declaring advice, setting up the conditions upon which the advised command will +actually be replaced by the advice, collecting the arguments of the advised +command and invoking it, and (de)activating the advice. + +Before the advising framework can be used, it must be installed into a selected +\pkg{pgfkeys} keypath (multiple installations into different keypaths are +allowed, even if they handle the same commands). Memoize installs the +framework into keypath \refkeypath{/mmz} and (primarily) uses it to +automatically memoize the results of compilation of selected commands and +environments. + +\begin{doc}{ + keypath={/handlers}, + key={name=.install advice, + sort index=install advice, + par=\marg{configuration keylist}, + }, + } + This key is a \pkg{pgfkeys} key handler (see \PGFmanual{87.3.5}) which + installs the advising framework into the keypath which it was invoked from + --- henceforth, the \meta{namespace}. + + For example, \code{\cs{pgfkeys}\bracestt{/my/\refkey{/handlers/.install + advice}}} installs the framework into keypath |/my|. + + Argument \meta{configuration keylist} may contain the following keys: + \yadocset{keypath=/advice/install} + \begin{doc}{key={ + name=setup key, + parameters=\marg{name}, + description={no default, initially \texttt{advice}}}, + } + This key determines the names of the user-interface keys used to setup + advice for commands and environments in \meta{namespace}. + + The keys whose names are determined by this key are the following: + \meta{name}, \code{\meta{name} csname}, \code{\meta{name} key}, + \code{\meta{name}'}, \code{\meta{name} csname'} and \code{\meta{name} + key'}. Memoize sets \refkey{/advice/install/setup key}|=auto|, and + thereby defines \refmmz{auto}, \refmmz{auto csname}, \refmmz{auto key}, + \refmmz{auto'}, \refmmz{auto csname'} and \refmmz{auto key'}. + \end{doc} + \begin{doc}{key={ + name=activation, + par=\meta{initial activation type}, + desc={no default, initially \texttt{immediate}} + }, + } + This key sets the \meta{initial activation type} for \meta{namespace}. + + At the end of the installation, the system will execute + \meta{namespace}|/|\refmmz{activation}|=|\meta{initial activation type}; + consequently, \meta{initial activation type} must be one of + \refmmz{activation=immediate} and \refmmz{activation=deferred}. In + Memoize, the \meta{initial activation type} is + \refmmz{activation=deferred}. + + Setting the \refmmz{activation} type during the installation only matters + in \hologo{LaTeX}, where the installation ends by advising \refcmd{begin} + to implement advising of environments. + \end{doc} + + \begin{tcolorbox}[warning] + Writing the documentation for Advice, I was faced with a dilemma. Should + the documentation reflect the fact that the full names of keys defined by + the package depend on the installed instance of the framework, in + particular on \meta{namespace} and \meta{setup key}? For example, should + the reference headers contain things like \meta{namespace}|/activate| and + \meta{namespace}|/|\meta{setup key} |csname|? In my opinion, this would + make the reference hard to read, so I decided to have the reference headers + refer to the Advice keys of the Memoize installation, where + \meta{namespace}=|/mmz| and \meta{setup key}=|auto|, resulting in + friendlier headers such as \refkeypath{/mmz}|/|\refmmz{activate} and + \refkeypath{/mmz}|/|\refmmz{auto csname}. (Consequently, it also made + sense to document Advice within the Memoize documentation.) + + The bottomline: if you're reading this section with a non-Memoize + installation in mind, you have to mentally replace any \refkeypath{/mmz} + and \refmmz{auto} in the reference headers with the \meta{namespace} and + the \meta{setup key} selected by that installation. + (Section~\ref{sec:ref:advice:memoization} is another matter. Keys + described there are only available in Memoize.) + \end{tcolorbox} + + In more detail, key handler \refkey{/handlers/.install advice} performs the + following actions (as explained in the box above, we assume that the + advising framework was installed into keypath \refkeypath{/mmz} with the + setup key named |auto|): + \begin{itemize} + \item \edef\origtolerance{\the\tolerance}\tolerance=1000 + It defines the following keys in keypath \refkeypath{/mmz}: + \refmmz{auto}, + \refmmz{auto csname}, + \refmmz{auto key}, + \refmmz{auto'}, + \refmmz{auto csname'}, + \refmmz{auto key'}, + \refmmz{activation}, + \refmmz{activate deferred}, + \refmmz{activate}, + \refmmz{deactivate}, + \refmmz{activate csname}, + \refmmz{deactivate csname}. + \refmmz{activate key}, + \refmmz{deactivate key}. + \refmmz{force activate}, + \refmmz{try activate}. + \item + It defines the following keys in keypath \refkeypath{/mmz/auto}: + \refmmzauto{run conditions}, + \refmmzauto{outer handler}, + \refmmzauto{bailout handler}, + \refmmzauto{collector}, + \refmmzauto{args}, + \refmmzauto{collector options}, + \refmmzauto{clear collector options}, + \refmmzauto{raw collector options}, + \refmmzauto{clear raw collector options}, + \refmmzauto{inner handler}, + \refmmzauto{options}, + \refmmzauto{clear options}, + \refmmzauto{reset}. + \item \tolerance\origtolerance\relax + It defines the |.unknown| key handler for \refkeypath{/mmz/auto}. + This handler appends any unknown keys (and their values) to + \refmmzauto{options}. + \item It executes \refmmz[show keypath]{activation}|=|\meta{initial + activation type}. + \item In \hologo{LaTeX}, it submits \refcmd{begin} to advising, thereby + enabling environment support in this format. Consequently, advising of + environments can switched off by writing \refmmz{deactivate}|=\begin|. + \end{itemize} +\end{doc} + +\paragraph*{The keys installed into keypath \metabf{namespace}} are used to +declare and (de)activate advice. In the documentation in this subsection, +we assume that \meta{namespace}=\refkeypath{/mmz} and that \meta{setup + key}=\refmmz{auto}. In particular, this also applies to the reference +headers. + +\begin{doc}{ + key={name=activation, par=\docAux{of=key:/mmz/activation, value={name=immediate}, + text=\Alt, value={name=deferred}}, desc={style, no default}}, + key={name=activate deferred, desc={style}}, + } + Key \refmmz{activation} selects the activation regime. Under the + \refmmz{activation=immediate} regime, keys \refmmz{activate}, + \refmmz{deactivate}, \refmmz{force activate} and \refmmz{try activate} behave + as described in their documentation below. Under the + \refmmz{activation=deferred} regime, however, those keys are not executed; + rather, their invocations are appended to style \refmmz{activate deferred}. + For example, writing \refmmz{activate}|=\foo| in the deferred activation + regime appends \refmmz{activate}|=\foo| to \refmmz{activate deferred}. It is + up to the user if and when to execute the keys collected in \refmmz{activate + deferred}; see the documentation of \refmmz{manual} to learn what Memoize + does with the contents of this style. +\end{doc} + + +\begin{doc}{easy, + par=\marg{list of commands and/or environments}, + desc={style}, + key={name=activate}, + key={name=deactivate}, + } + These keys activate or deactivate the advice for the given commands and + environments. When the advice is activated, it replaces the advised command; + when it is deactivated, the command is reverted to its original definition. + + In Memoize, these keys are most commonly used to activate or deactivate + automemoization for the given commands or environments. For example, write + \refmmz{deactivate}|={\tikz,tikzpicture}| to deactivate automemoization of + \TikZ pictures (which is declared and active by default). The curly braces + may be omitted if the list contains a single command or environment, e.g.\ + \refmmz{deactivate}|=\tikz| or \refmmz{deactivate}|=tikzpicture|. + + (De)activation of a piece of advice is completely orthogonal to its declaration with + \refmmz{auto}. For example, there is no need to deactivate a command before + redeclaring its advice, and reactivate it afterwards. A command may be + activated even before declaring its advice --- however, the command itself + must be defined at the time of activation. + + As the advice is normally automatically activated upon declaration with + \refmmz{auto}, explicit activation is rarely needed, but see \refmmz{auto'}. + The effect of these keys under the deffered activation regime is described in + \refmmz{activation}. + + Note that I sometimes speak of (de)activating a command, and sometimes of + (de)activating its advice. I mean the same thing. +\end{doc} + +\begin{doc}{ + par=\marg{control sequence name}, + desc={style}, + key={name=activate csname}, + key={name=deactivate csname}, + } + These keys activate and deactivate a command given by its \meta{control + sequence name}; for example, \refmmz{activate csname}|=foo| is equivalent + to \refmmz{activate}|=\foo|. Note that unlike the regular \refmmz{activate} + and \refmmz{deactivate}, their |csname| variants only accept a single command + at a time (otherwise, including a comma in the command name would be + impossible). +\end{doc} + +\begin{doc}{ + par=\marg{list of full key names}, + desc={style}, + key={name=activate key}, + key={name=deactivate key}, + } + These keys activate and deactivate |pgfkeys| keys. Note that \emph{full} key + names must be given, i.e.\ the names must include the keypath. + + Under the hood, these keys merely execute \refmmz{activate} and + \refmmz{deactivate} on the internal macros corresponding to the given keys. +\end{doc} + +\begin{doc}{ + key={name=try activate, conditional=false}, + } + When this conditional is set to true, \refmmz{activate} will not yield an + error if the advice is already activated, and \refmmz{deactivate} will not + yield an error if the advice is not yet activated. + + This key applies to the next, and only to the next, invocation of key + \refmmz{activate} or \refmmz{deactivate}, i.e.\ it is reset back to |false| + after invoking \refmmz{activate} or \refmmz{deactivate}. +\end{doc} + +\begin{doc}{ + key={name=force activate, conditional=false}, + } + When this conditional is set to true, \refmmz{activate} will activate even a + previously activated command, provided that, additionally, the command has + been redefined since the prior activation. + + In more detail, the original definition of the advised command is saved upon + activation (to provide the possibility of both deactivation and the usage of + the original command by the handler). Consequently, activation of an already + activated command would result in the saved original definition being + overwritten by the redefinition made during the first activation. However, + if the handled command was meanwhile redefined by a third party, reactivation + makes sense, under the assumption that the former original definition is + obsolete and should be replaced by the (third party) redefinition. As a + safeguard, however, \refmmz{activate} requires such reactivation to be + explicitly requested using conditional \refmmz{force activate}.\footnote{A + potential problem, not (yet) addressed, is that the third party might be + another incarnation of the advising framework. In this case, forced + reactivation will result in the loss of the original command and a circular + dependency between the two pieces of advice.} + + This key applies to the next, and only to the next, invocation of key + \refmmz{activate}, i.e.\ it is reset back to |false| after invoking + \refmmz{activate}. This key does not apply to \refmmz{deactivate}. +\end{doc} + +\begin{doc}{easy, + key={name=auto, par=\marg{command or environment}{\marg{keylist}}, desc=style}} + + This key sets up the advice for the given command or environment, or updates + the configuration of an existing piece of advice. + + In Memoize, this key is most commonly used to submit a command or environment + to automemoization. For an environment (say, |bar|), it suffices to write + \refmmz{auto}|=|\bracestt{bar}\bracestt{\refmmzauto{memoize}}; for a command, + we usually need to include its argument specification: + \refmmz{auto}|=\foo|\bracestt{\refmmzauto{memoize}, + \refmmzauto{args}=\bracestt{...}}. Another common usage is to prevent + memoization during the execution of a command or environment: + \refmmz{auto}|=|\bracestt{bar}\bracestt{\refmmzauto{nomemoize}}. For + details, see sections~\ref{sec:tut:automemoization}, + \ref{sec:tut:working-on-a-picture} and~\ref{sec:tut:verbatim}. + + The advice is configured by the given \meta{keylist}, which is executed with + the default keypath set to \docaux{key path}{mmz/auto}. Any unknown keys in + \meta{keylist} are passed on to key \refmmzauto{options}; for example, a + plain \refmmz{verbatim} or \refmmz{padding}|=2in| have the same effect as + \refmmzauto{options}|=|\refmmz{verbatim} or + \code{\refmmzauto{options}=\braces{\refmmz{padding}=2in}}. + + This key automatically activates the declared advice, unless it is already + activated; under the deferred activation regime, the automatic activation is + deferred as well. Use variant \refmmz{auto'} when you don't want to + automatically activate the advice. + + When this key is used on a command or environment with an existing piece of advice, + the advice is merely updated. This makes it easy to, for example, + temporarily switch to verbatim collection of an environment in Memoize: + \refmmz{auto}|=|\bracestt{tcolorbox}\braces{\refmmz{verbatim}}. Use key + \refmmzauto{reset} to setup the advice from scratch: + \refmmz{auto}|=|\bracestt{...}\bracestt{\refmmzauto{reset}, ...}. + + A piece of advice consists of several interlocked components, declared by keys + residing in path \refkeypath{/mmz/auto}: \refmmzauto{run conditions}, + \refmmzauto{bailout handler}, \refmmzauto{outer handler}, + \refmmzauto{collector} and \refmmzauto{inner handler}. During the execution + of the advice, these components are available through the following macros: + \refcmd{AdviceRunConditions}, \refcmd{AdviceBailoutHandler}, + \refcmd{AdviceOuterHandler}, \refcmd{AdviceCollector} and + \refcmd{AdviceInnerHandler}. These macros are also defined during setup, and + it is possible to change the configuration by modifying them directly; in + that case, it likely also makes sense to use the low-level variant of this + key, macro \refcmd{AdviceSetup}. + + Control sequences used in the advice components do not need to be defined at + the time of invoking key \refmmz{auto}, or activating the advice; they must + only be defined at the time the advice is actually executed. It is thus + perfectly fine to declare \refmmzauto{inner handler}|=\myinnerhandler| before + defining |\myinnerhandler|, or to redefine |\myinnerhandler| between the + invocations of the advised command. + + This key configures not only the components, but also the options of the + advice. These options are set by keys \refmmzauto{args}, + \refmmzauto{collector options}, \refmmzauto{raw collector options} and + \refmmzauto{options}. Whether these options are used or not depends on the + advice components. (Same as the components, the options have their + corresponding low-level macros: \refcmd{AdviceArgs}, + \refcmd{AdviceCollectorOptions}, \refcmd{AdviceRawCollectorOptions} and + \refcmd{AdviceOptions}.) + + Parameter symbols (i.e.\ |#|) are not allowed in advice settings. + + A command or environment may be submitted to several instances of the + advising framework, i.e.\ instances installed under different keypaths. The + effect of such chained advice depends on the order of activation. If advice + $A$ is activated before advice $B$, it will also be applied before $B$. + + The advice setup takes place in a group. Use key \refmmzauto{after setup} to + execute code outside this group. + + In general, the name of this key equals whatever was submitted to + \refkey{/advice/install/setup key} during the installation of the advising + framework via \refkey{/handlers/.install advice}. +\end{doc} + +\begin{doc}{ + key={name=auto csname, par=\marg{control sequence name}{\marg{keylist}}, desc=style} + } + This key is a variant of \refmmz{auto}, but with the command of the first + argument given as a control sequence name, i.e.\ \refmmz{auto + csname}|={foo}{...}| is equivalent to \refmmz{auto}|=\foo{...}|. +\end{doc} + +\begin{doc}{ + key={name=auto key, par=\marg{full key}{\marg{keylist}}, desc=style}, + } + This key is a variant of \refmmz{auto}, but it works with \pkg{pgfkeys} keys. + The first argument should be a \meta{full key} like |/tcb/float|, i.e.\ it + must consist of both the keypath and the keyname. + + This key sets up advice for the internal command corresponding to the given + \meta{full key}, and also properly initializes the collector, so that + \refmmzauto{inner handler} will ``just work.'' +\end{doc} + +\begin{doc}{ + key={name=auto', par=\marg{command or environment}{\marg{keylist}}, desc=style}, + key={name=auto csname', par=\marg{control sequence name}{\marg{keylist}}, desc=style}, + key={name=auto key', par=\marg{full key}{\marg{keylist}}, desc=style}, + } + These keys are variants of \refmmz{auto}, \refmmz{auto csname} and + \refmmz{auto key} which do not attempt to activate the command after setting + it up. +\end{doc} + +\begin{doc}{ + cmd={ + name=AdviceSetup, + par=\marg{namespace}\marg{command or environment}{\marg{setup code}} + }} + This macro is the low-level variant of key \refmmz{auto}. The differences + between the two are the following: + \begin{itemize} + \item An invocation of the macro must provide the namespace (i.e.\ the + installation keypath) as the first argument. + \item There is no automatic activation at the end of the setup. + \item The final argument should not be a keylist (of keys belonging to + \refkeypath{/mmz/auto}) but \hologo{TeX} code adjusting the contents of the + settings macros \refcmd{AdviceRunConditions}, \refcmd{AdviceBailoutHandler}, + \refcmd{AdviceOuterHandler}, etc. For the full list of available macros, see + the documentation of their corresponding keys below; the setting macros are + mentioned at the end of each entry. + \end{itemize} +\end{doc} + +\begin{doc}{ + cmd={name=AdviceTracingOn}, + cmd={name=AdviceTracingOff}, + } + Advice tracing is initially off. When it is on, Advice will show (on the + terminal and in the |.log| file) which advice components are executed, and + what arguments and options they have received. +\end{doc} + +\paragraph*{The keys installed into keypath \metabf{namespace}\texttt{/}\metabf{setup key}} +are used to configure advice. They may only occur within the second +argument of the setup key. In the documentation in this subsection, we assume +that \meta{namespace}=\refkeypath{/mmz} and that \meta{setup + key}=\refmmz{auto}. In particular, this also applies to the reference +headers. + +\begingroup +\yadocset{keypath=/mmz/auto} + +\begin{doc}{% + key={name=run conditions, par=\meta{\hologo{TeX} code}, + desc=initially and default: \refcmd{AdviceRuntrue}}, + } + + This key declares the \meta{control sequence} as the run conditions component + of the advice. + + The run conditions macro is executed at the very start of the advice. Its + function is to decide whether we should proceed to advise the command by + executing the outer handler, or execute the original command (after invoking + the bailout handler). + + The run conditions macro should take no arguments. If it determines that the + run conditions are satisfied, it should set the \hologo{TeX} conditional + \docaux{cmd}{ifAdviceRun} to true by executing \docaux{cmd}{AdviceRuntrue}. + There is no need to execute \docaux{cmd}{AdviceRunfalse} when the run + conditions are not satisfied. + + Initially, the run conditions are set to \refcmd{AdviceRuntrue}, translating to + ``always run.'' For two non-trivial examples, see \refmmzauto{run if + memoization is possible} and \refmmzauto{run if memoizing}. Executing this + key without a value restores it to the initial value. + + During advising and advice setup, the run conditions of the advised command + are accessible through \docaux{cmd}{AdviceRunConditions}, a parameterless + macro expanding to the given \meta{\hologo{TeX} code}. +\end{doc} + +\begin{doc}{% + key={name=bailout handler, par=\meta{\hologo{TeX} code}, + desc=initially and default: \cs{relax}}, + } + + This key declares the \meta{\hologo{TeX} code} as the bailout handler + component of the advice. + + The bailout handler is executed when the run conditions are not met, just prior + to executing the original definition of the advised command. The bailout + handler should take no arguments. + + The initial bailout handler, |\relax|, does nothing. Memoize defines and + uses a bailout handler which clears the next-options. Executing this key + without a value restores it to the initial value. + + During advising and advice setup, the bailout handler of the handled command is + accessible through \docaux{cmd}{AdviceBailoutHandler}, a parameterless macro + expanding to the given \meta{\hologo{TeX} code}. +\end{doc} + +\begin{doc}{ + key={name=outer handler,par=\meta{\hologo{TeX} code}, + desc=initially and default: see below}, + } + + This key declares the \meta{\hologo{TeX} code} as the outer handler component + of the advice. + + The outer handler can be safely imagined as the command which replaces the + handled command. This also holds for handled environments, but with a + caveat: for a \hologo{plainTeX} or \hologo{ConTeXt} environment |foo|, the + outer handler replaces |\foo| and |\startfoo|, respectively; in the case of a + \hologo{LaTeX} environment, it replaces |\begin{foo}|.%] + + The outer handler is the first component which has the opportunity to inspect + the arguments given to the handled command. It is invoked just in front of + these arguments (which are, in case \hologo{TeX} hasn't seen them yet, + untokenized), and while it is expected that the advice will consume + the same arguments as the advised command itself would, how precisely that + happens may vary from situation to situation. In particular, the argument + structure of the outer handler is not prescribed. + + In fact, the outer handler has complete control over the remainder of the + advising process. In situations where advising requires knowledge of the + advised command's arguments as a whole, the outer handler executes the + collector, which in turn invokes the inner handler, which does the real work; + see \refmmzauto{memoize} for the usage case which inspired this design. + Sometimes, however, it is the outer handler which does the real work (and + there is thus no inner handler). This is the case in situations when the + arguments of the handled command are irrelevant for the functioning of the + advice, or when the advice needs to inspect some individual argument of the + handled command; for examples of such situations, see \refmmzauto{abort} and + \refmmzauto{ref}. + + To reiterate the argument situation of the outer handler, it sees the + arguments of the handled command as they were given. The arguments are + \emph{not} collected before invoking the outer handler --- in fact, avoiding + the argument collection is the raison d'être of the outer handler! (In the case + of an advised environment, the environment body can be seen as an argument of + \pkg{xparse} type \docref{xparse:+}\docref{xparse:b}.) + + The outer handler (and any other component of the advice it invokes) has + access to the following auxiliary macros, defined by the framework: + \begin{itemize} + \item \tolerance 1000 the macros holding the configuration of the advised + command, as set up by \refmmz{auto}: \refcmd{AdviceRunConditions}, + \refcmd{AdviceBailoutHandler} and \refcmd{AdviceOuterHandler} are probably + useless, as they refer to components already invoked, but the remaining + components (\refcmd{AdviceCollector} and \refcmd{AdviceInnerHandler}) and + their options (\refcmd{AdviceArgs}, \refcmd{AdviceCollectorOptions}, + \refcmd{AdviceRawCollectorOptions} and \refcmd{AdviceOptions}) should be + commonly used. + \item the macros holding information about the namespace and the advised + command or environment: \refcmd{AdviceNamespace}, \refcmd{AdviceName}, + \refcmd{AdviceReplaced} and \refcmd{AdviceOriginal}. (Command + \refcmd{AdviceGetOriginal} might also be useful, although using + \refcmd{AdviceOriginal} will likely be more practical.) + \end{itemize} + + This key is initially set to an internal control sequence which merely + invokes the collector by executing \refcmd{AdviceCollector}; in other words, + the initial outer handler leaves all the work to the collector and the inner + handler. There is no need to specifically set up the outer handler when + using the inner handler. Executing this key without a value restores it to + the initial value. + + During advising and advice setup, the outer handler of the advised command is + accessible through \docaux{cmd}{AdviceOuterHandler}, a parameterless macro + expanding to the given \meta{\hologo{TeX} code}. +\end{doc} + +\begin{doc}{ + key={name=collector,par=\meta{\hologo{TeX} code}, + desc=initially and default: see below}, + } + + This key declares the \meta{\hologo{TeX} code} as the collector component of + the advice. + + The collector, if used, is invoked by the outer handler. It is invoked + immediately in front of the advised command's arguments (which are, in case + \hologo{TeX} hasn't seen them yet, untokenized), and its function is to + collect these arguments and pass them on, as a single argument, to the inner + handler. + + While this manual occasionally states that the initial argument collector is + \refcmd{CollectArguments} of package CollArgs, this is, if we're precise, + incorrect on two counts. For one, the initial collector is not a CollArgs + command, but a macro which acts as the ``bridge'' between Advice + and CollArgs. Second, the initial collector does not really invoke + \refcmd{CollectArguments}, but its cousin, \refcmd{CollectArgumentsRaw}, + which allows Advice (and Memoize) to fine tune its behaviour + using the fast low-level (``programmer interface'') commands rather than the + slower \pkg{pgfkeys} interface; clearly, the latter point also provides + raison d'être for \refmmzauto{raw collector options}. Summing up, this key + is initially set to an internal control sequence which compiles the settings + provided by \refmmzauto{args}, \refmmzauto{collector options} and + \refmmzauto{raw collector options} into an invocation of + \refcmd{CollectArgumentsRaw} of package CollArgs.\footnote{The initial + collector also sets the CollArgs' option \refcollargs{caller} to the + name of the advised command or environment.} Executing this key without a + value restores it to the initial value. + + The above-mentioned collector settings were clearly tailored to suit + \refcmd{CollectArgumentsRaw}. In general, a collector might or might not use + them, and if it does, it may interpret them in any way. For example, Advice + ships with a \refcmd{tikz} collector, \docaux{cmd}{mmzCollectTikZArguments}, which + ignores them completely, as it knows everything about the idiosyncrasies of + that command anyway. Incidentally, \refcmd{mmzCollectTikZArguments} becomes + available upon loading \reffile{advice-tikz.code.tex} (which Memoize does + automatically in the presence of \TikZ). + + The collector has access to the same auxiliary macros as the outer handler. + In particular, it will \emph{have} to use \refcmd{AdviceInnerHandler} (followed + by the braced collected arguments) to invoke the inner handler. + + During advising and advice setup, the collector of the advised command is + accessible through \docaux{cmd}{AdviceCollector}, a parameterless macro + expanding to the given \meta{\hologo{TeX} code}. +\end{doc} + +\begin{doc}{easy, + key={name=args,par=\meta{argument specification}, desc=initially and default: unset}, + } + + This key describes the \meta{argument specification} of the advised command. + + Assuming that the initial value of \refmmzauto{collector} has not been + modified, the given \meta{argument specification} is eventually interpreted + by command \refcmd{CollectArguments} of package CollArgs, which expects an + argument specification in the format specified by package \pkg{xparse}; the + format is summarized in the frame below for convenience, for details, see the + \pkg{xparse} manual. If the specification is not given, the initial collector + assumes that the advised command was defined using \refcmd{NewDocumentCommand} + (or similar) of package \pkg{xparse}, and will attempt to retrieve the argument + specification automatically via \refcmd{GetDocumentCommandArgSpec}. + + \begin{tcolorbox}[float, before float=\hfill, + title={The {\pkg[white]{xparse}} argument specification + (as understood by \refcmd[link color=white]{CollectArguments})}] + \begin{tabularx}{\linewidth}{>{\tt}lX} + \multicolumn{2}{l}{\rm\textbf{Mandatory argument types}}\\ + m&standard (a single token or multiple tokens in braces)\\ + r\meta{token$_1$}\meta{token$_2$}&delimited by + \meta{token$_1$} and \meta{token$_2$} \\ + v&verbatim, in the style of \cs{verb}\\ + b&the body of an environment\\ + [1ex]\multicolumn{2}{l}{\rm\textbf{Optional argument types}}\\ + o&in square brackets\\ + d\meta{token$_1$}\meta{token$_2$}&delimited by + \meta{token$_1$} and \meta{token$_2$}\\ + s&an optional star\\ + t\meta{token}&an optional \meta{token}\\ + e\marg{tokens}&a set of embellishments\\ + [1ex]\multicolumn{2}{l}{\rm\textbf{Weird argument types}}\\ + l&a mandatory argument until the first begin-group token\\ + u\marg{tokens}&\hologo{TeX}'s delimited argument\\ + g&an optional argument inside braces\\ + [1ex]\multicolumn{2}{l}{\rm\textbf{Modifiers}}\\ + +&allow the next argument to be long\\ + !&disallow spaces before arguments of type \docref{xparse:d} and \docref{xparse:t}\\ + >\marg{processor}&process the next argument\\ + [1ex]\multicolumn{2}{l}{\rm\textbf{CollArgs extensions}}\\ + \docref{xparse:b}\marg{name}&set the environment name for this environment\\ + \docref{xparse:amp}\marg{options}&apply CollArgs options to the next argument\\ + \docref{xparse:amp}\docref{xparse:amp}\marg{raw options}&apply raw CollArgs options to the next argument\\ + \end{tabularx} + + \smallskip + + \refcmd{CollectArguments} can grab an argument of any type in the + \refcollargs{verbatim} mode. + + As \refcmd{CollectArguments} does not use the arguments but only collects + them, it does not care about the default values of optional arguments. + Therefore, argument types with defaults (\docref{xparse:O}, + \docref{xparse:D} and \docref{xparse:R}) may be substituted by their + \texttt{-NoValue-} counterparts (\docref{xparse:o}, \docref{xparse:d} and + \docref{xparse:r}) and are therefore not included in the above table. + \end{tcolorbox} + + In general, however, an argument collector may this interpret this setting it + in any way it sees fit --- or not at all. For example, in Memoize the value + of \refmmzauto{args} is ignored for command \refcmd{tikz}, which requires a special + collector (\refcmd{mmzCollectTikZArguments}). + + When setting up advice for a \emph{command}, this key is initially + ``unset,'' i.e.\ it holds a special value indicating that the argument + specification is not provided. Note that this special value is not an empty + string --- \refmmzauto{args}|={}|, or simply \refmmzauto{args}|=|, indicates + a command which takes no arguments. During the execution of the advice, one + may use the \hologo{LaTeX}-style conditional + \docaux{cmd}{AdviceIfArgs}\marg{true branch}\marg{false branch} to test + whether the argument specification was provided. Executing this key without + a value restores it to the initial, unset value. + + When setting up the advice of an \emph{environment}, this key is + initialized to \docref{xparse:+}\docref{xparse:b} (a long environment body), + making it unnecessary to specify this value manually. Note that this holds + even for environments with arguments other that the environment body + ``argument'': those arguments will be caught as the start of the body even if + not explicitly specified. + + During advising and advice setup, the argument specification of the advised + command is accessible through \docaux{cmd}{AdviceArgs}, a parameterless macro + expanding to the given \meta{argument specification}. +\end{doc} + + +\begin{doc}{ + key={name=collector options, par=\marg{keylist}, + desc={cumulative, initially empty, value required}}, + key={name=raw collector options, par=\marg{code}, + desc={cumulative, initially empty, value required}}, + } + These keys append the given value to the list of user-friendly and raw + collector options, respectively. A comma is prefixed to the user-friendly + \meta{keylist} before appending it. + + Both kinds of collector options are intended to be used by the collector, + which may interpret them in any way it sees fit --- or not at all. The + initial collector, which invokes \refcmd{CollectArgumentsRaw} of package + CollArgs, passes both lists to this command, which interprets + \refmmzauto{collector options} as a user-friendly \pkg{pgfkeys} keylist + (which therefore requires a bit of processing) and \refmmzauto{raw collector + options} as plain \hologo{TeX} code (expecting it to contain only the + allowed, ``programmer's interface'' macros).\footnote{Clearly, + \refmmzauto{raw collector options} are why Advice deploys + \refcmd{CollectArgumentsRaw} rather than \refcmd{CollectArguments}. But + how does it then pass the user-friendly \refmmzauto{collector options} to + that command? It embeds them in \refcmd{collargsSet}.} The raw variant is + used internally by both Advice and Memoize, and may be used by a package + deploying the advising framework which wants to save a few processing cycles. + In CollArgs, the two kinds of options are functionally equivalent; both are + documented in section~\ref{sec:ref:collargs}. + + Initially, the list of collector options is empty, and for commands, so is + the list of raw collector options. For environments, however, the latter + list is initialized to set (the raw equivalent of) \refcollargs{environment} + to the environment name, and \refcollargs{end tag} to true. The rationale + for the latter is that the environment body containing the end tag (e.g.\ + |\end{foo}|) is nicely compatible with \refcmd{AdviceReplaced} (which equals +the begin tag, e.g.\ |\begin{foo}|) and \refcmd{AdviceOriginal} (which executes + the original definition of e.g.\ |\begin{foo}|). For example, thanks to + \refcollargs{end tag}, writing \refcmd{AdviceOriginal}|#1| in the inner + handler executes the original environment. Importantly, the original + environment can be executed without explicitly referring to the + environment's name, and with code that works not only for environments of + any \hologo{TeX} format, but is actually the same as the code which invokes + an original \emph{command}. Consequently, the same inner handler works for + both commands and environments, and in all \hologo{TeX} formats. + + Furthermore, the initial collector also sets option \refcollargs{caller} + to the name of the advised command or environment (however, + \refcollargs{caller} never appears in any of the collector options + lists; it is simply prefixed to them while constructing the invocation of + \refcmd{CollectArgumentsRaw}). And in Memoize, using keys + \refmmz{verbatim}, \refmmz{verb} or \refmmz{no verbatim} triggers the + addition of the cognominal \refcollargs{verbatim}, \refcollargs{verb} + or \refcollargs{no verbatim} among the collector options. + + Precious few CollArgs' options thus remain to be set by the author. For + memoization, the most likely candidates are \refcollargs{ignore nesting} + and \refcollargs{ignore other tags}, which could help deal with unusual + environments. Overriding the initial \refcollargs{end tag} by + \refcollargs{begin tag}, \refcollargs{end tag} and/or \refcollargs{tags} + might also be useful on occasion. + + During advising and advice setup, the \pkg{pgfkeys} and the raw collector + options of the advised command are accessible through + \docaux{cmd}{AdviceCollectorOptions} and + \docaux{cmd}{AdviceRawCollectorOptions}, both a parameterless macro expanding + to the given \meta{keylist} and \meta{code}, respectively. +\end{doc} + +\begin{doc}{ + key={name=clear collector options}, + key={name=clear raw collector options}, + } + These keys empty the list of user-friendly and raw collector options, + respectively. +\end{doc} + +\begin{doc}{ + key={name=inner handler, par=\meta{\hologo{TeX} code}, long description=0.5, + desc=initially and default: see below}, + } + + This key declares the \meta{\hologo{TeX} code} as the inner handler component + of the advice. + + The inner handler is intended to be used in situations which require + knowledge of the advised command's arguments as a whole. In such situations, + the outer handler will normally invoke the collector, which will in turn + execute the inner handler and provide it with a single (braced) argument, + containing the collected arguments of the advised command. See + \refmmzauto{memoize} for the usage case which inspired this design. + + The simplest example of an inner handler is a (single-parameter) macro which + does nothing. Surprisingly enough, such an inner handler could be useful. + Defining |\def\Gobble#1{}| and setting + \code{\refmmz{auto}=\cs{foo}\bracestt{\refmmzauto{inner handler}=\cs{Gobble}, + \refmmzauto{args}=\bracestt{...}}} with the argument structure + appropriate for |\foo| could be used to eradicate all invocations of |\foo| + from the document. + + The inner handler has access to all the macros available to the outer + handler, but given that most of them have already fulfilled their function, + only the following will likely be useful in the inner handler: + \refcmd{AdviceNamespace}, \refcmd{AdviceName}, \refcmd{AdviceReplaced}, + \refcmd{AdviceOriginal}, and \refcmd{AdviceOptions}. + + Because there is clearly no reasonable default for the inner handler, this key + is initially set to an internal control sequence producing an ``undefined + inner handler'' error. Note that it is not necessary to define a dummy inner + handler when handling is entirely performed by the outer handler, i.e.\ in + cases when the inner handler is not invoked. Executing this key without a + value restores it to the initial value. + + During advising and advice setup, the inner handler of the advised command is + accessible through \docaux{cmd}{AdviceInnerHandler}, a parameterless macro + expanding to the given \meta{\hologo{TeX} code}. +\end{doc} + +\begin{doc}{easy, + key={name=options,par=\marg{keylist}, + desc={cumulative, initially empty, value required}}, + key={name=clear options}, + } + + The first key appends the given \meta{keylist} to the list of advice options + (after prefixing it by a comma), and the second one empties this list. For a + \meta{key} undefined in keypath \refkeypath{/mmz/auto}, + \meta{key}|=|\meta{value} has the same effect as + \refmmzauto{options}|=|\bracestt{\meta{key}=\meta{value}}. + + In Memoize, the options set by this key are known as + \emph{auto-options} --- options which are applied (using \refcmd{mmzset}) at + every invocation of the advised command or environment. For example, the + \env{tcolorbox} environment of package \pkg{tcolorbox} is used extensively + for typesetting this manual, and I have submitted this environment to + automemoization. However, the \env{tcolorbox}es in this manual often include + code listings. To memoize such environments successfully, their bodies must + be grabbed verbatim. I have therefore submitted the \env{tcolorbox} + environment to automemoization like this: + \refmmz{auto}|={tcolorbox}|\bracestt{\refmmzauto{memoize}, + \refmmzauto{options}=\refmmz{verbatim}}; the simpler + \refmmz{auto}|={tcolorbox}|\bracestt{\refmmzauto{memoize}, \refmmz{verbatim}} + would work as well. + + In general, whether to use the options set by this key, and how, remains at + the sole discretion of the advice. Note that they might be used by either + the outer or the inner handler, or perhaps even the collector. + + During advising and advice setup, the options of the advised command are + accessible through \docaux{cmd}{AdviceOptions}, a parameterless macro expanding + to the given \meta{keylist}. +\end{doc} + +\begin{doc}{key={name=reset, desc=style}} + Executing this key restores all \refmmz{auto} keys to their initial values. + + Invoking \refmmz{auto} on the same command or environment again + \emph{updates} the advice configuration. Use this key to start from scratch. +\end{doc} + +\begin{doc}{key={name=after setup, desc={initially empty, cumulative}}} + The code given to this key will be executed after exiting the group opened by + \refmmz{auto}. The same effect may be achieved by appending to macro + \docaux{cmd}{AdviceAfterSetup}. + + For example, \refmmzauto{integrated driver} uses this key to declare a new + conditional. +\end{doc} + +\paragraph{Commands available during the execution of advice} + +With the exception of \refcmd{AdviceGetOriginal}, the commands listed below +only become available in the outer handler, and if that handler does nothing +funky, they should be available in the collector and the inner handler, as +well. However, once the advice yields control to foreign code, these macros +are not guaranteed to hold the expected values anymore, because the foreign +code might trigger another piece of advice. Consequently, these macros +should be expanded, once, before integrating them into arbitrary (non-advice) +code; in particular, this applies to \refcmd{AdviceOriginal}. + +\begin{doc}{cmd={name=AdviceNamespace}} + This macro holds the \meta{namespace}, i.e.\ the keypath which this instance + of the advising framework was installed into. +\end{doc} + +\begin{doc}{cmd={name=AdviceName}} + This macro holds the name of the advised command or environment, i.e.\ the + name which was used as the first argument to \refmmz{auto}. For a command, + this will be a control sequence, e.g.\ |\foo|; for environments (in any + \hologo{TeX} format), their name, e.g.\ |foo|. +\end{doc} + +\begin{doc}{cmd={name=AdviceReplaced}} + This macro holds the code which was replaced by the outer handler. For + commands, this will be the command itself, e.g.\ |\foo|, so + \refcmd{AdviceReplaced} will equal \refcmd{AdviceName}. For an environment + |foo|, \refcmd{AdviceReplaced} is set to |\begin{foo}| in \hologo{LaTeX}, + |\foo| in \hologo{plainTeX} and |\startfoo| in \hologo{ConTeXt}. +\end{doc} + +\begin{doc}{cmd={name=AdviceOriginal}} + This macro executes the original code of the advised command. + + This macro is defined as \refcmd{AdviceGetOriginal}\marg{namespace}\marg{name}, + and therefore acts as a shortcut for an explicit invocation of + \refcmd{AdviceGetOriginal}. When executing the original command directly from + the advice, one may safely write \refcmd{AdviceOriginal}. However, whenever + \refcmd{AdviceOriginal} is embedded in code which might contain other advised + commands, it should be pre-expanded, exactly once. +\end{doc} + +\begin{doc}{cmd={name=AdviceGetOriginal, par=\marg{namespace}\marg{control sequence}}} + This command invokes the original definition of the \meta{control sequence} + advised by the \meta{namespace} instantiation of Advice. It may be safely + used outside the advice, even if the advised command is not activated. + + For example, upon executing key |/ns/|\refmmz{auto}|=\foo{...}|, + |\AdviceGetOriginal{/ns}{\foo}| will recall the original definition of |\foo| + if |\foo| is activated, and simply execute |\foo| otherwise. + + The second argument of this command should \emph{not} be an environment name. + To execute the original environment |foo| in \hologo{TeX} or + \hologo{ConTeXt}, use \refcmd{AdviceGetOriginal} with the appropriate macro: + |\AdviceGetOriginal{/ns}{\foo}| or |\AdviceGetOriginal{/ns}{\startfoo}|. In + \hologo{LaTeX}, one should use |\AdviceGetOriginal{/ns}{\begin}{foo}|, which + executes the original \refcmd{begin} and provides it with the environment name. + + Within the advice, you will probably never have to use this command directly, + but will rather rely on the (plain or pre-expanded) \refcmd{AdviceOriginal}. + However, outside the advice, this command provides the only means to + access the original definition of an advised command. (Unlike the + commands described above, this command is available throughout the + document.) + + \begin{tcolorbox}[warning] + A typo in the invocation of this command may result in an infinite loop. + Assume that the advice for |\foo|, declared in namespace \refkeypath{/mmz}, + executes \refcmd{AdviceGetOriginal}|{/zzm}{\foo}|, which incorrectly refers + to the non-existing namespace |/zzm|, and that command |\foo| is activated. + Executing |\foo| will eventually execute + \refcmd{AdviceGetOriginal}|{/zzm}{\foo}|, which won't find the original + definition of |\foo| in the non-existing namespace |/zzm| and will thus + execute macro |\foo| (again), which, being advised, will lead to another + \refcmd{AdviceGetOriginal}|{/zzm}{\foo}|, etc. My advice is to define an + abbreviation like |\def\mmzAdviceGetOriginal{\AdviceGetOriginal{/mmz}}|. + And note that the name\-space is a full keypath, which begins with a slash + (|/|), but has no slash at the end. + \end{tcolorbox} +\end{doc} + +\paragraph{Support for specific packages} +At the moment, Advice only implements specific support for \TikZ, by defining a +\refmmzauto{collector} for command \refcmd{tikz}. + +\begin{doc}{ + cmd={name=AdviceCollectTikZArguments}, + } + This command collects the arguments in the format expected by \refcmd{tikz}, and + executes macro \refcmd{AdviceInnerHandler} with the collected arguments given + as a single braced argument. The collector supports both the group and the + semicolor invocation of |\tikz|, i.e.\ both |\tikz{...}| and |\tikz...;|. + + This command is only available upon |\input|ting file + \docaux{file}{advice-tikz.code.tex}. +\end{doc} + +\endgroup % keypath = /mmz/auto + +\subsubsection{Memoization-related additions to the advising framework} +\label{sec:ref:advice:memoization} + +In section~\ref{sec:ref:advice}, we have seen that Memoize installs the +advising framework into keypath \refkeypath{/mmz}, with setup key name +\refmmz{auto}. This populates keypaths \refkeypath{/mmz} and +\refkeypath{/mmz/auto} with various generic advice keys. However, Memoize +installs further advice\slash automemoization-related keys into these keypaths. +It is these keys which are described in this section.\footnote{One such key, + \refmmzauto{integrated driver}, is actually documented in + section~\ref{sec:ref:memoization}.} + +Therefore, in contrast to section~\ref{sec:ref:advice}, \refkeypath{/mmz} and +\refmmz{auto} have no secret generic meaning here, i.e.\ they should \emph{not} +be generalized to \meta{namespace} and \meta{setup key} of +\refkey{/handlers/.install advice}. + +\paragraph{Keys residing in \refkeypath{/mmz}} + +\begingroup +\setlength\textfloatsep{20pt plus 2pt minus 4pt}% back to the default + +\begin{doc}{easy, + key={name=manual, description={preamble-only,{ }}, conditional=false}, + } + When this conditional is set to true, no commands are \refmmz{activate}d at + the beginning of the document. The list of commands and environments advised + and activated out of the box can be found in Table~\ref{tab:advised-commands}. + + The auto-framework allows the activation to be deferred (see + \refmmz{activation} and \refkey{/handlers/.install advice}) but leaves it + open to the specific instance of the framework to use the deferred activation + commands as it sees fit. Normally, Memoize switches to immediate activation + at the end of the preamble (hook \refmmz{begindocument/before}) and issues + \refmmz{activate deferred} at the beginning of the document, more precisely + in hook \refmmz{begindocument/end} (afterwards, \refmmz{activate deferred} is + emptied). However, when \refmmz{manual} is in effect, the deferred + activation is suppressed (though it may be still carried out by the user by + executing \refmmz{activate deferred}). + + In \hologo{LaTeX}, \refmmz{manual} affects the (internal) activation of + \refcmd{begin} as well, which effectively deactivates handling of all environments. +\end{doc} + +\begin{table} + \centering + \begin{tabularx}{\linewidth}{llX} + \toprule + command/environment&handler¬es\\ + \midrule + \refcmd{begin}&custom&Only in \hologo{LaTeX}; declared by Advice.\\ + \refcmd{errmessage}&\refmmzauto{abort}&Not available in \hologo{LuaTeX}, + where better error-detection is implemented.\\ + \refenv{forest}&\refmmzauto{memoize}\\ + \refcmd{Forest}&\refmmzauto{memoize}\\ + \refcmd{index}&\refmmzauto{replicate}&The argument is expanded prior to replication.\\ + \refcmd{label}&custom&Globally appends \refcmd{mmzLabel}\marg{label key}\marg{current label} + to register \refcmd{mmzCCMemo}; \refmmzauto{run if memoizing}.\\ + \refcmd{pageref}&\refmmzauto{ref}\\ + \refcmd[into index=false]{pdfsavepos}&\refmmzauto{abort}&Not available in \hologo{LuaTeX}.\\ + \refcmd{pgfsys@getposition}&\refmmzauto{abort}&Available only in \TikZ is + loaded, it aborts memoization of a picture which gets accidentally marked as + ``remembered''.\\ + \refcmd{ref}&\refmmzauto{ref}\\ + \refcmd[short]{savepos}&\refmmzauto{abort}&Available only in \hologo{LuaTeX}.\\ + \refcmd{tikz}&\refmmzauto{memoize}\\ + \refenv{tikzpicture}&\refmmzauto{memoize}\\ + \bottomrule + \end{tabularx} + \caption{Commands advised by Memoize} + \label{tab:advised-commands} +\end{table} + +\begin{doc}{easy, + key={name=ignore spaces, conditional=false}, + } + Ignore any spaces following \emph{auto}memoized code. This key has no effect + for manual memoization, i.e.\ command \refcmd{mmz} and environment + \refenv{memoize}. + + It is common practice to conclude the definition of a command by \hologo{TeX} + primitive \refcmd{ignorespaces}, which consumes any following spaces, to + prevent unintended blank space after the command's invocation. Automemoizing + such a command disrupts this behaviour.\footnote{It is clear that + \refcmd{ignorespaces} is disrupted during utilization; in this case, the + original command, including the concluding \cs{ignorespaces}, is never even + executed. However, the disruption also occurs during memoization, and even + during regular compilation. In both cases, the memoized code is embedded + in some internal Memoize code. Therefore, the original \cs{ignorespaces} + does not occur directly in front of the rest of the document.} The + workaround is to use this key, normally as an option in the \refmmz{auto} + declaration; it will work both for automemoized macros and environments. +\end{doc} + +\paragraph{Keys residing in \refkeypath{/mmz/auto}} + +\begingroup +\yadocset{keypath=/mmz/auto} + +\begin{doc}{easy,key={name=memoize, desc=style}} + This key sets up advice which triggers memoization of the command or + environment whenever it is encountered; we often refer to such a command as + ``automemoized,'' or say that it was ``submitted to automemoization.'' + + An automemoized command will consume the next-options, whether memoization + actually occurs or not. + + Under the hood, this key declares both an \refmmzauto{outer handler} and an + \refmmzauto{inner handler}. The outer handler opens the memoization group + (so that options can be applied locally), applies the auto-options (given by + \refmmzauto{options} within \refmmz{auto}) and the next-options (given by + \refcmd{mmznext}) by executing \refmmzauto{apply options}, and appends the + verbatim keys to \refmmzauto{collector options} if necessary. The inner + handler invokes \refcmd{Memoize} (which closes the group opened by the outer + handler): the first argument is \refcmd{AdviceReplaced}, expanded once and + followed by the arguments of the handled command; the second argument is + \refcmd{AdviceOriginal}, also expanded once and followed by the arguments of + the handled command. The inner handler also makes sure that \refmmz{ignore + spaces} is respected. +\end{doc} + +\begin{doc}{easy,key={name=nomemoize,desc=style}} + This key installs advice which disables memoization for the space of the + command or environment; we sometimes refer to such commands as + ``autodisabled.'' + + This key is merely an abbreviation for \refmmzauto{noop}|,| + \refmmzauto{options}|=|\refmmz{disable}. See the documentation of + \refmmzauto{noop} for further details. +\end{doc} + +\begin{doc}{key={name=noop,desc=style}} + This key sets up advice which does nothing. + + Ok, not nothing at all. The installed handler applies the auto-options and + the next-options by executing \refmmzauto{apply options}, and makes sure that + \refmmz{verbatim} and \refmmz{ignore spaces} are respected. + + For commands and non-\hologo{LaTeX} environments, this key declares the same + outer handler as \refmmzauto{memoize}, while the inner handler merely + executes the original command (respecting the potential verbatim mode), + closes the group opened by the outer handler, and makes sure that + \refmmz{ignore spaces} is respected. + + For \hologo{LaTeX} environments, which open the group necessary for the local + application of options themselves, this key declares an outer handler which + adds the relevant code into the next hook |env/|\meta{environment + name}|/begin|. There is no need to open a group, collect the environment + body, or make special provisions for the verbatim mode. +\end{doc} + + +\begin{doc}{key={name=apply options,desc=style}} + This style, used by \refmmzauto{memoize}, \refmmzauto{nomemoize} and + \refmmzauto{noop} described above, installs two handlers: + \begin{itemize} + \item an outer handler which opens a group, applies auto-options and + next-options by executing \refcmd{mmzAutoInit}, and executes the collector; + and + \item a bailout handler which clears the next-options. + \end{itemize} +\end{doc} + + +\begin{doc}{cmd={name=mmzAutoInit}} + This macro applies the auto-options and the next-options. + + Additionally, if \refmmz{verbatim}, \refmmz{verb} or \refmmz{no verbatim} was + previously executed, this style appends the corresponding CollArgs key + (\refcollargs{verbatim}, \refcollargs{verb} or \refcollargs{no + verbatim}) to \refcmd{AdviceRawCollectorOptions}. In case several of the + verbatim keys were executed, the final one takes effect. +\end{doc} + + +\begin{doc}{easy, key={name=abort,desc=style}} + This key sets up advice which aborts any ongoing memoization. + + Under the hood, the advice merely executes \refcmd{mmzAbort} followed by + \refcmd{AdviceOriginal}. The advised command does \emph{not} consume the + next-options. Out of the box, we submit two control sequences to this + handler: + \begin{itemize} + \item \refcmd{errmessage}: this allows us to detect and abort upon at least some + errors. + \item \refcmd[into index=false]{pdfsavepos} (in \hologo{LuaTeX}, + \refcmd[short]{savepos}): one common effect is that memoization of any + \TikZ picture with \refkey{/tikz/remember picture} set is aborted. + \end{itemize} +\end{doc} + + +\begin{doc}{key={name=unmemoizable,desc=style}} + This key sets up advice which aborts the ongoing memoization and marks the + automemoized code as unmemoizable, so that it will be henceforth compiled + regularly. + + Under the hood, the advice merely executes \refcmd{mmzUnmemoizable} followed + by \refcmd{AdviceOriginal}. The advised command does \emph{not} consume the + next-options. + + Out of the box, we submit no control sequences to this advice, but it might + make sense to submit \refcmd[into index=false]{pdfsavepos}\slash + \refcmd[short]{savepos}. Keys \refmmzauto{abort}|=|\refcmd[short]{savepos} + and \refmmzauto{unmemoizable}|=|\refcmd[short]{savepos} will most often have + the same effect, as far as the author is concerned; the former was chosen as + the default because it does not produce a c-memo; see + \refcmd{mmzUnmemoizable} for a situation where \refmmzauto{unmemoizable} is + preferred. +\end{doc} + + +\begin{doc}{easy, + key={name=ref,desc=style}, + key={name=force ref,desc=style}, + } + + These keys set up advice which adds the reference key to the context + expression. They are intended to be used with cross-referencing commands + such as \refcmd{ref} and \refcmd{pageref}. + + Indeed, \refcmd{ref} and \refcmd{pageref} are submitted to this advice by + Memoize, with the effect that standard cross-referencing inside memoized code + ``just works.'' Note that the stabilization of the document after changing + the reference takes three compilation cycles, i.e.\ one cycle more than + without memoization. + + The advice set up by \refmmzauto{ref} aborts memoization if the reference + key is undefined, the rationale being that the produced memo and extern would + most often be useless, and could even obscure an undefined reference. The + \refmmzauto{force ref} handler produces the memo and the extern even when the + reference is undefined. + + The reference produced by the advised command should be fully expandable + (because it will be expanded as a part of the context expression). + + Typically, a \refcmd{ref} command takes a single argument, the reference key. + However, some packages may define a reference command which takes optional + arguments, as well; in particular, the \pkg{hyperref}'s incarnation of \refcmd{ref} + takes an optional star. This advice does not care: it will accept any number + of any kind of optional arguments, as long as the reference key is the first + braced argument following the advised command; for example, |\ref*{key}|, + |\ref[opt]{key}|, |\ref*[opt]{key}| etc.\ will all be handled correctly, + while |\ref{mand}{key}| will not work. Effectively, it is as if we had set + \refmmzauto{args}|=lm| --- and with the same downside, namely that an + unlikely unbraced single-token reference key, like |\ref k|, will not work. + + Under the hood, these two pieces of advice pass the reference key to macros + \refcmd{mmzNoRef} and \refcmd{mmzForceNoRef}, and it is these commands --- + which may also be used in user-defined advice or the document itself --- + which actually add the reference key to the context expression. +\end{doc} + +\begin{doc}{easy, + key={name=refrange,desc=style}, + key={name=force refrange,desc=style}, + } + These keys have the same function as \refmmzauto{ref} and \refmmzauto{force + ref}, but they operate on reference-range commands, such as \pkg{cleveref}'s + \refcmd{crefrange}, which take two arguments (the starting and the ending reference + key). +\end{doc} + +\begin{doc}{easy, + key={name=multiref,desc=style}, + key={name=force multiref,desc=style}, + } + These keys have the same function as \refmmzauto{ref} and \refmmzauto{force + ref}, but they operate on ``multireference'' commands, such as + \pkg{cleveref}'s \refcmd{cref}, which allow the author to list several + comma-separated reference keys in a single argument. +\end{doc} + +\begin{doc}{ + key={name=replicate, desc=style} + } + This key sets up advice which replicates the invocation of the command in + the cc-memo during memoization. + + When using this key, it is necessary to set \refmmzauto{args} as well. For + \refcmd{index}, Memoize executes + \refmmz{auto}|=\index|\bracestt{\refmmzauto{args}=m, \refmmzauto{replicate}}. + + This key takes an auto-option, \docAux{keypath=/mmz/auto/replicate, + key={name=expanded}}.\footnote{This option is unrelated to Memoize's options, + settable by \refcmd{mmzset}.} If given, the collected arguments will be + expanded before replicating them in the cc-memo; in \hologo{LaTeX}, this + expansion is |\protect|ed. + + In \hologo{LaTeX}, Memoize submits \refcmd{index} to this handler (with + expansion). Therefore, any |\index{key}| in the memoized code gets copied + into the cc-memo. Effectively, indexing from within the memoized code ``just + works.'' + + Note that \refcmd{label}, despite essentially requiring replication, cannot + use this advice, because it needs to replicate not only the label key but + \refcmd{@currentlabel} as well. +\end{doc} + +\begin{doc}{key={name=run if memoization is possible, desc=style}} + Under the run conditions installed by this key, a command is only advised if + Memoize is enabled but we're not already ``within Memoize,'' i.e.\ memoizing + or normally compiling some code submitted to memoization. In code: + \refcmd{ifmemoize}\refcmd{ifinmemoize}|\else|\refcmd{AdviceRuntrue}|\fi\fi|. + + Internally, this key is used by \refmmzauto{memoize} and \refmmzauto{noop}. +\end{doc} + +\begin{doc}{key={name=run if memoizing, desc=style}} + Under the run conditions installed by this key, a command is only advised + during memoization. In code: + \refcmd{ifmemoize}\refcmd{ifmemoizing}\refcmd{AdviceRuntrue}|\fi\fi|. + + Internally, this key is used by \refmmzauto{abort}, \refmmzauto{replicate}, + and \refmmzauto{ref} and friends. +\end{doc} + +\endgroup % keypath = /mmz/auto +\endgroup + + + +\subsubsection{Package CollArgs} +\label{sec:ref:collargs} + +\begingroup +\yadocset{keypath=/collargs} + +\begin{doc}{cmd={ + name=CollectArguments, + par=\oarg{options}\marg{argument specification}\marg{next-code}% + \textcolor{gray}{\meta{tokens}}}} + + This command determines the extent to which the \meta{tokens} following the + the three formal arguments of the command conform to the given \meta{argument + specification}, effectively splitting \meta{tokens} into \meta{argument + tokens} and the \meta{rest} of the tokens, and then executes + \meta{next-code} with the \meta{argument tokens} provided as a single, braced + argument: + \begin{center} + \meta{next-code}\marg{argument tokens}\textcolor{gray}{\meta{rest}} + \end{center} + If the initial part of \meta{tokens} does not conform to \meta{argument + specification}, \refcmd{CollectArguments} throws an error. (In this case, + \meta{next-code} is not executed, and the \meta{tokens} collected until the + error are thrown away.) + + The optional \meta{options} are processed using the \pkg{pgfkeys} utility of + PGF/\TikZ (see \PGFmanual{87}), with the default path set to + \docaux{key path}{collargs}. The given options apply to all the arguments in + \meta{argument specification}. The recognized keys are listed in the rest of + the section. + + The \meta{argument specification} should be given in the \pkg{xparse} format + (we summarize this format in the documentation for \refmmzauto{args} in + section~\ref{sec:ref:advice}), with several extensions:\footnote{Collargs + internally uses a dot (|.|) to delimit the argument specification from the + following argument tokens. Therefore, the dot really counts as an extra + argument type, in the sense that Collargs will stop working if the dot + becomes an argument type or a modifier in some future release of + \pkg{xparse}.} + \begin{itemize} + \item We introduce modifier \docAux{xparse modifier={name=\&,label=amp,index + annotation/.prefix={additional\ }, index annotation/.append={\ + (options)} }} taking a mandatory argument specifying the options to + apply to the following argument in the specification. Options given here + override the \meta{options} given as the optional argument. + \item The environment body type \docAux{xparse type={name=b,index + annotation/.append={\ (environment body)}}} may be followed by an optional + \emph{braced} argument providing the name of the environment to collect. + The name given here overrides the name given by the + \refcollargs{environment} option. + \item The number of collected ``arguments'' is unlimited. + \end{itemize} + + Also note that the effect of \docref{xparse:O}\marg{default} is the same as + the effect of \docref{xparse:o}, and similarly for other pairs of types with + and without defaults (\docref{xparse:R} and \docref{xparse:r}, + \docref{xparse:D} and \docref{xparse:d}, and \docref{xparse:E} and + \docref{xparse:e}). CollArgs is dedicated to collecting the argument tokens + precisely as they are given: if an optional argument is missing, its default + value is \emph{not} inserted among the collected arguments --- consequently, + \refcmd{CollectArguments} is utterly uninterested in the default value. + + Collection of environments automatically adapts to the format, i.e.\ given + environment body name |foo|, \refcmd{CollectArguments} knows to search for + \refcmd{begin}\bracestt{foo} |...| \refcmd{end}\bracestt{foo} in + \hologo{LaTeX}, \cs{foo} |...| \cs{endfoo} in \hologo{plainTeX}, and + \cs{startfoo} |...| \cs{stopfoo} in \hologo{ConTeXt}. For further + information on environment collection, see keys \refcollargs{ignore + nesting} and \refcollargs{tags}. +\end{doc} + +\begin{doc}{cmd={ + name=CollectArgumentsRaw, + par=\marg{option-setting code}\marg{argument specification}\marg{next-code}% + \textcolor{gray}{\meta{tokens}}}} + + This command is the programmer's interface to CollArgs, intended to be used + instead of \refcmd{CollectArguments} when compilation speed is an issue. The + two commands only differ in how they deal with options. + + One difference is that for \refcmd{CollectArgumentsRaw}, the options form a + mandatory rather than an optional argument. More importantly, however, they + do not take the form of a keylist, but should be composed out of low-level + option-setting commands. Each key documented in this section has a + corresponding low-level macro; these macros are listed in footnotes alongside + the keys. The name of the macro starts with |\collargs| and continues with + the name of the key, without spaces, each word capitalized; if the key is + boolean, this convention applies to the base of the \hologo{TeX} + conditional. For example, + \begin{tcblisting}{listing only, listing options app={escapechar=|}} +\CollectArguments[caller=\foo, tags, verbatim]|\marg{argument specification}\marg{next-code}| + \end{tcblisting} + is equivalent to + \begin{tcblisting}{listing only, listing options app={escapechar=|}} +\CollectArgumentsRaw{% + \collargsCaller{\foo}% + \collargsBeginTagtrue\collargsEndTagtrue + \collargsVerbatim +}|\marg{argument specification}\marg{next-code}| + \end{tcblisting} + + Withing the option-setting code, the programmer may also deploy macro + \docaux{cmd}{collargsSet}, which processes the \meta{options} in the keylist + format. One idea could be to execute this macro at the end of the low-level + options; this would set the ``defaults'' using the fast programmer's + interface, but still allow for user customization. +\end{doc} + + +\begin{doc}[ + pi={\docaux{cmd}{collargsCaller}}, + ]{ + key={name=caller, par=\meta{control sequence (name)}, + desc={no default, initially \cs{CollectArguments}}}, + } + Set the control sequence to refer to in error messages. + + If \meta{tokens} do not match the \meta{argument specification}, + \refcmd{CollectArguments} throws an error. By default, the error message + contains a reference to \refcmd{CollectArguments} itself, for example % + |! Argument of \CollectArguments has an extra }.| However, this might not be +very informative to the author. When \refcollargs{caller}|=\cs| is in effect, +the error messages will refer to the given |\cs| instead. + +If the value of this key is not a control sequence, it is assumed to be an +environment name, but as the caller must be a macro, this name will be +converted into a control sequence. Setting \refcollargs{caller}|=foo| will +result in error messages referencing |\foo| in \hologo{plainTeX}, |\startfoo| +in \hologo{ConTeXt} and |\begin{foo}| (a single control sequence!) in + \hologo{LaTeX}. +\end{doc} + +\begin{doc}[ + pi=\docaux{cmd}{collargsEnvironment}, + ]{key={name=environment, par=\meta{environment name}, + desc={applicable to type \docref{xparse:b}, no default, initially empty}} + } + + Set the name of the environment collected by argument type + \docref{xparse:b}. +\end{doc} + +\begin{doc}[ + pi={\docaux{cmd}{ifcollargsBeginTag}, \docaux{cmd}{ifcollargsEndTag}; + \refcollargs{tags} has no corresponding low-level command} + ]{ + key={name=begin tag, desc={applicable to type \docref{xparse:b},{ }}, conditional=false}, + key={name=end tag, desc={applicable to type \docref{xparse:b},{ }}, conditional=false}, + key={name=tags, par=\meta{boolean}, % not a conditional + desc={applicable to type \docref{xparse:b}, style, default |true|}}, + } + + When \refcollargs{begin tag}\slash \refcollargs{end tag} is in effect, the + begin\slash end tag will be will be prepended/appended to the collected + environment body. Style \refcollargs{tags} is a shortcut for setting + \refcollargs{begin tag} and \refcollargs{end tag} simultaneously. + + In \hologo{LaTeX}, using \refcollargs{tags} will thus dress up the + collected body in a pair or \refcmd{begin}\marg{environment name} and + \refcmd{end}\marg{environment name}. CollArgs will automatically use the tags + appropriate to the format. + + In the verbatim modes, the added tags are verbatim as well, with the detail + that in \hologo{LaTeX}, there is a slight difference between the full + \refcollargs{verbatim} and the partial \refcollargs{verb} mode. In the + full verbatim mode, the braces surrounding the environment name are verbatim + (the characters used as braces are actually determined by key + \refcollargs{braces}). In the partial verbatim, as well as the + non-verbatim mode, the environment name is surrounded by a pair of actual + braces of category 1 and 2, regardless of which characters are of these + categories in the calling code. +\end{doc} + +\begin{doc}[ + pi=\docaux{cmd}{ifcollargsIgnoreNesting}, + ]{ + key={name=ignore nesting, desc={applicable to type \docref{xparse:b},{ }}, + conditional=false}, + } + When this key is \emph{not} in effect, CollArgs respects the hierarchical + structure created by tag pairs such as \refcmd{begin}\bracestt{foo} and + \refcmd{end}\bracestt{foo}. Given the situation below on the + left, argument type |b{foo}| will collect everything up until the + \emph{second} |\end{foo}|. Now this is what we usually want, because +\hologo{LaTeX} keeps track of environment embedding as well. However, all +\emph{verbatim} environments I know of, starting with the standard +\hologo{LaTeX} \refenv{verbatim}, will ignore the nesting and simply scoop up +everything up to the first \cs{end}|{verbatim}|. In CollArgs, we can replicate +their behaviour by setting \refcollargs{ignore nesting}, as shown below on the +right. (Of course we also need to set \refcollargs{verbatim} if we want to +grab the environment body in the verbatim mode.) + + \begin{tcbraster}[raster columns=2] + \begin{tcblisting}{listing only, mark region={1}{5}, + example title=\texttt{ignore nesting=false}} + ... + \begin{foo} + ... + \end{foo} + ... +\end{foo} + \end{tcblisting} + \ExampleName{_collargs-verbatim} + \makeexample{\examplename.tex.c1} + \tcbinputexample{listing only, no attachment, mark region={1}{3}, + example title=\texttt{ignore nesting=true}} + \end{tcbraster} + + This key applies not only to argument type \docref{xparse:b} (in either + normal or verbatim mode), but also to the verbatim argument type + \docref{xparse:v} and to argument types \docref{xparse:m} and + \docref{xparse:g} in the \refcollargs{verbatim} (but not normal, or + \refcollargs{verb}) mode. With these keys, the relevant structure markers + are braces, |{| and |}|. +\end{doc} + +\begin{doc}[ + pi=\docaux{cmd}{ifcollargsIgnoreOtherTags}, + ]{ + key={name=ignore other tags, desc={applicable to type \docref{xparse:b},{ }}, + conditional=false}, + } + In \hologo{LaTeX}, the environment tags, \refcmd{begin}\marg{name} and + \refcmd{end}\marg{name}, contain braces, which retain their usual category codes + in the non-verbatim and in the partial verbatim mode. Consequently, CollArgs + cannot easily search for the full tags to delimit the + environment. + + When this key is \emph{not} in effect, CollArgs takes the easy path, and + determines the end of the environment only by inspection of \cs{begin}s and + \cs{end}s, without reference to what \meta{name} they begin or end. Only + when this key \emph{is} in effect does CollArgs inspect these \meta{name}s, + effectively ignoring any \cs{begin}s and \cs{end}s not followed by the name of + environment being collected. The effect of absence vs.\ presence of this key + is shown below, where the shaded area marks the code collected into + environment |foo|. + + \begin{tcbraster} + \ExampleName{_collargs-ignore-other-tags} + \makeexample{\examplename.tex.c1 N=2} + \tcbinputexample{listing only, no attachment, mark region={3}{3}, + example title=\texttt{ignore other tags=false}} + \tcbinputexample[.tex][.c2]{listing only, no attachment, mark region={3}{5}, + example title=\texttt{ignore other tags=true}} + \end{tcbraster} + + This key does not have any effect the full verbatim mode, which always + behaves as if this key was set to true, because braces are of category + ``other'' as well. Similarly, it is as if this key was always true in + \hologo{plainTeX} and \hologo{ConTeXt}, simply because environment tags in + these formats don't contain braces. +\end{doc} + +\begin{doc}[ + pi={\raggedright + \docaux{cmd}{collargsAppendPreprocessor}, + \docaux{cmd}{collargsPrependPreprocessor}, + \docaux{cmd}{collargsAppendPostprocessor}, + \docaux{cmd}{collargsPrependPostprocessor}}, + ]{ + key={name=append preprocessor, par=\meta{code}, desc={no default}}, + key={name=prepend preprocessor, par=\meta{code}, desc={no default}}, + key={name=append postprocessor, par=\meta{code}, desc={no default}}, + key={name=prepend postprocessor, par=\meta{code}, desc={no default}}, + } + These keys declare processors which will transform the collected argument + before appending it to the argument list. + + A collected argument undergoes the following transformations: + \begin{itemize} + \item First, the argument is processed by any \emph{pre}processors, in the + order indicated by |append| and |prepend|. + \item Next, the processed argument is dressed up in the delimiters according + to its type. For example, an optional argument of type \docref{xparse:o} + will be surrounded by square brackets. + \item Finally, the delimited argument is processed by any + \emph{post}processors, again in the order indicated by |append| and + |prepend|. + \end{itemize} + + \meta{code} will typically consist of a single control sequence pointing to a + one-argument macro, which will receive the collected argument (possibly + modified by the processors already applied). In general, however, the value + of this key may be any code; Collargs will execute \meta{code}\marg{collected + argument}. + + The processed argument should be returned by storing it into token register + \docaux{cmd}{collargsArg}. + + The following example illustrates how one could go about reimplementing Bruno + Le Floch ingenious package \pkg{cprotect}.\footnote{This example is merely a + proof of concept. For the bells and whistles which would make it useful in + real life, see the documentation of \pkg{cprotect}.} We define processor + |\writetofile| which dumps the argument into a file, replacing it with the + |\input| statement. (Of course, to allow for verbatim content in the + footnote, we also have to mark the argument as \refcollargs{verbatim}. + And we use \refcollargs{no delimiters} to get rid of the braces around the + footnote text.) + + \ExampleName{collargs-processor} + \makeexample{\examplename.tex.c1} + \tcbinputexample{listing and text, listing file=\examplepath.tex.c1} +\end{doc} + +\begin{doc}[ + pi={\docaux{cmd}{collargsClearPreprocessors}, + \docaux{cmd}{collargsClearPostprocessors}}, + ]{ + key={name=clear preprocessors}, + key={name=clear postprocessors}, + } + Clear the list of pre- or post-processors. +\end{doc} + +\begin{doc}[ + pi={\docaux{cmd}{collargsAppendExpandablePreprocessor}, + \docaux{cmd}{collargsPrependExpandablePreprocessor}, + \docaux{cmd}{collargsAppendExpandablePostprocessor}, + \docaux{cmd}{collargsPrependExpandablePostprocessor} + }, + ]{ + key={name=append expandable preprocessor, par=\meta{code}, desc={no default}}, + key={name=prepend expandable preprocessor, par=\meta{code}, desc={no default}}, + key={name=append expandable postprocessor, par=\meta{code}, desc={no default}}, + key={name=prepend expandable postprocessor, par=\meta{code}, desc={no default}}, + } + These keys may be used to add fully expandable processors. A processor added + with one of these keys will end up among the processors declared by + \refcollargs{append preprocessor} et al. + + A processor declared by one of these keys will define the processed argument + as the full expansion (|\edef|) of \meta{code}\marg{collected argument}. + \meta{code} will typically consist of a single control sequence pointing to a + fully expandable one-argument macro. + + For example, |\trim@spaces@noexp| from package \pkg{trimspaces} could be used + as an expandable processor of environment body to remove the spaces around + the grabbed environment body. +\end{doc} + +\begin{doc}[ + pi={\docaux{cmd}{collargsAppendPrewrap}, + \docaux{cmd}{collargsPrependPrewrap}, + \docaux{cmd}{collargsAppendPostwrap}, + \docaux{cmd}{collargsPrependPostwrap}}, + ]{ + key={name=append prewrap, par=\meta{macro definition}, desc={no default}}, + key={name=prepend prewrap, par=\meta{macro definition}, desc={no default}}, + key={name=append postwrap, par=\meta{macro definition}, desc={no default}}, + key={name=prepend postwrap, par=\meta{macro definition}, desc={no default}}, + } + These keys add processors which transform the collected argument in a single + expansion. + + The declared processor will use \meta{macro definition} to define a temporary + one-argument \meta{macro}, and then set the \meta{processed argument} to be + the single expansion of \meta{macro}\marg{collected argument}. + + For example, to add quotes around the collected argument, write + \refcollargs{append prewrap}|={``#1''}| (doubling the hash when executing + \refcmd{CollectArguments} from a macro, of course). Or, perhaps more + usefully, \refcollargs{append prewrap}|={\scantokens{#1}}| can be used to + retokenize a verbatim argument (during the execution of the + \meta{next-code}). +\end{doc} + + +\begin{doc}[ + pi=\docaux{cmd}{ifcollargsNoDelimiters} + ]{ + key={name=no delimiters, conditional=false}, + } + When this key is in effect, the collected argument will not be dressed up + into delimiters that it was dressed up in \meta{argument tokens}. For + example, an optional argument, encountered as [\meta{argument}] inside + \meta{argument tokens}, will be spit out simply as \meta{argument}. + + Any user-specified pre- or post-processing will still be applied. + \ExampleName{collargs-nodelimiters} + \makeexample{\examplename.tex.c1} + \tcbinputexample{comment=\input{\examplepath.tex.c1}} +\end{doc} + + +\begin{doc}[ + pi={\docaux{cmd}{collargsVerbatim}, + \docaux{cmd}{collargsVerb}, + \docaux{cmd}{collargsNoVerbatim}. + To ensure the same effect as with the keys, + place these macros at the end of the option code}, + ]{ + key={name=verbatim, desc=style}, + key={name=verb, desc=style}, + key={name=no verbatim, desc=style}, + } + Select the full verbatim, the partial verbatim, or the non-verbatim mode of + argument collection. + + In the full \refcollargs{verbatim} mode, the arguments are collected under + a category code regime in which all characters are of category 12, ``other''. + The same goes for the partial \refcollargs{verb} mode, except that in this + case, the grouping characters --- usually the braces |{| and |}| --- retain + their usual category codes 1 and 2. Key \refcollargs{no verbatim} selects + the normal, non-verbatim mode. + + The partial \refcollargs{verb} mode can be useful for verbatim collection + of an optional argument. To pass |]| as an optional argument to command +|\foo|, we normally enclose it in braces: ˇ\foo[{~]~}]ˇ. However, if we try to +collect |[{]}]| with \refcmd{CollectArguments}|[|\refmmz{verbatim}|]{o}|, we +will get |{| (and most likely an error, as well), because in the + \refmmz{verbatim} mode, braces do not have their grouping function. Using + the \refmmz{verb} mode solves the problem: occuring within braces, the first + |]| is ``invisible'' to \refcmd{CollectArguments}|[|\refmmz{verb}|]|, so the +optional argument is correctly recognized as ending at the second |]|. + +The partial \refcollargs{verb} mode is also useful for collecting the bodies +of \emph{\hologo{LaTeX}} environments. The full \refcollargs{verbatim} mode +will only correctly collect these bodies when the relevant \refcmd{begin} +and\slash or \refcmd{end} control sequences are followed by the grouped +environment name without any intervening spaces. The partial +\refcollargs{verb} mode has no such restriction. + +In the verbatim modes, modifier \docref{xparse:+} has no effect. The arguments +are always collected as if they were long. + +To correctly collect arguments in the verbatim modes, CollArgs has to mimic the +many details of \hologo{TeX}'s tokenization and argument delineation. These +details depend on the category code regime, and CollArgs automatically adapts +to the ``outside'' category code regime, i.e.\ the regime in effect at the time +of invoking \refcmd{CollectArguments}. In particular, CollArgs remembers which +characters were of category codes 0, 1, 2, 5, 10 and 11, and adapts the +argument collection accordingly. For example, it will correctly pick up a +control sequence as a single-token \docref{xparse:m}-type (\hologo{TeX}'s undelimited) +argument even when it begins with a non-standard character of category code 0. +The single caveat is that only a single pair of characters can function as the +grouping characters in the full verbatim mode; to compensate for the +deficiency, this character pair is customizable via key +\refcollargs{braces}. +\end{doc} + +\begin{doc}[ + pi={\docaux{cmd}{collargsFixFromVerbatim}, + \docaux{cmd}{collargsFixFromVerb}, + \docaux{cmd}{collargsFixFromNoVerbatim}}, + ]{ + key={name=fix from verbatim, desc=style}, + key={name=fix from verb, desc=style}, + key={name=fix from no verbatim, desc=style}, + } + Key \refcollargs{fix from no verbatim} should be used when the first + argument should be collected in a verbatim mode, but the outside code has + already tokenized the first character of the subsequent input stream (most + probably by a |\futurelet|) in the non-verbatim category code regime. Using + this key will trigger a CollArgs' ``mode transition'' (described below) which + will fix the situation. (This key is used in the implementation of + \refcmd{mmz}.) + + The other two keys should be used in the unlikely reverse situation, where + the outside code has tokenized the following character in a verb(atim) mode, + while CollArgs is requested to collect the first argument in the non-verbatim + mode. +\end{doc} + +\begin{doc}[ + pi=\docaux{cmd}{collargsBraces} + ]{ + key={name=braces, par={\meta{begin-group char}\meta{end-group char}}, + desc={no default, for details see below}}, + }% here + This key sets the verbatim begin-group and end-group characters. The setting + affects collection of argument types \docref{xparse:m}, \docref{xparse:g}, + \docref{xparse:v}, \docref{xparse:l}, \docref{xparse:e} and (in + \hologo{LaTeX}) \docref{xparse:b} in the \emph{full} verbatim + mode.\footnote{The choice of the verbatim grouping characters also affects + the effect of \refcollargs{begin tag} and\slash or \refcollargs{end tag}; + see the documentation of these keys for details.} + + For example, in the non-verbatim and the partial verbatim mode, an + \docref{xparse:m}-type argument may be delimited by any characters of + category code 1 (``begin-group'') and 2 (``end-group''). In the full + verbatim mode, there are of course no characters of these categories, so + CollArgs internally assigns the grouping function to some pair of characters. + When entering the full verbatim mode, CollArgs automatically sets the + verbatim grouping characters to characters which were of categories 1 and 2 + in the ``outside'' category code regime, i.e.\ the regime in effect at the + time of invoking \refcmd{CollectArguments}. However, in contrast to + \hologo{TeX}'s internal argument parser, only one pair of characters may + serve as the begin-group and the end-group character in CollArgs' full + verbatim mode. In case multiple characters were of category 1 or 2 on the + outside, CollArgs therefore has to make a choice, and it chooses the + candidate with the lowest character code. This choice may be overridden by + the user by invoking key \refcollargs{braces}; the user may even choose + characters which did not belong to categories 1 and 2 in the outside regime. + + When \meta{begin-group char} and \meta{end-group char} are of categories 1 + and 2 in the outside category regime, they must be enclosed in a triple + group. For example, if both |()| and |{}| have the grouping function on the + outside, and the user wants to select |{}| as the verbatim grouping + characters (CollArgs would go for |()|, as this pair has lower character + codes), the correct way to invoke this key is |braces={{{{}}}}| or + |braces=((({})))|. \footnote{This complication is due to the details of + \pkg{pgfkeys}' keylist processing, and does not apply to + \refcmd{collargsBraces}.} +\end{doc} + +\begin{doc}[ + pi=\docaux{cmd}{collargsVerbatimRanges} + ]{ + key={name=verbatim ranges, + par={\bracestt{\meta{from}\texttt{-}\meta{to}(\texttt{,} \meta{from}\texttt{-}\meta{to})*}}, + desc={no default, initially \texttt{0-255}}}, + } + If run under the \hologo{pdfTeX} or \hologo{XeTeX} engine, this key + determines which characters will be assigned category code 12 in the verbatim + mode. In \hologo{pdfTeX}, the range should remain at the initial |0-255|, + but in \hologo{XeTeX}, some rare situations might require extending this + range (don't attempt to set the full range of |0-1114111|, as this would be + very slow and you would most likely run out of save stack). + + In \hologo{LuaTeX}, we switch the category code regime using category code + tables, so this key has another meaning: it determines the range in which + CollArgs will scan for characters of category codes 1, 2 and 14, whose + identity it needs to know, for internal reasons. +\end{doc} + + + +\paragraph{Mode transition limitations} + +\refcmd{CollectArguments} has some minor limitations regarding the transition +from a verbatim into non-verbatim mode, or vice versa. The gist of the issue +is best illustrated with the optional argument type \docref{xparse:o} collected +in the verbatim mode. CollArgs determines whether an argument of this type is +present by peeking ahead (using \hologo{TeX}'s |\futurelet| primitive) into the +input stream. If the argument is present (i.e.\ if the input stream continues +with an open bracket, |[|%] +), all is well. But when the optional argument is absent, the peek-ahead will +tokenize the following character, which presents a problem when no more +arguments are present in the input stream, like in the example below, where the +verbatim \docref{xparse:o} is the (only and) final type in the argument +specification. In this case, the peek-ahead ``incorrectly'' assigns category +code 12 (``other'') to the first |$|. %$ +This character was intended to be tokenized as the math shift character of +category 3, to start the math mode after \refcmd{CollectArguments} is finished, +but having been assigned category code 12, it cannot perform this function, +resulting in error |! Missing $ inserted| %$ +once \hologo{TeX} encounters the superscript character |^|. + +\ExampleName{collargs-transition-ok} +\makeexample{\examplename.tex.c1} +\tcbinputexample{sidebyside, lefthand ratio=0.6, + comment=\input{\examplepath.tex.c1}} + +Well --- this is what \emph{would} happen if CollArgs didn't address the +transition issue described above. In fact, the above example compiles just +fine, because CollArgs \emph{does} address this issue, but unfortunately, +certain transition problems simply cannot be resolved --- read on to learn what +can go wrong. + +For example, you can typeset the name of the document author via +\hologo{LaTeX}'s internal command |\@author|, but to use this command in the +document, you have to precede it by |\makeatletter|. As shown by the first +line of the example below, this works rather nicely: |\makeatletter| sets the +category code of |@| to 11 (``letter''), so |@| may help form the control word +|\@author| --- importantly, |\makeatletter| sets the category code of |@| +\emph{before} control sequence |\@author| is constructed, even if it precedes +it immediately. + +\ExampleName{collargs-transition-cs} +\makeexample{\examplename.tex.c1} +\long\def\ShowArgs#1{Collected: ``{\color{red}\tt\detokenize{#1}}''} +\tcbinputexample{comment=\input{\examplepath.tex.c1}} + +In the second line of the example, our clever invocation of |\@author| is +immediately preceded by a call to \refcmd{CollectArguments}, which tries to +collect a verbatim argument of type \docref{xparse:o}. It doesn't find it, which results in +the wrong, verbatim tokenization of the escape character of |\makeletter|. +CollArgs realizes the problem and tries to fix it. But while it is searching +for the end of control sequence |\makeletter| (which it successfully +constructs), it triggers the tokenization of what follows --- which, as |@| is +at that point of category 12 (``other''), yields the control symbol |\@| (later +followed by word ``author'', typeset in the example). + +In short, the solution has created another, delayed instance of the problem --- +an instance which cannot be addressed any further. But we're nevertheless +better off, as this particular issue will bite only in the case when the +``corrupted'' control sequence immediately following the invocation +\refcmd{CollectArguments} changes category codes in a way that affects the +tokenization of what immediately follows it. + +This was an example of what can go wrong in the transition from the +\meta{argument tokens} to the \meta{rest} of the tokens following an invocation +of \refcmd{CollectArguments}. As the ``outside world'' is non-verbatim, this +transition can only be problematic if the argument which corrupted the first of +the \meta{rest} tokens was verbatim, so if the transition was from the verbatim +to the non-verbatim mode. Such a transition can also occur within the +\meta{argument tokens}, but the good news here is that CollArgs successfully +solves any problems that occur there, so you should only worry about the +end-of-arguments situation. + +The other direction of the transition, from the non-verbatim to the verbatim +mode, however, can affect both the internal and the external transitions. Let +us illustrate the problem with the internal transition. Say you want to +collect an optional argument (\docref{xparse:o}) in the non-verbatim mode, and +then a mandatory argument (\docref{xparse:m}) in (either full or partial) +verbatim mode. In the first invocation of \refcmd{CollectArguments} below, the +optional argument is present, and we get what we expect: the percent sign is +collected, verbatim, into the mandatory argument. In the second invocation, +however, the percent character retains its usual commenting function --- +despite the fact that we have requested verbatim mode for the mandatory +argument --- which results in the group in the second line being picked up as +the mandatory argument. Again, this happens because CollArgs has to peek ahead +in the input stream when determining whether the optional argument is present. +Having requested non-verbatim mode for the optional argument, the peeking is +performed in the non-verbatim mode, and as the optional argument is not +present, it finds the comment character, which fulfills its regular function of +disappearing along with the rest of the line. Once CollArgs sets to find the +(verbatim) mandatory argument, the rest of the line is already gone, so it +searches for, and finds, this argument in the next line. + +\ExampleName{collargs-transition-comment} +\makeexample{\examplename.tex.c1} +\long\def\ShowArgs#1{Collected: ``{\color{red}\tt\detokenize{#1}}''} +\tcbinputexample{listing and text} + +Nothing can be done here --- commenting deletes information, irrevocably --- +and in a similar fashion, nothing can be done to catch a verbatim end-of-line +character when preceded by an absent optional argument in the non-verbatim mode +(because it was already tokenized into a space token). + +Finally, the transition issues are not limited to transits from argument type +\docref{xparse:o}. The full list of argument types which give rise to +transition problems (when transiting \emph{from} arguments of these types) is +as follows: \docref{xparse:o}, \docref{xparse:d}, \docref{xparse:s}, +\docref{xparse:t}, \docref{xparse:g}, \docref{xparse:e}. + + +\endgroup % /collargs + + +\section{Varia} + +\subsectionclearpagefalse + +\subsection{Known issues} +\label{sec:known-issues} + +\paragraph*{Bitmap graphics export} is coming up in the next release of the +package. + + +\paragraph{Disappearing errors} +If a non-fatal internal \hologo{TeX} error occurs during memoization, the memos +and externs may be nevertheless produced and utilized in subsequent +compilations. In such a case, the erroneous code won't be compiled again, and +therefore won't yield any errors, giving the mistaken impression that the code +is error-free. + +This problem does not apply to errors which trigger \refcmd{errmessage}, +because that control sequence is advised by \refmmzauto{abort}. +Note that internal \hologo{TeX} errors like |Undefined control sequence| are +\emph{not} reported through \refcmd{errmessage}, and will therefore cause the +issue. + +This problem does not affect \hologo{LuaTeX}, because this engine allows +Memoize to detect errors and abort memoization if it encounters any. + + +\paragraph{A minimal issue with \hologo{XeLaTeX}} +If the very first page of a document of class |minimal|, compiled by +\hologo{XeLaTeX}, happens to be an extern page, we have a problem: all the +regular pages of the document will be of the same size as that extern page. +\hologo{pdfLaTeX} and \hologo{LuaLaTeX} do not exhibit this behaviour, nor do +\hologo{LaTeX} classes other than |minimal|, even when compiled with +\hologo{XeLaTeX}. + + +\paragraph{CollArgs} + +Due to an unfortunate design decision, CollArgs does not accept a dot |.| as +the \meta{token} argument of types, \docref{xparse:r}, \docref{xparse:R}, +\docref{xparse:d}, \docref{xparse:D}, and \docref{xparse:t}. Furthermore, +\refcollargs{append prewrap} and friends (and their macro counterparts) do not +accept a parameter symbol consistently. These issues will be fixed in the next +release. + + +\subsection{Troubleshooting} +\label{sec:troubleshooting} + +\paragraph{Extern extraction does not work} +\label{sec:fadings-problem} +\label{sec:loading-order} + +If the internal extern extraction does not work, you should have gotten one of +the following warnings: +\begin{enumerate} +\item \code{Package memoize Warning: Extraction of externs from document + "\meta{jobname}.pdf" using method "perl" was unsuccessful. Have you set the + shell escape mode as suggested in chapter 1 of the manual?} + + This warning is thrown when the extraction log \meta{jobname}|.mmz.log|, + which should be produced by the extraction script, is incomplete, i.e.\ it + does not finish by |\endinput|.\footnote{The extraction log will never be + absent, because Memoize clears it before executing the extraction script + --- and clearing it creates it if it doesn't exist.} The most likely + reason is that the script was not executed at all, so the question asked in + the warning message is pertinent. However, if all is well with the + shell-mode, you have a mystery at your hands. To gather information, I + suggest inspecting: + \begin{itemize} + \item \meta{jobname}|.log| --- search for \code{runsystem(memoize-extract.pl + ...)}, it will tell you whether the script was executed; + \item the terminal output --- if the script was executed, it should've + announced itself by \code{Extracting externs from \meta{jobname}.pdf}; are + there any further messages between this header and the warning message? + \item \meta{the path to the extern}|.log|, if you are using the + \hologo{TeX}-based extraction (\code{\refmmz{extract}=\refmmz{extract=tex}}). + \end{itemize} + \hologo{TeX}-based extraction will yield this error even in the case of a + missing or corrupted PDF, i.e.\ in + case~\ref{item:warning:extract:cannot-read} below. + +\item\label{item:warning:extract:cannot-read} + \code{Package memoize (perl-based extraction) Warning: Cannot read file + "\meta{jobname}.pdf". Perhaps you have to load Memoize earlier in the + preamble?} + + Embedded extern extraction requires an intact document PDF from the previous + compilation, so Memoize must be loaded before the document PDF is opened for + writing the results of the ongoing compilation. In particular, the PDF is + opened by \PGF library |fadings|, included by \TikZ's libraries |fadings| + and |shadows|, so Memoize must be loaded before any of these libraries. + + With \pkg{beamer}, the problem is particularly acute because the PDF is + opened while loading the class. In this case, simply moving + |\usepackage{memoize}| up the preamble, as suggested, won't help: you have to + write |\RequirePackage{memoize}| \emph{before} |\documentclass{beamer}|! + +\item\label{item:warning:extract:unexpected-size} \code{Package memoize + (perl-based extraction) Warning: I refuse to extract page $n$ from + "\meta{jobname}.pdf", because its size ($\meta{width}\times\meta{height}$) + is not what I expected\\ ($\meta{expected width}\times\meta{expected + height}$)} + + If the compilation which produced the offending extern pages yielded any + errors, you should probably disregard this warning, fix the errors, and + compile again. Otherwise, you have somehow winded up with mismatched + \meta{jobname}|.pdf| and \meta{jobname}\dmmz (the latter file contains + instructions on which pages to extract, complete with the expected + dimensions). Are you sure that they were produced by the same compilation, + and have remained untouched since? Are you perhaps trying to perform the + extraction the second time, after the first extraction + \refscript{memoize-extract.pl--prune}d the PDF? + + If the warning stubbornly persists, but you are sure that the page the script + is refusing to extract is correct, you can force the extraction by adding + option \refscript{memoize-extract.pl--force} to the script invocation, which + can be set by \refmmz{perl extraction options}. However, as such a situation + probably indicates a bug in Memoize, please let me know about it. +\item\code{\myfontexpansionon Invalid dictionary key at + /.../perl5/site\_perl/PDF/API2/Basic/PDF/File.pm line $N$\myfontexpansionoff} + + This can sometimes happen when extracting with the Perl-based script. The + issue might be related to PDF version --- by default, \hologo{TeX} produces + PDFs of version 1.5, while the PDF library + \hreftt{https://metacpan.org/pod/PDF::API2}{PDF::API2} officially only + supports versions up to 1.4 --- but I'm afraid I haven't identified the exact + circumstances yet. Possibly, the externalizing a picture containing an + embedded PDF file might be the culprit. The workaround is to use Python- or + \hologo{TeX}-based extraction, i.e.\ load Memoize with package option + \refmmz{extract}|=|\refmmz{extract=python} or + \refmmz{extract}|=|\refmmz{extract=tex}. +\end{enumerate} + +The failure to extract externs intentionally doesn't result in an error, +because what if you deleted the document PDF on purpose? At any rate, the +compilation will succeed, it's just that as Memoize cannot extract the externs, +they will be produced, and dumped into your document, at each and every +compilation. + +\paragraph{An extern won't be included} + +Did you receive a warning or error message? +\begin{enumerate} +\item \code{Package memoize Warning: Unexpected size of extern "\meta{extern + path}.pdf"; expected\\ $\meta{expected width}\times\meta{expected + height}$, got $\meta{width}\times\meta{height}$} + + This warning is related to warning~\ref{item:warning:extract:unexpected-size} + above, only that it occurs once the extern is extracted. The same + investigative methods apply. +\item \code{!pdfTeX error: pdflatex (file \meta{extern path}.pdf): reading + image file failed} + + This is a fatal error. The extern file got corrupted, somehow --- + inexistent, or even empty, extern files merely trigger recompilation. +\end{enumerate} + +If there was no warning or error --- are you certain that Memoize is +\refmmz{enable}d, and that it is not in the \refmmz{recompile} mode? Remember +that these settings can also apply only to a part of the document; search for +any stray \refcmd{mmzset} or \refcmd{mmznext} commands. + + +\paragraph*{Warnings about duplicate labels, indices, etc.} may be safely +disregarded. + +Externalization causes any (non-immediate) |\write| commands in the extern to +be executed twice, once upon the shipout of the regular page, and once upon the +shipout of the extern page. This results in warnings about doubly defined +labels, hyperreferences, indices, etc. For example, you might get +\texttt{LaTeX Warning: Label `' multiply defined} or \texttt{warning (pdf + backend): ignoring duplicate destination with the name ''}. You can +safely disregard these warnings; they will disappear once the extern is +utilized. + + +\paragraph{Memoization was aborted} + +This warning means that either: +\begin{itemize} +\item you are trying to (auto)memoize a \refenv{tikzpicture} with + \refkey{/tikz/remember picture} set, or more generally, some code which + contains \refcmd{savepos} --- this can't be done, see + section~\ref{sec:tut:good-to-know}; or +\item an error occurred during memoization --- in this case, Memoize cowardly + refuses to proceed with memoization, see section~\ref{sec:known-issues} for + details. +\end{itemize} + + +\subsection{License} + +Copyright \textcopyright\ 2020- SaÅ¡o Živanović. + +This work may be distributed and/or modified under the conditions of the +\hologo{LaTeX} Project Public License, either version 1.3c of this license or +(at your option) any later version. The latest version of this license is +in \url{https://www.latex-project.org/lppl.txt} and version 1.3 or later is +part of all distributions of \hologo{LaTeX} version 2008 or later. + +This work comprises of the sources, generated files, accompanying scripts, +auxiliary files and scripts, documentation, documentation sources, examples and +example sources of packages |memoize|, |nomemoize|, |memoizable|, |auto| and +|collargs|. The files belonging to this work and covered by LPPL are listed in +\meta{texmf}|/doc/generic/memoize/FILES|. + +This work has the LPPL maintenance status `maintained.' The Current Maintainer +of this work is SaÅ¡o Živanović. The work is available on CTAN +at \url{https://ctan.org/pkg/memoize} and on GitHub +at \url{https://github.com/sasozivanovic/memoize}. + + +\subsection{Changelog} + +\newcommand\githubrelease[2]{% + \href{https://github.com/sasozivanovic/memoize/releases/tag/#2}{#1 #2}% +} +\begin{description} +\item[\githubrelease{2020/07/17}{v0.1}] + The proof-of-concept, available only at GitHub. +\item[\githubrelease{2023/10/10}{v1.0.0}] + A complete, fully documented reimplementation. +\end{description} + +\subsection{Acknowledgments} + +First and foremost, my gratitude goes to Stefan Müller of Language Science +Press for his encouragement and patience --- without him, this package might've +remained an idea forever! + +But there were others as well. Shunsaku Hirata of the \hologo{XeTeX} team +promptly resolved an issue with forward references in |xdvipdfmx|, and thereby +made Memoize work with \hologo{XeTeX}. Joseph Wright kindly didn't object to +me misappropriating \pkg{etoolbox} for other formats. Petra Rübe-Pugliese +(CTAN) and Karl Berry (\hologo{TeX}Live) offered good advice on packaging the +package; I would never get to call Advice Advice without their advice. Karl +also performed a security review of the extraction scripts, providing some very +useful comments along the way, and agreed to include the scripts among the +shell escape commands allowed in \hologo{TeX}Live. + +Thank you all! + + +\printindex + +\end{document} + + +% Local Variables: +% TeX-engine: luatex +% TeX-master: t +% End: diff --git a/doc/yadoc.sty b/doc/yadoc.sty new file mode 100644 index 0000000..c069b11 --- /dev/null +++ b/doc/yadoc.sty @@ -0,0 +1,491 @@ +%% yadoc.sty +%% +%% This file is a part of Memoize, a TeX package for externalization of +%% graphics and memoization of compilation results in general, available at +%% https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize. +%% +%% Copyright (c) 2020- Saso Zivanovic +%% (Sa\v{s}o \v{Z}ivanovi\'{c}) +%% +%% This work may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License, either version 1.3c of this license or (at +%% your option) any later version. The latest version of this license is in +%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of +%% all distributions of LaTeX version 2008 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Saso Zivanovic. +%% +%% The files belonging to this work and covered by LPPL are listed in +%% (/doc/generic/memoize/)FILES. + +\RequirePackage{tcolorbox} +%\tcbuselibrary{listings,documentation,xparse,raster,hooks,breakable} +\tcbuselibrary{raster,skins} + +\RequirePackage{etoolbox} + +\newif\ifyadoc@into@index +\newif\ifyadoc@index@gather +\newif\ifyadoc@index@colorize@names +\newif\ifyadoc@ref@page +\newif\ifyadoc@show@keypath + +\newcommand\yadocset[1]{\pgfqkeys{/yadoc}{#1}\ignorespaces} + +\yadocset{ + cmd item/.style={ + name prefix=\textbackslash, + label prefix=cmd, + }, + key item/.style={ + name prefix={\ifdefempty{\yadoc@keypath}{}{% + \ifyadoc@show@keypath + \textcolor + {\yadoc@name@color!\yadoc@keypath@color@opacity}% + {\yadoc@keypath/}% + \fi + }% + }, + ref prefix={\protect\ifyadoc@show@keypath\yadoc@keypath/\protect\fi}, + index prefix=, + parameters prefix={\texttt{=}}, + label prefix:=key:\yadoc@keypath@label/, + index annotation={key\ifdefempty{\yadoc@keypath}{}{ in \texttt{\yadoc@keypath}}}, + }, + env item/.style={ + head prefix={\texttt{\cs{begin}\{}}, + head infix={\}}, + head suffix={% + \par\strut{\ttfamily\nobreakspace\nobreakspace}\meta{environment body}% + \par\strut\texttt{\cs{end}\{\yadoc@do@name\}}}, + index annotation=environment, + label prefix=env, + }, + register item/.style={ + name prefix=\textbackslash, + label prefix=reg, + index annotation=register, + }, + file item/.style={ + index annotation=file, + label prefix=file, + }, + value item/.style={ + index annotation={value of + {\docref[show keypath,into index=false,link color=gray]{\yadoc@of}}}, + label prefix:={\yadoc@of=}, + }, + scope/.code={% + \begingroup + \pgfkeysalso{#1}% + \endgroup + }, + generic item/.style={ + label prefix:=, + }, + % + raster options/.style={}, + before body/.store in=\yadoc@before@body, + after body/.store in=\yadoc@after@body, + left/.dimstore in=\yadoc@left, + right/.dimstore in=\yadoc@right, + left indent/.dimstore in=\kvtcb@doc@indentleft, + right indent/.dimstore in=\kvtcb@doc@indentright, + name/.store in=\yadoc@name, + name/.append style={label={#1}, index={#1}, sort index={#1}}, + parameters/.store in=\yadoc@parameters, + description/.store in=\yadoc@description, + label/.store in=\yadoc@label, + label prefix:/.store in=\yadoc@label@prefix, + label prefix/.style={label prefix:={#1:}}, + name font/.store in=\yadoc@name@font, + name color/.store in=\yadoc@name@color, + name prefix/.store in=\yadoc@name@prefix, + name suffix/.store in=\yadoc@name@suffix, + name prefix/.append style={index prefix={#1}, ref prefix={#1}}, + name suffix/.append style={index suffix={#1}, ref suffix={#1}}, + parameters font/.store in=\yadoc@parameters@font, + parameters prefix/.store in=\yadoc@parameters@prefix, + parameters suffix/.store in=\yadoc@parameters@suffix, + keypath/.store in=\yadoc@keypath, + keypath label/.store in=\yadoc@keypath@label, + keypath/.append style={keypath label={#1}}, + keypath color opacity/.store in=\yadoc@keypath@color@opacity, + show keypath/.is if=yadoc@show@keypath, + index/.store in=\yadoc@index, + index prefix/.store in=\yadoc@index@prefix, + index suffix/.store in=\yadoc@index@suffix, + index annotation/.initial=, + index font/.store in=\yadoc@index@font, + index annotation font/.store in=\yadoc@index@annotation@font, + sort index/.store in=\yadoc@sort@index, + index colorize names/.is if=yadoc@index@colorize@names, + index page number format/.store in=\yadoc@index@page@number@format, + index gather/.is if=yadoc@index@gather, + index command/.store in=\yadoc@index@command, + index actual/.store in=\yadoc@index@actual, + index quote/.store in=\yadoc@index@quote, + index level/.store in=\yadoc@index@level, + index encapsulator/.store in=\yadoc@index@encapsulator, + see/.initial=, + ref font/.store in=\yadoc@ref@font, + ref prefix/.store in=\yadoc@ref@prefix, + ref suffix/.store in=\yadoc@ref@suffix, + head prefix/.store in=\yadoc@head@prefix, + head infix/.store in=\yadoc@head@infix, + head suffix/.store in=\yadoc@head@suffix, + phrases/.code={\pgfqkeys{/yadoc/phrases}{#1}}, + phrases/.unknown/.code={\csdef{yadoc@phrases@\pgfkeyscurrentname}{#1}}, + ref page/.is if=yadoc@ref@page, + of/.store in=\yadoc@of, + link color/.code={\hypercolor{link}{#1}}, + long description/.style={% for do/def + head/.append style={ + sidebyside gap=1em, + lefthand ratio=#1, + }, + }, + long description/.default=0.6, + % + .unknown/.code={% + \pgfkeysifdefined{/yadoc/\pgfkeyscurrentname\space item/.@cmd}{% + \begingroup + \expandafter\pgfkeysalso\expandafter{% + \pgfkeyscurrentname\space item, + before,#1,after, + do + }% + \endgroup + }{% + \PackageError{yadoc}{Unknown item "\pgfkeyscurrentname"}% + {Perhaps you have misspelled an option name?}% + }% + }, + before/.code={}, + after/.code={}, + do/.is choice, + ref options/.style={ + show keypath=false, + }, + def options/.style={ + show keypath, + }, + aux options/.style={ + show keypath=false, + }, + foreign options/.style={ + show keypath=false, + cmd item/.append style={index annotation=command}, + }, + index options/.code=, + into index/.is if=yadoc@into@index, + print/.is if=yadoc@printref, +} + +\NewDocumentEnvironment{doc}{O{}m}{% + \begin{list}{}{% + \setlength{\leftmargin}{\yadoc@left}% + \setlength{\itemindent}{0pt}% + \setlength{\itemsep}{0pt}% + \setlength{\parsep}{0pt}% + \setlength{\rightmargin}{\yadoc@right}% + }% + \item + \begin{tcboxedraster}[ + raster columns=1, + raster row skip=0pt, + raster before skip=0pt, + raster after skip=0pt, + raster force size=false, + /yadoc/raster options + ]{blankest, + before skip=1\baselineskip plus 6\baselineskip minus .5\baselineskip, + after skip=0pt plus 2pt minus .5\baselineskip,% + #1% + }% + \yadocset{do/.default=def,def options,#2}% + \end{tcboxedraster} + \nopagebreak + \yadoc@before@body\relax + \nopagebreak + \ignorespaces +}{% + \ifvmode\else\unskip\fi + \yadoc@after@body\relax + \end{list}% +} + +\newcommand\docaux[2]{% + \begingroup + \yadocset{do/.default=aux,aux options,#1={name={#2}}}% + \endgroup +} + +\newcommand\docAux[1]{% + \begingroup + \yadocset{do/.default=aux,aux options,#1}% + \endgroup +} + +\newcommand\docForeign[1]{% + \begingroup + \yadoc@hyperreffalse + \yadocset{do/.default=foreign,foreign options,#1}% + \endgroup +} + +\newcommand\docindex[1]{% + \begingroup + \yadoc@hyperreffalse + \yadocset{do/.default=index,index options,#1}% + \endgroup +} + +\yadocset{ + do/def/.code={% + \begin{tcolorbox}[% + blank, + colback=white, colframe=white, + code={% + \tcbdimto\tcb@temp@grow@left{\yadoc@left}% + \tcbdimto\tcb@temp@grow@right{\yadoc@right}% + }, + grow to left by=\tcb@temp@grow@left, + grow to right by=\tcb@temp@grow@right, + sidebyside, sidebyside align=top, sidebyside gap=-\tcb@w@upper@real, + force nobeforeafter, + phantom=\phantomsection, + /yadoc/head, + ]% + \yadoc@head@prefix + \yadoc@do@name + \yadoc@do@index + \yadoc@do@label + \yadoc@head@infix + \yadoc@do@parameters + \yadoc@head@suffix + \yadoc@do@description + \end{tcolorbox} + \nopagebreak + }, + do/aux/.code={% + \yadoc@do@name + \yadoc@do@index + \yadoc@do@label + }, + do/foreign/.code={% + \yadoc@do@label + }, + do/index/.code={% + \yadoc@do@label + \yadoc@do@index + }, +} + +\def\yadoc@do@name{% + \begingroup + \yadoc@name@colorize{% + \yadoc@name@font + \strut\yadoc@name@prefix\yadoc@name\yadoc@name@suffix\strut + }% + \endgroup +} + +\def\yadoc@do@index{% + \ifyadoc@into@index + \yadoc@index@command{% + \yadoc@sort@index + \yadoc@index@actual + \yadoc@format@index + }% + \ifyadoc@index@gather + \yadoc@index@command{% + \yadoc@phrases@Commands + \yadoc@index@level + \yadoc@sort@index + \yadoc@index@actual + \yadoc@format@index + }% + \fi + \fi +} + +\def\yadoc@name@colorize{% + \ifdefempty\yadoc@name@color{}{% + \textcolor{\yadoc@name@color}% + }% +} + +\def\yadoc@format@index{% + {% + \ifyadoc@index@colorize@names\yadoc@name@colorize\fi + \yadoc@index@font + \yadoc@index@prefix\yadoc@index\yadoc@index@suffix + }% + {% + \ifkeyempty{/yadoc/index annotation}{}{% + \space\yadoc@index@annotation@font\pgfkeysvalueof{/yadoc/index annotation}% + }% + }% + \ifdefempty\yadoc@index@page@number@format{}{% + \yadoc@index@encapsulator + \yadoc@index@page@number@format + }% + \ifkeyempty{/yadoc/see}{}{% + \yadoc@index@encapsulator + see{\pgfkeysvalueof{/yadoc/see}}% + }% +} + +\def\yadoc@do@label{% + \ifdefempty{\yadoc@label}{}{% + \begingroup + \yadocset{ref options}% + \protected@edef\@currentlabel{% + \protect\ifyadoc@setupref + \ifyadoc@hyperref + \protect\yadoc@hyperreftrue + \else + \protect\yadoc@hyperreffalse + \fi + \protect\fi + \protect\ifyadoc@printref + \yadoc@ref@font + \yadoc@ref@prefix\yadoc@name\yadoc@ref@suffix + \protect\fi + \protect\ifyadoc@into@index + \yadoc@do@index + \protect\fi + }% + \label{\yadoc@label@prefix\yadoc@label}% + \endgroup + }% +} + +\def\yadoc@do@parameters{% + \ifdefempty\yadoc@parameters{}{% + \begingroup + \yadoc@parameters@font + \yadoc@parameters@prefix\yadoc@parameters\yadoc@parameters@suffix + \endgroup + }% +} + +\def\yadoc@do@description{% + \ifdefempty{\yadoc@description}{}{% + \tcblower + \raggedleft + \strut + (\yadoc@description)% + \strut + }% +} + +% ref + +\newif\ifyadoc@setupref +\newif\ifyadoc@printref +\newif\ifyadoc@hyperref +\yadoc@printreftrue +\yadoc@hyperreftrue +\DeclareRobustCommand\docref[2][]{% + \quitvmode % otherwise, extra vertical space if this begins an \item !?! + \begingroup + \yadocset{ref options,#1}% + \ifcsname r@#2\endcsname + \expanded{% + \noexpand\yadoc@setupreftrue + \ifyadoc@printref\noexpand\yadoc@printreffalse\fi + \ifyadoc@into@index\noexpand\yadoc@into@indexfalse\fi + \ifmemoize\noexpand\memoizefalse\fi + \ref*{#2}% + \noexpand\yadoc@setupreffalse + \ifyadoc@printref\noexpand\yadoc@printreftrue\fi + \ifyadoc@into@index\noexpand\yadoc@into@indextrue\fi + \ifmemoize\noexpand\memoizetrue\fi + }% + \fi + \ifyadoc@printref\else\yadoc@hyperreffalse\fi + \ifyadoc@hyperref + \ifnum\getpagerefnumber{#2}=\thepage\relax + \yadoc@into@indexfalse + \fi + \hyperref[#2]{% + \ref*{#2}% + \ifyadoc@printref + \ifyadoc@ref@page\yadoc@ref@pagenumber{#2}\fi + \fi + }% + \else + \ref*{#2}% + \ifyadoc@printref + \ifyadoc@ref@page\yadoc@ref@pagenumber{#2}\fi + \fi + \fi + \endgroup +} +\def\yadoc@ref@pagenumber#1{% + \ifnum\getpagerefnumber{#1}=\thepage\relax + \else% + \textsuperscript{% + {\fontfamily{pzd}\fontencoding{U}\fontseries{m}\fontshape{n}% + \selectfont\char213}% + \,\yadoc@phrases@pageshort\,\pageref*{#1}}% + \fi +} + + +\yadocset{ + before body=, + after body=, + left=2em, + right=0pt, + left indent=-2em, + right indent=0pt, + name=, + name font=\ttfamily\bfseries, + index font=\ttfamily, + ref font=\ttfamily, + index annotation font=, + name color=black, + name prefix=, + name suffix=, + label=, + label prefix=, + parameters=, + parameters font=, + parameters prefix=, + parameters suffix=, + keypath=, + keypath color opacity=30, + description=, + into index=true, + index colorize names=false, + index page number format=, + index command=\index, + index gather=false, + index actual={@}, + index quote={"}, + index level={!}, + index encapsulator={|}, + head prefix=, + head infix=, + head suffix=, + ref page=false, + phrases={ + index=Index, + pageshort=P., + Commands=Commands, + }, + text/.code={#1}, + comma/.code={,\ }, + and/.code={\ and\ }, +} + +\def\ifkeyempty#1{\ifcsempty{pgfk@#1}} + +\AddToHook{begindocument}{% + \robustify\index + \robustify\hypersetup +} diff --git a/examples/1-basic.pdf b/examples/1-basic.pdf deleted file mode 100644 index 8fd64535f9eef48ec9ab7a0ec78b10a46d9181c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 97470 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 R=i*>u] (cons x) -- node[right,pos=0.4]{$\sim$} (atomic x); - \end{tikzpicture} - \caption{Variants of restrictiveness} - \label{fig:rest-and-cons} -\end{figure} - -\begin{center} - \begin{forest} - [VP - [DP] - [V\rlap' - [V] - [DP] - ] - ] - \end{forest} -\end{center} - -If your {\tt -shell-escape} option (perhaps called {\tt--enable-write18}) is -enabled (if it operates in restricted mode, {\tt pdflatex} must be allowed), -things should ``just work.'' - -\begin{enumerate} -\item After the first compilation, you should get a document containing three - pages: the tikzpicture, the forest tree and the document itself. -\item After the second compilation, the first two pages should disappear. You - should find the \emph{memos} in files - \begin{itemize} - \item {\tt 1-basic.5809A894D3808C95F53EEE848F9C3BBA.memo.pdf} and - \item {\tt 1-basic.B2E679FB208DD0D53C20B5017B4A8DAA.memo.pdf}. - \end{itemize} - -\end{enumerate} - -The long numbers in memo names are the md5sums of the code that produced -them. Try changing the tikz or forest code and you will get a new memo file -after two passes. - -\bigskip - -\emph{If something goes wrong, try deleting the memos --- this is always safe - to do --- and recompiling.} - - -\end{document} - -%%% Local Variables: -%%% mode: latex -%%% TeX-master: t -%%% End: diff --git a/examples/2-memodir.memo.dir/.dummy b/examples/2-memodir.memo.dir/.dummy deleted file mode 100644 index e69de29..0000000 diff --git a/examples/2-memodir.pdf b/examples/2-memodir.pdf deleted file mode 100644 index 2348f62da6b15ddba20121f06ec163fc218e2814..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68065 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 diff --git a/examples/2-memodir.tex b/examples/2-memodir.tex deleted file mode 100644 index 9842751..0000000 --- a/examples/2-memodir.tex +++ /dev/null @@ -1,55 +0,0 @@ -\documentclass{article} -\usepackage{forest} - -\usepackage{memoize} -\memoizeset{memo dir} - -\begin{document} - -After loading the package with -\begin{center} - {\tt \string\usepackage{memoize}} -\end{center} -we wrote -\begin{center} - {\tt \string\memoizeset\{memo dir\}} -\end{center} -and now, the memo ({\tt B2E679FB208DD0D53C20B5017B4A8DAA.memo.pdf}) will appear -in folder {\tt 2-memodir.memo.dir}. - -\begin{center} - \begin{forest} - [VP - [DP] - [V\rlap' - [V] - [DP] - ] - ] - \end{forest} -\end{center} - -Most of user's interaction with Memoize is through macro {\tt - \string\memoizeset}. It can be used anywhere in the document, but some keys -only make sense in the preamble. The effects of {\tt \string\memoizeset} -persist until the end of the \TeX\ group. - -The argument of {\tt \string\memoizeset} is a {\tt pgfkeys} keylist. In short: -\begin{itemize} -\item A keylist is a comma-separated list of {\tt =} pairs, where - the {\tt =} part is not always mandatory. -\item In the keylist, spaces around keys and values are stripped away. Newlines - inside a keylist are allowed, but empty lines are not. -\item Characters {\tt ,}, {\tt =} and {\tt /} have special meaning in a - keylist. If you want to include one of them in the value, surround the value - by braces, like this: {\tt =\{\}} -\end{itemize} -For details, see section 88 of the PGF/TikZ manual. - -\end{document} - - -%%% Local Variables: -%%% mode: latex -%%% TeX-master: t -%%% End: diff --git a/examples/3-enable-disable-prevent.memo.dir/.dummy b/examples/3-enable-disable-prevent.memo.dir/.dummy deleted file mode 100644 index e69de29..0000000 diff --git a/examples/3-enable-disable-prevent.pdf b/examples/3-enable-disable-prevent.pdf deleted file mode 100644 index a441d2376b345aaf4442dd2a192a5e252ed988b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120337 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%0D_YX& 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 U=`+SWtlZ382ox0JiV_I_1z|7Ab^rhX diff --git a/examples/4-main.tex b/examples/4-main.tex deleted file mode 100644 index b86f8ac..0000000 --- a/examples/4-main.tex +++ /dev/null @@ -1,69 +0,0 @@ -\documentclass{article} -\usepackage{docmute} -\enlargethispage{1cm} -\pagestyle{empty} - -\usepackage{memoize} -\memoizeset{ - memo filename prefix={chapters/book.memo.dir/} -} - -\usepackage{tikz} - -\begin{document} - -\section{Introduction} - -When writing a longer document, it is often desirable to compile only a part of -the document, and there are several ways to achieve that. This example uses the -{\tt docmute} package to achieve that. But what we really want to know here is: -Can we use pictures externalized when compiling the included files when we -compile the main document, and vice versa? Sure! - -The template for names of memo files is not fixed. It is composed of: -\begin{enumerate} -\item the prefix which you can set by memoize key {\tt memo filename prefix}, -\item the automatically computed md5sum, and -\item the suffix which you can set by memoize key {\tt memo filename suffix}. -\end{enumerate} -Now crucially, the prefix can contain a path (which must exist, in the usual - setup TeX can't create folders for you). In this document, we have exploited -this to set -\begin{itemize} -\item {\tt memo filename prefix=\{chapters/book.memo.dir/\}} in the main file - --- note the braces around the value, and the slash at the end! --- and -\item {\tt memo filename prefix=\{book.memo.dir/\}} in the included file, which - resides in directory {\tt chapters}. -\end{itemize} - -\input{chapters/4-chapter} - -\section{Readonly} - -When {\tt \string\memoize\{readonly\}} is in effect, memoize will use any -pictures that were already externalized, but it will not externalize new stuff. -This is great when we work on a picture, because we don't want to see it as an -extra page all the time (and wait for the old version to be split off all the - time). - -One possible workflow is to say {\tt readonly} in the included file, as that is -the file that you will be compiling over and over again when you work on it. -Nothing will get externalized, but the compilation will be fast, because -externalized pictures will be used. Once you want to look at the whole book, -you compile the main file (which contains no {\tt readonly}) and everything -gets externalized. - -\section{Conclusion} - -Easy, right? - - - - - -\end{document} - -%%% Local Variables: -%%% mode: latex -%%% TeX-master: t -%%% End: diff --git a/examples/5-overlay.memo.dir/.dummy b/examples/5-overlay.memo.dir/.dummy deleted file mode 100644 index e69de29..0000000 diff --git a/examples/5-overlay.pdf b/examples/5-overlay.pdf deleted file mode 100644 index 650d3239c211fdfb2fe57d09f8b994976459a3be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 155561 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.memo.pdf}) - between tests. This will force - recompilation.}] - {If you compile the included file (twice) first, the main file will pick up - this externalized picture. And vice versa.}; - \end{tikzpicture} -\end{flushleft} - -\end{document} - - -%%% Local Variables: -%%% mode: latex -%%% TeX-master: t -%%% End: diff --git a/examples/chapters/book.memo.dir/.dummy b/examples/chapters/book.memo.dir/.dummy deleted file mode 100644 index e69de29..0000000 diff --git a/memoize-clean.pl b/memoize-clean.pl new file mode 100755 index 0000000..4e1334c --- /dev/null +++ b/memoize-clean.pl @@ -0,0 +1,163 @@ +#!/usr/bin/env perl + +# This file is a part of Memoize, a TeX package for externalization of +# graphics and memoization of compilation results in general, available at +# https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize. +# +# Copyright (c) 2020- Saso Zivanovic +# +# This work may be distributed and/or modified under the conditions of the +# LaTeX Project Public License, either version 1.3c of this license or (at +# your option) any later version. The latest version of this license is in +# https://www.latex-project.org/lppl.txt and version 1.3c or later is part of +# all distributions of LaTeX version 2008 or later. +# +# This work has the LPPL maintenance status `maintained'. +# The Current Maintainer of this work is Saso Zivanovic. +# +# The files belonging to this work and covered by LPPL are listed in +# /doc/generic/memoize/FILES. + +use strict; +use Getopt::Long; +# I intend to rewrite this script using Path::Class. +use Cwd 'realpath'; +use File::Spec; +use File::Basename; + +my $VERSION = '2023/10/10 v1.0.0'; + +my $usage = "usage: memoize-clean.py [-h] [--yes] [--all] [--quiet] [--prefix PREFIX] [mmz ...]\n"; +my $Help = < \$yes, + "all|a" => \$all, + "prefix|p=s" => \@prefixes, + "quiet|q|?" => \$quiet, + "help|h|?" => \$help, + "version|V" => \$print_version, + ) or die $usage; +$help and die "$usage\n$Help"; +if ($print_version) { print("memoize-clean.pl of Memoize $VERSION\n"); exit 0 } + +my (%keep, %prefixes); + +my $curdir = Cwd::getcwd(); + +for my $prefix (@prefixes) { + $prefixes{Cwd::realpath(File::Spec->catfile(($curdir), $prefix))} = ''; +} + +my @mmzs = @ARGV; + +for my $mmz (@mmzs) { + my ($mmz_filename, $mmz_dir) = File::Basename::fileparse($mmz); + @ARGV = ($mmz); + my $endinput = 0; + my $empty = -1; + my $prefix = ""; + while (<>) { + if (/^ *$/) { + } elsif ($endinput) { + die "Bailing out, \\endinput is not the last line of file $mmz.\n"; + } elsif (/^ *\\mmzPrefix *{(.*?)}/) { + $prefix = $1; + $prefixes{Cwd::realpath(File::Spec->catfile(($curdir,$mmz_dir), $prefix))} = ''; + $empty = 1 if $empty == -1; + } elsif (/^%? *\\mmz(?:New|Used)(?:CC?Memo|Extern) *{(.*?)}/) { + my $fn = $1; + if ($prefix eq '') { + die "Bailing out, no prefix announced before file $fn.\n"; + } + $keep{Cwd::realpath(File::Spec->catfile(($mmz_dir), $fn))} = 1; + $empty = 0; + if (rindex($fn, $prefix, 0) != 0) { + die "Bailing out, prefix of file $fn does not match " . + "the last announced prefix ($prefix).\n"; + } + } elsif (/^ *\\endinput *$/) { + $endinput = 1; + } else { + die "Bailing out, file $mmz contains an unrecognized line: $_\n"; + } + } + die "Bailing out, file $mmz is empty.\n" if $empty && !$all; + die "Bailing out, file $mmz does not end with \\endinput; this could mean that " . + "the compilation did not finish properly. You can only clean with --all.\n" + if $endinput == 0 && !$all; +} + +my @tbdeleted; +sub populate_tbdeleted { + my ($basename_prefix, $dir, $suffix_dummy) = @_; + opendir(MD, $dir) or die "Cannot open directory '$dir'"; + while( (my $fn = readdir(MD)) ) { + my $path = File::Spec->catfile(($dir),$fn); + if ($fn =~ /\Q$basename_prefix\E[0-9A-F]{32}(?:-[0-9A-F]{32})?(?:-[0-9]+)?(\.memo|(?:-[0-9]+)?\.pdf|\.log)/ and ($all || !exists($keep{$path}))) { + push @tbdeleted, $path; + } + } + closedir(MD); +} +for my $prefix (keys %prefixes) { + my ($basename_prefix, $dir, $suffix); + if (-d $prefix) { + populate_tbdeleted('', $prefix, ''); + } + populate_tbdeleted(File::Basename::fileparse($prefix)); +} +@tbdeleted = sort(@tbdeleted); + +my @allowed_dirs = ($curdir); +my @deletion_not_allowed; +for my $f (@tbdeleted) { + my $f_allowed = 0; + for my $dir (@allowed_dirs) { + if ($f =~ /^\Q$dir\E/) { + $f_allowed = 1; + last; + } + } + push(@deletion_not_allowed, $f) if ! $f_allowed; +} +die "Bailing out, I was asked to delete these files outside the current directory:\n" . + join("\n", @deletion_not_allowed) if (@deletion_not_allowed); + +if (scalar(@tbdeleted) != 0) { + my $a; + unless ($yes) { + print("I will delete the following files:\n" . + join("\n",@tbdeleted) . "\n" . + "Proceed (y/n)? "); + $a = lc(<>); + chomp $a; + } + if ($yes || $a eq 'y' || $a eq 'yes') { + foreach my $fn (@tbdeleted) { + print "Deleting ", $fn, "\n" unless $quiet; + unlink $fn; + } + } else { + die "Bailing out.\n"; + } +} elsif (!$quiet) { + print "Nothing to do, the directory seems clean.\n"; +} diff --git a/memoize-clean.py b/memoize-clean.py new file mode 100755 index 0000000..dd54332 --- /dev/null +++ b/memoize-clean.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python + +# This file is a part of Memoize, a TeX package for externalization of +# graphics and memoization of compilation results in general, available at +# https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize. +# +# Copyright (c) 2020- Saso Zivanovic +# +# This work may be distributed and/or modified under the conditions of the +# LaTeX Project Public License, either version 1.3c of this license or (at +# your option) any later version. The latest version of this license is in +# https://www.latex-project.org/lppl.txt and version 1.3c or later is part of +# all distributions of LaTeX version 2008 or later. +# +# This work has the LPPL maintenance status `maintained'. +# The Current Maintainer of this work is Saso Zivanovic. +# +# The files belonging to this work and covered by LPPL are listed in +# /doc/generic/memoize/FILES. + +__version__ = '2023/10/10 v1.0.0' + +import argparse, re, sys, pathlib, os + +parser = argparse.ArgumentParser( + description="Remove (stale) memo and extern files.", + epilog = "For details, see the man page or the Memoize documentation." +) +parser.add_argument('--yes', '-y', action = 'store_true', + help = 'Do not ask for confirmation.') +parser.add_argument('--all', '-a', action = 'store_true', + help = 'Remove *all* memos and externs.') +parser.add_argument('--quiet', '-q', action = 'store_true') +parser.add_argument('--prefix', '-p', action = 'append', default = [], + help = 'A path prefix to clean; this option can be specified multiple times.') +parser.add_argument('mmz', nargs= '*', help='.mmz record files') +parser.add_argument('--version', '-V', action = 'version', + version = f"%(prog)s of Memoize " + __version__) +args = parser.parse_args() + +re_prefix = re.compile(r'\\mmzPrefix *{(.*?)}') +re_memo = re.compile(r'%? *\\mmz(?:New|Used)(?:CC?Memo|Extern) *{(.*?)}') +re_endinput = re.compile(r' *\\endinput *$') + +prefixes = set(pathlib.Path(prefix).resolve() for prefix in args.prefix) +keep = set() + +# We loop through the given .mmz files, adding prefixes to whatever manually +# specified by the user, and collecting the files to keep. +for mmz_fn in args.mmz: + mmz = pathlib.Path(mmz_fn) + mmz_parent = mmz.parent.resolve() + try: + with open(mmz) as mmz_fh: + prefix = '' + endinput = False + empty = None + for line in mmz_fh: + line = line.strip() + + if not line: + pass + + elif endinput: + raise RuntimeError( + r'Bailing out, \endinput is not the last line of file $mmz_fn.') + + elif m := re_prefix.match(line): + prefix = m[1] + prefixes.add( (mmz_parent/prefix).resolve() ) + if empty is None: + empty = True + + elif m := re_memo.match(line): + if not prefix: + raise RuntimeError( + f'Bailing out, no prefix announced before file "{m[1]}".') + if not m[1].startswith(prefix): + raise RuntimeError( + f'Bailing out, prefix of file "{m[1]}" does not match ' + f'the last announced prefix ({prefix}).') + keep.add((mmz_parent / m[1])) + empty = False + + elif re_endinput.match(line): + endinput = True + continue + + else: + raise RuntimeError(fr"Bailing out, " + fr"file {mmz_fn} contains an unrecognized line: {line}") + + if empty and not args.all: + raise RuntimeError(fr'Bailing out, file {mmz_fn} is empty.') + + if not endinput and empty is not None and not args.all: + raise RuntimeError( + fr'Bailing out, file {mmz_fn} does not end with \endinput; ' + fr'this could mean that the compilation did not finish properly. ' + fr'You can only clean with --all.' + ) + + # It is not an error if the file doesn't exist. + # Otherwise, cleaning from scripts would be cumbersome. + except FileNotFoundError: + pass + +tbdeleted = [] +def populate_tbdeleted(folder, basename_prefix): + re_aux = re.compile( + re.escape(basename_prefix) + + '[0-9A-F]{32}(?:-[0-9A-F]{32})?(?:-[0-9]+)?(?:\.memo|(?:-[0-9]+)?\.pdf|\.log)$') + try: + for f in folder.iterdir(): + if re_aux.match(f.name) and (args.all or f not in keep): + tbdeleted.append(f) + except FileNotFoundError: + pass + +for prefix in prefixes: + # "prefix" is interpreted both as a directory (if it exists) and a basename prefix. + if prefix.is_dir(): + populate_tbdeleted(prefix, '') + populate_tbdeleted(prefix.parent, prefix.name) + +allowed_dirs = [pathlib.Path().absolute()] # todo: output directory +deletion_not_allowed = [f for f in tbdeleted if not f.is_relative_to(*allowed_dirs)] +if deletion_not_allowed: + raise RuntimeError("Bailing out, " + "I was asked to delete these files outside the current directory:\n" + + "\n".join(str(f) for f in deletion_not_allowed)) + +_cwd_absolute = pathlib.Path().absolute() +def relativize(path): + try: + return path.relative_to(_cwd_absolute) + except ValueError: + return path + +if tbdeleted: + tbdeleted.sort() + if not args.yes: + print('I will delete the following files:') + for f in tbdeleted: + print(relativize(f)) + print("Proceed (y/n)? ") + a = input() + if args.yes or a == 'y' or a == 'yes': + for f in tbdeleted: + if not args.quiet: + print("Deleting", relativize(f)) + try: + f.unlink() + except FileNotFoundError: + print(f"Cannot delete {f}") + else: + print("Bailing out.") +elif not args.quiet: + print('Nothing to do, the directory seems clean.') diff --git a/memoize-extract.pl b/memoize-extract.pl new file mode 100755 index 0000000..8fba3d3 --- /dev/null +++ b/memoize-extract.pl @@ -0,0 +1,205 @@ +#!/usr/bin/env perl + +# This file is a part of Memoize, a TeX package for externalization of +# graphics and memoization of compilation results in general, available at +# https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize. +# +# Copyright (c) 2020- Saso Zivanovic +# +# This work may be distributed and/or modified under the conditions of the +# LaTeX Project Public License, either version 1.3c of this license or (at +# your option) any later version. The latest version of this license is in +# https://www.latex-project.org/lppl.txt and version 1.3c or later is part of +# all distributions of LaTeX version 2008 or later. +# +# This work has the LPPL maintenance status `maintained'. +# The Current Maintainer of this work is Saso Zivanovic. +# +# The files belonging to this work and covered by LPPL are listed in +# /doc/generic/memoize/FILES. + +use strict; +use Getopt::Long; +use Path::Class; +use File::Spec; +use File::Basename; +use PDF::API2; + +my $VERSION = '2023/10/10 v1.0.0'; + +my $usage = "usage: memoize-extract.pl [-h] [--pdf PDF] [--prune] [--keep] [--force] [--log LOG] [--warning-template WARNING_TEMPLATE] [--quiet] [--mkdir] mmz\n"; +my $Help = < \$pdf_arg, + "keep|k" => \$keep, + "prune|p" => \$prune, + "log|l=s" => \$log, + "quiet|q" => \$quiet, + "embedded|e" => \$embedded, + "force|f" => \$force, + "warning-template|w=s" => \$warning_template, + "mkdir|m" => \$mkdir, + "help|h|?" => \$help, + "version|V" => \$print_version, + ) or die $usage; +if ($help) {print("$usage\n$Help"); exit 0} +if ($print_version) { print("memoize-extract.pl of Memoize $VERSION\n"); exit 0 } +die $usage unless @ARGV == 1; + +my $message_prefix = $embedded ? basename($0) . ': ' : ''; +print("\n") if ($embedded); + +my @output_paths = (dir()->absolute->resolve); +my $texmfoutput = `kpsewhich --var-value=TEXMFOUTPUT`; +$texmfoutput =~ s/^\s+|\s+$//g; +if ($texmfoutput) { + my $texmfoutput_dir = dir($texmfoutput)->absolute->resolve; + push(@output_paths, $texmfoutput_dir) unless $texmfoutput_dir->dir_list == 1 && ! $texmfoutput_dir->volume; +} + +sub paranoia { + my $file = $_[0]; + die "${message_prefix}Cannot create a hidden file or dir: $file" + if $file->basename =~ /^\./; + my $parent = $file->parent->absolute->resolve; + die "${message_prefix}Cannot write outside the current working or output directory tree: $file" + unless grep($_->contains($parent), @output_paths); +} + +my $mmz_arg = $ARGV[0]; +my $mmz_file = file($mmz_arg); +my $mmz_dir = $mmz_file->parent; + +if ($mkdir) { + my $dir = dir($mmz_arg)->cleanup; + my $current = dir(File::Spec->catpath($dir->volume, + $dir->is_absolute ? File::Spec->rootdir : File::Spec->curdir, + ''))->absolute; + for my $c ($dir->components) { + $current = $current->subdir($c); + if (-d $current) { + $current = $current->resolve; + } else { + paranoia($current); + mkdir($current); + print("${message_prefix}Created directory $current\n") unless $quiet; + } + } + exit; +} else { + die "${message_prefix}The 'mmz' argument should be a file with suffix '.mmz', not '$mmz_file'\n" unless $mmz_file->basename =~ /\.mmz$/; +} + +# Enable in-place editing (of the .mmz file). +paranoia($mmz_file) unless $keep; +$^I = "" unless $keep; + +my $pdf_file = $pdf_arg ? file($pdf_arg) : $mmz_dir->file($mmz_file->basename =~ s/\.mmz$/\.pdf/r)->cleanup; +paranoia($pdf_file) if $prune; + +if ($log) { + paranoia(file($log)); + open LOG, ">$log"; +} else { + *LOG = *STDERR; +} + +my ($pdf, %extern_pages); +print "${message_prefix}Extracting externs from $pdf_file:\n" unless $quiet; + +my $tolerance = 0.01; +my $done_message = "${message_prefix}Done (there was nothing to extract).\n"; + +while (<>) { + if (/^\\mmzNewExtern *{(?P(?P.*?)(?P[0-9A-F]{32})-(?P[0-9A-F]{32})(?:-[0-9]+)?.pdf)}{(?P[0-9]+)}{(?P[0-9.]*)pt}{(?P[0-9.]*)pt}/) { + my $extern_file = file($+{extern_path}); + if (! $extern_file->is_absolute) { + $extern_file = $mmz_dir->file($+{extern_path}); + } + paranoia($extern_file); + my $page = $+{page_n}; + my $expected_width_pt = $+{expected_width}; + my $expected_height_pt = $+{expected_height}; + my $c_memo_file = $mmz_dir->file($+{prefix} . $+{code_md5sum} . '.memo'); + my $cc_memo_file = $mmz_dir->file($+{prefix} . $+{code_md5sum} . '-' . $+{context_md5sum} . '.memo'); + if (!(-e $c_memo_file && -e $cc_memo_file)) { + print LOG ($warning_template =~ s/\\warningtext/Not extracting page $page into extern $extern_file, because the associated (c)c-memo does not exist/gr), "\n\\endinput\n"; + last; + } + eval { $pdf = PDF::API2->open($pdf_file->stringify) unless $pdf; }; + if ($@) { + print LOG ($warning_template =~ s/\\warningtext/Cannot read file "$pdf_file". Perhaps you have to load Memoize earlier in the preamble?/gr), "\n\\endinput\n"; + close LOG; + die "${message_prefix}File '$pdf_file' cannot be read, bailing out.\n"; + } + my $extern = PDF::API2->new(); + $extern->version($pdf->version); + $extern->import_page($pdf, $page); + my $extern_page = $extern->open_page(1); + my ($x0, $y0, $x1, $y1) = $extern_page->get_mediabox(); + my $width_pt = ($x1 - $x0) / 72 * 72.27; + my $height_pt = ($y1 - $y0) / 72 * 72.27; + my $warning = ''; + if (abs($width_pt - $expected_width_pt) > $tolerance + || abs($height_pt - $expected_height_pt) > $tolerance) + { + $warning = "I refuse to extract page $page from $pdf_file, because its size (${width_pt}pt x ${height_pt}pt) is not what I expected (${expected_width_pt}pt x ${expected_height_pt}pt)"; + print LOG ($warning_template =~ s/\\warningtext/$warning/gr), "\n"; + } + if ($warning && !$force) { + unlink $extern_file; + } else { + $extern->saveas($extern_file->stringify); + $done_message = "${message_prefix}Done.\n"; + print STDOUT "${message_prefix} Page $page --> $extern_file\n" unless $quiet; + $extern_pages{$page} = 1 if $prune; + print("%") unless $keep; + } + } + print unless $keep; +} + +print $done_message unless $quiet; + +if ($pdf and $prune) { + paranoia($pdf_file); + my $pruned_pdf = PDF::API2->new(); + for (my $n = 1; $n <= $pdf->page_count(); $n++) { + if (! $extern_pages{$n}) { + $pruned_pdf->import_page($pdf, $n); + } + } + $pruned_pdf->save($pdf_file->stringify); + print("${message_prefix}The following extern pages were pruned out of the PDF: ", + join(",", sort(keys(%extern_pages))) . "\n") unless $quiet; +} + +if ($log) { + print LOG "\\endinput\n"; + close LOG; +} diff --git a/memoize-extract.py b/memoize-extract.py new file mode 100755 index 0000000..54d8870 --- /dev/null +++ b/memoize-extract.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python3 + +# This file is a part of Memoize, a TeX package for externalization of +# graphics and memoization of compilation results in general, available at +# https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize. +# +# Copyright (c) 2020- Saso Zivanovic +# +# This work may be distributed and/or modified under the conditions of the +# LaTeX Project Public License, either version 1.3c of this license or (at +# your option) any later version. The latest version of this license is in +# https://www.latex-project.org/lppl.txt and version 1.3c or later is part of +# all distributions of LaTeX version 2008 or later. +# +# This work has the LPPL maintenance status `maintained'. +# The Current Maintainer of this work is Saso Zivanovic. +# +# The files belonging to this work and covered by LPPL are listed in +# /doc/generic/memoize/FILES. + +__version__ = '2023/10/10 v1.0.0' + +import argparse, re, sys, os, pdfrw, subprocess, itertools +from pathlib import Path + +parser = argparse.ArgumentParser( + description = "Extract extern pages out of the document PDF.", + epilog = "For details, see the man page or the Memoize documentation.", + prog = 'memoize-extract.py', +) +parser.add_argument('--pdf', '-P', help = 'extract from file PDF') +parser.add_argument('--prune', '-p', action = 'store_true', + help = 'remove the extern pages after extraction') +parser.add_argument('--keep', '-k', action = 'store_true', + help = 'do not mark externs as extracted') +parser.add_argument('--force', '-f', action = 'store_true', + help = 'extract even if the size-check fails') +parser.add_argument('--log', '-l', default = os.devnull, help = 'the log file') +parser.add_argument('--warning-template', '-w', default = '\warningtext', + help = '\warningtext in the template will be replaced by the warning message') +parser.add_argument('--quiet', '-q', action = 'store_true', + help = "describe what's happening") +parser.add_argument('--embedded', '-e', action = 'store_true', + help = "prefix all messages to the standard output with the script name") +parser.add_argument('--mkdir', '-m', action = 'store_true', + help = 'create a directory (and exit)') +parser.add_argument('mmz', + help = 'the record file produced by Memoize: doc.mmz when compiling doc.tex') +parser.add_argument('--version', '-V', action = 'version', + version = f"%(prog)s of Memoize " + __version__) + +args = parser.parse_args() + +message_prefix = parser.prog + ': ' if args.embedded else '' +if args.embedded: + print() + +# Even a bit more paranoid than required: +# (a) disallowing TEXMFOUTPUT=/ (while allowing C:\ on Windows) +# (b) waiting for access to '-output-directory'. +output_paths = [Path.cwd()] +if texmfoutput := subprocess.run( + ['kpsewhich', '--var-value=TEXMFOUTPUT'], + capture_output = True).stdout.decode().strip(): + texmfoutput_dir = Path(texmfoutput).resolve() + if len(texmfoutput_dir.parts) != 1 or texmfoutput_dir.drive: + output_paths.append(texmfoutput_dir) + +def paranoia(f): + p = Path(f).resolve() + if p.stem.startswith('.'): + raise RuntimeError(f"{message_prefix}Cannot create a hidden file or dir: {f}") + if not any(p.is_relative_to(op) for op in output_paths): + raise RuntimeError(f"{message_prefix}Cannot write outside the current working or output directory tree: {f}") + +mmz_file = Path(args.mmz) + +if args.mkdir: # Here, argument "mmz" is interpreted as the directory to create. + # We cannot simply say + # paranoia(mmz_file) + # mmz_file.mkdir(parents = True, exist_ok = True) + # because have be paranoid about the intermediate directories as well: + # memoize-extract.py -m a/../../BAD/..//b + # Note that paranoia might kick in only after a part of the given path was + # already created. This is in accord to how "mkdir" behaves wrt existing + # files. + for folder in itertools.chain(reversed(mmz_file.parents), (mmz_file,)): + if not folder.is_dir(): + paranoia(folder) + folder.mkdir(exist_ok = True) + if not args.quiet: + print(f"{message_prefix}Created directory {folder}") + sys.exit() +elif mmz_file.suffix != '.mmz': + raise RuntimeError(f"{message_prefix}The 'mmz' argument should be a file with suffix '.mmz', not '{mmz_file}'") + +mmz_dir = mmz_file.parent +pdf_file = Path(args.pdf) if args.pdf else mmz_file.with_suffix('.pdf') +paranoia(pdf_file) +pdf = None +extern_pages = [] +new_mmz = [] +args.log is os.devnull or paranoia(Path(args.log)) +re_newextern = re.compile(r'\\mmzNewExtern *{(?P(?P.*?)(?P[0-9A-F]{32})-(?P[0-9A-F]{32})(?:-[0-9]+)?.pdf)}{(?P[0-9]+)}{(?P[0-9.]*)pt}{(?P[0-9.]*)pt}') +tolerance = 0.01 +done_message = f"{message_prefix}Done (there was nothing to extract)." + +# Complication: I want to use 'with', but don't have to open stderr. +with open(args.log, 'w') as log: + log = sys.stderr if args.log is os.devnull else log + try: + mmz = mmz_file.open() + except FileNotFoundError: + print(f'''{message_prefix}File "{mmz_file}" does not exist, assuming there's nothing to do.''', + file = sys.stderr) + else: + if not args.quiet: + print(f"{message_prefix}Extracting externs from {pdf_file}") + for line in mmz: + if m := re_newextern.match(line): + extern_file = mmz_dir / m['extern_fn'] + paranoia(extern_file) + page_n = int(m['page_n'])-1 + c_memo = mmz_dir / (m['prefix'] + m['code_md5sum'] + '.memo') + cc_memo = mmz_dir / (m['prefix'] + m['code_md5sum'] + '-' + m['context_md5sum'] + '.memo') + if not (c_memo.exists() and cc_memo.exists()): + print(args.warning_template.replace('\warningtext', f'Not extracting page {page_n} into extern {extern_file}, because the associated (c)c-memo does not exist'), file = log) + continue + if not pdf: + try: + pdf = pdfrw.PdfReader(pdf_file) + except pdfrw.errors.PdfParseError: + print(f'{message_prefix}File "{pdf_file}" cannot be read, bailing out.', file = sys.stderr) + print(args.warning_template.replace('\warningtext', f'Cannot read file "{pdf_file}". Perhaps you have to load Memoize earlier in the preamble?'), file = log) + args.keep = True + break + extern = pdfrw.PdfWriter(extern_file) + page = pdf.pages[page_n] + expected_width_pt, expected_height_pt = float(m['expected_width']), float(m['expected_height']) + mb = page['/MediaBox'] + width_bp, height_bp = float(mb[2]) - float(mb[0]), float(mb[3]) - float(mb[1]) + width_pt = width_bp / 72 * 72.27 + height_pt = height_bp / 72 * 72.27 + warning = None + if abs(width_pt - expected_width_pt) > tolerance \ + or abs(height_pt - expected_height_pt) > tolerance: + warning = ( + f'I refuse to extract page {page_n+1} from "{pdf_file}", ' + f'because its size ({width_pt}pt x {height_pt}pt) is not ' + f'what I expected ({expected_width_pt}pt x {expected_height_pt}pt)') + print(args.warning_template.replace('\warningtext', warning), file = log) + if warning and not args.force: + extern_file.unlink(missing_ok = True) + else: + extern.addpage(page) + if not args.quiet: + print(f"{message_prefix} Page {page_n+1} --> {extern_file}", file = sys.__stdout__) + extern.write() + done_message = f"{message_prefix}Done." + if args.prune: + extern_pages.append(page_n) + if not args.keep: + line = '%' + line + if not args.keep: + new_mmz.append(line) + mmz.close() + if not args.quiet: + print(done_message) + if not args.keep: + paranoia(mmz_file) + with open(mmz_file, 'w') as mmz: + for line in new_mmz: + print(line, file = mmz, end = '') + if args.prune and extern_pages: + pruned_pdf = pdfrw.PdfWriter(pdf_file) + pruned_pdf.addpages( + page for n, page in enumerate(pdf.pages) if n not in extern_pages) + pruned_pdf.write() + if not args.quiet: + print(f"{message_prefix}The following extern pages were pruned out of the PDF:", + ",".join(str(page+1) for page in extern_pages)) + if args.log is not os.devnull: + print(r'\endinput', file = log) diff --git a/memoize-tikz.tex b/memoize-tikz.tex deleted file mode 100644 index 502aebf..0000000 --- a/memoize-tikz.tex +++ /dev/null @@ -1,41 +0,0 @@ -% Command handler for tikz: - -\makeatletter % todo: this can't be here, if it's for plain TeX as well - -% \tikz [] {} -% or -% \tikz [] ; -% -% = :key={value}, ... - -\def\mmz@tikz{% - \mmz@temptoks={}% - \mmz@tikz@anim -} -\def\mmz@tikz@anim{% - \pgfutil@ifnextchar[{\mmz@tikz@opt}{% - \pgfutil@ifnextchar:{\mmz@tikz@anim@a}{% - \mmz@tikz@code}}%] -}% -\def\mmz@tikz@anim@a#1=#2{% - \apptotoks\mmz@temptoks{#1={#2}}% - \mmz@tikz@anim -}% -\def\mmz@tikz@opt[#1]{% - \apptotoks\mmz@temptoks{[#1]}% - \mmz@tikz@code -} -\def\mmz@tikz@code{% - \pgfutil@ifnextchar\bgroup\mmz@tikz@braced\mmz@tikz@single -} -\def\mmz@tikz@braced#1{\apptotoks\mmz@temptoks{{#1}}\mmz@tikz@done} -\def\mmz@tikz@single#1;{\apptotoks\mmz@temptoks{#1;}\mmz@tikz@done} -\def\mmz@tikz@done{% - \expandafter\MemoizeWrapper\expandafter{% - \expandafter\tikz\the\mmz@temptoks - }% -} - -\memoizeset{ - handler=\tikz\mmz@tikz, -} diff --git a/memoize.edtx b/memoize.edtx new file mode 100644 index 0000000..10794c7 --- /dev/null +++ b/memoize.edtx @@ -0,0 +1,3597 @@ +% \iffalse +% +% memoize.edtx (this is not a .dtx file; to produce a .dtx, process it with edtx2dtx) +% +%% This file is a part of Memoize, a TeX package for externalization of +%% graphics and memoization of compilation results in general, available at +%% https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize. +%% +%% Copyright (c) 2020- Saso Zivanovic +%% (Sa\v{s}o \v{Z}ivanovi\'{c}) +%% +%% This work may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License, either version 1.3c of this license or (at +%% your option) any later version. The latest version of this license is in +%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of +%% all distributions of LaTeX version 2008 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Saso Zivanovic. +%% +%% The files belonging to this work and covered by LPPL are listed in +%% (/doc/generic/memoize/)FILES. +% +% \fi +% +% \begin{macrocode} +% +% \relax +% +% This file contains the documented source code of +% package \href{https://ctan.org/pkg/memoize}{Memoize} and, somewhat +% unconventionally, its two independently distributed auxiliary +% packages \href{https://ctan.org/pkg/advice}{Advice} +% and \href{https://ctan.org/pkg/collargs}{CollArgs}. +% +% The source code of the \hologo{TeX} parts of the package resides in +% |memoize.edtx|, |advice.edtx| and |collargs.edtx|. These files are written +% in \href{https://ctan.org/pkg/easydtx}{EasyDTX}, a format of my own invention +% which is almost like the DTX format but eliminates the need for all those +% pesky |macrocode| environments: Any line introduced by a single comment +% counts as documentation, and to top it off, documentation lines may be +% indented. An |.edtx| file is converted to a |.dtx| by a little Perl script +% called |edtx2dtx|; there is also a rudimentary Emacs mode, implemented in +% |easydoctex-mode.el|, which takes care of fontification, indentation, and +% forward and inverse search. +% +% The |.edtx| files contain the code for all three formats supported by the +% three packages --- \hologo{LaTeX} (guard |latex|), \hologo{plainTeX} (guard +% |plain|) and \hologo{ConTeXt} (guard |context|) --- but upon reading the +% code, it will quickly become clear that Memoize was first developed for +% \hologo{LaTeX}. In \S\ref{sec:code:identification}, we manually define +% whatever \hologo{LaTeX} tools are ``missing'' in \hologo{plainTeX} and +% \hologo{ConTeXt}. Even worse, \hologo{ConTeXt} code is often just the same +% as \hologo{plainTeX} code, even in cases where I'm sure \hologo{ConTeXt} +% offers the relevant tools. This nicely proves that I have no clue about +% \hologo{ConTeXt}. If you are willing to \hologo{ConTeXt}-ualize my code --- +% please do so, your help is welcome! +% +% The runtimes of Memoize (and also Advice) comprise of more than just the main +% runtime for each format. Memoize ships with two additional stub packages, +% |nomemoize| and |memoizable|, and a \hologo{TeX}-based extraction script +% |memoize-extract-one|; Advice optionally offers a \TikZ; support defined in +% |advice-tikz.code.tex|. For the relation between guards and runtimes, +% consult the core of the |.ins| files below. +% +% \tcbset{ins listing/.style={listing only, fonttitle=\ttfamily\footnotesize, +% leftupper=-1.5mm, lefttitle=2mm, right=0mm, top=2mm, bottom=2.65mm, +% listing options app={basicstyle=\ttfamily\scriptsize}}} +% +% \begin{tcbraster}[raster columns=100] +% \tcbinputlisting{raster multicolumn=55, ins listing, top=1mm, bottom=1mm, title=memoize.ins,listing file=../memoize.ins, linerange={27-38}, leftupper=1mm} +% \begin{tcboxedraster}[raster columns=1]{blankest, raster multicolumn=45} +% \tcbinputlisting{ins listing, title=advice.ins, listing file=../advice.ins, linerange=28-31} +% \tcbinputlisting{ins listing, title=collar\raisebox{0pt}[\height][0pt]{g}s.ins, listing file=../collargs.ins, linerange=29-31} +% \end{tcboxedraster} +% \end{tcbraster} +% +% Memoize also contains two scripts, |memoize-extract| and |memoize-clean|. +% Both come in two functionally equivalent implementations: Perl (|.pl|) and a +% Python (|.py|). The code is listed in \S\ref{sec:code:scripts}, I believe it +% is self-explanatory enough to lack more than a occasional comment. +% +% +% \thispagestyle{empty} +% \clearpage +% \tableofcontents +% \clearpage +% +% \newgeometry{left=4cm,right=1cm,top=1cm,bottom=1cm, +% marginparwidth=3cm,marginparsep=0pt,nohead,includefoot} +% \settowidth\marginparsep{\ } +% +% \section{First things first} +% \label{sec:code:identification} +% +% \paragraph{Identification} of |memoize|, |memoizable| and |nomemoize|. +%<*mmz> +%\ProvidesPackage{memoize}[2023/10/10 v1.0.0 Fast and flexible externalization] +%%D \module[ +%%D file=t-memoize.tex, +%%D version=1.0.0, +%%D title=Memoize, +%%D subtitle=Fast and flexible externalization, +%%D author=Saso Zivanovic, +%%D date=2023-10-10, +%%D copyright=Saso Zivanovic, +%%D license=LPPL, +%%D ] +%\writestatus{loading}{ConTeXt User Module / memoize} +%\unprotect +%\startmodule[memoize] +%% Package memoize 2023/10/10 v1.0.0 +% +%<*mmzable> +%\ProvidesPackage{memoizable}[2023/10/10 v1.0.0 A programmer's stub for Memoize] +%%D \module[ +%%D file=t-memoizable.tex, +%%D version=1.0.0, +%%D title=Memoizable, +%%D subtitle=A programmer's stub for Memoize, +%%D author=Saso Zivanovic, +%%D date=2023-10-10, +%%D copyright=Saso Zivanovic, +%%D license=LPPL, +%%D ] +%\writestatus{loading}{ConTeXt User Module / memoizable} +%\unprotect +%\startmodule[memoizable] +%% Package memoizable 2023/10/10 v1.0.0 +% +%<*nommz> +%\ProvidesPackage{nomemoize}[2023/10/10 v1.0.0 A no-op stub for Memoize] +%%D \module[ +%%D file=t-nomemoize.tex, +%%D version=1.0.0, +%%D title=Memoize, +%%D subtitle=A no-op stub for Memoize, +%%D author=Saso Zivanovic, +%%D date=2023-10-10, +%%D copyright=Saso Zivanovic, +%%D license=LPPL, +%%D ] +%\writestatus{loading}{ConTeXt User Module / nomemoize} +%\unprotect +%\startmodule[nomemoize] +%% Package nomemoize 2023/10/10 v1.0.0 +% +% +% \paragraph{Required packages} and \hologo{LaTeX}ization of \hologo{plainTeX} +% and \hologo{ConTeXt}. +%<*(mmz,mmzable,nommz)&(plain,context)> +\input miniltx +% +% Some stuff which is ``missing'' in |miniltx|, copied here from |latex.ltx|. +%<*mmz&(plain,context)> +\def\PackageWarning#1#2{{% + \newlinechar`\^^J\def\MessageBreak{^^J\space\space#1: }% + \message{#1: #2}}} +% +% Same as the official definition, but without |\outer|. Needed for record +% file declarations. +%<*mmz&plain> +\def\newtoks{\alloc@5\toks\toksdef\@cclvi} +\def\newwrite{\alloc@7\write\chardef\sixt@@n} +% +% |Nomemoize| has to load |pgfopts| as well, and process package options (right +% away, why not), otherwise \hologo{LaTeX} will complain. +%<*latex> +%\RequirePackage{pgfopts} % pgfkeys-based package options +%\pgfkeys{/memoize/package options/.unknown/.code={}} +%\ProcessPgfPackageOptions{/memoize/package options} +% +% I can't really write any code without |etoolbox| \dots +%<*mmz> +%\RequirePackage{etoolbox} +%\input etoolbox-generic +% Setup the |memoize| namespace in \hologo{LuaTeX}. +\ifdefined\luatexversion + \directlua{memoize = {}} +\fi +% |pdftexcmds.sty| eases access to some PDF primitives, but I cannot manage to +% load it in \hologo{ConTeXt}, even if it's supposed to be a generic +% package. So let's load |pdftexcmds.lua| and copy--paste what we need from +% |pdftexcmds.sty|. +%\RequirePackage{pdftexcmds} +%\input pdftexcmds.sty +%<*context> +\directlua{% + require("pdftexcmds") + tex.enableprimitives('pdf@', {'draftmode'}) +} +\long\def\pdf@mdfivesum#1{% + \directlua{% + oberdiek.pdftexcmds.mdfivesum("\luaescapestring{#1}", "byte")% + }% +}% +\def\pdf@system#1{% + \directlua{% + oberdiek.pdftexcmds.system("\luaescapestring{#1}")% + }% +} +\let\pdf@primitive\primitive +% Lua function |oberdiek.pdftexcmds.filesize| requires the |kpse| library, +% which is not loaded in \hologo{ConTeXt}, +% see \url(https://){github.com/latex3/lua-uni-algos/issues/3}, so we define our +% own filesize function. +\directlua{% + function memoize.filesize(filename) + local filehandle = io.open(filename, "r") + % We can't easily use |~=|, as |~| is an active character, so the |else| + % workaround. + if filehandle == nil then + else + tex.write(filehandle:seek("end")) + io.close(filehandle) + end + end +}% +\def\pdf@filesize#1{% + \directlua{memoize.filesize("\luaescapestring{#1}")}% +} +% +% Take care of some further differences between the engines. +\ifdef\pdftexversion{% +}{% + \def\pdfhorigin{1true in}% + \def\pdfvorigin{1true in}% + \ifdef\XeTeXversion{% + \let\quitvmode\leavevmode + }{% + \ifdef\luatexversion{% + \let\pdfpagewidth\pagewidth + \let\pdfpageheight\pageheight + \def\pdfmajorversion{\pdfvariable majorversion}% + \def\pdfminorversion{\pdfvariable minorversion}% + }{% + \PackageError{memoize}{Support for this TeX engine is not implemented}{}% + }% + }% +} +% +% In \hologo{ConTeXt}, |\unexpanded| means |\protected|, and the usual +% |\unexpanded| is available as |\normalunexpanded|. Option one: use dtx +% guards to produce the correct control sequence. I tried this option. I find +% it ugly, and I keep forgetting to guard. Option two: |\let| an internal +% control sequence, like |\mmz@unexpanded|, to the correct thing, and use that +% all the time. I never tried this, but I find it ugly, too, and I guess I +% would forget to use the new control sequence, anyway. Option three: use +% |\unexpanded| in the |.dtx|, and |sed| through the generated \hologo{ConTeXt} +% files to replace all its occurrences by |\normalunexpanded|. Oh yeah! +% +% +% \paragraph.{Shipout} +% We will next load our own auxiliary package, CollArgs, but before we do +% that, we need to grab |\shipout| in \hologo{plainTeX}. The problem is, +% Memoize needs to hack into the shipout routine, but it has best chances +% of working as intended if it redefines the \emph{primitive} |\shipout|. +% However, CollArgs loads |pgfkeys|, which in turn (and perhaps with no for +% reason) loads |atbegshi|, which redefines |\shipout|. For details, see +% section~\ref{sec:code:extern}. Below, we first check that the current +% meaning of |\shipout| is primitive, and then redefine it. +% +%<*plain> +\def\mmz@regular@shipout{% + \global\advance\mmzRegularPages1\relax + \mmz@primitive@shipout +} +\edef\mmz@temp{\string\shipout}% +\edef\mmz@tempa{\meaning\shipout}% +\ifx\mmz@temp\mmz@tempa + \let\mmz@primitive@shipout\shipout + \let\shipout\mmz@regular@shipout +\else + \PackageError{memoize}{Cannot grab \string\shipout, it is already redefined}{}% +\fi +% +% Our auxiliary package (\MS\ref{sec:ref:collargs}, \S\ref{sec:code:collargs}). +% We also need it in |nomemoize|, to collect manual environments. +%\RequirePackage{advice} +%\input advice +%\input t-advice +% +% +% \paragraph.{Loading order} |memoize| and |nomemoize| are mutually exclusive, +% and |memoizable| must be loaded before either of them. |\mmz@loadstatus|: 1 +% = memoize, 2 = memoizable, 3 = nomemoize. +%<*(plain,context)&(mmz,nommz,mmzable)> +\def\ifmmz@loadstatus#1{% + \ifnum#1=0\csname mmz@loadstatus\endcsname\relax + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi +} +% +%<*mmz> +%\@ifpackageloaded{nomemoize}% +%\ifmmz@loadstatus{3}% +{% + \PackageError{memoize}{Cannot load the package, as "nomemoize" is already + loaded. Memoization will NOT be in effect}{Packages "memoize" and + "nomemoize" are mutually exclusive, please load either one or the other.}% + %\pgfkeys{/memoize/package options/.unknown/.code={}} + %\ProcessPgfPackageOptions{/memoize/package options} + \endinput +}{}% +%\@ifpackageloaded{memoizable}% +%\ifmmz@loadstatus{2}% +{% + \PackageError{memoize}{Cannot load the package, as "memoizable" is already + loaded}{Package "memoizable" is loaded by packages which support + memoization. Memoize must be loaded before all such packages. The + compilation log can help you figure out which package loaded "memoizable"; + please move + %"\string\usepackage{memoize}" + %"\string\input memoize" + %"\string\usemodule[memoize]" + before the + %"\string\usepackage" + %"\string\input" + %"\string\usemodule" + of that package.}% + %\pgfkeys{/memoize/package options/.unknown/.code={}} + %\ProcessPgfPackageOptions{/memoize/package options} + \endinput +}{}% +%\ifmmz@loadstatus{1}{\endinput}{}% +%\def\mmz@loadstatus{1}% +% +%<*mmzable> +%\@ifpackageloaded{memoize}% +%\ifmmz@loadstatus{1}% +{\endinput}{} +%\@ifpackageloaded{nomemoize}% +%\ifmmz@loadstatus{3}% +{\endinput}{}% +%\ifmmz@loadstatus{2}{\endinput}{}% +%\def\mmz@loadstatus{2}% +% +%<*nommz> +%\@ifpackageloaded{memoize} +%\ifmmz@loadstatus{1}% +{% + \PackageError{nomemoize}{Cannot load the package, as "memoize" is already + loaded; memoization will remain in effect}{Packages "memoize" and + "nomemoize" are mutually exclusive, please load either one or the other.}% + \endinput }{}% +%\@ifpackageloaded{memoizable}% +%\ifmmz@loadstatus{2}% +{% + \PackageError{nomemoize}{Cannot load the package, as "memoizable" is already + loaded}{Package "memoizable" is loaded by packages which support + memoization. (No)Memoize must be loaded before all such packages. The + compilation log can help you figure out which package loaded + "memoizable"; please move + %"\string\usepackage{nomemoize}" + %"\string\input memoize" + %"\string\usemodule[memoize]" + before the + %"\string\usepackage" + %"\string\input" + %"\string\usemodule" + of that package.}% + \endinput +}{}% +%\ifmmz@loadstatus{3}{\endinput}{}% +%\def\mmz@loadstatus{3}% +% +% +%<*mmz> +% +% \begin{macro}{\filetotoks} +% Read \hologo{TeX} file |#2| into token register |#1| (under the current +% category code regime); |\toksapp| is defined in CollArgs. +\def\filetotoks#1#2{% + \immediate\openin0{#2}% + #1={}% + \loop + \unless\ifeof0 + \read0 to \totoks@temp + % We need the |\expandafter|s for our |\toksapp| macro. + \expandafter\toksapp\expandafter#1\expandafter{\totoks@temp}% + \repeat + \immediate\closein0 +} +% \end{macro} +% +% \paragraph{Other} little things. +\newif\ifmmz@temp +\newtoks\mmz@temptoks +\newbox\mmz@box +\newwrite\mmz@out +% +% \section{The basic configuration} +% \label{sec:code:configuration} +% +% \begin{macro}{\mmzset} +% The user primarily interacts with |Memoize| through the |pgfkeys|-based +% configuration macro |\mmzset|, which executes keys in path |/mmz|. In +% |nomemoize| and |memoizable|, is exists as a no-op. +\def\mmzset#1{\pgfqkeys{/mmz}{#1}\ignorespaces} +% +%\def\mmzset#1{\ignorespaces} +% \end{macro} +% +% \begin{macro}{\mmzset} +% Any |/mmz| keys used outside of |\mmzset| must be declared by this macro +% for |nomemoize| package to work. +%\def\nommzkeys#1{} +%<*nommz,mmzable> +\def\nommzkeys{\pgfqkeys{/mmz}} +\pgfqkeys{/mmz}{.unknown/.code={\pgfkeysdef{\pgfkeyscurrentkey}{}}} +% +% \end{macro} +% +% \begin{key}{enable, disable} +% \begin{macro}{\ifmemoize} +% These keys set \hologo{TeX}-style conditional \cs{ifmemoize}, used as the +% central on/off switch for the functionality of the package --- it is +% inspected in |\Memoize| and by run conditions of automemoization handlers. +% +% If used in the preamble, the effect of these keys is delayed until the +% beginning of the document. The delay is implemented through a special +% style, |begindocument|, which is executed at |begindocument| hook in +% \hologo{LaTeX}; in other formats, the user must invoke it manually +% (\MS\ref{sec:ref:loading}). +% +% |Nomemoize| does not need the keys themselves, but it does need the +% underlying conditional --- which will be always false. +%\newif\ifmemoize +%<*mmz> +\mmzset{% + enable/.style={begindocument/.append code=\memoizetrue}, + disable/.style={begindocument/.append code=\memoizefalse}, + begindocument/.append style={ + enable/.code=\memoizetrue, + disable/.code=\memoizefalse, + }, + % Memoize is enabled at the beginning of the document, unless explicitly + % disabled by the user in the preamble. + enable, +} +% \end{macro} +% \end{key} +% +% \begin{key}{normal,readonly,recompile} +% When Memoize is enabled, it can be in one of three modes +% (\MS\ref{sec:tut:working-on-a-picture}): normal, readonly, and recompile. +% The numeric constants are defined below. The mode is stored in +% |\mmz@mode|, and only matters in |\Memoize| (and +% |\mmz@process@ccmemo|).\footnote{In fact, this code treats anything but 1 +% and 2 as normal.} +\def\mmz@mode@normal{0} +\def\mmz@mode@readonly{1} +\def\mmz@mode@recompile{2} +\let\mmz@mode\mmz@mode@normal +\mmzset{% + normal/.code={\let\mmz@mode\mmz@mode@normal}, + readonly/.code={\let\mmz@mode\mmz@mode@readonly}, + recompile/.code={\let\mmz@mode\mmz@mode@recompile}, +} +% \end{key} +% +% \begin{key}{path, path/relative, path/dir, path/prefix} +% Key |path| executes the given keylist in path |/mmz/path|, to determine the +% full \emph{path prefix} to memo and extern files +% (\MS\ref{sec:tut:memodir},\ref{sec:memos}): |relative|, true by default, +% determines whether the location of these files is relative to the current +% directory; |dir| sets their directory; and |prefix| sets the first, fixed +% part of their basename; the second part containing the MD5 sum(s) is not +% under user control, and neither is the suffix. These subkeys will be +% initialized a bit later, via |no memo dir|. +\mmzset{% + path/.code={\pgfqkeys{/mmz/path}{#1}}, + path/.cd, + relative/.is if=mmz@relativepath, + dir/.store in=\mmz@dir, + dir/.value required, + prefix/.store in=\mmz@prefix, + prefix/.value required, +} +\newif\ifmmz@relativepath +% Key |path| concludes by performing two post-path-setting actions: creating +% the given directory if |mkdir| is in effect, and noting the new path prefix +% in record files (by eventually executing |record/prefix|, which typically +% puts a |\mmzPrefix| line in the |.mmz| file). These actions are the reason +% for having the path setting keys grouped under |path| --- we don't want them +% to be triggered by changes of the individual components of the path. +% Similarly, we don't want them triggered by multiple invocations of |path| in +% the preamble; only the final setting matters, so |path| is only equipped with +% the action-triggering code at the beginning of the document. +\mmzset{% + begindocument/.append style={ + path/.append code=\mmz@maybe@mkmemodir\mmz@record@prefix, + }, + % Consequently, the post-path-setting actions must be triggered manually at + % the beginning of the document. Below, we trigger directory creation; + % |record/prefix| will be called from |record/begin|, which is executed at + % the beginning of the document, so it shouldn't be mentioned here. + begindocument/.append code=\mmz@maybe@mkmemodir, +} +% Define the paths to the memo directory and the prefix. +\def\mmz@dir@path{\ifmmz@relativepath.\fi/\mmz@dir} +\def\mmz@prefix@path{\mmz@dir@path/\mmz@prefix} +% \end{key} +% +% \begin{key}{mkdir, mkdir command} +% Should we create the memo/extern directory if it doesn't exist? And which +% command should we use to create it? Of course, shell escape must be +% properly configured for this to work (\MS\ref{sec:shell-escape}). +% ^^A todo: What about quoting the paths containing spaces on Windows? Will this work? +\mmzset{ + mkdir/.is if=mmz@mkdir, + mkdir command/.code={\def\mmz@mkdir@command##1{#1}}, + mkdir command={mkdir "#1"}, +} +% The underlying conditional \cs{ifmmz@mkdir} is only ever used in +% |\mmz@maybe@mkmemodir| below, which is itself only executed at the end of +% |path| and in |begindocument|. +\newif\ifmmz@mkdir +\def\mmz@maybe@mkmemodir{% + \ifmmz@mkdir + \pdf@system{\mmz@mkdir@command{\mmzOutputDirectory\mmz@dir@path}}% + \fi +} +% \end{key} +% +% \begin{key}{memo dir, no memo dir} +% Shortcuts for two common settings of |path| keys. The default |no memo +% dir| will place the memos and externs in the current directory, prefixed +% with |#1.|, where |#1| defaults to (unquoted) |\jobname|. Key |memo dir| +% places the memos and externs in a dedicated directory, |#1.memo.dir|; the +% filenames themselves have no prefix. Furthermore, |memo dir| triggers the +% creation of the directory. +\mmzset{% + memo dir/.style={ + mkdir, + path={ + relative, + dir={#1.memo.dir}, + prefix={}, + }, + }, + memo dir/.default=\mmzUnquote\jobname, + no memo dir/.style={ + mkdir=false, + path={ + relative, + dir={}, + prefix={#1.}, + }, + }, + no memo dir/.default=\mmzUnquote\jobname, + no memo dir, +} +% \end{key} +% +% \begin{macro}{\mmzUnquote} +% If the expanded argument is surrounded by double quotes, remove them. This +% relies on |#1| containing no quotes other than the potential surrounding +% quotes, which should be the case when applying the macro to |\jobname|. An +% empty |#1| is dealt with correctly, even if |\jobname| can hardly ever be +% empty (needs |openout_any=a|). +% +% We use this macro when we are passing a filename constructed from +% |\jobname| to external programs. +\def\mmzUnquote#1{\expanded{\noexpand\mmz@unquote#1}\mmz@unquote@end} +\def\mmz@unquote#1{% + \ifx\mmz@unquote@end#1% + \else + \ifx"#1% + \expandafter\expandafter\expandafter\mmz@unquote@quotes + \else + \expandafter\expandafter\expandafter\mmz@unquote@noquotes + \expandafter\expandafter\expandafter#1% + \fi + \fi +} +\def\mmz@unquote@quotes#1"\mmz@unquote@end{#1} +\def\mmz@unquote@noquotes#1\mmz@unquote@end{#1} +% \end{macro} +% +% \begin{key}{ignore spaces} +% The underlying conditional will be inspected by automemoization handlers, +% to maybe put |\ignorespaces| after the invocation of the handler. +\newif\ifmmz@ignorespaces +\mmzset{ + ignore spaces/.is if=mmz@ignorespaces, +} +% \end{key} +% +% \begin{key}{verbatim, verb, no verbatim} +% These keys are tricky. For one, there's |verbatim|, which sets all +% characters' category codes to other, and there's |verb|, which leaves +% braces untouched (well, honestly, it redefines them). But Memoize itself +% doesn't really care about this detail --- it only uses the underlying +% conditional \cs{ifmmz@verbatim}. It is CollArgs which cares about the +% difference between the ``long'' and the ``short'' verbatim, so we need to +% tell it about it. That's why the verbatim options ``append themselves'' to +% |\mmzRawCollectorOptions|, which is later passed on to +% |\CollectArgumentsRaw| as a part of its optional argument. +\newif\ifmmz@verbatim +\def\mmzRawCollectorOptions{} +\mmzset{ + verbatim/.code={% + \def\mmzRawCollectorOptions{\collargsVerbatim}% + \mmz@verbatimtrue + }, + verb/.code={% + \def\mmzRawCollectorOptions{\collargsVerb}% + \mmz@verbatimtrue + }, + no verbatim/.code={% + \def\mmzRawCollectorOptions{\collargsNoVerbatim}% + \mmz@verbatimfalse + }, +} +% \end{key} +% \section{Memoization} +% \label{sec:code:memoization} +% +% \subsection{Manual memoization} +% \label{sec:code:memoization:manual} +% +% \begin{macro}{\mmz} +% The core of this macro will be a simple invocation of |\Memoize|, but to +% get there, we have to collect the optional argument carefully, because we +% might have to collect the memoized code verbatim. +\protected\def\mmz{\futurelet\mmz@temp\mmz@i} +\def\mmz@i{% + % Anyone who wants to call |\Memoize| must open a group, because |\Memoize| + % will close a group. + \begingroup + % As the optional argument occurs after a control sequence (|\mmz|), any + % spaces were consumed and we can immediately test for the opening bracket. + \ifx\mmz@temp[%] + \def\mmz@verbatim@fix{}% + \expandafter\mmz@ii + \else + % If there was no optional argument, the opening brace (or the unlikely + % single token) of our mandatory argument is already tokenized. If we are + % requested to memoize in a verbatim mode, this non-verbatim tokenization + % was wrong, so we will use option |\collargsFixFromNoVerbatim| to ask + % CollArgs to fix the situation. (|\mmz@verbatim@fix| will only be used in + % the verbatim mode.) + \def\mmz@verbatim@fix{\noexpand\collargsFixFromNoVerbatim}% + % No optional argument, so we can skip |\mmz@ii|. + \expandafter\mmz@iii + \fi +} +\def\mmz@ii[#1]{% + % Apply the options given in the optional argument. + \mmzset{#1}% + \mmz@iii +} +\def\mmz@iii{% + % In the non-verbatim mode, we avoid collecting the single mandatory argument + % using |\CollectArguments|. + \ifmmz@verbatim + \expandafter\mmz@do@verbatim + \else + \expandafter\mmz@do + \fi +} +% This macro grabs the mandatory argument of |\mmz| and calls |\Memoize|. +\long\def\mmz@do#1{% + \Memoize{#1}{#1}% +}% +% +% The following macro uses |\CollectArgumentsRaw| of package CollArgs +% (\S\ref{sec:code:collargs}) to grab the argument verbatim; the appropriate +% verbatim mode triggering raw option was put in |\mmzRawCollectorOptions| by +% key |verb(atim)|. The macro also |\mmz@verbatim@fix| contains the potential +% request for a category code fix (\S\ref{sec:code:collargs:fix}). +\def\mmz@do@verbatim#1{% + \expanded{% + \noexpand\CollectArgumentsRaw{% + \noexpand\collargsCaller{\noexpand\mmz}% + \expandonce\mmzRawCollectorOptions + \mmz@verbatim@fix + }% + }{+m}\mmz@do +} +% \end{macro} +% +% \begin{environment}{memoize} +% The definition of the manual memoization environment proceeds along the +% same lines as the definition of |\mmz|, except that we also have to +% implement space-trimming, and that we will collect the environment using +% |\CollectArguments| in both the verbatim and the non-verbatim and mode. +% +% We define the \hologo{LaTeX}, \hologo{plainTeX} and \hologo{ConTeXt} +% environments in parallel. The definition of the \hologo{plainTeX} and +% \hologo{ConTeXt} version is complicated by the fact that space-trimming is +% affected by the presence vs.\ absence of the optional argument (for +% purposes of space-trimming, it counts as present even if it is empty). +%<*latex> +% We define the \hologo{LaTeX} environment using |\newenvironment|, which +% kindly grabs any spaces in front of the optional argument, if it exists --- +% and if doesn't, we want to trim spaces at the beginning of the environment +% body anyway. +\newenvironment{memoize}[1][\mmz@noarg]{% + % We close the environment right away. We'll collect the environment body, + % complete with the end-tag, so we have to reintroduce the end-tag somewhere. + % Another place would be after the invocation of |\Memoize|, but that would + % put memoization into a double group and |\mmzAfterMemoization| would not work. + \end{memoize}% + % % We open the group which will be closed by |\Memoize|. + \begingroup + % As with |\mmz| above, if there was no optional argument, we have to ask + % Collargs for a fix. The difference is that, as we have collected the + % optional argument via |\newcommand|, we have to test for its presence in a + % roundabout way. + \def\mmz@temp{#1}% + \ifx\mmz@temp\mmz@noarg + \def\mmz@verbatim@fix{\noexpand\collargsFixFromNoVerbatim}% + \else + \def\mmz@verbatim@fix{}% + \mmzset{#1}% + \fi + \mmz@env@iii +}{} +\def\mmz@noarg{\mmz@noarg} +% +%\def\memoize{% +%\def\startmemoize{% +%<*plain,context> + \begingroup + % In \hologo{plainTeX} and \hologo{ConTeXt}, we don't have to worry about any + % spaces in front of the optional argument, as the environments are opened by + % a control sequence. + \futurelet\mmz@temp\mmz@env@i +} +\def\mmz@env@i{% + \ifx\mmz@temp[%] + \def\mmz@verbatim@fix{}% + \expandafter\mmz@env@ii + \else + \def\mmz@verbatim@fix{\noexpand\collargsFixFromNoVerbatim}% + \expandafter\mmz@env@iii + \fi +} +\def\mmz@env@ii[#1]{% + \mmzset{#1}% + \mmz@env@iii +} +% +\def\mmz@env@iii{% + \long\edef\mmz@do##1{% + % |\unskip| will ``trim'' spaces at the end of the environment body. + \noexpand\Memoize{##1}{##1\unskip}% + }% + \expanded{% + \noexpand\CollectArgumentsRaw{% + % |\CollectArgumentsRaw| will adapt the caller to the format automatically. + \noexpand\collargsCaller{memoize}% + % |verb(atim)| is in here if it was requested. + \expandonce\mmzRawCollectorOptions + % The category code fix, if needed. + \ifmmz@verbatim\mmz@verbatim@fix\fi + }% + % Spaces at the beginning of the environment body are trimmed by setting + % the first argument to |!t| and disappearing it with + % |\collargsAppendPostwrap{}|; note that this removes any number of space + % tokens. |\CollectArgumentsRaw| automatically adapts the argument type + % |b| to the format. + % + }{&&{\collargsAppendPostwrap{}}!t{ }+b{memoize}}{\mmz@do}% +}% +% +% \end{environment} +% +% \begin{macro}{\nommz} +% We throw away the optional argument if present, and replace the opening +% brace with begin-group plus |\memoizefalse|. This way, the ``argument'' of +% |\nommz| will be processed in a group (with Memoize disabled) and even the +% verbatim code will work because the ``argument'' will not have been +% tokenized. +% +% As a user command, |\nommz| has to make it into package |nomemoize| as +% well, and we'll |\let| |\mmz| equal it there; it is not needed in +% |mmzable|. +%<*mmz,nommz> +\protected\def\nommz#1#{% + \afterassignment\nommz@i + \let\mmz@temp +} +\def\nommz@i{% + \bgroup + \memoizefalse +} +%\let\mmz\nommz +% \end{macro} +% +% \begin{environment}{nomemoize} +% We throw away the optional argument and take care of the spaces at the +% beginning and at the end of the body. +%<*latex> +\newenvironment{nomemoize}[1][]{% + \memoizefalse + \ignorespaces +}{% + \unskip +} +% +%<*plain,context> +%\def\nomemoize{% +%\def\startnomemoize{% +% Start a group to delimit |\memoizefalse|. + \begingroup + \memoizefalse + \futurelet\mmz@temp\nommz@env@i +} +\def\nommz@env@i{% + \ifx\mmz@temp[%] + \expandafter\nommz@env@ii + % No optional argument, no problems with spaces. + \fi +} +\def\nommz@env@ii[#1]{% + \ignorespaces +} +%\def\endnomemoize{% +%\def\stopnomemoize{% + \endgroup + \unskip +} +% +%<*nommz> +%\let\memoize\nomemoize +%\let\endmemoize\endnomemoize +%\let\startmemoize\startnomemoize +%\let\stopmemoize\stopnomemoize +% +% \end{environment} +% +% \subsection{The memoization process} +% \label{sec:code:memoization-process} +% +% \begin{macro}{\ifmemoizing} +% This conditional is set to true when we start memoization (but not when +% we start regular compilation or utilization); it should never be set +% anywhere else. It is checked by |\Memoize| to prevent nested +% memoizations, deployed in advice run conditions set by |run only if +% memoizing|, etc. +\newif\ifmemoizing +% \end{macro} +% +% \begin{macro}{\ifinmemoize} +% This conditional is set to true when we start either memoization or +% regular compilation (but not when we start utilization); it should never +% be set anywhere else. It is deployed in the default advice run conditions, +% making sure that automemoized commands are not handled even when we're +% regularly compiling some code submitted to memoization. +\newif\ifinmemoize +% \end{macro} +% +% \begin{macro}{\mmz@maybe@scantokens} +% An auxiliary macro which rescans the given +% code using |\scantokens| if the verbatim mode is active. We also need it +% in NoMemoize, to properly grab verbatim manually memoized code. +% +%<*mmz> +\def\mmz@maybe@scantokens{% + \ifmmz@verbatim + \expandafter\mmz@scantokens + \else + \expandafter\@firstofone + \fi +} +% Without |\newlinechar=13|, |\scantokens| would see receive the entire +% argument as one long line --- but it would not \emph{see} the entire +% argument, but only up to the first newline character, effectively losing most +% of the tokens. (We need to manually save and restore |\newlinechar| because +% we don't want to execute the memoized code in yet another group.) +\long\def\mmz@scantokens#1{% + \expanded{% + \newlinechar=13 + \unexpanded{\scantokens{#1\endinput}}% + \newlinechar=\the\newlinechar + }% +} +% \end{macro} +% +% \begin{macro}{\Memoize} +% Memoization is invoked by executing |\Memoize|. This macro is a decision +% hub. It test for the existence of the memos and externs associated with +% the memoized code, and takes the appropriate action (memoization: +% |\mmz@memoize|; regular compilation: |\mmz@compile|, utilization: +% |\mmz@process@cmemo| plus |\mmz@process@ccmemo| plus further complications) +% depending on the memoization mode (normal, readonly, recompile). Note that +% one should open a \hologo{TeX} group prior to executing |\Memoize|, because +% |\Memoize| will close a group (\MS\ref{sec:Memoize}). +% +% |\Memoize| takes two arguments, which contain two potentially different +% versions of the code submitted to memoization: |#1| contains the code which +% \meta{code MD5 sum} is computed off of, while |#2| contains the code which +% is actually executed during memoization and regular compilation. The +% arguments will contain the same code in the case of manual memoization, but +% they will differ in the case of automemoization, where the executable code +% will typically prefixed by |\AdviceOriginal|. As the two +% codes will be used not only by |\Memoize| but also by macros called from +% |\Memoize|, |\Memoize| stores them into dedicated toks registers, declared +% below. +\newtoks\mmz@mdfive@source +\newtoks\mmz@exec@source +% Finally, the definition of the macro. In package NoMemoize, we should simply +% execute the code in the second argument. But in Memoize, we have work to do. +\let\Memoize\@secondoftwo +\long\def\Memoize#1#2{% + % We store the first argument into token register |\mmz@mdfive@source| + % because we might have to include it in tracing info (when |trace| is in + % effect), or paste it into the c-memo (depending on |include source in + % cmemo|). + \mmz@mdfive@source{#1}% + % We store the executable code in |\mmz@exec@source|. In the verbatim mode, + % the code will have to be rescanned. This is implemented by + % |\mmz@maybe@scantokens|, and we wrap the code into this macro right away, + % once and for all. Even more, we pre-expand |\mmz@maybe@scantokens| (three + % times), effectively applying the current \cs{ifmmz@verbatim} and + % eliminating the need to save and restore this conditional in + % |\mmz@compile|, which (regularly) compiles the code \emph{after} closing + % the |\Memoize| group --- after this pre-expansion, |\mmz@exec@source| will + % contain either |\mmz@scantokens{...}| or |\@firstofone{...}|. + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter + \mmz@exec@source + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter + {% + \mmz@maybe@scantokens{#2}% + }% + \mmz@trace@Memoize + % In most branches below, we end up with regular compilation, so let this be + % the default action. + \let\mmz@action\mmz@compile + % If Memoize is disabled, or if memoization is currently taking place, we + % will perform a regular compilation. + \ifmemoizing + \else + \ifmemoize + % Compute \meta{code md5sum} off of the first argument, and globally + % store it into |\mmz@code@mdfivesum| --- globally, because we need it in + % utilization to include externs, but the |\Memoize| group is closed (by + % |\mmzMemo|) while inputting the cc-memo. + \xdef\mmz@code@mdfivesum{\pdf@mdfivesum{\the\mmz@mdfive@source}}% + \mmz@trace@code@mdfive + % Recompile mode forces memoization. + \ifnum\mmz@mode=\mmz@mode@recompile\relax + \ifnum\pdf@draftmode=0 + \let\mmz@action\mmz@memoize + \fi + \else + % In the normal and the readonly mode, we try to utilize the memos. The + % c-memo comes first. If the c-memo does not exist (or if something is + % wrong with it), |\mmz@process@cmemo| (defined in + % \S\ref{sec:code:c-memo}) will set |\ifmmz@abort| to true. It might + % also set |\ifmmzUnmemoizable| which means we should compile normally + % regardless of the mode. + \mmz@process@cmemo + \ifmmzUnmemoizable + \mmz@trace@cmemo@unmemoizable + \else + \ifmmz@abort + % If there is no c-memo, or it is invalid, we memoize, unless the + % read-only mode is in effect. + \mmz@trace@process@cmemo@fail + \ifnum\mmz@mode=\mmz@mode@readonly\relax + \else + \ifnum\pdf@draftmode=0 + \let\mmz@action\mmz@memoize + \fi + \fi + \else + \mmz@trace@process@cmemo@ok + % If the c-memo was fine, the formal action decided upon is to try + % utilizing the cc-memo. If it exists and everything is fine with + % it, |\mmz@process@ccmemo| (defined in + % section~\ref{sec:code:cc-memo}) will utilize it, i.e.\ the core + % of the cc-memo (the part following |\mmzMemo|) will be executed + % (typically including the single extern). Otherwise, + % |\mmz@process@ccmemo| will trigger either memoization (in the + % normal mode) or regular compilation (in the readonly mode). This + % final decision is left to |\mmz@process@ccmemo| because if we + % made it here, the code would get complicated, as the cc-memo must + % be processed outside the |\Memoize| group and all the + % conditionals in this macro. + \let\mmz@action\mmz@process@ccmemo + \fi + \fi + \fi + \fi + \fi + \mmz@action +} +% \end{macro} +% +% \begin{macro}{\mmz@compile} +% This macro performs regular compilation --- this is signalled to the +% memoized code and the memoization driver by setting \cs{ifinmemoize} to +% true for the duration of the compilation; \cs{ifmemoizing} is not touched. +% The group opened prior to the invocation of |\Memoize| is closed before +% executing the code in |\mmz@exec@source|, so that compiling the code has +% the same local effect as if was not submitted to memoization; it is closing +% this group early which complicates the restoration of \cs{ifinmemoize} at +% the end of compilation. Note that |\mmz@exec@source| is already set to +% properly deal with the current verbatim mode, so any further inspection of +% \cs{ifmmz@verbatim} is unnecessary; the same goes for +% \cs{ifmmz@ignorespaces}, which was (or at least should be) taken care of by +% whoever called |\Memoize|. +\def\mmz@compile{% + \mmz@trace@compile + \expanded{% + \endgroup + \noexpand\inmemoizetrue + \the\mmz@exec@source + \ifinmemoize\noexpand\inmemoizetrue\else\noexpand\inmemoizefalse\fi + }% +} +% \end{macro} +% \begin{luafun}{abortOnError} +% \begin{macro}{\mmz@lua@atbeginmemoization,\mmz@lua@atendmemoization} +% In \hologo{LuaTeX}, we can whether an error occurred during memoization, +% and abort if it did. (We're going through |memoize.abort|, because +% |tex.print| does not seem to work during error handling.) We omit all +% this in \hologo{ConTeXt}, as it appears to stop on any error? +%<*!context> +\ifdefined\luatexversion + \directlua{% + luatexbase.add_to_callback( + "show_error_message", + function() + memoize.abort = true + texio.write_nl(status.lasterrorstring) + end, + "Abort memoization on error" + ) + }% + \def\mmz@lua@atbeginmemoization{% + \directlua{memoize.abort = false}% + }% + \def\mmz@lua@atendmemoization{% + \directlua{% + if memoize.abort then + tex.print("\noexpand\\mmzAbort") + end + }% + }% +\else +% + \let\mmz@lua@atbeginmemoization\relax + \let\mmz@lua@atendmemoization\relax +%\fi +% \end{macro} +% \end{luafun} +% \begin{macro}{\mmz@memoize} +% This macro performs memoization --- this is signalled to the memoized code +% and the memoization driver by setting both \cs{ifinmemoize} and +% \cs{ifinmemoizing} to true. +\def\mmz@memoize{% + \mmz@trace@memoize + \memoizingtrue + \inmemoizetrue + % Initialize the various macros and registers used in memoization (to be + % described below, or later). Note that most of these are global, as they + % might be adjusted arbitrarily deep within the memoized code. + \edef\memoizinggrouplevel{\the\currentgrouplevel}% + \global\mmz@abortfalse + \global\mmzUnmemoizablefalse + \global\mmz@seq 0 + \global\setbox\mmz@tbe@box\vbox{}% + \global\mmz@ccmemo@resources{}% + \global\mmzCMemo{}% + \global\mmzCCMemo{}% + \global\mmzContextExtra{}% + \gdef\mmzAtEndMemoizationExtra{}% + \gdef\mmzAfterMemoizationExtra{}% + \mmz@lua@atbeginmemoization + % Execute the pre-memoization hook, the memoized code (wrapped in the + % driver), and the post-memoization hook. + \mmzAtBeginMemoization + \mmzDriver{\the\mmz@exec@source}% + \mmzAtEndMemoization + \mmzAtEndMemoizationExtra + \mmz@lua@atendmemoization + \ifmmzUnmemoizable + % To permanently prevent memoization, we have to write down the c-memo + % (containing |\mmzUnmemoizabletrue|). We don't need the extra context in + % this case. + \global\mmzContextExtra{}% + \gtoksapp\mmzCMemo{\global\mmzUnmemoizabletrue}% + \mmz@write@cmemo + \mmz@trace@endmemoize@unmemoizable + \PackageWarning{memoize}{Marking this code as unmemoizable}% + \else + \ifmmz@abort + % If memoization was aborted, we create an empty c-memo, to make sure that + % no leftover c-memo tricks Memoize into thinking that the code was + % successfully memoized. + \mmz@trace@endmemoize@aborted + \PackageWarning{memoize}{Memoization was aborted}% + \mmz@write@empty@cmemo + \else + % If memoization was not aborted, we compute the \meta{context md5sum}, + % open and write out the memos, and shipout the externs (as pages into the + % document). + \mmz@compute@context@mdfivesum + \mmz@write@cmemo + \mmz@write@ccmemo + \mmz@shipout@externs + \mmz@trace@endmemoize@ok + \fi + \fi + % After closing the group, we execute the final, after-memoization hook (we + % pre-expand the regular macro; the extra macro was assigned to globally). In + % the after-memoization code, |\mmzIncludeExtern| points to a macro which can + % include the extern from |\mmz@tbe@box|, which makes it possible to typeset + % the extern by dropping the contents of |\mmzCCMemo| into this hook --- but + % note that this will only work if |\ifmmzkeepexterns| was in effect at the + % end of memoization. + \expandafter\endgroup + \expandafter\let + \expandafter\mmzIncludeExtern\expandafter\mmz@include@extern@from@tbe@box + \mmzAfterMemoization + \mmzAfterMemoizationExtra +} +% \end{macro} +% +% \begin{macro}{\memoizinggrouplevel} +% This macro stores the group level at the beginning of memoization. It is +% deployed by |\IfMemoizing|, normally used by integrated drivers. +\def\memoizinggrouplevel{-1}% +% \end{macro} +% +% \begin{macro}{\mmzAbort} +% Memoized code may execute this macro to abort memoization. +\def\mmzAbort{\global\mmz@aborttrue} +% \end{macro} +% +% \begin{macro}{\ifmmz@abort} +% This conditional serves as a signal that something went wrong during +% memoization (where it is set to true by |\mmzAbort|), or c(c)-memo +% processing. The assignment to this conditional should always be global +% (because it may be set during memoization). +\newif\ifmmz@abort +% \end{macro} +% +% \begin{macro}{\mmzUnmemoizable} +% Memoized code may execute |\mmzUnmemoizable| to abort memoization and mark +% (in the c-memo) that memoization should never be attempted again. The +% c-memo is composed by |\mmz@memoize|. +\def\mmzUnmemoizable{\global\mmzUnmemoizabletrue} +% \end{macro} +% +% \begin{macro}{\ifmmzUnmemoizable} +% This conditional serves as a signal that the code should never be +% memoized. It can be set (a) during memoization (that's why it should be +% assigned globally), after which it is inspected by |\mmz@memoize|, and +% (b) from the c-memo, in which case it is inspected by |\Memoize|. +\newif\ifmmzUnmemoizable +% \end{macro} +% +% \begin{macro}{\mmzAtBeginMemoization,\mmzAtEndMemoization,\mmzAfterMemoization} +% \begin{key}{at begin memoization, at end memoization, after memoization} +% The memoization hooks and their keys. The hook macros may be set either +% before or during memoization. In the former case, one should modify the +% primary macro (|\mmzAtBeginMemoization|, |\mmzAtEndMemoization|, +% |\mmzAfterMemoization|), and the assignment should be local. In the +% latter case, one should modify the extra macro +% (|\mmzAtEndMemoizationExtra|, |\mmzAfterMemoizationExtra|; there is no +% |\mmzAtBeginMemoizationExtra|), and the assignment should be global. The +% keys automatically adapt to the situation, by appending either to the +% primary or the the extra macro; if |at begin memoization| is used during +% memoization, the given code is executed immediately. We will use this +% ``extra'' approach and the auto-adapting keys for other options, like +% |context|, as well. +\def\mmzAtBeginMemoization{} +\def\mmzAtEndMemoization{} +\def\mmzAfterMemoization{} +\mmzset{ + at begin memoization/.code={% + \ifmemoizing + \expandafter\@firstofone + \else + \expandafter\appto\expandafter\mmzAtBeginMemoization + \fi + {#1}% + }, + at end memoization/.code={% + \ifmemoizing + \expandafter\gappto\expandafter\mmzAtEndMemoizationExtra + \else + \expandafter\appto\expandafter\mmzAtEndMemoization + \fi + {#1}% + }, + after memoization/.code={% + \ifmemoizing + \expandafter\gappto\expandafter\mmzAfterMemoizationExtra + \else + \expandafter\appto\expandafter\mmzAfterMemoization + \fi + {#1}% + }, +} +% \end{key} +% \end{macro} +% +% \begin{key}{driver} +% This key sets the (formal) memoization driver. The function of the driver +% is to produce the memos and externs while executing the submitted code. +\mmzset{ + driver/.store in=\mmzDriver, + driver=\mmzSingleExternDriver, +} +% \end{key} +% +% \begin{macro}{\ifmmzkeepexterns} +% This conditional causes Memoize not to empty out |\mmz@tbe@box|, holding +% the externs collected during memoization, while shipping them out. +\newif\ifmmzkeepexterns +% \end{macro} +% +% \begin{macro}{\mmzSingleExternDriver} +% The default memoization driver externalizes the submitted code. It always +% produces exactly one extern, and including the extern will be the only +% effect of inputting the cc-memo (unless the memoized code contained some +% commands, like |\label|, which added extra instructions to the cc-memo.) +% The macro (i) adds |\quitvmode| to the cc-memo, if we're capturing into a +% horizontal box, and it puts it to the very front, so that it comes before +% any |\label| and |\index| replications, guaranteeing (hopefully) that they +% refer to the correct page; (ii) takes the code and typesets it in a box +% (|\mmz@box|); (iii) submits the box for externalization; (iv) adds the +% extern-inclusion code to the cc-memo, and (v) puts the box into the +% document (again prefixing it with |\quitvmode| if necessary). (The listing +% region markers help us present this code in the manual.) +% \begin{listingregion}{single-extern-driver.tex} +\long\def\mmzSingleExternDriver#1{% + \xtoksapp\mmzCCMemo{\mmz@maybe@quitvmode}% + \setbox\mmz@box\mmz@capture{#1}% + \mmzExternalizeBox\mmz@box\mmz@temptoks + \xtoksapp\mmzCCMemo{\the\mmz@temptoks}% + \mmz@maybe@quitvmode\box\mmz@box +} +% \end{listingregion} +% \end{macro} +% +% \begin{key}{capture} +% The default memoization driver uses |\mmz@capture| and +% |\mmz@maybe@quitvmode|, which are set by this key. |\mmz@maybe@quitvmode| +% will be expanded, but for \hologo{XeTeX}, we have defined |\quitvmode| as a +% synonym for |\leavevmode|, which is a macro rather than a primitive, so we +% have to prevent its expansion in that case. It is easiest to just add +% |\noexpand|, regardless of the engine used. +\mmzset{ + capture/.is choice, + capture/hbox/.code={% + \let\mmz@capture\hbox + \def\mmz@maybe@quitvmode{\noexpand\quitvmode}% + }, + capture/vbox/.code={% + \let\mmz@capture\vbox + \def\mmz@maybe@quitvmode{}% + }, + capture=hbox, +} +% \end{key} +% The memoized code may be memoization-aware; in such a case, we say that the +% driver is \emph{integrated} into the code. Code containing an integrated +% driver must take care to execute it only when memoizing, and not during a +% regular compilation. The following key and macro can help here, see +% \MS\ref{sec:memoization-complex-single-driver} for details. +% +% \begin{mmzautokey}{integrated driver} +% This is an advice key, residing in |/mmz/auto|. Given \meta{suffix} as the +% only argument, it declares conditional \cs{ifmemoizing}\meta{suffix}, and +% sets the driver for the automemoized command to a macro which sets this +% conditional to true. The declared conditional is \emph{internal} and +% should not be used directly, but only via |\IfMemoizing| --- because it +% will not be declared when package NoMemoize or only Memoizable is loaded. +\mmzset{ + auto/integrated driver/.style={ + after setup={\expandafter\newif\csname ifmmz@memoizing#1\endcsname}, + driver/.expand once={% + \csname mmz@memoizing#1true\endcsname + % Without this, we would introduce an extra group around the memoized + % code. + \@firstofone + }% + }, +} +% \end{mmzautokey} +% +% \begin{macro}{\IfMemoizing} +% Without the optional argument, the condition is satisfied when the internal +% conditional \cs{ifmemoizing}\meta{suffix}, declared by |integrated driver|, +% is true. With the optional argument \meta{offset}, the current group level +% must additionally match the memoizing group level, modulo \meta{offset} --- +% this makes sure that the conditional comes out as false in a regular +% compilation embedded in a memoization. +\newcommand\IfMemoizing[2][\mmz@Ifmemoizing@nogrouplevel]{%>\fi +\csname ifmmz@memoizing#2\endcsname%>\if + % One |\relax| is for the |\numexpr|, another for |\ifnum|. Complications + % arise when |#1| is the optional argument default (defined below). In + % that case, the content of |\mmz@Ifmemoizing@nogrouplevel| closes off the + % |\ifnum| conditional (with both the true and the false branch empty), and + % opens up a new one, |\iftrue|. Effectively, we're not testing for the + % group level match. + \ifnum\currentgrouplevel=\the\numexpr\memoizinggrouplevel+#1\relax\relax + \expandafter\expandafter\expandafter\@firstoftwo + \else + \expandafter\expandafter\expandafter\@secondoftwo + \fi +\else + \expandafter\@secondoftwo +\fi +} +\def\mmz@Ifmemoizing@nogrouplevel{0\relax\relax\fi\iftrue} +% \end{macro} +% +% \paragraph.{Tracing} We populate the hooks which send the tracing info to the +% terminal. +\def\mmz@trace#1{\immediate\write16{[tracing memoize] #1}} +\def\mmz@trace@context{\mmz@trace{\space\space + Context: "\expandonce{\mmz@context@key}" --> \mmz@context@mdfivesum}} +\def\mmz@trace@Memoize@on{% + \mmz@trace{% + Entering \noexpand\Memoize (% + \ifmemoize enabled\else disabled\fi, + \ifnum\mmz@mode=\mmz@mode@recompile recompile\fi + \ifnum\mmz@mode=\mmz@mode@readonly readonly\fi + \ifnum\mmz@mode=\mmz@mode@normal normal\fi + \space mode) on line \the\inputlineno + }% + \mmz@trace{\space\space Code: \the\mmz@mdfive@source}% +} +\def\mmz@trace@code@mdfive@on{\mmz@trace{\space\space + Code md5sum: \mmz@code@mdfivesum}} +\def\mmz@trace@compile@on{\mmz@trace{\space\space Compiling}} +\def\mmz@trace@memoize@on{\mmz@trace{\space\space Memoizing}} +\def\mmz@trace@endmemoize@ok@on{\mmz@trace{\space\space + Memoization completed}}% +\def\mmz@trace@endmemoize@aborted@on{\mmz@trace{\space\space + Memoization was aborted}} +\def\mmz@trace@endmemoize@unmemoizable@on{\mmz@trace{\space\space + Marking this code as unmemoizable}} +% No need for |\mmz@trace@endmemoize@fail|, as abortion results in a package +% warning anyway. +\def\mmz@trace@process@cmemo@on{\mmz@trace{\space\space + Attempting to utilize c-memo \mmz@cmemo@path}} +\def\mmz@trace@process@no@cmemo@on{\mmz@trace{\space\space + C-memo does not exist}} +\def\mmz@trace@process@cmemo@ok@on{\mmz@trace{\space\space + C-memo was processed successfully}\mmz@trace@context} +\def\mmz@trace@process@cmemo@fail@on{\mmz@trace{\space\space + C-memo input failed}} +\def\mmz@trace@cmemo@unmemoizable@on{\mmz@trace{\space\space + This code was marked as unmemoizable}} +\def\mmz@trace@process@ccmemo@on{\mmz@trace{\space\space + Attempting to utilize cc-memo \mmz@ccmemo@path\space + (\ifmmz@direct@ccmemo@input\else in\fi direct input)}} +\def\mmz@trace@resource@on#1{\mmz@trace{\space\space + Extern file does not exist: #1}} +\def\mmz@trace@process@ccmemo@ok@on{% + \mmz@trace{\space\space Utilization successful}} +\def\mmz@trace@process@no@ccmemo@on{% + \mmz@trace{\space\space CC-memo does not exist}} +\def\mmz@trace@process@ccmemo@fail@on{% + \mmz@trace{\space\space Cc-memo input failed}} +% +% \begin{key}{tracing} +% \begin{macro}{\mmzTracingOn,\mmzTracingOff} +% The user interface for switching the tracing on and off; initially, it is +% off. Note that there is no underlying conditional. The off version +% simply |\let|s all the tracing hooks to |\relax|, so that the overhead of +% having the tracing functionality available is negligible. +\mmzset{% + trace/.is choice, + trace/.default=true, + trace/true/.code=\mmzTracingOn, + trace/false/.code=\mmzTracingOff, +} +\def\mmzTracingOn{% + \let\mmz@trace@Memoize\mmz@trace@Memoize@on + \let\mmz@trace@code@mdfive\mmz@trace@code@mdfive@on + \let\mmz@trace@compile\mmz@trace@compile@on + \let\mmz@trace@memoize\mmz@trace@memoize@on + \let\mmz@trace@process@cmemo\mmz@trace@process@cmemo@on + \let\mmz@trace@endmemoize@ok\mmz@trace@endmemoize@ok@on + \let\mmz@trace@endmemoize@unmemoizable\mmz@trace@endmemoize@unmemoizable@on + \let\mmz@trace@endmemoize@aborted\mmz@trace@endmemoize@aborted@on + \let\mmz@trace@process@cmemo\mmz@trace@process@cmemo@on + \let\mmz@trace@process@cmemo@ok\mmz@trace@process@cmemo@ok@on + \let\mmz@trace@process@no@cmemo\mmz@trace@process@no@cmemo@on + \let\mmz@trace@process@cmemo@fail\mmz@trace@process@cmemo@fail@on + \let\mmz@trace@cmemo@unmemoizable\mmz@trace@cmemo@unmemoizable@on + \let\mmz@trace@process@ccmemo\mmz@trace@process@ccmemo@on + \let\mmz@trace@resource\mmz@trace@resource@on + \let\mmz@trace@process@ccmemo@ok\mmz@trace@process@ccmemo@ok@on + \let\mmz@trace@process@no@ccmemo\mmz@trace@process@no@ccmemo@on + \let\mmz@trace@process@ccmemo@fail\mmz@trace@process@ccmemo@fail@on +} +\def\mmzTracingOff{% + \let\mmz@trace@Memoize\relax + \let\mmz@trace@code@mdfive\relax + \let\mmz@trace@compile\relax + \let\mmz@trace@memoize\relax + \let\mmz@trace@process@cmemo\relax + \let\mmz@trace@endmemoize@ok\relax + \let\mmz@trace@endmemoize@unmemoizable\relax + \let\mmz@trace@endmemoize@aborted\relax + \let\mmz@trace@process@cmemo\relax + \let\mmz@trace@process@cmemo@ok\relax + \let\mmz@trace@process@no@cmemo\relax + \let\mmz@trace@process@cmemo@fail\relax + \let\mmz@trace@cmemo@unmemoizable\relax + \let\mmz@trace@process@ccmemo\relax + \let\mmz@trace@resource\@gobble + \let\mmz@trace@process@ccmemo@ok\relax + \let\mmz@trace@process@no@ccmemo\relax + \let\mmz@trace@process@ccmemo@fail\relax +} +\mmzTracingOff +% \end{macro} +% \end{key} +% +% +%\newcommand\IfMemoizing[2][]{\@secondoftwo} +%<*mmz> +% +% \subsection{Context} +% \label{sec:code:context} +% +% \begin{macro}{\mmzContext,\mmzContextExtra} +% The context expression is stored in two token registers. Outside +% memoization, we will locally assign to |\mmzContext|; during memoization, +% we will globally assign to |\mmzContextExtra|. +\newtoks\mmzContext +\newtoks\mmzContextExtra +% \end{macro} +% \begin{key}{context, clear context} +% The user interface keys for context manipulation hide the complexity +% underlying the context storage from the user. +\mmzset{% + context/.code={% + \ifmemoizing + \expandafter\gtoksapp\expandafter\mmzContextExtra + \else + \expandafter\toksapp\expandafter\mmzContext + \fi + % We append a comma to the given context chunk, for disambiguation. + {#1,}% + }, + clear context/.code={% + \ifmemoizing + \expandafter\global\expandafter\mmzContextExtra + \else + \expandafter\mmzContext + \fi + {}% + }, + clear context/.value forbidden, + % \end{key} + % \begin{key}{meaning to context, csname meaning to context, key meaning to + % context, key value to context, /handlers/.meaning to context, + % /handlers/.value to context} + % Utilities to put the meaning of various stuff into |context|. + meaning to context/.code={\forcsvlist\mmz@mtoc{#1}}, + csname meaning to context/.code={\mmz@mtoc@cs{#1}}, + key meaning to context/.code={\forcsvlist\mmz@mtoc\mmz@mtoc@keycmd{#1}}, + key value to context/.code={\forcsvlist\mmz@mtoc@key{#1}}, + /handlers/.meaning to context/.code={% + \expanded{\noexpand\mmz@mtoc@cs{pgfk@\pgfkeyscurrentpath/.@cmd}}}, + /handlers/.value to context/.code={% + \expanded{\noexpand\mmz@mtoc@cs{pgfk@\pgfkeyscurrentpath}}}, +} +\def\mmz@mtoc#1{% + \collargs@cs@cases{#1}% + {\mmz@mtoc@cmd{#1}}% + {\mmz@mtoc@error@notcsorenv{#1}}% + {% + \mmz@mtoc@cs{% + %start% + #1}% + \mmz@mtoc@cs{% + %end% + %stop% + #1}% + }% +} +\def\mmz@mtoc@cmd#1{% + \begingroup + \escapechar=-1 + \expandafter\endgroup + \expandafter\mmz@mtoc@cs\expandafter{\string#1}% +} +\def\mmz@mtoc@cs#1{% + \pgfkeysvalueof{/mmz/context/.@cmd}% + \expandafter\string\csname#1\endcsname={\expandafter\meaning\csname#1\endcsname}% + \pgfeov +} +\def\mmz@mtoc@key#1{\mmz@mtoc@cs{pgfk@#1}} +\def\mmz@mtoc@key#1{\mmz@mtoc@cs{pgfk@#1/.@cmd}} +\def\mmz@mtoc@error@notcsorenv#1{% + \PackageError{memoize}{'\detokenize{#1}' passed to key 'meaning to context' is neither a command nor an environment}{}% +} +% \end{key} +% +% +% \subsection{C-memos} +% \label{sec:code:c-memo} +% +% \paragraph{The path} to a c-memo consists of the path prefix, the MD5 sum of +% the memoized code, and suffix |.memo|. +\def\mmz@cmemo@path{\mmz@prefix@path\mmz@code@mdfivesum.memo} +% \begin{macro}{\mmzCMemo} +% The additional, free-form content of the c-memo is collected in this token +% register. +\newtoks\mmzCMemo +% \end{macro} +% +% \begin{key}{include source in cmemo} +% \begin{macro}{\ifmmz@include@source} +% Should we include the memoized code in +% the c-memo? By default, yes. \bigskip +\mmzset{% + include source in cmemo/.is if=mmz@include@source, +} +\newif\ifmmz@include@source +\mmz@include@sourcetrue +% \end{macro} +% \end{key} +% +% \begin{macro}{\mmz@write@cmemo} +% This macro creates the c-memo from the contents of |\mmzContextExtra| and +% |\mmzCMemo|. +\def\mmz@write@cmemo{% + % Open the file for writing. + \immediate\openout\mmz@out{\mmz@cmemo@path}% + % The memo starts with the |\mmzMemo| marker (a signal that the memo is valid). + \immediate\write\mmz@out{\noexpand\mmzMemo}% + % We store the content of |\mmzContextExtra| by writing out a command that + % will (globally) assign its content back into this register. + \immediate\write\mmz@out{% + \global\mmzContextExtra{\the\mmzContextExtra}\collargs@percentchar + }% + % Write out the free-form part of the c-memo. + \immediate\write\mmz@out{\the\mmzCMemo\collargs@percentchar}% + % When |include source in cmemo| is in effect, add the memoized code, hiding + % it behind the |\mmzSource| marker. + \ifmmz@include@source + \immediate\write\mmz@out{\noexpand\mmzSource}% + \immediate\write\mmz@out{\the\mmz@mdfive@source}% + \fi + % Close the file. + \immediate\closeout\mmz@out + % Record that we wrote a new c-memo. + \pgfkeysalso{/mmz/record/new cmemo={\mmz@cmemo@path}}% +} +% \end{macro} +% +% \begin{macro}{\mmz@write@empty@cmemo} +% This macro is used to create an empty c-memo on aborted memoization, to +% make sure that no leftover c-memo tricks Memoize into thinking that the +% code was successfully memoized. +\def\mmz@write@empty@cmemo{% + \immediate\openout\mmz@out{\mmz@cmemo@path}% + \immediate\closeout\mmz@out +} +% \end{macro} +% +% +% \begin{macro}{\mmzSource} +% The c-memo memoized code marker. This macro is synonymous with |\endinput|, +% so the source following it is ignored when inputting the c-memo. +\let\mmzSource\endinput +% \end{macro} +% +% \begin{macro}{\mmz@process@cmemo} +% This macro inputs the c-memo, which will update the context code, which we +% can then compute the MD5 sum of. +\def\mmz@process@cmemo{% + \mmz@trace@process@cmemo + % |\ifmmz@abort| serves as a signal that the c-memo exists and is of correct + % form. + \global\mmz@aborttrue + % If c-memo sets |\ifmmzUnmemoizable|, we will compile regularly. + \global\mmzUnmemoizablefalse + \def\mmzMemo{\global\mmz@abortfalse}% + % Just a safeguard \dots\ c-memo assigns to |\mmzContextExtra| anyway. + \global\mmzContextExtra{}% + % Input the c-memo, if it exists, and record that we have used it. + \IfFileExists{\mmz@cmemo@path}{% + \input{\mmz@cmemo@path}% + \pgfkeysalso{/mmz/record/used cmemo={\mmz@cmemo@path}}% + }{% + \mmz@trace@process@no@cmemo + }% + % Compute the context MD5 sum. + \mmz@compute@context@mdfivesum +} +% \end{macro} +% +% \begin{macro}{\mmz@compute@context@mdfivesum} +% This macro computes the MD5 sum of the concatenation of |\mmzContext| and +% |\mmzContextExtra|, and writes out the tracing info when |trace context| is +% in effect. The argument is the tracing note. +% \end{macro} +\def\mmz@compute@context@mdfivesum{% + \xdef\mmz@context@key{\the\mmzContext\the\mmzContextExtra}% + % A special provision for padding, which occurs in the context by default, + % and may contain otherwise undefined macros referring to the extern + % dimensions. We make sure that when we expand the context key, + % |\mmz@paddings| contains the stringified |\width| etc., while these macros + % (which may be employed by the end user in the context expression), are + % returned to their original definitions. + \begingroup + \begingroup + \def\width{\string\width}% + \def\height{\string\height}% + \def\depth{\string\depth}% + \edef\mmz@paddings{\mmz@paddings}% + \expandafter\endgroup + \expandafter\def\expandafter\mmz@paddings\expandafter{\mmz@paddings}% + % We pre-expand the concatenated context, for tracing\slash inclusion in the + % cc-memo. In \hologo{LaTeX}, we protect the expansion, as the context + % expression may contain whatever. + %\protected@xdef + %\xdef + \mmz@context@key{\mmz@context@key}% + \endgroup + % Compute the MD5 sum. We have to assign globally, because this macro is (also) + % called after inputting the c-memo, while the resulting MD5 sum is used to + % input the cc-memo, which happens outside the |\Memoize| group. + % |\mmz@context@mdfivesum|. + \xdef\mmz@context@mdfivesum{\pdf@mdfivesum{\expandonce\mmz@context@key}}% +} +% +% +% \subsection{Cc-memos} +% \label{sec:code:cc-memo} +% +% \paragraph{The path} to a cc-memo consists of the path prefix, the +% hyphen-separated MD5 sums of the memoized code and the (evaluated) context, +% and suffix |.memo|. +\def\mmz@ccmemo@path{% + \mmz@prefix@path\mmz@code@mdfivesum-\mmz@context@mdfivesum.memo} +% +% \paragraph{The structure} of a cc-memo: +% \begin{itemize} +% \item the list of resources consisting of calls to |\mmzResource|; +% \item the core memo code (which includes the externs when executed), +% introduced by marker |\mmzMemo|; and, +% \item optionally, the context expansion, introduced by marker +% |\mmzThisContext|. +% \end{itemize} +% +% We begin the cc-memo with a list of extern files included by the core memo +% code so that we can check whether these files exist prior to executing the +% core memo code. Checking this on the fly, while executing the core memo +% code, would be too late, as that code is arbitrary (and also executed outside +% the |\Memoize| group). +% +% \begin{macro}{\mmzCCMemo} +% During memoization, the core content of the cc-memo is collected into this +% token register. +\newtoks\mmzCCMemo +% \end{macro} +% +% \begin{key}{include context in ccmemo} +% \begin{macro}{\ifmmz@include@context} +% Should we include the context expansion in the cc-memo? By default, no. +% \bigskip +\newif\ifmmz@include@context +\mmzset{% + include context in ccmemo/.is if=mmz@include@context, +} +% \end{macro} +% \end{key} +% +% \begin{key}{direct ccmemo input} +% \begin{macro}{\ifmmz@direct@ccmemo@input} +% When this conditional is false, the +% cc-memo is read indirectly, via a token register, to facilitate +% inverse search. \bigskip +\newif\ifmmz@direct@ccmemo@input +\mmzset{% + direct ccmemo input/.is if=mmz@direct@ccmemo@input, +} +% \end{macro} +% \end{key} +% +% \begin{macro}{\mmz@write@ccmemo} +% This macro creates the cc-memo from the list of resources in +% |\mmz@ccmemo@resources| and the contents of |\mmzCCMemo|. +\def\mmz@write@ccmemo{% + % Open the cc-memo file for writing. Note that the filename contains the + % context MD5 sum, which can only be computed after memoization, as the + % memoized code can update the context. This is one of the two reasons why + % we couldn't write the cc-memo directly into the file, but had to collect + % its contents into token register |\mmzCCMemo|. + \immediate\openout\mmz@out{\mmz@ccmemo@path}% + % Token register |\mmz@ccmemo@resources| consists of calls to + % |\mmz@ccmemo@append@resource|, so the following code writes down the list + % of created externs into the cc-memo. Wanting to have this list at the top + % of the cc-memo is the other reason for the roundabout creation of the + % cc-memo --- the resources become known only during memoization, as well. + \begingroup + \the\mmz@ccmemo@resources + \endgroup + % Write down the content of |\mmzMemo|, but first introduce it by the + % |\mmzMemo| marker. + \immediate\write\mmz@out{\noexpand\mmzMemo}% + \immediate\write\mmz@out{\the\mmzCCMemo\collargs@percentchar}% + % Write down the context tracing info when |include context in ccmemo| is in + % effect. + \ifmmz@include@context + \immediate\write\mmz@out{\noexpand\mmzThisContext}% + \immediate\write\mmz@out{\expandonce{\mmz@context@key}}% + \fi + % Insert the end-of-file marker and close the file. + \immediate\write\mmz@out{\noexpand\mmzEndMemo}% + \immediate\closeout\mmz@out + % Record that we wrote a new cc-memo. + \pgfkeysalso{/mmz/record/new ccmemo={\mmz@ccmemo@path}}% +} +% \end{macro} +% +% \begin{macro}{\mmz@ccmemo@append@resource} +% Append the resource to the cc-memo (we are nice to external utilities and +% put each resource on its own line). |#1| is the sequential number of the +% extern belonging to the memoized code; below, we assign it to |\mmz@seq|, +% which appears in |\mmz@extern@name|. Note that |\mmz@extern@name| only +% contains the extern filename --- without the path, so that externs can be +% used by several projects, or copied around. +\def\mmz@ccmemo@append@resource#1{% + \mmz@seq=#1\relax + \immediate\write\mmz@out{% + \string\mmzResource{\mmz@extern@name}\collargs@percentchar}% +} +% \end{macro} +% +% \begin{macro}{\mmzResource} +% A list of these macros is located at the top of a cc-memo. The macro +% checks for the existence of the extern file, given as |#1|. If the extern +% does not exist, we redefine |\mmzMemo| to |\endinput|, so that the core +% content of the cc-memo is never executed; see also |\mmz@process@ccmemo| +% above. +\def\mmzResource#1{% + % We check for existence using |\pdffilesize|, because an empty PDF, which + % might be produced by a failed \hologo{TeX}-based extraction, should count + % as no file. The |0| behind |\ifnum| is there because |\pdffilesize| + % returns an empty string when the file does not exist. + \ifnum0\pdf@filesize{\mmz@dir@path/#1}=0 + \ifmmz@direct@ccmemo@input + \let\mmzMemo\endinput + \else + % With indirect cc-memo input, we simulate end-of-input by grabbing + % everything up to the end-of-memo marker. In the indirect cc-memo + % input, a |\par| token shows up after |\mmzEndMemo|, I'm not sure why + % (|\everyeof={}| does not help). + \long\def\mmzMemo##1\mmzEndMemo\par{}% + \fi + \mmz@trace@resource{#1}% + \fi +} +% \end{macro} +% +% \begin{macro}{\mmz@process@ccmemo,\mmzThisContext,\mmzEndMemo} +% This macro processes the cc-memo. +\def\mmz@process@ccmemo{% + \mmz@trace@process@ccmemo + % The following conditional signals whether cc-memo was successfully + % utilized. If the cc-memo file does not exist, |\ifmmz@abort| will remain + % true. If it exists, it is headed by the list of resources. If a + % resource check fails, |\mmzMemo| (which follows the list of resources) is + % redefined to |\endinput|, so |\ifmmz@abort| remains true. However, if + % all resource checks are successful, |\mmzMemo| marker is reached with + % the below definition in effect, so |\ifmmz@abort| becomes false. Note + % that this marker also closes the |\Memoize| group, so that the core + % cc-memo content is executed in the original group --- and that this + % does not happen if anything goes wrong! + \global\mmz@aborttrue + % Note that |\mmzMemo| may be redefined by |\mmzResource| upon an unavailable + % extern file. + \def\mmzMemo{% + \endgroup + \global\mmz@abortfalse + % We |\let| the control sequence used for extern inclusion in the cc-memo to + % the macro which includes the extern from the extern file. + \let\mmzIncludeExtern\mmz@include@extern + }% + % Define |\mmzEndMemo| wrt |\ifmmz@direct@ccmemo@input|, whose value will be + % lost soon because |\mmMemo| will close the group --- that's also why this + % definition is global. + \xdef\mmzEndMemo{% + \ifmmz@direct@ccmemo@input + \noexpand\endinput + \else + % In the indirect cc-memo input, a |\par| token shows up after + % |\mmzEndMemo|, I'm not sure why (|\everyeof={}| does not help). + \unexpanded{% + \def\mmz@temp\par{}% + \mmz@temp + }% + \fi + }% + % The cc-memo context marker, again wrt |\ifmmz@direct@ccmemo@input| and + % globally. With direct cc-memo input, this macro is synonymous with + % |\endinput|, so the (expanded) context following it is ignored when + % inputting the cc-memo. With indirect input, we simulate end-of-input by + % grabbing everything up to the end-of-memo marker (plus gobble the |\par| + % mentioned above). + \xdef\mmzThisContext{% + \ifmmz@direct@ccmemo@input + \noexpand\endinput + \else + \unexpanded{% + \long\def\mmz@temp##1\mmzEndMemo\par{}% + \mmz@temp + }% + \fi + }% + % Input the cc-memo if it exists. + \IfFileExists{\mmz@ccmemo@path}{% + \ifmmz@direct@ccmemo@input + \input{\mmz@ccmemo@path}% + \else + % Indirect cc-memo input reads the cc-memo into a token register and + % executes the contents of this register. + \filetotoks\toks@{\mmz@ccmemo@path}% + \the\toks@ + \fi + % Record that we have used the cc-memo. + \pgfkeysalso{/mmz/record/used ccmemo={\mmz@ccmemo@path}}% + }{% + \mmz@trace@process@no@ccmemo + }% + \ifmmz@abort + % The cc-memo doesn't exist, or some of the resources don't. We need to + % memoize, but we'll do it only if |readonly| is not in effect, otherwise + % we'll perform a regular compilation. (Note that we are still in the group + % opened prior to executing |\Memoize|.) + \mmz@trace@process@ccmemo@fail + \ifnum\mmz@mode=\mmz@mode@readonly\relax + \expandafter\expandafter\expandafter\mmz@compile + \else + \expandafter\expandafter\expandafter\mmz@memoize + \fi + \else + \mmz@trace@process@ccmemo@ok + \fi +} +% \end{macro} +% +% \subsection{The externs} +% \label{sec:code:extern} +% +% \paragraph{The path} to an extern is like the path to a cc-memo, modulo +% suffix |.pdf|, of course. However, in case memoization of a chunk produces +% more than one extern, the filename of any non-first extern includes +% |\mmz@seq|, the sequential number of the extern as well (we start the +% numbering at $0$). We will have need for several parts of the full path to +% an extern: the basename, the filename, the path without the suffix, and the +% full path. +\newcount\mmz@seq +\def\mmz@extern@basename{% + \mmz@prefix\mmz@code@mdfivesum-\mmz@context@mdfivesum + \ifnum\mmz@seq>0 -\the\mmz@seq\fi +} +\def\mmz@extern@name{\mmz@extern@basename.pdf} +\def\mmz@extern@basepath{\mmz@dir@path/\mmz@extern@basename} +\def\mmz@extern@path{\mmz@extern@basepath.pdf} +% +% \begin{key}{padding left, padding right, padding top, padding bottom} +% These options set the amount of space surrounding the bounding box of the +% externalized graphics in the resulting PDF, i.e.\ in the extern file. This +% allows the user to deal with \TikZ; overlays, |\rlap| and |\llap|, etc. +\mmzset{ + padding left/.store in=\mmz@padding@left, + padding right/.store in=\mmz@padding@right, + padding top/.store in=\mmz@padding@top, + padding bottom/.store in=\mmz@padding@bottom, +% \end{key} +% +% \begin{key}{padding} +% A shortcut for setting all four paddings at once. + padding/.style={ + padding left=#1, padding right=#1, + padding top=#1, padding bottom=#1 + }, + % The default padding is what \hologo{pdfTeX} puts around the page anyway, 1 + % inch, but we'll use |1 in| rather than |1 true in|, which is the true + % default value of |\pdfhorigin| and |\pdfvorigin|, as we want the padding to + % adjust with magnification. + padding=1in, +% \end{key} +% + % \begin{key}{padding to context} + % This key adds padding to the context. Note that we add the padding + % expression (|\mmz@paddings|, defined below, refers to all the individual + % padding macros), not the actual value (at the time of expansion). This + % is so because |\width|, |\height| and |\depth| are not defined outside + % extern shipout routines, and the context is evaluated elsewhere. + padding to context/.style={ + context={padding=(\mmz@paddings)}, + }, + % \end{key} + % + % Padding nearly always belongs into the context --- the exception being + % memoized code which produces no externs (\MS\ref{sec:pure-memoization}) --- + % so we execute this key immediately. + padding to context, +} +\def\mmz@paddings{% + \mmz@padding@left,\mmz@padding@bottom,\mmz@padding@right,\mmz@padding@top +} +% +% \begin{macro}{\mmzExternalizeBox} +% This macro is the public interface to externalization. In Memoize itself, +% it is called from the default memoization driver, |\mmzSingleExternDriver|, +% but it should be called by any driver that wishes to produce an extern, see +% \MS\ref{sec:memoization-drivers} for details. It takes two arguments: +% \begin{enumerate}[\tt\#1] +% \item The box that we want to externalize. It's content will remain intact. +% The box may be given either as a control sequence, declared via |\newbox|, +% or as box number (say, 0). +% \item The token register which will receive the code that includes the extern +% into the document; it is the responsibility of the memoization driver to +% (globally) include the contents of the register in the cc-memo, i.e.\ in +% token register |\mmzCCMemo|. This argument may be either a control +% sequence, declared via |\newtoks|, or a |\toks|\meta{token register +% number}. +% \end{enumerate} +\def\mmzExternalizeBox#1#2{% + \begingroup + % A courtesy to the user, so they can define padding in terms of the size of + % the externalized graphics. + \def\width{\wd#1 }% + \def\height{\ht#1 }% + \def\depth{\dp#1 }% + % Store the extern-inclusion code in a temporary macro, which will be + % smuggled out of the group. + \xdef\mmz@global@temp{% + % Executing |\mmzIncludeExtern| from the cc-memo will include the extern + % into the document. + \noexpand\mmzIncludeExtern + % |\mmzIncludeExtern| identifies the extern by its sequence number, + % |\mmz@seq|. + {\the\mmz@seq}% + % What kind of box? We |\noexpand| the answer just in case someone + % redefined them. + \ifhbox#1\noexpand\hbox\else\noexpand\vbox\fi + % The dimensions of the extern. + {\the\wd#1}% + {\the\ht#1}% + {\the\dp#1}% + % The padding values. + {\the\dimexpr\mmz@padding@left}% + {\the\dimexpr\mmz@padding@bottom}% + {\the\dimexpr\mmz@padding@right}% + {\the\dimexpr\mmz@padding@top}% + }% + % Prepend the new extern box into the global extern box where we collect all + % the externs of this memo. Note that we |\copy| the extern box, retaining + % its content --- we will also want to place the extern box in its regular + % place in the document. + \global\setbox\mmz@tbe@box\vbox{\copy#1\unvbox\mmz@tbe@box}% + % Add the extern to the list of resources, which will be included at the top + % of the cc-memo, to check whether the extern files exists at the time the + % cc-memo is utilized. In the cc-memo, the list will contain full extern + % filenames, which are currently unknown, but no matter; right now, providing + % the extern sequence number suffices, the full extern filename will be + % produced at the end of memoization, once the context MD5 sum is known. + \xtoksapp\mmz@ccmemo@resources{% + \noexpand\mmz@ccmemo@append@resource{\the\mmz@seq}% + }% + % Increment the counter containing the sequence number of the extern within + % this memo. + \global\advance\mmz@seq1 + % Assign the extern-including code into the token register given in |#2|. + % This register may be given either as a control sequence or as + % |\toks|\meta{token register number}, and this is why we have temporarily + % stored the code (into |\mmz@global@temp|) globally: a local storage with + % |\expandafter\endgroup\expandafter| here would fail with the receiving + % token register given as |\toks|\meta{token register number}. + \endgroup + #2\expandafter{\mmz@global@temp}% +} +% \end{macro} +% +% \begin{macro}{\mmz@ccmemo@resources} +% This token register, populated by |\mmz@externalize@box| and used by +% |\mmz@write@ccmemo|, holds the list of externs produced by memoization of +% the current chunk. +\newtoks\mmz@ccmemo@resources +% \end{macro} +% +% \begin{macro}{\mmz@tbe@box} +% |\mmz@externalize@box| does not directly dump the extern into the document +% (as a special page). Rather, the externs are collected into +% |\mmz@tbe@box|, whose contents are dumped into the document at the end of +% memoization of the current chunk. In this way, we guarantee that aborted +% memoization does not pollute the document. +\newbox\mmz@tbe@box +% \end{macro} +% +% \begin{macro}{\mmz@shipout@externs} +% This macro is executed at the end of +% memoization, when the externs are waiting for us in |\mmz@tbe@box| and need +% to be dumped into the document. It loops through the contents of +% |\mmz@tbe@box|,\footnote{The looping code is based on TeX.SE +% answer \url(https://){tex.stackexchange.com/a/25142/16819} by Bruno Le +% Floch.}, putting each extern into |\mmz@box| and calling +% |\mmz@shipout@extern|. Note that the latter macro is executed within the +% group opened by |\vbox| below. +\def\mmz@shipout@externs{% + \global\mmz@seq 0 + \setbox\mmz@box\vbox{% + % Set the macros below to the dimensions of the extern box, so that the + % user can refer to them in the padding specification (which is in turn + % used in the page setup in |\mmz@shipout@extern|). + \def\width{\wd\mmz@box}% + \def\height{\ht\mmz@box}% + \def\depth{\dp\mmz@box}% + \vskip1pt + \ifmmzkeepexterns\expandafter\unvcopy\else\expandafter\unvbox\fi\mmz@tbe@box + \@whilesw\ifdim0pt=\lastskip\fi{% + \setbox\mmz@box\lastbox + \mmz@shipout@extern + }% + }% +} +% \end{macro} +% +% \begin{macro}{\mmz@shipout@extern} +% This macro ships out a single extern, which +% resides in |\mmz@box|, and records the creation of the new extern. +\def\mmz@shipout@extern{% + % Calculate the expected width and height. We have to do this now, before we + % potentially adjust the box size and paddings for magnification. + \edef\expectedwidth{\the\dimexpr + (\mmz@padding@left) + \wd\mmz@box + (\mmz@padding@right)}% + \edef\expectedheight{\the\dimexpr + (\mmz@padding@top) + \ht\mmz@box + \dp\mmz@box + (\mmz@padding@bottom)}% + % Apply the inverse magnification, if |\mag| is not at the default + % value. We'll do this in a group, which will last until shipout. + \begingroup + \ifnum\mag=1000 + \else + \mmz@shipout@mag + \fi + % Setup the geometry of the extern page. In \hologo{plainTeX} and + % \hologo{LaTeX}, setting |\pdfpagewidth| and |\pdfpageheight| seems to do + % the trick of setting the extern page dimensions. In \hologo{ConTeXt}, + % however, the resulting extern page ends up with the PDF |/CropBox| + % specification of the current regular page, which is then used (ignoring our + % |mediabox| requirement) when we're including the extern into the document + % by |\mmzIncludeExtern|. Typically, this results in a page-sized extern. + % I'm not sure how to deal with this correctly. In the workaround below, we + % use Lua function |backends.codeinjections.setupcanvas| to set up page + % dimensions: we first remember the current page dimensions + % (|\edef\mmz@temp|), then set up the extern page dimensions + % (|\expanded{...}|), and finally, after shipping + % out the extern page, revert to the current page dimensions by executing + % |\mmz@temp| at the very end of this macro. + %<*plain,latex> + \pdfpagewidth\dimexpr + (\mmz@padding@left) + \wd\mmz@box + (\mmz@padding@right)\relax + \pdfpageheight\dimexpr + (\mmz@padding@top) + \ht\mmz@box + \dp\mmz@box+ (\mmz@padding@bottom)\relax + % + %<*context> + \edef\mmz@temp{% + \noexpand\directlua{ + backends.codeinjections.setupcanvas({ + paperwidth=\the\numexpr\pagewidth, + paperheight=\the\numexpr\pageheight + }) + }% + }% + \expanded{% + \noexpand\directlua{ + backends.codeinjections.setupcanvas({ + paperwidth=\the\numexpr\dimexpr + \mmz@padding@left + \wd\mmz@box + \mmz@padding@right\relax, + paperheight=\the\numexpr\dimexpr + \mmz@padding@top + \ht\mmz@box + \dp\mmz@box+ \mmz@padding@bottom\relax + }) + }% + }% + % + % + % We complete the page setup by setting the content offset. + \hoffset\dimexpr\mmz@padding@left - \pdfhorigin\relax + \voffset\dimexpr\mmz@padding@top - \pdfvorigin\relax + % We shipout the extern page using the |\shipout| primitive, so that the + % extern page is not modified, or even registered, by the shipout code of the + % format or some package. I can't imagine those shipout routines ever + % needing to know about the extern page. In fact, most often knowing about + % it would be undesirable. For example, \hologo{LaTeX} and \hologo{ConTeXt} + % count the ``real'' pages, but usually to know whether they are shipping out + % an odd or an even page, or to make the total number of pages available to + % subsequent compilations. Taking the extern pages into account would + % disrupt these mechanisms. + % + % Another thing: delayed |\write|s. We have to make sure that any + % \hologo{LaTeX}-style protected stuff in those is not expanded. We don't + % bother introducing a special group, as we'll close the |\mag| group right + % after the shipout anyway. + %\let\protect\noexpand + \pdf@primitive\shipout\box\mmz@box + %\mmz@temp + \endgroup + % Advance the counter of shipped-out externs. We do this before preparing + % the recording information below, because the extern extraction tools expect + % the extern page numbering to start with $1$. + \global\advance\mmzExternPages1 + % Prepare the macros which may be used in |record//new extern| code. + \edef\externbasepath{\mmz@extern@basepath}% + % Adding up the counters below should result in the real page number of the + % extern. Macro |\mmzRegularPages| holds the number of pages which were + % shipped out so far using the regular shipout routine of the format; + % |\mmzExternPages| holds the number of shipped-out extern pages; and + % |\mmzExtraPages| holds, or at least should hold, the number of pages + % shipped out using any other means. + \edef\pagenumber{\the\numexpr\mmzRegularPages + % In \hologo{LaTeX}, the |\mmzRegularPages| holds to number of pages + % already shipped out. In \hologo{ConTeXt}, the counter is already + % increased while processing the page, so we need to subtract $1$. +% -1% + +\mmzExternPages+\mmzExtraPages}% + % Record the creation of the new extern. We do this after shipping out the + % extern page, so that the recording mechanism can serve as an after-shipout + % hook, for the unlikely situation that some package really needs to do + % something when our shipout happens. Note that we absolutely refuse to + % provide a before-shipout hook, because we can't allow anyone messing with + % our extern, and that using this after-shipout ``hook'' is unnecessary for + % counting extern shipouts, as we already provide this information in the + % public counter |\mmzExternPages|. + \mmzset{record/new extern/.expanded=\mmz@extern@path}% + % Advance the sequential number of the extern, in the context of the current + % memoized code chunk. This extern numbering starts at 0, so we only do this + % after we wrote the cc-memo and called |record/new extern|. + \global\advance\mmz@seq1 +} +% \end{macro} +% +% \begin{macro}{\mmz@shipout@mag} +% This macro applies the inverse magnification, so that the extern ends up +% with its natural size on the extern page. +\def\mmz@shipout@mag{% + % We scale the extern box using the PDF primitives: |q| and |Q| save and + % restore the current graphics state; |cm| applies the given coordinate + % transformation matrix. ($a$ $b$ $c$ $d$ $e$ $f$ |cm| transforms $(x,y)$ + % into $(ax+cy+e,bx+dy+f)$.) + \setbox\mmz@box\hbox{% + \pdfliteral{q \mmz@inverse@mag\space 0 0 \mmz@inverse@mag\space 0 0 cm}% + \copy\mmz@box\relax + \pdfliteral{Q}% + }% + % We first have to scale the paddings, as they might refer to the |\width| + % etc.\ of the extern. + \dimen0=\dimexpr\mmz@padding@left\relax + \edef\mmz@padding@left{\the\dimexpr\mmz@inverse@mag\dimen0}% + \dimen0=\dimexpr\mmz@padding@bottom\relax + \edef\mmz@padding@bottom{\the\dimexpr\mmz@inverse@mag\dimen0}% + \dimen0=\dimexpr\mmz@padding@right\relax + \edef\mmz@padding@right{\the\dimexpr\mmz@inverse@mag\dimen0}% + \dimen0=\dimexpr\mmz@padding@top\relax + \edef\mmz@padding@top{\the\dimexpr\mmz@inverse@mag\dimen0}% + % Scale the extern box. + \wd\mmz@box=\mmz@inverse@mag\wd\mmz@box\relax + \ht\mmz@box=\mmz@inverse@mag\ht\mmz@box\relax + \dp\mmz@box=\mmz@inverse@mag\dp\mmz@box\relax +} +% \end{macro} +% +% \begin{macro}{\mmz@inverse@mag} +% The inverse magnification factor, i.e.\ the number we have to multiply the +% extern dimensions with so that they will end up in their natural size. We +% compute it, once and for all, at the beginning of the document. To do +% that, we borrow the little macro |\Pgf@geT| from |pgfutil-common| (but +% rename it). +{\catcode`\p=12\catcode`\t=12\gdef\mmz@Pgf@geT#1pt{#1}} +\mmzset{begindocument/.append code={% + \edef\mmz@inverse@mag{\expandafter\mmz@Pgf@geT\the\dimexpr 1000pt/\mag}% + }} +% \end{macro} +% +% \begin{macro}{\mmzRegularPages} +% This counter holds the number of pages shipped out by the format's shipout +% routine. \hologo{LaTeX} and \hologo{ConTeXt} keep track of this in +% dedicated counters, so we simply use those. In \hologo{plainTeX}, we have +% to hack the |\shipout| macro to install our own counter. In fact, we +% already did this while loading the required packages, in order to avoid it +% being redefined by |atbegshi| first. All that is left to do here is to +% declare the counter. +%\let\mmzRegularPages\ReadonlyShipoutCounter +%\let\mmzRegularPages\realpageno +%\newcount\mmzRegularPages +% \end{macro} +% +% \begin{macro}{\mmzExternPages} +% This counter holds the number of extern pages shipped out so far. +\newcount\mmzExternPages +% \end{macro} +% +% The total number of new externs is announced at the end of the compilation, +% so that \hologo{TeX} editors, |latexmk| and such can propose recompilation. +\mmzset{ + enddocument/afterlastpage/.append code={% + \ifnum\mmzExternPages>0 + \PackageWarning{memoize}{The compilation produced \the\mmzExternPages\space + new extern\ifnum\mmzExternPages>1 s\fi.}% + \fi + }, +} +% +% \begin{macro}{\mmzExtraPages} +% This counter will probably remain at zero forever. It should be advanced by +% any package which (like Memoize) ships out pages bypassing the regular +% shipout routine of the format. +\newcount\mmzExtraPages +% \end{macro} +% +% \begin{macro}{\mmz@include@extern} +% This macro, called from cc-memos as |\mmzIncludeExtern|, inserts an extern +% file into the document. |#1| is the sequential number, |#2| is either +% |\hbox| or |\vbox|, |#3|, |#4| and |#5| are the (expected) width, height +% and the depth of the externalized box; |#6|--|#9| are the paddings (left, +% bottom, right, and top). +\def\mmz@include@extern#1#2#3#4#5#6#7#8#9{% + % Set the extern sequential number, so that we open the correct extern file + % (|\mmz@extern@basename|). + \mmz@seq=#1\relax + % Use the primitive PDF graphics inclusion commands to include the extern + % file. Set the correct depth or the resulting box, and shift it as + % specified by the padding. + \setbox\mmz@box=#2{% + \setbox0=\hbox{% + \lower\dimexpr #5+#7\relax\hbox{% + \hskip -#6\relax + \setbox0=\hbox{% + \mmz@insertpdfpage{\mmz@extern@path}{1}% + }% + \unhbox0 + }% + }% + \wd0 \dimexpr\wd0-#8\relax + \ht0 \dimexpr\ht0-#9\relax + \dp0 #5\relax + \box0 + }% + % Check whether the size of the included extern is as expected. There is no + % need to check |\dp|, we have just set it. (|\mmz@if@roughly@equal| is + % defined in section~\ref{sec:code:extract:tex}.) + \mmz@tempfalse + \mmz@if@roughly@equal{\mmz@tolerance}{#3}{\wd\mmz@box}{% + \mmz@if@roughly@equal{\mmz@tolerance}{#4}{\ht\mmz@box}{% + \mmz@temptrue + }{}}{}% + \ifmmz@temp + \else + \mmz@use@memo@warning{\mmz@extern@path}{#3}{#4}{#5}% + \fi + % Use the extern box, with the precise size as remembered at memoization. + \wd\mmz@box=#3\relax + \ht\mmz@box=#4\relax + \box\mmz@box + % Record that we have used this extern. + \pgfkeysalso{/mmz/record/used extern={\mmz@extern@path}}% +} +% \end{macro} +\def\mmz@use@memo@warning#1#2#3#4{% + \PackageWarning{memoize}{Unexpected size of extern "#1"; + expected #2\space x \the\dimexpr #3+#4\relax, + got \the\wd\mmz@box\space x \the\dimexpr\the\ht\mmz@box+\the\dp\mmz@box\relax}% +} +% \begin{macro}{\mmz@insertpdfpage} +% This macro inserts a page from the PDF into the document. We define it +% according to which engine is being used. Note that \hologo{ConTeXt} always +% uses \hologo{LuaTeX}. +%\ifdef\luatexversion{% + \def\mmz@insertpdfpage#1#2{% #1 = filename, #2 = page number + \saveimageresource page #2 mediabox {#1}% + \useimageresource\lastsavedimageresourceindex + }% +%<*latex,plain> +}{% + \ifdef\XeTeXversion{% + \def\mmz@insertpdfpage#1#2{% + \XeTeXpdffile #1 page #2 media + }% + }{% pdfLaTeX + \def\mmz@insertpdfpage#1#2{% + \pdfximage page #2 mediabox {#1}% + \pdfrefximage\pdflastximage + }% + }% +} +% +% \end{macro} +% +% \begin{macro}{\mmz@include@extern@from@tbe@box} +% Include the extern number |#1| residing in |\mmz@tbe@box| into the +% document. This helper macro makes it possible for a complex memoization +% driver to process the cc-memo right after memoization --- by using the +% |\mmzkeepexternstrue\xtoksapp\mmzAfterMemoizationExtra{\the\mmzCCMemo}| +% trick --- to ensure that the result of the memoizing compilation matches +% the result of inputting the cc-memo. The rest of the arguments are +% gobbled, as we don't have to do any size adjustment or checking here, and +% the box is of the correct type. +\def\mmz@include@extern@from@tbe@box#1#2#3#4#5#6#7#8#9{% + \setbox0\vbox{% + \@tempcnta#1\relax + \vskip1pt + \unvcopy\mmz@tbe@box + \@whilenum\@tempcnta>0\do{% + \setbox0\lastbox + \advance\@tempcnta-1\relax + }% + \global\setbox1\lastbox + \@whilesw\ifdim0pt=\lastskip\fi{% + \setbox0\lastbox + }% + \box\mmz@box + }% + \box1 +} +% \end{macro} +% +% \section{Extraction} +% \label{sec:code:extract} +% +% \subsection{Extraction mode and method} +% \label{sec:code:extraction-mode-method} +% +% \begin{key}{extract} +% This key selects the extraction mode and method. It normally occurs in the +% package options list, less commonly in the preamble, and never in the +% document body. +\def\mmzvalueof#1{\pgfkeysvalueof{/mmz/#1}} +\mmzset{ + extract/.estore in=\mmz@extraction@method, + extract/.value required, + begindocument/.append style={extract/.code=\mmz@preamble@only@warning}, + % \end{key} + % + % \begin{key}{extract/perl, extract/python} + % Any other value will select internal extraction with the given method. + % Memoize ships with two extraction scripts, a Perl script and a Python + % script, which are selected by |extract=perl| (the default) and + % |extract=python|, respectively. We run the scripts in verbose mode + % (without |-q|), and keep the |.mmz| file as is, i.e.\ we're not commenting + % out the |\mmzNewExtern| lines, because we're about to overwrite it + % anyway. We also request the log file, which will contain + % |\mmzExtractionSuccessful| if extraction was successful. + extract/perl/.code={% + \mmz@clear@extraction@log + \pdf@system{% + \mmzvalueof{perl extraction command}\space + \mmzvalueof{perl extraction options}% + }% + \mmz@check@extraction@log{perl}% + \def\mmz@mkdir@command##1{\mmzvalueof{perl extraction command}\space --mkdir "##1"}% + }, + perl extraction command/.initial=memoize-extract.pl, + perl extraction options/.initial={% +% \begin{listingregion}{perl-extraction-options.tex} + -e -l "\mmzOutputDirectory\mmzUnquote\jobname.mmz.log" -w + %"\string\PackageWarning{memoize (perl-based extraction)}{\string\warningtext}" + %"\string\warning{memoize (perl-based extraction): \string\warningtext}" + %"\string\warning{memoize (perl-based extraction): \string\warningtext}" + "\mmzOutputDirectory\mmzUnquote\jobname.mmz" +% \end{listingregion} + }, + extract=perl, + extract/python/.code={% + \mmz@clear@extraction@log + \pdf@system{% + \mmzvalueof{python extraction command}\space + \mmzvalueof{python extraction options}% + }% + \mmz@check@extraction@log{python}% + \def\mmz@mkdir@command##1{\mmzvalueof{python extraction command}\space --mkdir "##1"}% + }, + python extraction command/.initial=memoize-extract.py, + python extraction options/.initial={% + -e -l "\mmzOutputDirectory\mmzUnquote\jobname.mmz.log" -w + %"\string\PackageWarning{memoize (python-based extraction)}{\string\warningtext}" + %"\string\warning{memoize (python-based extraction): \string\warningtext}" + %"\string\warning{memoize (python-based extraction): \string\warningtext}" + "\mmzOutputDirectory\mmzUnquote\jobname.mmz" + }, +} +\def\mmz@preamble@only@warning{% + \PackageWarning{memoize}{% + Ignoring the invocation of "\pgfkeyscurrentkey". + This key may only be executed in the preamble}% +} +% \end{key} +% +% \paragraph*{The extraction log} +% As we cannot access the exit status of a system command in \hologo{TeX}, we +% communicate with the system command via the ``extraction log file,'' produced +% by both \hologo{TeX}-based extraction and the Perl and Python extraction +% script. This file signals whether the embedded extraction was successful --- +% if it is, the file contains |\mmzExtractionSuccessful| --- and also contains +% any size-mismatch warnings (these are currently only thrown by the +% \hologo{TeX}-based extraction). As the log is really a \hologo{TeX} file, +% the idea is to simply input it after extracting each extern (for +% \hologo{TeX}-based extraction) or after the extraction of all externs (for +% the external scripts). +\def\mmz@clear@extraction@log{% + \begingroup + \immediate\openout0{\mmzUnquote\jobname.mmz.log"}% + \immediate\closeout0 + \endgroup +} +% |#1| is the extraction method. +\def\mmz@check@extraction@log#1{% + \begingroup \def\extractionmethod{#1}% + \mmz@tempfalse \let\mmz@orig@endinput\endinput + \def\endinput{\mmz@temptrue\mmz@orig@endinput}% + \@input{\jobname.mmz.log}% + \ifmmz@temp \else \mmz@extraction@error \fi \endgroup } +\def\mmz@extraction@error{% + \PackageWarning{memoize}{Extraction of externs from document "\mmzUnquote\jobname.pdf" + using method "\extractionmethod" was unsuccessful. Have you set the + shell escape mode as suggested in chapter 1 of the manual?}{}} +% +% \subsection{The record files} +% \label{sec:code:record} +% +% \begin{key}{record} +% This key activates a record \meta{type}: the hooks defined by that record +% \meta{type} will henceforth be executed at the appropriate places. +% +% A \meta{hook} of a particular \meta{type} resides in |pgfkeys| path +% |/mmz/record/|\meta{type}|/|\meta{hook}, and is invoked via +% |/mmz/record/|\meta{hook}. Record type activation thus appends a call of +% the former to the latter. It does so using handler |.try|, so that +% unneeded hooks may be left undefined. +% +\mmzset{ + record/.style={% + record/begin/.append style={ + /mmz/record/#1/begin/.try, + % The |begin| hook also executes the |prefix| hook, so that |\mmzPrefix| + % surely occurs at the top of the |.mmz| file. Listing each prefix type + % separately in this hook ensures that |prefix| of a certain type is + % executed after that type's |begin|. + /mmz/record/#1/prefix/.try/.expanded=\mmz@prefix@path, + }, + record/prefix/.append style={/mmz/record/#1/prefix/.try={##1}}, + record/new extern/.append style={/mmz/record/#1/new extern/.try={##1}}, + record/used extern/.append style={/mmz/record/#1/used extern/.try={##1}}, + record/new cmemo/.append style={/mmz/record/#1/new cmemo/.try={##1}}, + record/new ccmemo/.append style={/mmz/record/#1/new ccmemo/.try={##1}}, + record/used cmemo/.append style={/mmz/record/#1/used cmemo/.try={##1}}, + record/used ccmemo/.append style={/mmz/record/#1/used ccmemo/.try={##1}}, + record/end/.append style={/mmz/record/#1/end/.try}, + }, +} +% \end{key} +% +% \begin{key}{no record} +% This key deactivates all record types. Below, we use it to initialize the +% relevant keys; in the user code, it may be used to deactivate the +% preactivated |mmz| record type. +\mmzset{ + no record/.style={% + % The |begin| hook clears itself after invocation, to prevent double + % execution. Consequently, |record/begin| may be executed by the user in + % the preamble, without any ill effects. + record/begin/.style={record/begin/.style={}}, + % The |prefix| key invokes itself again when the group closes. This way, + % we can correctly track the path prefix changes in the |.mmz| even if + % |path| is executed in a group. + record/prefix/.code={\aftergroup\mmz@record@prefix}, + record/new extern/.code={}, + record/used extern/.code={}, + record/new cmemo/.code={}, + record/new ccmemo/.code={}, + record/used cmemo/.code={}, + record/used ccmemo/.code={}, + % The |end| hook clears itself after invocation, to prevent double + % execution. Consequently, |record/end| may be executed by the user before + % the end of the document, without any ill effects. + record/end/.style={record/end/.code={}}, + } +} +% \end{key} +% We define this macro because |\aftergroup|, used in |record/prefix|, only +% accepts a token. +\def\mmz@record@prefix{% + \mmzset{/mmz/record/prefix/.expanded=\mmz@prefix@path}% +} +% \paragraph{Initialize} the hook keys, preactivate |mmz| record type, and +% execute hooks |begin| and |end| at the edges of the document. +\mmzset{ + no record, + record=mmz, + begindocument/.append style={record/begin}, + enddocument/afterlastpage/.append style={record/end}, +} +% +% \subsubsection{The \texttt{.mmz} file} +% \label{sec:code:record:mmz} +% +% Think of the |.mmz| record file as a \hologo{TeX}-readable log file, which +% lets the extraction procedure know what happened in the previous compilation. +% The file is in \hologo{TeX} format, so that we can trigger internal +% \hologo{TeX}-based extraction by simply inputting it. The commands it +% contains are intentionally as simple as possible (just a macro plus braced +% arguments), to facilitate parsing by the external scripts. +% +% These hooks simply put the calls of the corresponding macros into the file. +% All but hooks but |begin| and |end| receive the full path to the relevant +% file as the only argument (ok, |prefix| receives the full path prefix, as set +% by key |path|). +% +% \begin{key}{record/mmz/...} +\mmzset{ + record/mmz/begin/.code={% + \newwrite\mmz@mmzout + % The record file has a fixed name (the jobname plus the |.mmz| suffix) and + % location (the current directory, i.e.\ the directory where \hologo{TeX} + % is executed from; usually, this will be the directory containing the + % \hologo{TeX} source). + \immediate\openout\mmz@mmzout{\jobname.mmz}% + }, + % The |\mmzPrefix| is used by the clean-up script, which will remove all + % files with the given path prefix but (unless called with |--all|) those + % mentioned in the |.mmz|. Now this script could in principle figure out + % what to remove by inspecting the paths to utilized\slash created + % memos\slash externs in the |.mmz| file, but this method could lead to + % problems in case of an incomplete (perhaps empty) |.mmz| file created by a + % failed compilation. Recording the path prefix in the |.mmz| radically + % increases the chances of a successful clean-up, which is doubly important, + % because a clean-up is sometimes precisely what we need to do to recover + % after a failed compilation. + record/mmz/prefix/.code={% + \immediate\write\mmz@mmzout{\noexpand\mmzPrefix{#1}}% + }, + record/mmz/new extern/.code={% + % While this key receives a single formal argument, Memoize also prepares + % macros |\externbasepath| (|#1| without the |.pdf| suffix), |\pagenumber| + % (of the extern page in the document PDF), and |\expectedwidth| and + % |\expectedheight| (of the extern page). + \immediate\write\mmz@mmzout{% + \noexpand\mmzNewExtern{#1}{\pagenumber}{\expectedwidth}{\expectedheight}% + }% + }, + record/mmz/new cmemo/.code={% + \immediate\write\mmz@mmzout{\noexpand\mmzNewCMemo{#1}}% + }, + record/mmz/new ccmemo/.code={% + \immediate\write\mmz@mmzout{\noexpand\mmzNewCCMemo{#1}}% + }, + record/mmz/used extern/.code={% + \immediate\write\mmz@mmzout{\noexpand\mmzUsedExtern{#1}}% + }, + record/mmz/used cmemo/.code={% + \immediate\write\mmz@mmzout{\noexpand\mmzUsedCMemo{#1}}% + }, + record/mmz/used ccmemo/.code={% + \immediate\write\mmz@mmzout{\noexpand\mmzUsedCCMemo{#1}}% + }, + record/mmz/end/.code={% + % Add the |\endinput| marker to signal that the file is complete. + \immediate\write\mmz@mmzout{\noexpand\endinput}% + \immediate\closeout\mmz@mmzout + }, + % + % \end{key} + % \subsubsection{The shell scripts} +% +% We define two shell script record types: |sh| for Linux, and |bat| for +% Windows. +% +% \begin{key}{sh, bat} +% These keys set the shell script filenames. +% \bigskip + sh/.store in=\mmz@shname, + sh=memoize-extract.\jobname.sh, + bat/.store in=\mmz@batname, + bat=memoize-extract.\jobname.bat, +% \end{key} +% +% \begin{key}{record/sh/...} Define the Linux shell script record type. + record/sh/begin/.code={% + \newwrite\mmz@shout + \immediate\openout\mmz@shout{\mmz@shname}% + }, + record/sh/new extern/.code={% + \begingroup + % Macro |\mmz@tex@extraction@systemcall| is customizable through |tex + % extraction command|, |tex extraction options| and |tex extraction + % script|. + \immediate\write\mmz@shout{\mmz@tex@extraction@systemcall}% + \endgroup + }, + record/sh/end/.code={% + \immediate\closeout\mmz@shout + }, +% \end{key} +% +% \begin{key}{record/bat/...} +% Rinse and repeat for Windows. + record/bat/begin/.code={% + \newwrite\mmz@batout + \immediate\openout\mmz@batout{\mmz@batname}% + }, + record/bat/new extern/.code={% + \begingroup + \immediate\write\mmz@batout{\mmz@tex@extraction@systemcall}% + \endgroup + }, + record/bat/end/.code={% + \immediate\closeout\mmz@batout + }, +% \end{key} +% +% \subsubsection{The Makefile} +% +% The implementation of the Makefile record type is the most complex so far, as +% we need to keep track of the targets. +% +% \begin{key}{makefile} +% This key sets the makefile filename. + makefile/.store in=\mmz@makefilename, + makefile=memoize-extract.\jobname.makefile, +} +% \end{key} +% +% We need to define a macro which expands to the tab character of catcode +% ``other'', to use as the recipe prefix. +\begingroup +\catcode`\^^I=12 +\gdef\mmz@makefile@recipe@prefix{^^I}% +\endgroup +% \begin{key}{record/makefile/...} +% Define the Makefile record type. +\mmzset{ + record/makefile/begin/.code={% + % We initialize the record type by opening the file and setting makefile + % variables |.DEFAULT_GOAL| and |.PHONY|. + \newwrite\mmz@makefileout + \newtoks\mmz@makefile@externs + \immediate\openout\mmz@makefileout{\mmz@makefilename}% + \immediate\write\mmz@makefileout{.DEFAULT_GOAL = externs}% + \immediate\write\mmz@makefileout{.PHONY: externs}% + }, + % The crucial part, writing out the extraction rule. The target comes first, + % then the recipe, which is whatever the user has set by |tex extraction + % command|, |tex extraction options| and |tex extraction script|. + record/makefile/new extern/.code={% + % The target extern file: + \immediate\write\mmz@makefileout{#1:}% + \begingroup + % The recipe is whatever the user set by |tex extraction + % command|, |tex extraction options| and |tex extraction script|. + \immediate\write\mmz@makefileout{% + \mmz@makefile@recipe@prefix\mmz@tex@extraction@systemcall}% + \endgroup + % Append the extern file to list of targets. + \xtoksapp\mmz@makefile@externs{#1\space}% + }, + record/makefile/end/.code={% + % Before closing the file, we list the extern files as the prerequisites of + % our phony default target, |externs|. + \immediate\write\mmz@makefileout{externs: \the\mmz@makefile@externs}% + \immediate\closeout\mmz@makefileout + }, +} +% \end{key} +% +% +% \subsection{\hologo{TeX}-based extraction} +% \label{sec:code:extract:tex} +% +% \begin{key}{extract/tex} +% We trigger the \hologo{TeX}-based extraction by inputting the |.mmz| record +% file. +\mmzset{ + extract/tex/.code={% + \begingroup + \@input{\jobname.mmz}% + \endgroup + }, +} +% \end{key} +% +% \begingroup +% \setlength\MacroIndent{2em} +% \begin{macro}{\mmzUsedCMemo,\mmzUsedCCMemo,\mmzUsedExtern,\mmzNewCMemo,\mmzNewCCMemo,\mmzPrefix} +% We can ignore everything but |\mmzNewExtern|s. All these macros receive a +% single argument. +\def\mmzUsedCMemo#1{} +\def\mmzUsedCCMemo#1{} +\def\mmzUsedExtern#1{} +\def\mmzNewCMemo#1{} +\def\mmzNewCCMemo#1{} +\def\mmzPrefix#1{} +% \end{macro} +% \endgroup +% +% \begin{macro}{\mmzNewExtern} +% Command |\mmzNewExtern| takes four arguments. It instructs us to extract +% page |#2| of document |\jobname.pdf| to file |#1|. During the extraction, +% we will check whether the size of the extern matches the given expected +% width (|#3|) and total height (|#4|). +% +% We perform the extraction by an embedded \hologo{TeX} call. The system +% command that gets executed is stored in |\mmz@tex@extraction@systemcall|, +% which is set by |tex extraction command| and friends; by default, we +% execute |pdftex|. +% +\def\mmzNewExtern#1{% + % The \hologo{TeX} executable expects the basename as the argument, so we + % strip away the |.pdf| suffix. + \mmz@new@extern@i#1\mmz@temp +} +\def\mmz@new@extern@i#1.pdf\mmz@temp#2#3#4{% + \begingroup + % Define the macros used in |\mmz@tex@extraction@systemcall|. + \def\externbasepath{#1}% + \def\pagenumber{#2}% + \def\expectedwidth{#3}% + \def\expectedheight{#4}% + % Empty out the extraction log. + \mmz@clear@extraction@log + % Extract. + \pdf@system{\mmz@tex@extraction@systemcall}% + % Was the extraction successful? We temporarily redefine the extraction + % error message macro (suited for the external extraction scripts, which + % extract all externs in one go) to report the exact problematic extern page. + \let\mmz@extraction@error\mmz@pageextraction@error + \mmz@check@extraction@log{tex}% + \endgroup +} +% \end{macro} +\def\mmz@pageextraction@error{% + \PackageError{memoize}{Extraction of extern page \pagenumber\space from + document "\mmzUnquote\jobname.pdf" using method "\extractionmethod" was unsuccessful. + Have you set the shell escape mode as suggested in chapter 1 of the + manual?}{If "\mmzvalueof{tex extraction command}" was executed, + shell escape mode is not the problem, and inspecting "\externbasepath.log" + might give you a clue what's wrong}} +% +% \begin{key}{tex extraction command, tex extraction options, tex extraction script} +% Using these keys, we set the system call +% which will be invoked for each extern page. The value of this key is +% expanded when executing the system command. The user may deploy the +% following macros in the value of these keys: +% \begin{itemize} +% \item |\externbasepath|: the extern PDF that should be produced, minus the +% |.pdf| suffix; +% \item |\pagenumber|: the page number to be extracted; +% \item |\expectedwidth|: the expected width of the extracted page; +% \item |\expectedheight|: the expected total height of the extracted page; +% \end{itemize} +\def\mmz@tex@extraction@systemcall{% + \mmzvalueof{tex extraction command}\space + \mmzvalueof{tex extraction options}\space + "\mmzvalueof{tex extraction script}"% +} +% \end{key} +% +% \paragraph{The default} system call for \hologo{TeX}-based extern extraction. +% As this method, despite being \hologo{TeX}-based, shares no code with the +% document, we're free to implement it with any engine and format we want. For +% reasons of speed, we clearly go for the plain \hologo{pdfTeX}.\footnote{I +% implemented the first version of \hologo{TeX}-based extraction using +% \hologo{LaTeX} and package \texttt{graphicx}, and it was (running with +% \hologo{pdfTeX} engine) almost four times slower than the current plain +% \hologo{TeX} implementation.} We perform the extraction by a little +% \hologo{TeX} script, |memoize-extract-one|, inputted at the end of the value +% given to |tex extraction script|. +\mmzset{ + tex extraction command/.initial=pdftex, + tex extraction options/.initial={% +% \begin{listingregion}{tex-extraction-options.tex} + -halt-on-error + -interaction=batchmode + -jobname "\externbasepath" + \ifdefempty\mmzOutputDirectory{}{-output-directory "\mmzOutputDirectory"} +% \end{listingregion} + }, + tex extraction script/.initial={% +% \begin{listingregion}{tex-extraction-script.tex} ^^A todo: context + \def\noexpand\fromdocument{"\mmzOutputDirectory"\jobname.pdf}% + \def\noexpand\pagenumber{\pagenumber}% + \def\noexpand\expectedwidth{\expectedwidth}% + \def\noexpand\expectedheight{\expectedheight}% + \def\noexpand\logfile{\jobname.mmz.log}% + \unexpanded{% + \def\warningtemplate{% + %\noexpand\PackageWarning{memoize}{\warningtext}% + %\warning{memoize: \warningtext}% + %\warning{memoize: \warningtext}% + }}% + \ifdef\XeTeXversion{}{% + \def\noexpand\mmzpdfmajorversion{\the\pdfmajorversion}% + \def\noexpand\mmzpdfminorversion{\the\pdfminorversion}% + }% + \noexpand\input memoize-extract-one +% \end{listingregion} + }, +} +% +% +% \subsubsection{\texttt{memoize-extract-one.tex}} +% +% The rest of the code of this section resides in file +% |memoize-extract-one.tex|. It is used to extract a single extern page from +% the document; it also checks whether the extern page dimensions are as +% expected, and passes a warning to the main job if that is not the case. For +% the reason of speed, the extraction script is in \hologo{plainTeX} format. +% For the same reason, it is compiled by \hologo{pdfTeX} engine by default, but +% we nevertheless take care that it will work with other (supported) engines as +% well. +% +%<*extract-one> +\catcode`\@11\relax +\def\@firstoftwo#1#2{#1} +\def\@secondoftwo#1#2{#2} +% +% Set the PDF version (maybe) passed to the script via |\mmzpdfmajorversion| +% and |\mmzpdfminorversion|. +\ifdefined\XeTeXversion +\else + \ifdefined\luatexversion + \def\pdfmajorversion{\pdfvariable majorversion}% + \def\pdfminorversion{\pdfvariable minorversion}% + \fi + \ifdefined\mmzpdfmajorversion + \pdfmajorversion\mmzpdfmajorversion\relax + \fi + \ifdefined\mmzpdfminorversion + \pdfminorversion\mmzpdfminorversion\relax + \fi +\fi +% Allocate a new output stream, always --- |\newwrite| is |\outer| and thus +% cannot appear in a conditional. +\newwrite\extractionlog +% Are we requested to produce a log file? +\ifdefined\logfile + \immediate\openout\extractionlog{\logfile}% + % Define a macro which both outputs the warning message and writes it to the + % extraction log. + \def\doublewarning#1{% + \message{#1}% + \def\warningtext{#1}% + % This script will be called from different formats, so it is up to the + % main job to tell us, by defining macro |\warningtemplate|, how to throw a + % warning in the log file. + \immediate\write\extractionlog{% + \ifdefined\warningtemplate\warningtemplate\else\warningtext\fi + }% + }% +\else + \let\doublewarning\message +\fi +\newif\ifforce +\ifdefined\force + \csname force\force\endcsname +\fi +% \begin{macro}{\mmz@if@roughly@equal} +% This macro checks whether the given dimensions (|#2| and |#3|) are equal +% within the tolerance given by |#1|. We use the macro both in the +% extraction script and in the main package. (We don't use |\ifpdfabsdim|, +% because it is unavailable in \hologo{XeTeX}.) +% +%<*mmz,extract-one> +\def\mmz@tolerance{0.01pt} +\def\mmz@if@roughly@equal#1#2#3{% + \dimen0=\dimexpr#2-#3\relax + \ifdim\dimen0<0pt + \dimen0=-\dimen0\relax + \fi + \ifdim\dimen0>#1\relax + \expandafter\@secondoftwo + \else + % The exact tolerated difference is, well, tolerated. This is a must to + % support |tolerance=0pt|. + \expandafter\@firstoftwo + \fi +}% +% +%<*extract-one> +% Grab the extern page from the document and put it in a box. +\ifdefined\XeTeXversion + \setbox0=\hbox{\XeTeXpdffile \fromdocument\space page \pagenumber media}% +\else + \ifdefined\luatexversion + \saveimageresource page \pagenumber mediabox {\fromdocument}% + \setbox0=\hbox{\useimageresource\lastsavedimageresourceindex}% + \else + \pdfximage page \pagenumber mediabox {\fromdocument}% + \setbox0=\hbox{\pdfrefximage\pdflastximage}% + \fi +\fi +% Check whether the extern page is of the expected size. +\newif\ifbaddimensions +\ifdefined\expectedwidth + \ifdefined\expectedheight + \mmz@if@roughly@equal{\mmz@tolerance}{\wd0}{\expectedwidth}{% + \mmz@if@roughly@equal{\mmz@tolerance}{\ht0}{\expectedheight}% + {}% + {\baddimensionstrue}% + }{\baddimensionstrue}% + \fi +\fi +% We'll setup the page geometry of the extern file and shipout the extern --- +% if all is well, or we're forced to do it. +\ifdefined\luatexversion + \let\pdfpagewidth\pagewidth + \let\pdfpageheight\pageheight + \def\pdfhorigin{\pdfvariable horigin}% + \def\pdfvorigin{\pdfvariable vorigin}% +\fi +\def\do@shipout{% + \pdfpagewidth=\wd0 + \pdfpageheight=\ht0 + \ifdefined\XeTeXversion + \hoffset -1 true in + \voffset -1 true in + \else + \pdfhorigin=0pt + \pdfvorigin=0pt + \fi + \shipout\box0 +} +\ifbaddimensions + \doublewarning{I refuse to extract page \pagenumber\space from + "\fromdocument", because its size (\the\wd0 \space x \the\ht0) is not + what I expected (\expectedwidth\space x \expectedheight)}% + \ifforce\do@shipout\fi +\else + \do@shipout +\fi +% If logging is in effect and the extern dimensions were not what we expected, +% write a warning into the log. +\ifdefined\logfile + \immediate\write\extractionlog{\noexpand\endinput}% + \immediate\closeout\extractionlog +\fi +\bye +% +% \end{macro} +% +% \section{Automemoization} +% \label{sec:code:automemoization} +% +% \paragraph{Install} the advising framework implemented by our auxiliary +% package Advice, which automemoization depends on. This will define keys +% |auto|, |activate| etc.\ in our keypath. +%<*mmz> +\mmzset{ + .install advice={setup key=auto, activation=deferred}, + % We switch to the immediate activation at the end of the preamble. + begindocument/before/.append style={activation=immediate}, +} +% +% \begin{key}{manual} +% Unless the user switched on |manual|, we perform the deferred +% (de)activations at the beginning of the document (and then clear the style, +% so that any further deferred activations will start with a clean slate). +% In \hologo{LaTeX}, we will use the latest possible hook, +% |begindocument/end|, as we want to hack into commands defined by other +% packages. (The \hologo{TeX} conditional needs to be defined before using +% it in |.append code| below. +\newif\ifmmz@manual +\mmzset{ + manual/.is if=mmz@manual, + begindocument/end/.append code={% + \ifmmz@manual + \else + \pgfkeysalso{activate deferred,activate deferred/.code={}}% + \fi + }, +% \end{key} +% +% \paragraph{Announce} Memoize's run conditions and handlers. + auto/.cd, + run if memoization is possible/.style={ + run conditions=\mmz@auto@rc@if@memoization@possible + }, + run if memoizing/.style={run conditions=\mmz@auto@rc@if@memoizing}, + apply options/.style={ + bailout handler=\mmz@auto@bailout, + outer handler=\mmz@auto@outer, + }, + memoize/.style={ + run if memoization is possible, + apply options, + inner handler=\mmz@auto@memoize + }, + %<*latex> + noop/.style={run if memoization is possible, noop \AdviceType}, + noop command/.style={apply options, inner handler=\mmz@auto@noop}, + noop environment/.style={ + outer handler=\mmz@auto@noop@env, bailout handler=\mmz@auto@bailout}, + % + %noop/.style={inner handler=\mmz@auto@noop}, + nomemoize/.style={noop, options=disable}, + replicate/.style={run if memoizing, inner handler=\mmz@auto@replicate}, +} +% +% \paragraph{Abortion} +% We cheat and let the |run conditions| do the work --- it is cheaper to just +% always abort than to invoke the outer handler. (As we don't set +% |\AdviceRuntrue|, the run conditions will never be satisfied.) +% \begin{listingregion}{_auto-abort.tex} +\mmzset{ + auto/abort/.style={run conditions=\mmzAbort}, +} +% \end{listingregion} +% And the same for |unmemoizable|: +\mmzset{ + auto/unmemoizable/.style={run conditions=\mmzUnmemoizable}, +} +% For one, we abort upon |\pdfsavepos| (called |\savepos| in \hologo{LuaTeX}). +% Second, unless in \hologo{LuaTeX}, we submit |\errmessage|, which allows us +% to detect at least some errors --- in \hologo{LuaTeX}, we have a more +% bullet-proof system of detecting errors, see |\mmz@memoize| in +% \S\ref{sec:code:memoization-process}. +\ifdef\luatexversion{% + \mmzset{auto=\savepos{abort}} +}{% + \mmzset{ + auto=\pdfsavepos{abort}, + auto=\errmessage{abort}, + } +} +% +% \begin{mmzautokey}{run if memoization is possible} +% \begin{macro}{\mmz@auto@rc@if@memoization@possible} +% These run conditions are used by |memoize| and |noop|: Memoize should be +% enabled, but we should not be already within Memoize, i.e.\ memoizing or +% normally compiling some code submitted to memoization. +% \begin{listingregion}{_auto-run-if-memoization-is-possible.tex} +\def\mmz@auto@rc@if@memoization@possible{% + \ifmemoize + \ifinmemoize + \else + \AdviceRuntrue + \fi + \fi +} +% \end{listingregion} +% \end{macro} +% \end{mmzautokey} +% +% \begin{mmzautokey}{run if memoizing} +% \begin{macro}{\mmz@auto@rc@if@memoizing} +% These run conditions are used by |\label| and |\ref|: they should +% be handled only during memoization (which implies that Memoize is enabled). +\def\mmz@auto@rc@if@memoizing{% + \ifmemoizing\AdviceRuntrue\fi +} +% \end{macro} +% \end{mmzautokey} +% +% \begin{macro}{\mmznext} +% The next-options, set by this macro, will be applied to the next, and only +% next instance of automemoization. We set the next-options globally, so +% that only the linear order of the invocation matters. Note that |\mmznext|, +% being a user command, must also be defined in package |nomemoize|. +% +%\def\mmznext#1{\ignorespaces} +%<*mmz> +\def\mmznext#1{\gdef\mmz@next{#1}\ignorespaces} +\mmznext{}% +% \end{macro} +% +% \begin{mmzautokey}{apply options} +% \begin{macro}{\mmz@auto@outer,\mmz@auto@bailout} +% The outer and the bailout handler defined here work as a team. The outer +% handler's job is to apply the auto- and the next-options; therefore, the +% bailout handler must consume the next-options as well. To keep the +% option application local, the outer handler opens a group, which is +% expected to be closed by the inner handler. This key is used by +% |memoize| and |noop command|. +% \begin{listingregion}{_auto-memoize-outer.tex} +\def\mmz@auto@outer{% + \begingroup + \mmzAutoInit + \AdviceCollector +} +% \end{listingregion} +% \begin{listingregion}{_auto-memoize-bailout.tex} +\def\mmz@auto@bailout{% + \mmznext{}% +} +% \end{listingregion} +% \bigskip +% \end{macro} +% \end{mmzautokey} +% +% \begin{macro}{\mmzAutoInit} +% Apply first the auto-options, and then the next-options (and clear the +% latter). Finally, if we have any extra collector options (set by the +% |verbatim| keys), append them to Advice's (raw) collector options. +\def\mmzAutoInit{% + \ifdefempty\AdviceOptions{}{\expandafter\mmzset\expandafter{\AdviceOptions}}% + \ifdefempty\mmz@next{}{\expandafter\mmzset\expandafter{\mmz@next}\mmznext{}}% + \eappto\AdviceRawCollectorOptions{\expandonce\mmzRawCollectorOptions}% +} +% \end{macro} +% +% \begin{mmzautokey}{memoize} +% \begin{macro}{\mmz@auto@memoize} +% This key installs the inner handler for memoization. If you compare this +% handler to the definition of |\mmz| in +% section~\ref{sec:code:memoization:manual}, you will see that the only +% thing left to do here is to start memoization with |\Memoize|, everything +% else is already done by the advising framework, as customized by Memoize. +% +% The first argument to |\Memoize| is the memoization key (which the code +% md5sum is computed off of); it consists of the handled code (the contents +% of |\AdviceReplaced|) and its arguments, which were collected into |##1|. +% The second argument is the code which the memoization driver will +% execute. |\AdviceOriginal|, if invoked right away, would execute the +% original command; but as this macro is only guaranteed to refer to this +% command within the advice handlers, we expand it before calling |\Memoize|. +% that command. +% +% Note that we don't have to define different handlers for commands and +% environments, and for different \hologo{TeX} formats. When memoizing +% command |\foo|, |\AdviceReplaced| contains |\foo|. When memoizing +% environment |foo|, |\AdviceReplaced| contains |\begin{foo}|, |\foo| or +% |\startfoo|, depending on the format, while the closing tag +% (|\end{foo}|, |\endfoo| or |\stopfoo|) occurs at the end of the +% collected arguments, because |apply options| appended +% |\collargsEndTagtrue| to |raw collector options|. +% +% This macro has no formal parameters, because the collected arguments will +% be grabbed by |\mmz@marshal|, which we have to go through because +% executing |\Memoize| closes the memoization group and we lose the current +% value of |\ifmmz@ignorespaces|. (We also can't use |\aftergroup|, +% because closing the group is not the final thing |\Memoize| does.) +% \begin{listingregion}{_auto-memoize-inner.tex} +\long\def\mmz@auto@memoize#1{% + \expanded{% + \noexpand\Memoize + {\expandonce\AdviceReplaced\unexpanded{#1}}% + {\expandonce\AdviceOriginal\unexpanded{#1}}% + \ifmmz@ignorespaces\ignorespaces\fi + }% +} +% \end{listingregion} +% \end{macro} +% \end{mmzautokey} +% +% \begin{mmzautokey}{noop} +% \begin{macro}{\mmz@auto@noop,\mmz@auto@noop@env} +% The no-operation handler can be used to apply certain options for the +% span of the execution of the handled command or environment. This is +% exploited by |auto/nomemoize|, which sets |disable| as an auto-option. +% +% The handler for commands and non-\hologo{LaTeX} environments is +% implemented as an inner handler. On its own, it does nothing except +% honor |verbatim| and |ignore spaces| (only takes care of |verbatim| and +% |ignore spaces| (in the same way as the memoization handler above), but +% it is intended to be used alongside the default outer handler, which +% applies the auto- and the next-options. As that handler opens a group +% (and this handler closes it), we have effectively delimited the effect of +% those options to this invocation of the handled command or environment. +\long\def\mmz@auto@noop#1{% + \expandafter\mmz@maybe@scantokens\expandafter{\AdviceOriginal#1}% + \expandafter\endgroup + \ifmmz@ignorespaces\ignorespaces\fi +} +% In \hologo{LaTeX}, and only there, commands and environments need separate +% treatment. As \hologo{LaTeX} environments introduce a group of their own, we +% can simply hook our initialization into the beginning of the environment (as +% a one-time hook). Consequently, we don't need to collect the environment +% body, so this can be an outer handler. +%<*latex> +\def\mmz@auto@noop@env{% + \AddToHookNext{env/\AdviceName/begin}{% + \mmzAutoInit + \ifmmz@ignorespaces\ignorespacesafterend\fi + }% + \AdviceOriginal +} +% +% \end{macro} +% \end{mmzautokey} +% +% \begin{mmzautokey}{replicate} +% \begin{macro}{\mmz@auto@replicate} +% This inner handler writes a copy of the handled command or environment's +% invocation into the cc-memo (and then executes it). As it is used +% alongside |run if memoizing|, the replicated command in the cc-memo will +% always execute the original command. The system works even if +% replication is off when the cc-memo is input; in that case, the control +% sequence in the cc-memo directly executes the original command. +% +% This handler takes an option, |expanded| --- if given, the collected +% arguments will be expanded (under protection) before being written into +% the cc-memo. +\def\mmz@auto@replicate#1{% + \begingroup + \let\mmz@auto@replicate@expansion\unexpanded + \expandafter\pgfqkeys\expanded{{/mmz/auto/replicate}{\AdviceOptions}}% + %\let\protect\noexpand + \expanded{% + \endgroup + \noexpand\gtoksapp\noexpand\mmzCCMemo{% + \expandonce\AdviceReplaced\mmz@auto@replicate@expansion{#1}}% + \expandonce\AdviceOriginal\unexpanded{#1}% + }% +} +\pgfqkeys{/mmz/auto/replicate}{ + expanded/.code={\let\mmz@auto@replicate@expansion\@firstofone}, +} +% \end{macro} +% \end{mmzautokey} +% +% \subsection{\hologo{LaTeX}-specific handlers} +% +% We handle cross-referencing (both the |\label| and the |\ref| side) and +% indexing. Note that the latter is a straightforward instance of replication. +% +%<*latex> +% \begin{listingregion}{_auto-memoize-ref.tex} +\mmzset{ + auto/.cd, + ref/.style={outer handler=\mmz@auto@ref\mmzNoRef, run if memoizing}, + force ref/.style={outer handler=\mmz@auto@ref\mmzForceNoRef, run if memoizing}, +} +% \end{listingregion} +\mmzset{ + auto=\ref{ref}, + auto=\pageref{ref}, + auto=\label{run if memoizing, outer handler=\mmz@auto@label}, + auto=\index{replicate, args=m, expanded}, +} +% +% \begin{mmzautokey}{ref, force ref} +% \begin{macro}{\mmz@auto@ref} +% These keys install an outer handler which appends a cross-reference to the +% context. |force ref| does this even if the reference key is undefined, +% while |ref| aborts memoization in such a case --- the idea is that it makes +% no sense to memoize when we expect the context to change in the next +% compilation anyway. +% +% Any command taking a mandatory braced reference key argument potentially +% preceded by optional arguments of (almost) any kind may be submitted to +% these keys. This follows from the parameter list of |\mmz@auto@ref@i|, +% where |#2| grabs everything up to the first opening brace. The downside of +% the flexibility regarding the optional arguments is that unbraced +% single-token reference keys will cause an error, but as such usages of +% |\ref| and friends should be virtually inexistent, we let the bug stay. +% +% |#1| should be either |\mmzNoRef| or |\mmzForceNoRef|. |#2| will receive +% any optional arguments of |\ref| (or |\pageref|, or whatever), and |#3| in +% |\mmz@auto@ref@i| is the cross-reference key. +% \begin{listingregion}{_auto-memoize-ref.tex} +\def\mmz@auto@ref#1#2#{\mmz@auto@ref@i#1{#2}} +\def\mmz@auto@ref@i#1#2#3{% + #1{#3}% + \AdviceOriginal#2{#3}% +} +% \end{listingregion} +% \end{macro} +% \end{mmzautokey} +% +% \begin{macro}{\mmzForceNoRef,\mmzNoRef} +% These macros do the real job in the outer handlers for cross-referencing, +% but it might be useful to have them publicly available. |\mmzForceNoRef| +% appends the reference key to the context. |\mmzNoRef| only does that if +% the reference is defined, otherwise it aborts the memoization. +\def\mmzForceNoRef#1{% + \ifmemoizing + \expandafter\gtoksapp\expandafter\mmzContextExtra + \else + \expandafter\toksapp\expandafter\mmzContext + \fi + {r@#1={\csname r@#1\endcsname}}% + \ignorespaces +} +\def\mmzNoRef#1{% + \ifcsundef{r@#1}{\mmzAbort}{\mmzForceNoRef{#1}}% + \ignorespaces +} +% \end{macro} +% +% \begin{mmzautokey}{refrange, force refrange} +% \begin{macro}{\mmz@auto@refrange} +% Let's rinse and repeat for reference ranges. The code is virtually the +% same as above, but we grab two reference key arguments (|#3| and |#4|) in +% the final macro.\indentmacrocode +\mmzset{ + auto/.cd, + refrange/.style={outer handler=\mmz@auto@refrange\mmzNoRef, + bailout handler=\relax, run if memoizing}, + force refrange/.style={outer handler=\mmz@auto@refrange\mmzForceNoRef, + bailout handler=\relax, run if memoizing}, +} +% \noindentmacrocode +\def\mmz@auto@refrange#1#2#{\mmz@auto@refrange@i#1{#2}} +\def\mmz@auto@refrange@i#1#2#3#4{% + #1{#3}% + #1{#4}% + \AdviceOriginal#2{#3}{#4}% +} +% \end{macro} +% \end{mmzautokey} +% +% \begin{mmzautokey}{multiref, force multiref} +% \begin{macro}{\mmz@auto@multiref} +% And one final time, for ``multi-references'', such as |cleveref|'s +% |\cref|, which can take a comma-separated list of reference keys in the +% sole argument. Again, only the final macro is any different, this time +% distributing |#1| (|\mmzNoRef| or |\mmzForceNoRef|) over |#3| by +% |\forcsvlist|. +\mmzset{ + auto/.cd, + multiref/.style={outer handler=\mmz@auto@multiref\mmzNoRef, + bailout handler=\relax, run if memoizing}, + force multiref/.style={outer handler=\mmz@auto@multiref\mmzForceNoRef, + bailout handler=\relax, run if memoizing}, +} +\def\mmz@auto@multiref#1#2#{\mmz@auto@multiref@i#1{#2}} +\def\mmz@auto@multiref@i#1#2#3{% + \forcsvlist{#1}{#3}% + \AdviceOriginal#2{#3}% +} +% \end{macro} +% \end{mmzautokey} +% +% \begin{macro}{\mmz@auto@label} +% The outer handler for \cs{label} must be defined specifically for this +% command. The generic replicating handler is not enough here, as we need to +% replicate both the invocation of |\label| and the definition of +% |\@currentlabel|. +\def\mmz@auto@label#1{% + \xtoksapp\mmzCCMemo{% + \noexpand\mmzLabel{#1}{\expandonce\@currentlabel}% + }% + \AdviceOriginal{#1}% +} +% \end{macro} +% +% \begin{macro}{\mmzLabel} +% This is the macro that |\label|'s handler writes into the cc-memo. The +% first argument is the reference key; the second argument is the value of +% |\@currentlabel| at the time of invocation |\label| during memoization, +% which this macro temporarily restores. +\def\mmzLabel#1#2{% + \begingroup + \def\@currentlabel{#2}% + \label{#1}% + \endgroup +} +% +% +% +% \end{macro} +% +% \section{Support for various classes and packages} +% +% \subsection{\TikZ;} +% \label{sec:code:mmz:tikz} +% +% In this section, we activate \TikZ; support (the collector is defined by +% Advice). All the action happens at the end of the preamble, so that we can +% detect whether \TikZ; was loaded (regardless of whether Memoize was loaded +% before \TikZ;, or vice versa), but still input the definitions. +%<*mmz> +\mmzset{ + begindocument/before/.append code={% + %\@ifpackageloaded{tikz}{% + %\ifdefined\tikz + \input advice-tikz.code.tex + %}{}% + %\fi + % We define and activate the automemoization handlers for the \TikZ; command + % and environment. + \mmzset{% + % \begin{listingregion}{_auto-tikz-collector.tex} + auto=\tikz{memoize, collector=\AdviceCollectTikZArguments}, + % \end{listingregion} + %/utils/exec={\tracingall}, + auto={tikzpicture}{memoize}, + % A hack to prevent memoizing pictures which are accidentally marked as + % remembered --- accidentally in the sense that because the document + % changed, the |.aux| file contains a |\pgfsyspdfmark| command which + % erroneously refers to the picture being memoized. We know that + % memoizing a remembered picture can't be right, as we always abort on + % |\pdfsavepos|. This is implemented by hacking into PGF's + % |\pgfsys@getposition|, and aborting memoization if the mark does not + % equal |\relax|. (We have to duplicate |#| because of |.append code|.) + auto=\pgfsys@getposition{ + run if memoizing, outer handler=\mmz@pgfsys@getposition}, + }% + \def\mmz@pgfsys@getposition##1{% + \expandafter\ifx\csname pgf@sys@pdf@mark@pos@##1\endcsname\relax + \else + \mmzAbort + \fi + \AdviceOriginal{##1}% + }% + }, +} +% +% +% +% \subsection{Forest} +% \label{sec:code:forest} +% +% Forest will soon feature extensive memoization support, but for now, let's +% just enable the basic, single extern externalization. +%<*mmz> +%<*latex> +\mmzset{ + begindocument/before/.append code={% + \@ifpackageloaded{forest}{% + \mmzset{ + auto={forest}{memoize}, +% Yes, |\Forest| is defined using |xparse|. + auto=\Forest{memoize}, + }% + }{}% + }, +} +% +% +% \subsection{Beamer} +% \label{sec:code:beamer} +% +% The Beamer code is explained in \MS\ref{sec:per-overlay}. +% +%<*latex> +\AddToHook{begindocument/before}{\@ifclassloaded{beamer}{% + % \begin{listingregion}{per-overlay.tex} + \mmzset{per overlay/.style={ + /mmz/context={% + overlay=\csname beamer@overlaynumber\endcsname, + pauses=\ifmemoizing + \mmzBeamerPauses + \else + \expandafter\the\csname c@beamerpauses\endcsname + \fi + }, + /mmz/at begin memoization={% + \xdef\mmzBeamerPauses{\the\c@beamerpauses}% + \xtoksapp\mmzCMemo{% + \noexpand\mmzSetBeamerOverlays{\mmzBeamerPauses}{\beamer@overlaynumber}}% + \gtoksapp\mmzCCMemo{% + \only<\mmzBeamerOverlays>{}}% + }, + /mmz/at end memoization={% + \xtoksapp\mmzCCMemo{% + \noexpand\setcounter{beamerpauses}{\the\c@beamerpauses}}% + }, + /mmz/per overlay/.code={}, + }} + \def\mmzSetBeamerOverlays#1#2{% + \ifnum\c@beamerpauses=#1\relax + \gdef\mmzBeamerOverlays{#2}% + \ifnum\beamer@overlaynumber<#2\relax \mmz@temptrue \else \mmz@tempfalse \fi + \else + \mmz@temptrue + \fi + \ifmmz@temp + \appto\mmzAtBeginMemoization{% + \gtoksapp\mmzCMemo{\mmzSetBeamerOverlays{#1}{#2}}}% + \fi + }% + % \end{listingregion} +}{}} +% +% +% +% \section{Initialization} +% \label{sec:code:initialization} +% +% \begin{key}{begindocument/before, begindocument, begindocument/end, +% enddocument/afterlastpage} +% These styles contain the initialization +% and the finalization code. They were populated throughout the source. +% Hook |begindocument/before| contains the package support code, which must +% be loaded while still in the preamble. Hook |begindocument| contains the +% initialization code whose execution doesn't require any particular timing, +% as long as it happens at the beginning of the document. Hook +% |begindocument/end| is where the commands are activated; this must +% crucially happen as late as possible, so that we successfully override +% foreign commands (like |hyperref|'s definitions). In \hologo{LaTeX}, we +% can automatically execute these hooks at appropriate places: +%<*latex> +\AddToHook{begindocument/before}{\mmzset{begindocument/before}} +\AddToHook{begindocument}{\mmzset{begindocument}} +\AddToHook{begindocument/end}{\mmzset{begindocument/end}} +\AddToHook{enddocument/afterlastpage}{\mmzset{enddocument/afterlastpage}} +% +% In \hologo{plainTeX}, the user must execute these hooks manually; but at +% least we can group them together and given them nice names. Provisionally, +% manual execution is required in \hologo{ConTeXt} as well, as I'm not sure +% where to execute them --- please help! +%<*plain,context> +\mmzset{ + begin document/.style={begindocument/before, begindocument, begindocument/end}, + end document/.style={enddocument/afterlastpage}, +} +% +% \end{key} +% +% \paragraph{\texttt{memoize.cfg}} Load the configuration file. Note that +% |nomemoize| must input this file as well, because any special +% memoization-related macros defined by the user should be available; for +% example, my |memoize.cfg| defines |\ifregion| (see +% \MS\ref{sec:tut:multifile}). +% +%\InputIfFileExists{memoize.cfg}{}{} +%<*mmz> +% +% Formats other than \hologo{plainTeX} need a way to prevent extraction during +% package-loading. +\mmzset{ + %extract/no/.code={}, +% \begin{key}{output directory} +% \begin{macro}{mmzOutputDirectory} +% Set the |-output-directory| --- manually, as there is no other way. +% \indentmacrocode + output-directory/.store in=\mmzOutputDirectory, +} +% \end{macro} +% \end{key} +% +% \paragraph{Process} the package options (except in \hologo{plainTeX}). +%\ProcessPgfPackageOptions{/mmz} +%\expandafter\mmzset\expandafter{\currentmoduleparameters} +% +% Define |\mmzOutputDirectory| if |output-directory| was not given. +\ifdefined\mmzOutputDirectory +\else + \def\mmzOutputDirectory{}% +\fi +\mmzset{output directory/.code={\PackageError{memoize}{Key "output-directory" + may only be used as a package option}{}}} +\mmzset{ + % \paragraph{Extract} the externs using the method given by |memoize.cfg| or + % the package options --- unless we're running \hologo{plainTeX}. + %<*!plain> + extract/\mmz@extraction@method, + % In non-\hologo{plainTeX} formats, also disable |extract| in the preamble. + extract/.code={\PackageError{memoize}{Key "extract" is only allowed as a + package option.}{If you really want to extract in the preamble, execute + "extract/".}}, + % + %<*plain> + % In \hologo{plainTeX}, where extraction must be invoked after + % loading the package, we now have to redefine |extract|, so that it will + % immediately trigger extraction. + extract/.is choice, + extract/.default=\mmz@extraction@method, + % But only once: + extract/.append style={ + extract/.code={\PackageError{memoize}{Key "extract" is only allowed to + be used once.}{If you really want to extract again, execute + "extract/".}}, + }, + % +} +% +% Memoize was not really born for the draft mode, as it cannot produce new +% externs there. But we don't want to disable the package, as utilization is +% still perfectly valid in this mode, so let's just warn the user. +\ifnum\pdf@draftmode=1 + \PackageWarning{memoize}{No memoization will be performed in the draft mode}% +\fi +% +% +% \paragraph{The end} of |memoize|, |nomemoize| and |memoizable|. +%<*mmz,nommz,mmzable> +%\resetatcatcode +%\stopmodule +%\protect +% +% That's all, folks! +% +% \end{macrocode} +% +% \endinput +% +% Local Variables: +% TeX-engine: luatex +% TeX-master: "doc/memoize-code.tex" +% TeX-auto-save: nil +% End: \ No newline at end of file diff --git a/memoize.ins b/memoize.ins new file mode 100644 index 0000000..f288e8e --- /dev/null +++ b/memoize.ins @@ -0,0 +1,39 @@ +%% memoize.ins +%% +%% This file is a part of Memoize, a TeX package for externalization of +%% graphics and memoization of compilation results in general, available at +%% https://ctan.org/pkg/memoize and https://github.com/sasozivanovic/memoize. +%% +%% Copyright (c) 2020- Saso Zivanovic +%% (Sa\v{s}o \v{Z}ivanovi\'{c}) +%% +%% This work may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License, either version 1.3c of this license or (at +%% your option) any later version. The latest version of this license is in +%% https://www.latex-project.org/lppl.txt and version 1.3c or later is part of +%% all distributions of LaTeX version 2008 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Saso Zivanovic. +%% +%% The files belonging to this work and covered by LPPL are listed in +%% (/doc/generic/memoize/)FILES. +%% +\input docstrip.tex +\keepsilent +\preamble +\endpreamble +\askforoverwritefalse +\generate{% + \file{memoize.sty}{\from{memoize.dtx}{mmz,latex}}% + \file{memoize.tex}{\from{memoize.dtx}{mmz,plain}}% + \file{t-memoize.tex}{\from{memoize.dtx}{mmz,context}}% + \file{nomemoize.sty}{\from{memoize.dtx}{nommz,latex}}% + \file{nomemoize.tex}{\from{memoize.dtx}{nommz,plain}}% + \file{t-nomemoize.tex}{\from{memoize.dtx}{nommz,context}}% + \file{memoizable.sty}{\from{memoize.dtx}{mmzable,latex}}% + \file{memoizable.tex}{\from{memoize.dtx}{mmzable,plain}}% + \file{t-memoizable.tex}{\from{memoize.dtx}{mmzable,context}}% + \file{memoize-extract-one.tex}{\from{memoize.dtx}{extract-one}}% +} +\endbatchfile diff --git a/memoize.sty b/memoize.sty deleted file mode 100644 index 27b5d20..0000000 --- a/memoize.sty +++ /dev/null @@ -1,923 +0,0 @@ -% memoize.sty -% -% Memoize is a LaTeX package for externalization of graphics and memoization of -% compilation results in general. -% -% Copyright (c) 2020 Saso Zivanovic -% (Sa\v{s}o \v{Z}ivanovi\'{c}) -% -% This work may be distributed and/or modified under the conditions of the -% LaTeX Project Public License, either version 1.3 of this license or (at your -% option) any later version. The latest version of this license is in -% -% http://www.latex-project.org/lppl.txt -% -% and version 1.3 or later is part of all distributions of LaTeX -% version 2005/12/01 or later. -% -% This work is not yet published at CTAN. -% -% This work consists of the following files: -% - memoize.sty -% - memomanager.py -% - nomemoize.sty -% - memoize-tikz.tex -% - README.md -% and -% - xparse-arglist.sty -% -\ProvidesPackage{memoize}[2020/07/17 Memoization, including externalization] - -\RequirePackage{pgfopts} % pgfkeys-based package options -% \RequirePackage{pgfkeys} % for UI, loaded by pgfopts -\RequirePackage{etoolbox} % generally useful -\RequirePackage{graphicx} % for including externalized graphics -\RequirePackage{environ} % for automemoization of environments: -\RequirePackage{pdftexcmds} % unified access to pdf primitives across engines, - % notably to md5sum in luatex - -% The def is here, because we will redefine this for xetex. -\def\mmz@if@roughly@equal#1#2{% - \ifpdfabsdim\dimexpr#1-#2\relax<\mmz@tolerance\relax - \expandafter\@firstoftwo - \else - \expandafter\@secondoftwo - \fi -} - -% Some engine-specific stuff we have to define despite pdftexcmds. -\ifdef\pdftexversion{% - \def\mmz@latex@binary{pdflatex}% -}{% - % Only pdftex seems to have these: - \def\pdfhorigin{1true in}% - \def\pdfvorigin{1true in}% - \ifdef\XeTeXversion{% - \def\mmz@latex@binary{xelatex}% - % pdftex and luatex profide \quitvmode (replacement for \leavevmode, see pdftex - % manual 8.21), but xetex doesn't. - \let\quitvmode\leavevmode - % xetex does not have \if(pdf)absdim - \def\mmz@if@roughly@equal#1#2{% - \begingroup - \@tempdima=\dimexpr#1-#2\relax - \ifdim\@tempdima<0pt \@tempdima=-\@tempdima\relax\fi - \expandafter\expandafter\expandafter\endgroup - \ifdim\@tempdima<\mmz@tolerance\relax - \expandafter\@firstoftwo - \else - \expandafter\@secondoftwo - \fi - } - }{% - \ifdef\luatexversion{% - % Is there a way to shipout a memoized page to a new pdf, thereby - % avoiding the separate splitting stage? - \def\mmz@latex@binary{lualatex}% - \let\ifpdfabsdim\ifabsdim - \let\pdfpagewidth\pagewidth - \let\pdfpageheight\pageheight - }{% - \PackageError{memoize}{Support for this TeX engine is not implemented.}{}% - }% - }% -} - - -% Registers and such -\newif\ifmemoize -\newif\ifmemoizing -\newif\ifmmz@readonly -\newif\ifmmz@temp -\newwrite\mmz@out -\newbox\mmz@box -\newcount\mmz@realpage -\newtoks\mmz@temptoks -\newif\ifmmz@loadonly -\newif\ifmmz@light -\newif\ifmmz@manual -\newif\ifmmz@shipout@only@memoized -\newif\ifmmz@cancel - -\pgfqkeys{/memoize/package options}{ - loadonly/.is if=mmz@loadonly, % disabled, no automemoization - light/.is if=mmz@light, % without xparse - manual/.is if=mmz@manual, -} -\ProcessPgfPackageOptions{/memoize/package options} - - -% Some useful stuff. -\def\mmz@valueof#1{\pgfkeysvalueof{/memoize/#1}} -\def\apptotoks#1#2{\expandafter#1\expandafter{\the#1#2}} - -% Copied from pgfutil-common.tex (and renamed), for self-containment -\newif\ifmmzutil@in@ -\def\mmzutil@in@#1#2{% - \def\mmzutil@in@@##1#1##2##3\mmzutil@in@@{% - \ifx\mmzutil@in@##2\mmzutil@in@false\else\mmzutil@in@true\fi}% - \mmzutil@in@@#2#1\mmzutil@in@\mmzutil@in@@} - -\def\mmz@split@filename#1#2#3{% - % input: #1 = filename (absolute, relative, with or without path component) - % output: #2 = path, #3 = name - \edef\pgfkeyscurrentkey{#1}% - \expandafter\mmzutil@in@\expandafter/\expandafter{\pgfkeyscurrentkey}% - \ifmmzutil@in@ - \pgfkeys@split@path - \edef#2{\pgfkeyscurrentpath/}% - \let#3\pgfkeyscurrentname - \else - \def#2{}% - % \edef here gets rid of \@empty used in \mmz@updatefilenames. - \edef#3{#1}% - \fi -} - - -%%%%%%%%%%%%%%%%%%%%% UI - -\def\memoizeset#1{\pgfqkeys{/memoize}{#1}} - -% todo: preamble vs. all-the-time options --- redefine \memoizeset to another path! -\memoizeset{% - % When the TeX job starts, \jobname contains the basename of the PDF that - % will be created. If we set \jobname (using the below key) to some other - % filename (without ".tex" suffix), we will fool LaTeX into using and - % writing the auxiliary files of the "real job". By default, the real job - % equals \jobname, i.e. we memoize "inline". - % - % Include the path, but don't add ".tex" here. - jobname/.estore in=\jobname, - % - % After each compilation, "\primitive\jobname.mmz" will contain the list of memoized - % stuff. On the next run, tex will split the memo PDFs off the big PDF we - % have generated in the first compilation. (The second step can also be - % achieved by the external tool "memoize-split.py") - % - % The keys "memo filename prefix/suffix" tell the package where to store the - % separate externalized pictures (memos). The prefix can contain the path, - % which must be relative to real job folder. - % - % For example, say "memo filename prefix={\jobname.memo.dir/}" --- DON'T - % FORGET THE SLASH AND THE BRACES --- to store memos in the - % "\jobname.memo.dir" folder --- where \jobname is the name of the real job. - % You need to create the folder by hand. - % - % Default: We store the externalized files in the same folder (filename of - % form \jobname..memo), because we don't know if we can write - % elsewhere. - memo filename prefix/.initial={\mmz@jobbasename.}, - memo filename suffix/.initial={.memo}, - % A shortcut for a .memo.dir: without an argument, defaults to the job name, - % but any base name can be given. - memo dir/.style={memo filename prefix={#1.memo.dir/}}, - memo dir/.default=\mmz@jobbasename, - % - % System call for embedded LaTeX compilations. The engine (pdftex, xetex - % etc.) is chosen automatically, but can be changed by "latex binary" key. - latex binary/.store in=\mmz@latex@binary, - latex system call/.initial={\mmz@latex@binary\space - -halt-on-error - -interaction=batchmode - \mmz@valueof{latex system call options}\space - -jobname "\detokenize\expandafter{\mmz@syscall@jobname}" - "\detokenize\expandafter{\mmz@syscall@commands}"}, - % Additional options for the LaTeX system call - latex system call options/.initial={}, - % - % enable and disable are defined later - % - % When we say "readonly" (or "readonly=true"), we will use whatever is - % already memoized, but not memoize any new stuff. - readonly/.is if=mmz@readonly, - % padding (for dealing with tikz overlays, \rlap and \llap etc.) - padding left/.store in=\mmz@padding@left, - padding right/.store in=\mmz@padding@right, - padding top/.store in=\mmz@padding@top, - padding bottom/.store in=\mmz@padding@bottom, - padding x/.style={padding left=#1, padding right=#1}, - padding y/.style={padding top=#1, padding bottom=#1}, - padding/.style={padding x=#1, padding y=#1}, - default padding/.style={padding x=\pdfhorigin, padding y=\pdfvorigin}, - default padding, - % todo: page padding --- for "remember picture" - % - if readonly/.code 2 args={ - \ifmmz@readonly\pgfkeysalso{#1}\else\pgfkeysalso{#2}\fi}, - if memoize/.code 2 args={ - \ifmemoize\pgfkeysalso{#1}\else\pgfkeysalso{#2}\fi}, - if memoizing/.code 2 args={ - \ifmemoizing\pgfkeysalso{#1}\else\pgfkeysalso{#2}\fi}, - if manual/.code 2 args={ - \ifmmz@manual\pgfkeysalso{#1}\else\pgfkeysalso{#2}\fi}, - % This might need to go, as the regular output might define some stuff needed - % in the memoized output, see https://github.com/sasozivanovic/memoize/issues/1 - shipout only memoized/.is if=mmz@shipout@only@memoized, -} - -\def\mmz@updatefilenames{% - \mmz@split@filename - \jobname - \mmz@jobpath - \mmz@jobbasename - \mmz@split@filename - % Split the "memo filename prefix" (relative to the job path) into path and - % basename. The "\noexpand\@empty" below makes sure that \pgfkeys@split@path - % will work when "memo filename prefix" specifies a directory, i.e.\ when it - % ends with "/" --- this is the case when we use "memo dir". - {\mmz@jobpath\mmz@valueof{memo filename prefix}\noexpand\@empty}% - \mmz@memo@path - \mmz@memo@basenameprefix -} - -% Manual memoization: \memoize[memoization key]{the code to be memoized}. In a -% manual invocation, the optional argument should usually be unnecessary. So, -% #1 is the memoization key (what md5sum is computed from), and #2 is the code -% to be executed for memoization. -% -% we might need to redefine \memoize from "nomemoize.sty": -\let\memoize\relax -\newcommand\memoize[2][]{% - \quitvmode - \ifmemoize - \ifstrempty{#1}{% - \edef\mmz@id{\expandafter\pdf@mdfivesum\expandafter{\detokenize{#2}}}% - }{% - \edef\mmz@id{\expandafter\pdf@mdfivesum\expandafter{\detokenize{#1}}}% - }% - \mmz@ifmemoized{% - \ifmmz@@disabled - \let\mmz@next\memoize@compile - \else - \let\mmz@next\mmz@use@memoized - \fi - }{% - \ifmmz@readonly - \let\mmz@next\memoize@compile - \else - \let\mmz@next\mmz@memoize - \fi - }% - \else - \let\mmz@next\memoize@compile - \fi - \mmz@next{#2}% - % In all cases, we are left with \mmz@box. - \box\mmz@box -}% todo: flexibility, optimization - -\let\nomemoize\relax -\newcommand\nomemoize[1]{{\memoizedisable#1}} - - -%%%%%%%%%%%%%%%%%%%% THE CORE - -\long\def\memoize@compile#1{% - % We compile in a \hbox, so that the situation is the same as when - % memoization is active --- both in terms of the typeset output and the - % content of registers etc. - \setbox\mmz@box=\hbox{\memoizefalse#1}% -} - -% \mmz@ifmemoized{true code}{false code} -% Is there memoized data for \mmz@id? If yes, leave it in various macros (see -% \memoized) and execute {true code}. If no, \mmz@@filename will be undefined -% and we run {false code}. -\def\mmz@ifmemoized{% - % If inputing .memo sets the filename, we found it! - \let\memoized\memoized@search - \undef\mmz@@filename - \@input{\mmz@memo@filename\mmz@id}% - \let\mmz@next\@secondoftwo % not found - \ifmmz@@disabled - % disabled counts as found, so that we don't try to memoize again - \let\mmz@next\@firstoftwo - \else - \ifdef\mmz@@filename{% - % Well ... if that file exists. First, we prefix the correct folder: - \epreto\mmz@@filename\mmz@memo@path - \IfFileExists{\mmz@@filename}% - {\let\mmz@next\@firstoftwo}% yes! - {}% - }{}% - \fi - \mmz@next -} - -% We use the "graphics" package, so we don't have to deal with various TeX -% engines. And then, we actually use "graphicsx", because I have no idea how -% trim the padding without it. -\def\mmz@tolerance{0.01pt} -\long\def\mmz@use@memoized#1{% - \PackageInfo{memoize}{Using \mmz@@id\space}% - \setbox\mmz@box=\hbox{\lower\mmz@@dp\hbox{\includegraphics[trim=% - {\mmz@@padding@left} {\mmz@@padding@bottom} - {\mmz@@padding@right} {\mmz@@padding@top}]{\mmz@@filename}}}% - % I have no idea why this doesn't work. - % \setbox\mmz@box=\hbox{\lower\mmz@@dp\hbox{\includegraphics - % [\mmz@@padding@left,\mmz@@padding@bottom]% - % [\dimexpr\mmz@@padding@left+\mmz@@wd\relax,% - % \dimexpr\mmz@@padding@bottom+\mmz@@dp+\mmz@@ht\relax]% - % {\mmz@@filename}}}% - % Safety net: Warn if we include a page of unexpected dimensions. - \mmz@tempfalse - \mmz@if@roughly@equal{\mmz@@wd}{\wd\mmz@box}{% - \mmz@if@roughly@equal{\mmz@@ht}{\ht\mmz@box}{% - % no need to check \dp, we have just set it - \mmz@temptrue - }{}}{}% - \ifmmz@temp\else\mmz@use@memoized@warning\fi - \immediate\write\mmz@out{\noexpand\usedmemoized{\mmz@@id}% - {filename={\mmz@@filename}, page=\mmz@@page, - wd=\mmz@@wd, ht=\mmz@@ht, dp=\mmz@@dp, - padding left=\the\dimexpr\mmz@@padding@left, - padding bottom=\the\dimexpr\mmz@@padding@bottom, - padding right=\the\dimexpr\mmz@@padding@right, - padding top=\the\dimexpr\mmz@@padding@top% - }% - \@percentchar - }% -} -\def\mmz@use@memoized@warning{% - \PackageWarning{memoize}{Wrong dimensions of externalized graphics \mmz@@id. - Did something go wrong?}} - -% Memoize and leave the box in \mmz@box. -\long\def\mmz@memoize#1{% - \PackageInfo{memoize}{Memoizing \mmz@id\space}% - % Typeset the code. - \setbox\mmz@box=\hbox{% - \memoizefalse - \memoizingtrue - % Detect whether memoization of this particular picture (id) should be disabled, - % e.g. if \pdfsavepos was used - \global\mmz@cancelfalse - \mmz@cancel@setup - #1% - }% todo: smuggle \mmz@toks and \mmz@global@toks, once we have them! - \ifmmz@cancel\mmz@memoize@no\else{\mmz@memoize@yes}\fi -} -\def\mmz@memoize@yes{% - % So that the user can define padding in terms of the size of the - % externalized graphics: - \edef\width{\the\wd\mmz@box}% - \edef\height{\the\ht\mmz@box}% - \edef\depth{\the\dp\mmz@box}% - % Set the dimensions of the page: \mmz@box + padding - \hoffset\dimexpr\mmz@padding@left - \pdfhorigin\relax - \voffset\dimexpr\mmz@padding@top - \pdfvorigin\relax - \pdfpagewidth\dimexpr\mmz@padding@left + \wd\mmz@box + \mmz@padding@right\relax - \pdfpageheight\dimexpr\mmz@padding@top + \ht\mmz@box + - \dp\mmz@box+ \mmz@padding@bottom\relax - % - % If we are compiling by xelatex, using \documentclass{minimal} and if the - % first \shipout is our externalization shipout, we get a weird error: - % all the pages of the document have the same size as our first - % shipout. Our own shipouts have the size set correctly. Pdflatex does - % not exhibit this behaviour. - % - % Debug PDF: \pdfcompresslevel=0 \pdfobjcompresslevel=0 - % - % Use the original \shipout here, otherwise we can get in trouble with other - % packages like pdfpages. Let's just hope that (i) some other package - % doesn't count shipouts as well (then, they are in trouble), or (ii) doesn't - % use the primitive \shipout (then, we are in trouble). - \global\advance\mmz@realpage1 - \pdf@primitive\shipout\copy\mmz@box - % Store memoized data and the link to the .pdf in to .mmz file. - \immediate\write\mmz@out{\noexpand\memoized{\mmz@id}% - {filename={\pdf@primitivejobbasename.pdf}, page=\the\mmz@realpage, - wd=\the\wd\mmz@box, ht=\the\ht\mmz@box, dp=\the\dp\mmz@box, - % order as in graphicx: - padding left=\the\dimexpr\mmz@padding@left, - padding bottom=\the\dimexpr\mmz@padding@bottom, - padding right=\the\dimexpr\mmz@padding@right, - padding top=\the\dimexpr\mmz@padding@top}% - \@percentchar - }% -} -\def\mmz@memoize@no{% - \immediate\write\mmz@out{\noexpand\memoized{\mmz@id}% - {disable}% - \@percentchar - }% -} - - -%%%%%% Creating and reading .mmz and .memo files - -% A simple .memo file consists of a call to \memoized containing the -% information memoized at a call to \memoize. Crucially, this information -% includes the "link" to the externalized picture (todo: picture*s*). Like -% this: -% -% \memoized{md5sum}{pdf filename}{pdf page number}{width}{height}{depth} -% -% \item todo: context -% \item todo: code, input file, input line (if verbose) --- maybe check -% currfile package? -% -% The pdf filename is a path to the pdf relative to the location of the .memo -% file. -% -% A complex .memo file will contain a series of calls to \memoized. A .mmz -% file is really a complex .memo file. The different suffix indicates the -% different function. .mmz files are transitory, the idea is to split them -% into several .memo files, one for each \memoize(d). ".memo" files are -% permanent, their filenames contain md5sum. -% -% Memoization always produces a complex .memo file (.mmz), which is then split -% into several ".memo" files, each with a corresponding -% ".memo.pdf". However, the idea is to also support inclusion of -% externalized graphics from a single .memo -- .memo.pdf pair (probably slower, -% but easier to share). This is why \memoized@search below skips entries with a -% wrong md5sum, i.e. \memoized@search will only store the information when the -% md5sum argument (#1) matches \mmz@id. (The idea is to \undef something, like -% \mmz@@filename, and test it with \ifdef after inputting the .memo file.) -% -% The following macros store the info from .memo file into \mmz@@... macros. -\def\memoized@search#1{% - \def\mmz@@id{#1}% - \ifdefstrequal\mmz@@id\mmz@id{% - \let\memoized@next\endinput - \memoized@found - }{% - \let\memoized@next\skip - \memoized@skip - }% -} - -\newif\ifmmz@@disabled -\pgfqkeys{/memoized}{ - filename/.store in=\mmz@@filename, - page/.store in=\mmz@@page, - wd/.store in=\mmz@@wd, - ht/.store in=\mmz@@ht, - dp/.store in=\mmz@@dp, - padding left/.store in=\mmz@@padding@left, - padding bottom/.store in=\mmz@@padding@bottom, - padding right/.store in=\mmz@@padding@right, - padding top/.store in=\mmz@@padding@top, - disable/.is if=mmz@@disabled, -} - -\def\memoized@found#1{% - \def\mmz@@filename{}% - \def\mmz@@page{}% - \def\mmz@@wd{}% - \def\mmz@@ht{}% - \def\mmz@@dp{}% - \def\mmz@@padding@left{}% - \def\mmz@@padding@bottom{}% - \def\mmz@@padding@right{}% - \def\mmz@@padding@top{}% - \mmz@@disabledfalse - \pgfqkeys{/memoized}{#1}% - \memoized@next -} -\def\memoized@skip#1{} -\def\usedmemoized#1{\memoized@skip} - -% \jobname needs to be split into \mmz@jobpath and \mmz@jobbasename before -% calling this: -\def\mmz@memo@filename#1{% - \mmz@jobpath - \mmz@valueof{memo filename prefix}% - #1% - \mmz@valueof{memo filename suffix}% -} - - -\memoizeset{ - % This is the stuff we need to do before we can start memoizing. - initialize/.style={ - if readonly={}{initialize shipout}, - open mmz, - if manual={}{enable environments}, - define memoizeenable, - }, - % Hijack \shipout. If "shipout only memoized" is in effect, we prevent the - % shipout of (regular) pages. Otherwise, we count how many pages were - % shipped out, so that we know which pages are ours --- can this be done - % otherwise, maybe by "total_pages" in LuaTeX? - initialize shipout/.code={% - \let\mmz@orig@shipout\shipout - \ifmmz@shipout@only@memoized - \def\shipout{% - \deadcycles=0 - \setbox0=% - } - \else - \def\shipout{% - \global\advance\mmz@realpage1 - \mmz@orig@shipout - }% - \fi - }, - % Open the .mmz control file. This needs to be done after splitting but - % before the first externalization. By default, we do it in - % \AtBeginDocument, - open mmz/.code={% - % The .mmz has to sit next to the generated PDF, so \primitive\jobname! - \edef\pdf@primitivejobname{\pdf@primitive\jobname}% - \mmz@split@filename{\pdf@primitive\jobname}\mmz@temp\pdf@primitivejobbasename - \immediate\openout\mmz@out=\pdf@primitive\jobname.mmz - % Prefix and suffix info are used when splitting, either by an embedded - % call of from the external tool. - \immediate\write\mmz@out{% - \noexpand\memoizeset{% - memo filename prefix={\mmz@valueof{memo filename prefix}}, - memo filename suffix={\mmz@valueof{memo filename suffix}}, - jobname={\jobname}% - }\@percentchar - }% - % - % Close the .mmz file at the end. - \AtEndDocument{\immediate\closeout\mmz@out}% - }, - % Enable enabling memoization :D - define memoizeenable/.code={% - \def\memoizeenable{\AfterPreamble{\memoizetrue}}% - }, - % Split the .pdf generated in the previous compilation into ".memo.pdf"s - split/.code={% - \let\memoized\memoized@split - {% .mmz sets "jobname" and "memo filename prefix/suffix". We need them - % there because "split" is called before the user had the chance to ever - % call \memoizeset. But we don't want them to override anything, so we - % do the splitting in a group. - \def\memoizeset##1{\pgfqkeys{/memoize}{##1}\mmz@updatefilenames}% - \@input{\pdf@primitive\jobname.mmz}% - }% - % Disable afterwards, we really don't want to split twice! - \memoizeset{split/.code={}}% - }, -} - -\def\memoized@split#1{% - \def\mmz@@id{#1}% - \let\memoized@next\memoized@split@a - \memoized@found -} -\def\memoized@split@a{% - \ifmmz@@disabled\memoized@split@disabled\else\memoized@split@b\fi -} -\def\memoized@split@b{% - % Split the relevant page off to the memo .pdf. - \edef\mmz@syscall@jobname{\mmz@memo@filename\mmz@@id}% - \edef\mmz@marshal{% - \noexpand\justmemoized@prepare@syscall@commands{\mmz@jobpath\mmz@@filename}{\mmz@@page}% - }\mmz@marshal - \pdf@system{\mmz@valueof{latex system call}}% - % Write the .memo file. - \IfFileExists{\mmz@syscall@jobname.pdf}{% - \immediate\openout\mmz@out=\mmz@syscall@jobname - \immediate\write\mmz@out{% - \noexpand\memoized{\mmz@@id}% - {filename={\mmz@memo@basenameprefix\mmz@@id - \mmz@valueof{memo filename suffix}.pdf}, page=1, - wd=\mmz@@wd, ht=\mmz@@ht, dp=\mmz@@dp, - padding left=\mmz@@padding@left, padding bottom=\mmz@@padding@bottom, - padding right=\mmz@@padding@right, padding top=\mmz@@padding@top}% - \@percentchar - }% - \immediate\closeout\mmz@out - }{\justmemoized@error}% -} -\def\justmemoized@prepare@syscall@commands#1#2{% - % By using pdfpages, we don't care about the engine we use. And we're bound - % to LaTeX anyway ... - \def\mmz@syscall@commands{% - \documentclass{minimal} - \nofiles - % Debug PDF: \pdfcompresslevel=0 \pdfobjcompresslevel=0 - \usepackage{pdfpages} - \begin{document} - \includepdf[pages=#2,fitpaper]{#1} - \end{document} - }% -}% -\def\justmemoized@error{% - \PackageError{memoize}{Failed to extract page \mmz@@page\space of - "\mmz@jobpath\mmz@@filename" to "\mmz@syscall@jobname.pdf".}{}} -\def\memoized@split@disabled{% - \edef\mmz@syscall@jobname{\mmz@memo@filename\mmz@@id}% - \immediate\openout\mmz@out=\mmz@syscall@jobname - \immediate\write\mmz@out{% - \noexpand\memoized{\mmz@@id}% - {disable}% - \@percentchar - }% - \immediate\closeout\mmz@out -} - - -% AUTO-MEMOIZATION - -% UI: -\memoizeset{ - % * without an argument: general \memoizeenable / \memoizedisable - % (prevent is not allowed) - % * the argument is a control sequence: enable/disable/prevent - % memoizing a command - % * otherwise: enable/disable/prevent memoizing an environment - enable/.code={\def\mmz@handle@how{enable}\mmz@handle#1\mmz@end}, - disable/.code={\def\mmz@handle@how{disable}\mmz@handle#1\mmz@end}, - prevent/.code={\def\mmz@handle@how{prevent}\mmz@handle#1\mmz@end}, - enable/.default={}, - disable/.default={}, - prevent/.default={}, - % Non-xparse-defined commands must be registered. Todo in docs: if you get - % "LaTeX3 Error: Command '\foo' not defined using xparse.", you forgot to - % register the command. - register/.code 2 args={% - % #1 = the handled command - % #2 = the xparse argument specification of the handled command - \def\ArgumentSpecification{#2}% - \mmz@declare@handler#1% - }, - % Let #2 handle #1 (which can be either a command or an environment). The - % user is responsible for correct argument structure in the case of #1 being - % a command. If #1 is an environment, the handler should take two arguments, - % the environment name and the environment body (long). The handler is used - % for both "enable" and "prevent" mode: when it is called, \MemoizeWrapper - % will be \let to either \memoize or \nomemoize. Todo: "extract" mode? - handler/.code 2 args={\cslet{\mmz@repl@{#1}}#2}, - % Enable/disable auto-memoization of *all* environments. This patches \begin. - % By default, this is done in "initialize", unless option package option - % "manual" was given. - enable environments/.code={% - \ifdefequal\mmz@orig@begin\relax{}{% - \let\mmz@orig@begin\begin - \let\begin\mmz@begin - }{}% - }, - disable environments/.code={% - \ifdef\mmz@orig@begin{% - \let\begin\mmz@orig@begin - \let\mmz@orig@begin\relax - }{}% - }, - cancel/.code={% - \ifstrempty{#1}{% - \def\mmz@cancel@setup{}% - }{% - \eappto\mmz@cancel@setup{% - \let\mmz@canc#1\noexpand#1% - \def\noexpand#1{\global\noexpand\mmz@canceltrue\mmz@canc#1}% - }% - }% - }, -} - -\def\mmz@cancel@setup{}% -\def\mmz@canc#1{\expandonce{\csname mmz@canc@\string#1\endcsname}} - - -% Control sequences where we will store the handlers: -\def\mmz@orig#1{mmz@orig@\string#1} % the original command -\def\mmz@repl#1{mmz@repl@\string#1} % the initial part of the handler -\def\mmz@repl@#1{mmz@repl@\string#1@} % the handler replacing the original commmand - -% End-of-arguments marker: -\def\mmz@end{\mmz@end} - -% general, command or environment? -\def\mmz@handle{\futurelet\mmz@temp\mmz@handle@a} -\def\mmz@handle@a{% - \ifx\mmz@temp\mmz@end - \expandafter\mmz@handle@noarg % general - \else - \ifcat\noexpand\mmz@temp\relax - \expandafter\expandafter\expandafter\mmz@handle@cmd - \else - \expandafter\expandafter\expandafter\mmz@handle@env - \fi - \fi -} - -% General: -\def\mmz@handle@noarg\mmz@end{\csuse{memoize\mmz@handle@how}} -\def\memoizeenable{\PackageError{memoize}{You need to call - \string\memoizeset{initialize} before \string\memoizeenable}{}} -\def\memoizedisable{\AfterPreamble{\memoizefalse}} -\def\memoizeprevent{\PackageError{memoize}{Key "prevent" requires an argument - (environment or command name)}{}} - -% Command: -\def\mmz@handle@cmd{\csname mmz@handle@cmd@\mmz@handle@how\endcsname} - -% Enable automemoizing the command: -\def\mmz@handle@cmd@enable{\mmz@handle@cmd@ep\memoize} - -% Prevent memoization within the command: -\def\mmz@handle@cmd@prevent{\mmz@handle@cmd@ep\nomemoize} - -% Enable automemoization / prevent memoization within the command -% #1 = handled (original) \cs -\def\mmz@handle@cmd@ep#1#2\mmz@end{% - % #1 = the wrapper: \memoize / \nomemoize - % #2 = the handled command - \ifcsdef{\mmz@repl@{#2}}{% We already have a handler for #2, use it. - }{% #2 may only be an xparse-defined command, extract the argspec. - \mmz@handle@cmd@ep@heavy#2% - }% - \mmz@handler@init#2#1% -} - -\ifmmz@light %%%%%%%%%%%%%%%% begin light - -\def\mmz@handle@cmd@ep@heavy#1{\PackageError{memoize}{Handler for \string#1 is - not defined.}{If \string#1 was defined using package "xparse", you need to - remove package option "light" to handle it automatically.}{}} -\def\mmz@declare@handler#1{\PackageError{memoize}{Fancy command handling with - package "xparse" is not available when package option "light" is given.}{}} - -\else %%%%%%%%%%%%%%%% begin heavy - -\RequirePackage{xparse-arglist} -\def\mmz@handle@cmd@ep@heavy#1{% #1 = the handled command - \GetDocumentCommandArgSpec{#1}% - \mmz@declare@handler#1% -} -\def\mmz@declare@handler#1{% - \edef\mmz@marshal{% - \noexpand\DeclareDocumentCommand - \expandonce{\csname \mmz@repl#1@\endcsname}% - {\expandonce{\ArgumentSpecification}}% - {% - % todo: add a hook for users setup; prevent user from changing \MemoizeWrapper? - \edef\noexpand\mmz@marshal{% - \noexpand\noexpand\noexpand\MemoizeWrapper{% - \noexpand\noexpand\expandonce{\csname\mmz@orig#1\endcsname}% - \ArgumentList - }% - }\noexpand\mmz@marshal - }% - }\mmz@marshal -} - -\fi %%%%%%%%%%%%%%%% end light/heavy - - -% Define the initial part of the handler for #1, and let it replace the -% original command -\def\mmz@handler@init#1#2{% - % Define the initial part: in that part, we check \ifmemoize without - % expanding any arguments, and \let \MemoizeWrapper - % #1 = handled command \cs - % #2 = \memoize / \nomemoize - \edef\mmz@marshal{% - \noexpand\DeclareRobustCommand - \expandonce{\csname\mmz@repl#1\endcsname}% - {% - \noexpand\ifmemoize - \let\noexpand\MemoizeWrapper\noexpand#2% - \noexpand\expandafter\expandonce{\csname \mmz@repl@#1\endcsname}% - \noexpand\else - \noexpand\expandafter\expandonce{\csname\mmz@orig#1\endcsname}% - \noexpand\fi - }% - }\mmz@marshal - % Save the original (handled) command, if we don't have it yet. - \ifcsmacro{\mmz@orig{#1}}{}{% - \cslet{\mmz@orig{#1}}#1% - }% - % Replace the original command with the handler. - \letcs#1{\mmz@repl{#1}}% -} - -% Restore the original command: -\def\mmz@handle@cmd@disable#1#2\mmz@end{% - \ifstrempty{#2}{}{\mmz@handle@cmd@disable@error#1}% - \ifcsdef{\mmz@orig{#1}}{% - \letcs#1{\mmz@orig{#1}}% - % \undef, so that subsequent enable/prevent can pick up a new original - \csundef{\mmz@orig{#1}}% - }{}% -} -\def\mmz@handle@cmd@disable@error#1{% - \PackageWarning{memoize}{Ignoring argument specification while disabling - \string#1}} - -% Environments: We only need to remember how environment #1 should be handled: -% #1 = enable / disable / prevent, cs "\mmz@repl{#1}" is let to -% \mmz@begin@enable/disable/prevent. These are defined later. -\def\mmz@handle@env#1\mmz@end{% - \csletcs{\mmz@repl{#1}}{mmz@begin@\mmz@handle@how}} - -% The real work is done by our redefinitions of \begin. -% \item todo: environment hooks (etoolbox) -\DeclareRobustCommand\mmz@begin{% - \ifmemoize - \expandafter\mmz@begin@a - \else - \expandafter\mmz@orig@begin - \fi -} - -% \mmz@repl@ is \let to \mmz@begin@enable/disable/prevent -\def\mmz@begin@a#1{% - \expandafter\ifx\csname\mmz@repl{#1}\endcsname\relax - \expandafter\mmz@orig@begin - \else - \expandafter\mmz@begin@handled - \fi - {#1}% -} - -% Automemoize an environment. -\def\mmz@begin@handled#1{% - \edef\mmz@marshal{\noexpand\mmz@begin@handled@a{\@currenvir}{#1}}% - % We need to temporarily redefine \@currenvir for \Collect@Body to work. - \def\@currenvir{#1}% - \Collect@Body\mmz@marshal -} -\long\def\mmz@begin@handled@a#1#2#3\end#4{% - % #1 = the previous environment - % #2 = the handled environment name - % #3 = the handled environment body - % #4 = #2 - \csuse{\mmz@repl{#2}}{#2}{#3}% - \def\@currenvir{#1}% -} - -% Environment handlers: -% #1 = environment name -% #2 = environment code -\long\def\mmz@begin@enable#1#2{% - \memoize{\begin{#1}#2\end{#1}}} -\long\def\mmz@begin@prevent#1#2{% - \nomemoize{\begin{#1}#2\end{#1}}} -\let\mmz@begin@disable\relax - - - -\AtEndPreamble{% - \mmz@updatefilenames % even if loadonly! -} - -\unless\ifmmz@loadonly %%%%%%%%%%%%%%%% begin not loadonly - -\AtEndPreamble{% - \unless\ifmmz@manual %%%%%%%%%%%%%%%% begin automemoization - % Enable auto-memoization for tikz, if it is loaded. - \@ifpackageloaded{tikz}{% - \input memoize-tikz % Here we define and install \tikz handler. - \memoizeset{ - enable=tikzpicture, - enable=\tikz, - }% - }{}% - % Enable auto-memoization for forest, if it is loaded. - % todo: Move this into forest itself. - \@ifpackageloaded{forest}{% - \memoizeset{ - enable=forest, - % \Forest is defined by xparse, so no need to register it. - enable=\Forest, - }% - }{}% - \fi %%%%%%%%%%%%%%%% end automemoization - % -} -\memoizeset{cancel=\pdfsavepos} - -% We do the patching as late as possible. -\AtBeginDocument{% - \memoizeset{ - initialize, - % We can't split while the new PDF is being produced. - split/.code={\PackageError{memoize}{Splitting is only allowed in the preamble}{}}, - }% - \memoizeenable -} - -% We split while loading the package. Why? Some packages, when loaded, already -% start producing the PDF, but we need the PDF from the previous compilation -% intact to split! So splitting now makes it possible for the user to avoid -% this problem by ordering memoize before any offending packages. -% -% Obviously, this only affects splitting via an embedded system call. -% -% This problem is also why we load memo filename prefix and suffix from ".mmz". -% We can't include it among the package options, because of the spaces in the -% key name (and we don't want a cryptic package key option). Plus, for the user -% it makes sense that these affixes can be specified in the same location as -% everything else. Plus, loading it from .mmz is consistent with memomanager. -% -% The list of stuff that should be loaded after "memoize" for splitting to -% work: tikz library "shadows". -\memoizeset{split} - -\fi %%%%%%%%%%%%%%%% end not loadonly - - - - - -%%% Local Variables: -%%% mode: latex -%%% TeX-master: "test1" -%%% End: diff --git a/memomanager.py b/memomanager.py deleted file mode 100755 index 4b077b7..0000000 --- a/memomanager.py +++ /dev/null @@ -1,148 +0,0 @@ -#!/bin/env python - -import argparse, fileinput, os, os.path, collections -# from IPython import embed - -from pdfrw import PdfReader, PdfWriter -from pyparsing import Word, alphas, nestedExpr, CharsNotIn, \ - Suppress, ZeroOrMore, Group, Optional, delimitedList - - -# a rudimentary .memo parser - -Command = Word('\\', alphas) -Argument = nestedExpr('{', '}') -Key = CharsNotIn('=,') -Val = CharsNotIn('=,') -Whitespace = Suppress(ZeroOrMore(' ')) -Keyval = Group(Whitespace + Key + Optional( - Whitespace + Suppress('=') + Whitespace + Val, default = None)) -Keylist = delimitedList(Keyval) - -class CommandCall: - - def __init__(self, line): - self.command = Command.parseString(line)[0] - self.arguments = [] - for _, start, end in Argument.scanString(line): - self.arguments.append(collections.OrderedDict( - Keylist.parseString(line[start+1:end-1]).asList())) - - def __str__(self): - return self.command + ' ' + "".join( - '{' + - ", ".join( - key if val is None else f'{key}={val}' - for key, val in argument.items() - ) - + '}' - for argument in self.arguments - ) + '%' - -def process_mmz(mmz, args): - with fileinput.input(args.mmz) as mmz: - memoizeset = { - 'memo filename prefix': args.prefix, - 'memo filename suffix': args.suffix - } - for mmz_line in mmz: - command_call = CommandCall(mmz_line) - if command_call.command == '\memoizeset': - memoizeset.update(command_call.arguments[0]) - continue - else: - yield command_call, memoizeset - -class Pages(dict): - def __missing__(self, filename): - temp = self[filename] = (PdfReader(filename).pages, set()) - return temp - - -def unbrace(s): - return s[1:-1] if s.startswith('{') and s.endswith('}') else s - -def brace(s): - return '{' + s + '}' - -def split(args): - pages = Pages() - for cc, ms in process_mmz(args.mmz, args): - if cc.command != '\\memoized': - continue - md5 = list(cc.arguments[0].keys())[0] - m = cc.arguments[1] - out_basename = os.path.join(args.mmz_path, unbrace(ms['memo filename prefix']) + md5 + unbrace(ms['memo filename suffix'])) - if 'disable' not in m: - if args.verbose: - print(os.path.join(args.mmz_path, unbrace(m['filename'])), m['page'], - '-->', out_basename + ".pdf") - memo_pdf = PdfWriter(out_basename + '.pdf') - memo_pdf.addpage(pages[unbrace(m['filename'])][0][int(m['page'])-1]) - memo_pdf.write() - pages[unbrace(m['filename'])][1].add(int(m['page'])-1) - m['filename'] = brace(os.path.basename(unbrace(ms['memo filename prefix'])) + md5 + unbrace(ms['memo filename suffix']) + ".pdf") - with open(out_basename, 'w') as memo: - print(cc, file = memo) - if args.prune: - for filename, (reader_pages, extracted_pages) in pages.items(): - if args.verbose: - print(f'Pruning', filename, '-- keeping pages: ', end = '') - out_pdf = PdfWriter(filename) - for n, page in enumerate(reader_pages): - if n not in extracted_pages: - out_pdf.addpage(reader_pages[n]) - if args.verbose: - print(f'{n+1}, ', end = '') - out_pdf.write() - if args.verbose: - print() - if args.verbose: - print(f'{args.mmz} is empty now, backup in {args.mmz+".bak"}') - # todo: don't remove once we have the option to ignore .mmz in .sty - os.rename(args.mmz, args.mmz + '.bak') - -def remove_memos(args): - for cc, ms in process_mmz(args.mmz, args): - if cc.command != '\\usedmemoized': - continue - m = cc.arguments[1] - memo_filename, _ = os.path.splitext(unbrace(m['filename'])) - for fn in (memo_filename, unbrace(m['filename']), memo_filename + '.log'): - try: - os.remove(fn) - if args.verbose: - print(f'Removed {memo_filename}, plus its .log and .pdf') - except FileNotFoundError: - pass - -def adhoc(args): - with fileinput.input(args.mmz) as mmz: - for line in mmz: - print(line.strip()) - print(CommandCall(line)) - print() - - -parser = argparse.ArgumentParser(description='Manage memoize memos.') -parser.add_argument('--verbose', '-v', action = 'store_true') -parser.add_argument('--prefix', help='memo filename prefix') -parser.add_argument('--suffix', help='memo filename suffix') - -subparsers = parser.add_subparsers(title = 'Commands') - -parser_split = subparsers.add_parser('split', help = 'Split the memos off the pdf generated in the last compilation') -parser_split.add_argument('--prune', action = 'store_true', help='Should we prune the original file?') -parser_split.set_defaults(func=split) - -parser_remove = subparsers.add_parser('remove', aliases = ['delete'], help = 'Remove the memos used in the last compilation') -parser_remove.set_defaults(func=remove_memos) - -parser_adhoc = subparsers.add_parser('adhoc') -parser_adhoc.set_defaults(func=adhoc) - -parser.add_argument('mmz', help='.mmz file') - -args = parser.parse_args() -args.mmz_path = os.path.dirname(args.mmz) -args.func(args) diff --git a/nomemoize.sty b/nomemoize.sty deleted file mode 100644 index eb86e6f..0000000 --- a/nomemoize.sty +++ /dev/null @@ -1,22 +0,0 @@ -\ProvidesPackage{nomemoize}[2020/05/17 A stub for memoize] - -% This package allows us to switch off "memoize" but leave the memoize commands -% in the document. -% -% Packages with "memoize" support should \RequirePackage{nomemoize}. This way, -% they can safely use memoize's commands without actually loading it. - -\RequirePackage{pgfopts} % pgfkeys-based package options -\pgfqkeys{/memoize/package options}{ - loadonly/.code={}, - minimal/.code={}, -} -\ProcessPgfPackageOptions{/memoize/package options} - -\providecommand\memoizeset[1]{} -\providecommand\memoize[2][]{{#2}} -\providecommand\nomemoize[1]{{#1}} -\providecommand\memoizeenable{} -\providecommand\memoizedisable{} -\newif\ifmemoize -\newif\ifmemoizing diff --git a/xparse-arglist.sty b/xparse-arglist.sty deleted file mode 100644 index 9e1d372..0000000 --- a/xparse-arglist.sty +++ /dev/null @@ -1,72 +0,0 @@ -\ProvidesPackage{xparse-arglist} -\RequirePackage{xparse} - -% This package provides a way to define an xparse-based command which is -% "aware" of how it was called. In other words, while executing the command, -% we construct the argument list that was used to call it (or at least -% something very close to, and functionally equivalent to this argument list). -% -% To construct the argument list, we need to provide \ArgumentSpecification, -% either manually or by calling \GetDocumentCommandArgSpec (see xparse manual -% 3.4) and then expand \ArgumentList in the following way: -% -% \ArgumentList must be first fully expanded both when defining the command, -% and the result must be then fully expanded while executing the command. -% -% For example, to have \foo itself with the same arguments again :D define it -% like this: -% -% \edef\outermarshal{% -% \noexpand\NewDocumentCommand -% \noexpand\foo -% {\expandonce{\ArgumentSpecification}}% -% {% -% \unexpanded{...}% -% \edef\noexpand\innermarshal{% -% \noexpand\noexpand\noexpand\foo\ArgumentList -% }\innermarshal -% \noexpand\foo\ArgumentList -% \unexpanded{...}% -% }% -% }\outermarshal -% -% This package was implemented during the development of "memoize", which -% needs to compute the md5sum of a command plus its arguments, and then -% (sometimes) execute the command. -% -% Now maybe this exists somewhere in xparse, but I haven't been able to find -% it. And I know I should've used expl3 for this ... but plain TeX way -% compiles faster. ;-) - -\def\ArgumentList{% - \expandafter\xp@arglist\expandafter0\ArgumentSpecification.% -} - -\def\xp@arglist#1#2{% - \ifcsname xp@arglist@#2\endcsname - \csname xp@arglist@#2\expandafter\expandafter\expandafter\endcsname - \else - \expandafter\xp@arglist@error - \fi - \expandafter{\the\numexpr#1+1\relax}% -} - -% \xp@arglist@...: #1 = the argument number -\def\xp@arglist@m#1{\noexpand\unexpanded{{#####1}}\xp@arglist{#1}} -\def\xp@arglist@r#1#2#3{\noexpand\unexpanded{#2#####1#3}\xp@arglist{#1}} -\def\xp@arglist@R#1#2#3#4{\noexpand\unexpanded{#2#####1#3}\xp@arglist{#1}} -\def\xp@arglist@v#1{{Handled commands with verbatim arguments are not - supported}\xp@arglist{#1}} % error -\def\xp@arglist@b#1{{This is not the way to handle - environment}\xp@arglist{#1}} % error -\def\xp@arglist@o#1{\noexpand\unexpanded{[#####1]}\xp@arglist{#1}} -\def\xp@arglist@d#1#2#3{\noexpand\unexpanded{#2#####1#3}\xp@arglist{#1}} -\def\xp@arglist@O#1#2{\noexpand\unexpanded{[#####1]}\xp@arglist{#1}} -\def\xp@arglist@D#1#2#3#4{\noexpand\unexpanded{#2#####1#3}\xp@arglist{#1}} -\def\xp@arglist@s#1{\noexpand\IfBooleanT{#####1}{*}\xp@arglist{#1}} -\def\xp@arglist@t#1#2{\noexpand\IfBooleanT{#####1}{#2}\xp@arglist{#1}} -\csdef{xp@arglist@+}#1{\expandafter\xp@arglist\expandafter{\the\numexpr#1-1\relax}}% -\csdef{xp@arglist@.}#1{} -% e,E: Embellishments are not supported. -% > Argument processors are not supported. And how could they be? -\def\xp@arglist@error#1.{{Unknown argument type}}