% \iffalse meta-comment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % forest-ext-tagging.dtx % Additions and changes Copyright (C) 2025-2026 Clea F. Rees. % Code from skeleton.dtx Copyright (C) 2015-2024 Scott Pakin (see below). % % 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-05-04 or later. % % This work has the LPPL maintenance status 'muaintained'. % % The Current Maintainer of this work is Clea F. Rees. % % This work consists of all files listed in manifest.txt. % % The file forest-ext-tagging.dtx is a derived work under the terms of the % LPPL. It is based on version 2.4 of skeleton.dtx which is part of % dtxtut by Scott Pakin. A copy of dtxtut, including the % unmodified version of skeleton.dtx is available from % https://www.ctan.org/pkg/dtxtut and released under the LPPL. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \fi % % \iffalse %<*driver> \RequirePackage{svn-prov} % ref. ateb Max Chernoff: https://tex.stackexchange.com/a/723294/ \def\MakePrivateLetters{\makeatletter\ExplSyntaxOn\endlinechar13} \ExplSyntaxOff \ProvidesFileSVN{$Id: forest-ext-tagging.dtx 11545 2026-01-19 07:08:04Z cfrees $}[v0.2 \revinfo][\filebase DTX: ] \DefineFileInfoSVN[forest-ext-tagging] \documentclass[11pt,british]{ltxdoc} % l3doc loads fancyvrb % fancyvrb overwrites svn-prov's macros without warning % restore \fileversion \filerev in case we're using l3doc \GetFileInfoSVN{forest-ext-tagging} \begin{document} % \let\MakePrivateLetters\MyMakePrivateLetters \DocInput{\filename} \end{document} % % \fi % \title{ext.tagging} % \author{Clea F. Rees\thanks{% % Bug tracker: % \href{https://codeberg.org/cfr/prooftrees/issues}{\url{codeberg.org/cfr/prooftrees/issues}} % \textbar{} Code: % \href{https://codeberg.org/cfr/prooftrees}{\url{codeberg.org/cfr/prooftrees}} % % \textbar{} Mirror: % % \href{https://github.com/cfr42/prooftrees}{\url{github.com/cfr42/prooftrees}}% % }} % \date{\forestextdocdate} % \maketitle % % ^^A forest-lib-ext.tagging{-debug} % ^^A <<< %<*sty> %<@@=tagforest> % \permissivelines % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} %% $Id: forest-ext-tagging.dtx 11545 2026-01-19 07:08:04Z cfrees $} % \ProvidesForestLibrary{ext.tagging}[v0.1] % \ProvidesForestLibrary{ext.tagging-debug}[v0.1] % % \disable@package@load {forest-lib-ext.tagging-debug} % \disable@package@load {forest-lib-ext.tagging} {% % \PackageWarning {ext.tagging (forest library)} % \PackageWarning {ext.tagging-debug (forest library)} {Only one of ext.tagging and ext.tagging-debug should be loaded. Since the % ext.tagging % ext.tagging-debug library has already been loaded, I will ignore your request for % ext.tagging-debug.% % ext.tagging.% }% } % \end{macrocode} % We don't want inconsistent names in hooks. % \begin{macrocode} \SetDefaultHookLabel{forest-ext/tagging} % \end{macrocode} % \iffalse % ^^A Paid â defnyddio \GetFileInfoSVN*/\GetFileInfoSVN{} yn y fan hon!! % \fi % As the name suggests, we need \emph{tagging keylists} from \pkg{ext.utils}. % \begin{macrocode} % \useforestlibrary*{ext.utils} % \useforestlibrary*{ext.utils-debug} \ExplSyntaxOn % \end{macrocode} % \begin{macro}{\l_@@_toks_tl} % \lpack{expl3} variable to store non-\lpack{expl3} \emph{toks}. % \begin{macrocode} \tl_new:N \l_@@_toks_tl % \end{macrocode} % \end{macro} % \begin{macro}{\l_@@_tmpa_str} % \begin{macrocode} \str_new:N \l_@@_tmpa_str % \end{macrocode} % \end{macro} % \begin{macrocode} % \end{macrocode} % \begin{macro}{\l_forestext_tagging_custom_bool} % \begin{fcodekey}{custom~tagging} % Public boolean to allow custom config to override e.g.~\pkg{prooftrees}. % \begin{macrocode} \bool_new:N \l_forestext_tagging_custom_bool \bool_set_false:N \l_forestext_tagging_custom_bool \forestset{ custom~tagging/.code={ \use:c {bool_set_#1:N} \l_forestext_tagging_custom_bool }, custom~tagging/.default=true, not~custom~tagging/.code={ \bool_set_false:N \l_forestext_tagging_custom_bool }, } % \end{macrocode} % \end{fcodekey} % \end{macro} % \begin{macro}{% % \_@@_pgftikz_tag_bbox:nnn, % \_@@_pgftikz_tag_bbox:enn, % } % Retrieve saved coordinates. % \begin{macrocode} \cs_new_nopar:Npn \_@@_pgftikz_tag_bbox:nnn #1#2#3 { \_@@_pgftikz_tag_bbox_aux:eenn { \property_ref:ee {#1}{xpos} } { \property_ref:ee {#1}{ypos} } {#2}{#3} } \cs_generate_variant:Nn \_@@_pgftikz_tag_bbox:nnn {enn} % \end{macrocode} % \end{macro} % \begin{macro}{% % \_@@_pgftikz_tag_bbox_aux:nnnn, % \_@@_pgftikz_tag_bbox_aux:eenn, % } % The tagging code requires the bounding box for \emph{alt}. % Getting the exact value would require something more complicated, but this calculates a reasonable approximation for simple cases. % It is not exact because it does not, for instance, account for line widths at the least and greatest coordinates. % A more serious deficiency is that it ignores any annotations added to the tree, including labels, edge labels, additional drawing commands etc. % % The problem here is that if we wait until the end of the \env{tikzpicture}, the tokens required to create the \texttt{alt} text no longer exist. % A better solution might be to \pkg{memoize} the tree and get the bounding box that way. % Then we can simply write the tokens we need to file and access them at any point during subsequent compilations. % Or maybe it would be better to just save the tokens and write this after the tree is drawn? % But then we probably have to save them globally in order to ‘smuggle’ them out, which is a bit obnoxious. % \begin{macrocode} \cs_new_nopar:Npn \_@@_pgftikz_tag_bbox_aux:nnnn #1#2#3#4 { \dim_to_decimal_in_bp:n {#1sp} \c_space_tl \dim_to_decimal_in_bp:n {#2sp} \c_space_tl \dim_to_decimal_in_bp:n {#1sp+#3} \c_space_tl \dim_to_decimal_in_bp:n {#2sp+#4} } \cs_generate_variant:Nn \_@@_pgftikz_tag_bbox_aux:nnnn {eenn} % \end{macrocode} % \end{macro} % \begin{socket}{tagsupport/forest/init,tagsupport/forest/tag,tagsupport/forest/tag/mmz,tagsupport/forest/setup} % Is there an equivalent of the \env{macro} environment for sockets/plugs/hooks? % % The support for \pkg{memoize} is currently \texttt{noop}, but we create the sockets. % % \texttt{tagsupport/forest/setup} doesn't correspond to anything in \pkg{latex-lab} \autocite{latex-project-latex-lab} because I'm not sure how to make it. % \begin{macrocode} \socket_new:nn {tagsupport/forest/init}{0} \socket_new:nn {tagsupport/forest/tag}{2} \socket_new:nn {tagsupport/forest/tag/mmz}{2} \socket_new:nn {tagsupport/forest/setup}{0} % \end{macrocode} % \end{socket} % \begin{macro}{% % \_@@_tag_suspend:n, % \_@@_tag_resume:n, % } % We are going to redefine the standard \cs{tag\_suspend:n} and \cs{tag\_resume:n} to prevent the tagging code being continuously stopped and started during tree construction. % Before doing that, we make private copies of both commands so that we can \begin{enumerate*}[label=(\roman*)]\item still stop/start tagging ourselves and \item restore the original definitions when we're done\end{enumerate*}. % % This rather less than ideal solution is required because there is no way to disable the tagging support for \pkg{tikz} locally: the only documented way to disable is global. % But we do not want to interfere with \pkg{latex-lab}'s tagging code for \emph{other} \env{tikzpicture} environments. % We just want to stop it interfering in \env{forest} trees. % Hence the hacks. % \begin{macrocode} \cs_new_eq:NN \_@@_tag_suspend:n \tag_suspend:n \cs_new_eq:NN \_@@_tag_resume:n \tag_resume:n % \end{macrocode} % \end{macro} % \begin{macro}{\_@@_noop:n} % Something to \cs{let} the suspend/resume functions to. % \begin{macrocode} \cs_new_nopar:Npn \_@@_noop:n #1 {} % \end{macrocode} % \end{macro} % \begin{splug}{tagsupport/forest/init tag} % This plug corresponds roughly to \texttt{tagsupport/tikz/picture/init}, but the division of labour between sockets/plugs is a bit different for \env{forest}. % \begin{macrocode} \socket_new_plug:nnn {tagsupport/forest/init}{tag} { % \end{macrocode} % This part is modified from \textcite{latex-project-latex-lab-tikz}, but runs in a different socket. % I had a note that using socket \texttt{para/begin} didn't work here. % That's probably from tableaux? % But I can't remember what I thought the problem was \dots. % \begin{macrocode} \mode_if_vertical:T { \if@inlabel \mode_leave_vertical: \else \tag_socket_use:n {para/begin} \fi } \tag_mc_end_push: % \end{macrocode} % Note that assigning \texttt{noop} to all of the \pkg{latex-lab} sockets and suspending tagging is \textbf{not} sufficient to suspend tagging. % This is because hook code includes tagging commands, including commands which start/stop tagging, unconditionally. % \begin{macrocode} \socket_assign_plug:nn {tagsupport/tikz/picture/init}{noop} \socket_assign_plug:nn {tagsupport/tikz/picture/begin}{noop} \socket_assign_plug:nn {tagsupport/tikz/picture/end}{noop} % \end{macrocode} % This does the \pkg{forest} \autocite{saso-forest} setup before the \emph{tagging keylists} are turned into \emph{keylist options}. % \begin{macrocode} \socket_use:n {tagsupport/forest/setup} % \end{macrocode} % Since we can't disable that code only locally, we instead redefine the relevant commands. % Even this does not completely pause the tagging code, but it stops enough to yield a valid structure, albeit one with a lot of empty \texttt{mc}s. % \begin{macrocode} \cs_set_eq:NN \tag_suspend:n \_@@_noop:n \cs_set_eq:NN \tag_resume:n \_@@_noop:n % \end{macrocode} % Suspend tagging using private copy of public function. % \begin{macrocode} \_@@_tag_suspend:n {tagforest} } % \end{macrocode} % \end{splug} % \begin{splug}{tagsupport/forest/setup~alt} % This doesn't correspond to anything in \textcite{latex-project-latex-lab-tikz} because I'm not sure how to make it. % \begin{macrocode} \socket_new_plug:nnn {tagsupport/forest/setup}{alt} { \forestset{ tag~plug=alt, tag~nodes~uses=alt~text, collate~tags~uses=alt~text, tag~tree~uses=alt, } } % \end{macrocode} % \end{splug} % \begin{splug}{tagsupport/forest/tag~alt} % This plug corresponds to \pkg{latex-lab}'s \texttt{alt} plug for \pkg{tikz} \autocite{latex-project-latex-lab-tikz}. % So far as possible, these plugs are verbatim copies of the official plugs\footnote{% % In other words, the bits that work are shamelessly copied from Ulrike Fischer's code, while the bits which don't are mine.% % }, but some changes are necessary for \pkg{forest}. % \begin{macrocode} \socket_new_plug:nnn {tagsupport/forest/tag}{alt} { % \end{macrocode} % Straight from \pkg{latex-lab}. % \begin{macrocode} \tag_struct_begin:n { tag=Figure, alt=\l_@@_toks_tl, } \tag_mc_begin:n {tag=Figure} \cs_new:cpe {tagforest@mark@pos@\the\tagforest@id} { % \end{macrocode} % The only real differences are that, as noted above, some code is used in the \texttt{init} socket rather than here and that we use different functions to determine the coordinates of the origin and size of the bounding box. % Whereas \pkg{latex-lab} uses \pkg{pgf}'s \texttt{remember picture} functionality to record the origin, we use \pkg{ltproperties}. % Similarly, where \pkg{latex-lab} uses \pkg{pgf} to determine the extent of the bounding box, we use \pkg{forest} to calculate approximate dimensions for the tree before it is drawn. % % The use of \pkg{ltproperties} is quite all right, I think, and necessary as \pkg{latex-lab}'s method is not compatible with \pkg{forest}. % However, \pkg{latex-lab}'s bounding box calculation is \emph{far} superior to the method used here, so it would be useful to see if that can be modified for use once the rest of the code works. % (It should also be significantly faster.) % \begin{macrocode} \_@@_pgftikz_tag_bbox:enn {tagforest-id\the\tagforest@id} {#1}{#2} } % \end{macrocode} % Revert to copying \pkg{latex-lab} verbatim. % \begin{macrocode} \tag_struct_gput:ene {\tag_get:n {struct_num}} {attribute} { /O /Layout /BBox~ [ \use:c {tagforest@mark@pos@\the\tagforest@id} ] } } % \end{macrocode} % \end{splug} % \begin{macro}{\_@@_init:} % Corresponds to the analogous \pkg{latex-lab} function. % Tests whether tagging is active and sets a \pkg{forest} boolean accordingly. % \begin{macrocode} \cs_new_nopar:Npn \_@@_init: { \global\advance\tagforest@id~by~1\relax \tag_if_active:TF { \forestset{ tagging=1, % debug~tagforest={Tagging~active.}, } % \end{macrocode} % If tagging is active and unless custom tagging is set, installs sets register \texttt{plut} to \texttt{alt} and assigns plugs and sockets. % If custom tagging is set, we just set the \pkg{forest} boolean \texttt{tagging} and make \cs{\_\_tagforest\_end:} noop. % The custom stages are still in place, but these should hopefully have no effect on anything. % In any case, they are partially overridden by e.g.~\pkg{prooftrees} which installs a somewhat different and more complicated set. % % ^^A tag nodes uses=alt text is a style which sets the tag nodes and collate tags keylists; tag tree is a noop style by default; tag tree uses alt text is a get dims and call tagging fn. % \begin{macrocode} \bool_if:NTF \l_forestext_tagging_custom_bool { % \tagforest@debug@typeout{Custom~tagging~configured.} \cs_set_eq:NN \_@@_end: \_@@_noop:n }{ \cs_set_eq:NN \_@@_end: \_@@_tag_end: % \tagforest@debug@typeout{Custom~tagging~not~configured.} \str_if_eq:eeT {tagforest@plug@NONE} {\foresteregister{setup~plug}} { % \tagforest@debug@typeout{Looking~for~setup~plug~as~none~configured.} \socket_get_plug:nN {tagsupport/tikz/picture/begin} \l_@@_tmpa_str \exp_args:NnV \socket_if_plug_exist:nnTF {tagsupport/forest/setup} \l_@@_tmpa_str { \PackageInfo{ext.tagging~(forest~lib)}{ Installing~setup~plug~for~tagging~forest~trees~to~match~selection~for~ tikz~pictures. } \exp_args:Ne \forestset{setup~plug \exp_not:N = \l_@@_tmpa_str} } { \PackageWarning{ext.tagging~(forest~lib)}{ Using~alt~setup~plug~for~tagging~as~no~match~exists~for~plug~ selected~for~tikz~pictures } \forestset{setup~plug=alt} } } \str_if_eq:eeT {tagforest@plug@NONE} {\foresteregister{tag~plug}} { % \tagforest@debug@typeout{Looking~for~tag~plug~as~none~configured.} \exp_args:NnV \socket_if_plug_exist:nnTF {tagsupport/forest/tag} \l_@@_tmpa_str { \PackageInfo{ext.tagging~(forest~lib)}{ Installing~tag~plug~for~tagging~forest~trees~to~match~selection~for~ tikz~pictures. } \exp_args:Ne \forestset{tag~plug \exp_not:N = \l_@@_tmpa_str} } { \PackageWarning{ext.tagging~(forest~lib)}{ Using~alt~tag~plug~for~tagging~as~no~match~exists~for~plug~ selected~for~tikz~pictures } \forestset{tag~plug=alt} } } % \tagforest@debug@typeout{Assigning~plug~tag~to~tagsupport/forest/init.} \socket_assign_plug:nn {tagsupport/forest/init}{tag} % \tagforest@debug@typeout{Using~socket~tagsupport/forest/init.} \socket_use:n {tagsupport/forest/init} % \end{macrocode} % We also do what we can to stop the residual tagging code from marking up useless content. % This mitigates the problem, but does not entirely solve it. % \begin{macrocode} \def\pgfsys@begin@text{} \def\pgfsys@end@text{} } }{ \forestset{tagging=0, % debug~tagforest={Tagging~inactive.}, } \cs_set_eq:NN \_@@_end: \_@@_noop:n } } % \end{macrocode} % \end{macro} % \begin{macro}{\_@@_end:, % \_@@_tag_end:} % Again, analogous to the corresponding \pkg{latex-lab} function \autocite{latex-project-latex-lab-tikz}. % \begin{macrocode} \cs_new_eq:NN \_@@_end: \_@@_noop:n \cs_new_nopar:Npn \_@@_tag_end: { \_@@_tag_resume:n {tagforest} % \end{macrocode} % Restore the format's definitions of \cs{tag\_suspend:n} and \cs{tag\_resume:n}. % \begin{macrocode} \cs_set_eq:NN \tag_suspend:n \_@@_tag_suspend:n \cs_set_eq:NN \tag_resume:n \_@@_tag_resume:n % \end{macrocode} % Standardish? % \begin{macrocode} % \if@tagforest@debug % \ShowTagging{mc-current} % \fi \tag_mc_end: \tag_struct_end: \tag_mc_begin_pop:n {} } % \end{macrocode} % \end{macro} % \begin{macro}{\_@@_tag_tree_tag:nnn,\tagforest@tag@tree@tag} % This function is responsible for recording the tree's page coordinates, tidying up the collected tokens for the \texttt{alt} text and utilising the tagging socket. % \begin{macrocode} \cs_new_nopar:Npn \_@@_tag_tree_tag:nnn #1#2#3 { \tex_savepos:D \property_record:ee {tagforest-id\the\tagforest@id} {xpos,ypos} \tex_savepos:D \tl_set:Ne \l_@@_toks_tl { \exp_args:No \text_purify:n { \the\tagforest@toks } } % \end{macrocode} % Utilising the socket requires briefly reenabling tagging else the commands would have no useful effects. % \begin{macrocode} \_@@_tag_resume:n {tagforest} \socket_assign_plug:nn {tagsupport/forest/tag}{#1} \ifmemoizing \socket_assign_plug:nn {tagsupport/forest/tag/mmz}{#1} \fi \socket_use:nnn {tagsupport/forest/tag}{#2}{#3} \socket_use:nnn {tagsupport/forest/tag/mmz}{#2}{#3} \_@@_tag_suspend:n {tagforest} } % \end{macrocode} % Alias for use in \env{pgf} syntax. % \begin{macrocode} \cs_new_eq:NN \tagforest@tag@tree@tag \_@@_tag_tree_tag:nnn % \end{macrocode} % \end{macro} % \begin{macro}{\tagforest@init} % Alias. % \begin{macrocode} \cs_new_eq:NN \tagforest@init \_@@_init: % \end{macrocode} % \end{macro} % \changes{v0.2}{2026-01-18}{Add hook ordering rule as switching utils (back) to begin env hook.} % \begin{macrocode} \hook_gput_code:nnn {env/forest/end}{.} { \_@@_end: } \hook_gput_code:nnn {env/forest/begin}{.} { \_@@_init: } \hook_gset_rule:nnnn {env/forest/begin}{.}<{forest-ext/utils} % \end{macrocode} % \begin{macrocode} \ExplSyntaxOff % \end{macrocode} % \begin{macro}{\tagforest@toks} % \begin{macro}{\LogTagForestToks} % Name for a new toks and some ways to peek when debugging. % \begin{macrocode} \newtoks\tagforest@toks % \newcommand \LogTagForestToks{% % \expandafter\typeout\expandafter{\expanded{% % \detokenize{[tagforest debug]:: current toks: }% % \expandafter\detokenize\expandafter{\the\tagforest@toks}% % }% % }% % } % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\tagforest@id} % \begin{macro}{\LogTagForestId} % Name for a new count. % \begin{macrocode} \newcount\tagforest@id % \newcommand \LogTagForestId{% % \expandafter\typeout\expandafter{\expanded{% % \detokenize{[tagforest debug]:: current id: }% % \the\tagforest@id % }% % }% % } % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{% % \if@tagforest@debug,% % \@tagforest@debugfalse,% % \@tagforest@debugtrue,% % \tagforest@debug@typeout % } % Conditional for debugging. % \begin{macrocode} \newif\if@tagforest@debug % \@tagforest@debugfalse % \@tagforest@debugtrue \newcommand \tagforest@debug@typeout [1]{% \if@tagforest@debug \ExpandArgs {e} \typeout{[tagforest debug]:: \detokenize{#1}}% \fi } % \end{macrocode} % \end{macro} % \begin{macrocode} \forestset{ % \end{macrocode} % For debugging. %<*debug> % \begin{macrocode} debug tagforest/.code={ \tagforest@debug@typeout{#1}% }, % \end{macrocode} % % Various additions in the form of \pkg{forest} options and registers. % By default, these are noop. % \begin{macrocode} declare boolean register={tagging}, tagging=0, declare toks register={setup plug}, setup plug=tagforest@plug@NONE, declare toks register={tag plug}, tag plug=tagforest@plug@NONE, Autoforward register={setup plug}{% TeX={% \IfSocketPlugExistsTF {tagsupport/forest/setup}{#1}{% \AssignSocketPlug {tagsupport/forest/setup}{#1}% }{% \PackageError{ext.tagging (forest library)}{% No plug named '#1' exists for socket 'tagsupport/forest/setup'.% }{% See the forest-ext manual for details.% }% }% }, }, Autoforward register={tag plug}{% TeX={% \IfSocketPlugExistsTF {tagsupport/forest/tag}{#1}{% \AssignSocketPlug {tagsupport/forest/tag}{#1}% }{% \PackageError{ext.tagging (forest library)}{% No plug named '#1' exists for socket 'tagsupport/forest/tag'.% }{% See the forest-ext manual for details.% }% }% }, }, plug/.style={% setup plug={#1}, tag plug={#1}, }, % \end{macrocode} % \begin{ftagkeylist}{% % tag~nodes,collate~tags% % } % I wanted to use a nodewalk styles for tagging and collation, but couldn't (easily) figure out how, so sticking to keylists and processing orders for now. % Hence, only the final step is a stage \dots. % But I suspect there's a performance hit here \dots. % (Or maybe not without comparing internals with public interfaces? % \pkg{prooftrees} uses keylists and I don't think Sašo suggested substituting code keys for speed at any point? % But that was a long time ago \dots.) % \begin{macrocode} declare tagging keylist={tag nodes}{}, declare tagging keylist={collate tags}{}, % \end{macrocode} % \end{ftagkeylist} % \begin{fkeylist}{% % before~tagging~nodes, % before~collating~tags, % before~tagging~tree% % } % Regular keylist options. % \begin{macrocode} declare keylist={before tagging nodes}{}, declare keylist={before collating tags}{}, declare keylist={before tagging tree}{}, % \end{macrocode} % \end{fkeylist} % \begin{autotoks}{% % node@ttoks, % alt text% % } % Private and public. % \begin{macrocode} declare autowrapped toks={node@ttoks}{}, declare autowrapped toks={alt text}{}, % \end{macrocode} % \end{autotoks} % \begin{autotoksr}{% % is~root, % is~leaf, % is~child, % is~edge~label, % has~branches, % is~branch% % } % Structural descriptors. % \begin{macrocode} declare autowrapped toks register={is root}, is root={root}, declare autowrapped toks register={is leaf}, is leaf={end branch}, declare autowrapped toks register={is child}, is child={child}, declare autowrapped toks register={is edge label}, is edge label={edge label}, declare autowrapped toks register={has branches}, has branches={branches}, declare autowrapped toks register={is branch}, is branch={branch}, % \end{macrocode} % \end{autotoksr} % The tagging code depends on injecting additional processing steps into \pkg{forest}'s processing of the tree. % This requires redefining \texttt{stages} to include the extra steps. % This has global effect, but hopefully does no harm \dots. % \begin{macrocode} stages/.style={ for root'={ process keylist register=default preamble, process keylist register=preamble }, process keylist=given options, process keylist=before typesetting nodes, typeset nodes stage, process keylist=before packing, pack stage, process keylist=before computing xy, compute xy stage, % \end{macrocode} % The additions for tagging are inserted between \texttt{compute xy stage} and \texttt{before drawing tree}. % \begin{macrocode} % debug tagforest={Process keylist: before tagging nodes ...}, process keylist=before tagging nodes, % debug tagforest={Process keylist: tag nodes ...}, process keylist=tag nodes, % debug tagforest={Process keylist: before collating tags ...}, process keylist=before collating tags, % debug tagforest={Process keylist: collate tags ...}, process keylist=collate tags, % debug tagforest={Process keylist: before tagging tree ...}, process keylist=before tagging tree, % debug tagforest={Stage: tag tree stage ...}, tag tree stage, % debug tagforest={Completed all tagging stages!}, process keylist=before drawing tree, draw tree stage }, tag nodes processing order/.nodewalk style={unique=tree}, collate tags processing order={unique=tree depth first}, tag tree stage/.style={for root'=tag tree}, % \end{macrocode} % By default, the crucial stage does nothing. % \begin{macrocode} tag tree/.style={}, % \end{macrocode} % Redefine various of the additions to \texttt{stages} to do something useful. % The remaining additions are to allow user interventions. % % We split this up so bits can be used more flexibly e.g.~by \pkg{prooftrees}. % \pkg{prooftrees} doesn't want the code which generates tags, but it does want \texttt{tag tree}. % (Well, \pkg{prooftrees} had this code first, so it wants what \pkg{ext.tagging} is pinching. % \begin{choicekey}{tag~nodes~uses} % How to tag individual nodes. % Currently, only nodes can be tagged. % \begin{macrocode} tag nodes uses/.is choice, tag nodes uses/noop/.style={% redeclare tagging keylist={tag nodes}{}, }, tag nodes uses/alt text/.style={% redeclare tagging keylist={tag nodes}{% delay={% if level=0{% if alt text={}{% +node@ttoks/.process={Rw{is root}{##1\ }}, }{}, }{}, }, if phantom={}{% if alt text={}{% if edge label={}{% % debug tagforest/.process={Ow {id}{Node id: ##1}}, % debug tagforest/.process={Ow{content}{No edge label. % Content is ##1}}, node@ttoks/.process={Ow{content}{##1}}, }{% % debug tagforest/.process={Ow {id}{Node id: ##1}}, % debug tagforest/.process={Ow{edge label}{Edge label is ##1}}, % debug tagforest/.process={Ow{content}{Content is ##1}}, node@ttoks/.process={ROOw3{is edge label}{content}{edge label}{\ ##1 ##2 ##3\ }}, }, if={>O_>{n children}{1}}{% % debug tagforest/.process={OOw2 {id}{n children}{Node id: ##1 has ##2 branches}}, node@ttoks+/.process={ORw2{n children}{has branches}{\ ##1 ##2\ }}, delay={% for children={% % debug tagforest/.process={Ow {id}{Node id: ##1}}, % debug tagforest/.process={Ow{n}{Branch no. is ##1}}, +node@ttoks/.process={ROw2{is branch}{n}{\ ##1 ##2\ }}, }, }, }{% if n children=1{% delay={% % debug tagforest/.process={Ow {id}{Node id: ##1 has 1 child}}, !1.+node@ttoks/.process={Rw{is child}{\ ##1\ }}, }, }{% % debug tagforest/.process={Ow {id}{Node id: ##1 is a leaf}}, node@ttoks+/.process={Rw{is leaf}{\ ##1\ }}, }, }, delay n=2{% alt text'/.option=node@ttoks, }, }{}, }, }, }, % \end{macrocode} % \end{choicekey} % \begin{choicekey}{collate~tags~uses} % I don't really like this way of doing this. % I'd rather use e.g.~a \texttt{.choice} key or something for \texttt{collate tags}, but I'm not sure how to do that and have the keylist be public \dots. % \begin{macrocode} collate tags uses/.is choice, collate tags uses/noop/.style={% redeclare tagging keylist={collate tags}{}, }, collate tags uses/alt text/.style={% redeclare tagging keylist={collate tags}{% collate tag/.option=alt text, }, }, % \end{macrocode} % \end{choicekey} % \begin{fcodekey}{collate~tag} % How to collate the tags. % \begin{macrocode} collate tag/.code={% % \tagforest@debug@typeout{Appending toks #1 .}% \forestext@toksapp\tagforest@toks{#1 }% }, % \end{macrocode} % \end{fcodekey} % \begin{choicekey}{tag~tree~uses} % Calculate dimensions used to determine an approximate bounding box size. % \begin{macrocode} tag tree uses/.is choice, tag tree uses/noop/.style={% tag tree/.style={}, }, tag tree uses/alt/.style={% wrong bbox!! tag tree/.style={% tempdimc/.max={>OOw2+d{x}{max x}{####1+####2}}{tree}, tempdimc-/.min={>OOw2+d{x}{min x}{####1+####2}}{tree}, tempdimd/.max={>OOw2+d{y}{max y}{####1+####2}}{tree}, tempdimd-/.min={>OOw2+d{y}{min y}{####1+####2}}{tree}, % debug tagforest={Dimensions (x then y) are }, % debug tagforest/.register=tempdimc, % debug tagforest/.register=tempdimd, % \end{macrocode} % The next line should create the tagging structure and insert the assembled \texttt{alt} text. % \begin{macrocode} % debug tagforest/.process={RRRw3{tag plug}{tempdimc}{tempdimd}{% % Tagging tree now with tag plug=####1, x=####2, y=####3 ...}}, TeX/.process={RRRw3{tag plug}{tempdimc}{tempdimd}{% \tagforest@tag@tree@tag{####1}{####2}{####3}}% }, }, }, % \end{macrocode} % \end{choicekey} % \begin{macrocode} } % \end{macrocode} % \begin{splug}{tagsupport/forest/tag/mmz~alt} % From \pkg{prooftrees}, which will use it from here, hopefully. % \begin{macrocode} \ExplSyntaxOn \socket_new_plug:nnn {tagsupport/forest/tag/mmz}{alt} { \gtoksapp\mmzCCMemo{ \csname cctab_begin:c\endcsname {c_@@_nexpl_at_cctab} \global\advance\tagforest@id~by~1\relax \tex_savepos:D \property_record:ee {tagforest-id\the\tagforest@id} {xpos,ypos} \tex_savepos:D \mode_if_vertical:T { \if@inlabel \mode_leave_vertical: \else \tag_socket_use:n {para/begin} \fi } \tag_mc_end_push: \tag_struct_begin:n } \xtoksapp\mmzCCMemo{ \c_left_brace_str tag=Figure, alt= \c_left_brace_str } \exp_args:NNV \gtoksapp\mmzCCMemo \l_@@_toks_tl \xtoksapp\mmzCCMemo{ \c_right_brace_str \c_right_brace_str } \gtoksapp\mmzCCMemo{ \tag_mc_begin:n {tag=Figure} } \gtoksapp\mmzCCMemo{ \cs_new:cpe {tagforest@mark@pos@\the\tagforest@id} { \@@_pgftikz_tag_bbox:enn {tagforest-id\the\tagforest@id} {#1}{#2} } \tag_struct_gput:ene {\tag_get:n {struct_num}} {attribute} { /O /Layout /BBox~ [ \use:c {tagforest@mark@pos@\the\tagforest@id} ] } \tag_mc_end: \tag_struct_end: \tag_mc_begin_pop:n{} \cctab_end: } } % \end{macrocode} % \end{splug} % \begin{macrocode} \hook_gput_code:nnn {begindocument/before}{.} { \@ifpackageloaded{memoize} { \tag_if_active:T { \mmzset{direct~ccmemo~input=true,} } }{} \@ifpackageloaded{memoize-ext} { \cs_new_eq:NN \@@_property_ref_orig:nn \__mmzx_property_ref_orig:nn \cs_new_eq:NN \c_@@_nexpl_at_cctab \c__mmzx_nexpl_at_cctab }{ \cs_new_eq:NN \@@_property_ref_orig:nn \property_ref:nn \cctab_const:Nn \c_@@_nexpl_at_cctab { \cctab_select:N \c_code_cctab \makeatletter \int_set:Nn \tex_endlinechar:D { 13 } \char_set_catcode_space:n { 9 } \char_set_catcode_space:n { 32 } \char_set_catcode_active:n { 126 } % tilde } } } \ExplSyntaxOff % \end{macrocode} % %^^A >>> % % ^^A \Finale % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %^^A vim: et:tw=0:sw=2:ts=2:foldmethod=marker:fmr=<<<,>>>: