Estoy intentando utilizar una estructura de datos de pila (como se explica aquí:¿Empujar/pop o guardar una longitud/dimensión?) para almacenar los distintos nombres de un conjunto de nombres de nodos de tikzmark (como se explica entikzmark
manual) dispersos a lo largo de mi texto.
Por separado, la implementación de la pila (WE1) y \tikzmark
(WE2) funcionan perfectamente, pero sus comportamientos combinados de alguna manera chocan con múltiples errores.
Por mi vida, no puedo descubrir qué está saliendo mal cuando intento pasar los elementos de datos de la pila emergente como nombres de nodos dentro de un \tikzmark
comando (MWE a continuación). ¿Es este un problema que surge de que mi código LaTeX no evalúa inmediatamente los comandos \pop (he intentado jugar con ellos \expandafter
y \edef
sin éxito...)? También intenté pasar \pop{\latexstack}
a a \newcommand{}
, pero tampoco logré que ese método funcione...
MWE[Comportamientos combinados incorrectos...]
\documentclass{article}
\usepackage{blindtext, tikz}
\newtoks\latexstack
\latexstack={\empty}
\def\push#1#2{
\begingroup
\toks0={{#1}}
\edef\act{\endgroup\global#2={\the\toks0 \the#2}}\act
}
\def\pop#1{
\begingroup
\edef\act{\endgroup\noexpand\SplitOff\the#1(tail)#1}\act
}
\def\SplitOff#1#2(tail)#3{
\ifx#1\empty
\errhelp{Attempting to pop empty stack #3.}
\errmessage{You can't pop an empty stack.}
\else
#1\global#3={#2}
\fi
}
\newcommand\tikzmark[1]{\tikz[overlay,remember picture] \node(#1) {};}
\begin{document}
\push{A1}{\latexstack}
\push{B2}{\latexstack}
\blindtext \tikzmark{\pop{\latexstack}}\\
\blindtext \tikzmark{\pop{\latexstack}}\\
\begin{tikzpicture}[remember picture,overlay,scale=0.5]
\draw[red] (A) -- (B);
\end{tikzpicture}
\end{document}
WE1[Comportamiento correcto de la estructura de datos de la pila: A1, B2, C3 y D4 se insertan y extraen secuencialmente de la estructura de datos]
\documentclass{article}
\newtoks\latexstack
\latexstack={\empty}
\def\push#1#2{
\begingroup
\toks0={{#1}}
\edef\act{\endgroup\global#2={\the\toks0 \the#2}}\act
}
\def\pop#1{
\begingroup
\edef\act{\endgroup\noexpand\SplitOff\the#1(tail)#1}\act
}
\def\SplitOff#1#2(tail)#3{
\ifx#1\empty
\errhelp{Attempting to pop empty stack #3.}
\errmessage{You can't pop an empty stack.}
\else
#1\global#3={#2}
\fi
}
\begin{document}
\push{A1}{\latexstack}
\push{B2}{\latexstack}
\push{C3}{\latexstack}
\push{D4}{\latexstack}
\pop{\latexstack},\\
\pop{\latexstack},\\
\pop{\latexstack},\\
\pop{\latexstack}.
\end{document}
WE2[Comportamiento correcto de \tikzmark
: Los puntos A y B están marcados y conectados entre sí con una línea roja]
\documentclass{article}
\usepackage{blindtext, tikz}
\newcommand\tikzmark[1]{\tikz[overlay,remember picture] \node(#1) {};}
\begin{document}
\blindtext \tikzmark{A}\\
\blindtext \tikzmark{B}
\begin{tikzpicture}[remember picture,overlay,scale=0.5]
\draw[red] (A) -- (B);
\end{tikzpicture}
\end{document}
Respuesta1
Creo que el problema aquí es la expansión. Cuando TikZ crea nodos, el nombre del nodo se expande completamente usando \edef
.
Suponiendo el código original de los OP, considere lo siguiente
\push{A1}{\latexstack}
\push{B2}{\latexstack}
\edef\nodename{\pop{\latexstack}}
\show\nodename
Esto ilustra la expansión completa y dará (en el archivo de registro):
! Undefined control sequence.
\pop #1^^@- \begingroup \edef \act
{\endgroup \noexpand \SplitOff \the #1(tail...
l.36 \edef\nodename{\pop{\latexstack}
}
! Undefined control sequence.
\pop ... \noexpand \SplitOff \the #1(tail)#1}\act
l.36 \edef\nodename{\pop{\latexstack}
}
> \nodename=macro:
-> \begingroup \edef {\endgroup \SplitOff {B2}{A1}\empty (tail)\latexstack }.
l.37 \show\nodename
Tenga en cuenta que el problema esnoeso \act
no está definido. Los errores desaparecerán si \let\act=\relax
se colocan en algún lugar del preámbulo, pero el contenido \nodename
sigue siendo un montón de código LaTeX, no el nombre del nodo deseado.
Una solución es tener un \popto
comando que muestre el valor en la parte superior de la pila en una macro que luego se use como nombre de nodo (NB. También reimplementé la \push
macro):
\def\push#1#2{%
\def\tmp{{#1}}%
\expandafter\expandafter\expandafter%
#2\expandafter\expandafter\expandafter{\expandafter\tmp\the#2}%
\ignorespaces}
\def\popto#1#2{%
\expandafter\SplitOffTo\the#1\stop{#1}{#2}%
}
\def\SplitOffTo#1#2\stop#3#4{%
\def\tmp{#1}%
\ifx\tmp\empty%
\errhelp{Attempting to pop empty stack #3.}%
\errmessage{You can't pop an empty stack.}%
\else%
\def#4{#1}\global#3={#2}%
\fi%
}
Esto se puede utilizar así:
\newtoks\latexstack
\latexstack={\empty}
\push{A1}{\latexstack}
\push{B2}{\latexstack}
\popto{\latexstack}{\nodename}
\tikzmark{\nodename}
\show\nodename
Some text \tikzmark{\nodename}
\popto{\latexstack}{\nodename}
\tikzmark{\nodename}
\show\nodename
Some more text \tikzmark{\nodename}
El archivo de registro mostrará (algo como) esto:
> \nodename=macro:
->B2.
l.31 \show\nodename
> \nodename=macro:
->A1.
l.34 \show\nodename
Si todo eso parece un poco molesto, entonces \popto
todo podría estar vinculado en una \tikzmarkpop
macro:
\documentclass[border=5]{standalone}
\usepackage{tikz}
\def\push#1#2{%
\def\tmp{{#1}}%
\expandafter\expandafter\expandafter%
#2\expandafter\expandafter\expandafter{\expandafter\tmp\the#2}%
\ignorespaces}
\def\popto#1#2{%
\expandafter\SplitOffTo\the#1\stop{#1}{#2}%
}
\def\SplitOffTo#1#2\stop#3#4{%
\def\tmp{#1}
\ifx\tmp\empty%
\errhelp{Attempting to pop empty stack #3.}%
\errmessage{You can't pop an empty stack.}%
\else%
\def#4{#1}\global#3={#2}%
\fi}
\def\tikzmarkpop#1{%
\popto{#1}{\nodename}%
\tikz[remember picture, overlay]\coordinate(\nodename);}
\newtoks\latexstack
\latexstack={\empty}
\begin{document}
\push{A1}{\latexstack}
\push{B2}{\latexstack}
Some text\tikzmarkpop{\latexstack}
Some more text\tikzmarkpop{\latexstack}
\begin{tikzpicture}[remember picture, overlay]
\draw [red, <->] (A1) -- (B2);
\end{tikzpicture}
\end{document}