![Justifique el cuadro en el margen izquierdo manteniendo \parindent pegamento/obedeciendo \noindent si está presente](https://rvso.com/image/420064/Justifique%20el%20cuadro%20en%20el%20margen%20izquierdo%20manteniendo%20%5Cparindent%20pegamento%2Fobedeciendo%20%5Cnoindent%20si%20est%C3%A1%20presente.png)
Cómo definir un comando que toma dos argumentos y a partir del primer argumento crea un nuevo párrafo donde el margen derecho de un cuadro que contiene el segundo argumento se justifica en el margen izquierdo de ese párrafo con el punto de referencia de ese cuadro verticalmente en el línea de base de la primera línea de texto de ese párrafo?
Si lo hago
\long\def\Command#1#2{\leavevmode\llap{#2}#1}
\Command{The text of the paragraph.}{Left justified?}
\Command{\noindent The text of the paragraph.}{Left justified?}
\bye
, entonces (como se esperaba) \noindent
no tiene ningún efecto y el margen derecho del cuadro que contiene la frase "¿Justificado a la izquierda?" no está justificado al margen izquierdo del párrafo pero sí a la izquierda de la letra T
.
Si en lugar de \leavevmode
lo hago \noindent
, entonces el margen derecho del cuadro que contiene la frase "¿Justificado a la izquierda?" está justificado tanto en el margen izquierdo del párrafo como a la izquierda de la carta, T
pero no habrá \parindent
pegamento antes de la carta T
a menos que lo agregue "a mano" como parte del \Command
primer argumento de ':
\long\def\Command#1#2{\noindent\llap{#2}#1}
\Command{The text of the paragraph.}{Left justified?}
\Command{\noindent The text of the paragraph.}{Left justified?}
\bye
Entonces, después de pasar días analizando frases ambiguas e inescrutables del TeXbook, solo encontré formas de no lograr lo que deseo y solo aprendí por qué mis intentos no funcionan.
¿Alguien podría señalar una manera quehace¿trabajar?
Respuesta1
Respuesta2
Tomé tu comentario
Casi. Gracias.
\Command{\hbox{This box should be part of the paragraph, too} text text}{Left justified?}
no funciona...
enLa respuesta de David Carlisleen cuenta:
La caja horizontal de ancho \parindent
al inicio del modo horizontal se produce y se coloca sin sacar el gancho \everyhbox
.
Por lo tanto, puede crear un mecanismo para configurar un \if...
interruptor en caso de que \everyhbox
/ \everyvbox
se active antes \everypar
:
Cree un cuadro vertical temporal a partir \Command
del primer argumento.
Mientras crea ese cuadro vertical temporal, anteponga a los ganchos \everyhbox
/ \everyvbox
un macro-token que establece globalmente un \if...
interruptor.
Anteponga a cada uno de los ganchos \everyhbox
/ \everyvbox
y \everypar
una directiva para restaurar todos estos ganchos.
Efecto:
En caso de que \everypar
se lleve a cabo antes de \everyvbox
o \everyhbox
, los ganchos se restaurarán y, por lo tanto, la directiva para cambiar el \if..
interruptor adjunto a \everyhbox
/ \everyvbox
desaparecerá y nunca se ejecutará.
En caso de que \everyvbox
o \everyhbox
se lleve a cabo antes \everypar
, la directiva para configurar el \if
interruptor se ejecuta una vez y se restablecen todos los ganchos.
Como hay tres ganchos involucrados ( \everypar
,, ), definí una rutina recursiva en la que puede proporcionar una lista de tuplas, el primer componente indica un gancho y el segundo componente indica tokens para que este gancho se entregue antes de restaurar todos \everyvbox
los ganchos en la lista de tuplas y entregar. las señales que el gancho también entregó antes de redefinir.\everyhbox
\prependtorestorehooks
También necesita algunas precauciones en caso de que el mecanismo \Command
esté anidado.
Advertencias:
Agregar a ganchos/restaurar ganchos solo funciona siempre que los propios ganchos no contengan
\outer
tokens. Por ejemplo, el siguiente código genera un mensaje de error! Forbidden control sequence found while scanning text of \everypar.
:\begingroup \everypar={\problem}% \outer\def\problem{How to overcome the problem?}% \everypar=\expandafter{\the\everypar Again: How to overcome the problem?}% \endgroup \bye
\everyhbox
/\everyvbox
se activa al crear un\hbox
/\vbox
sin importar si ese cuadro llega al archivo de salida o ingresa a un registro de cuadro cuyo contenido nunca llegará al archivo de salida. Por lo tanto, se puede engañar al mecanismo colocando, por ejemplo, una\setbox
asignación al comienzo del\Command
argumento de.\vbox
Se crea un temporal a partir\Command
del primer argumento de para configurar el\if...
interruptor -en caso de que\everyhbox
/\everyvbox
se active antes\everypar
. Así, el material del\Command
primer argumento de se procesa dos veces: una para crear el cuadro temporal. Una vez para crear el párrafo que debería ir al archivo de salida. Puede haber cosas\immediate\write
que no quieras que se hagan dos veces. Desafortunadamente, no existe un modo "obtener propiedades de caja"/"medición de caja" donde esas cosas puedan desactivarse.
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
%\prependtorestorehooks{%
% {{hook 1}{prepend 1}}%
% {{hook 2}{prepend 2}}%
% ...
%}%
\long\def\prependtorestorehooks#1{%
\prependtorestorehookscreraterestore{}{#1}#1\relax
}%
\long\def\prependtorestorehookscreraterestore#1#2#3{%
% #1 - Restore-List created so far
% #2 - entire list
% #3 - next element
\ifx\relax#3\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{\prependtorestorehooksprependtohooks{}{#1}#2\relax}%
{%
\prependtorestorehooksextract#3{#1}{#2}%
}%
}%
\long\def\prependtorestorehooksextract#1#2{%
\expandafter\prependtorestorehooksextractinner\expandafter{\the#1}{#1}%
}%
\long\def\prependtorestorehooksextractinner#1#2#3{%
\prependtorestorehookscreraterestore{#3#2={#1}}%
}%
\long\def\prependtorestorehooksprependtohooks#1#2#3{%
%#1 prepend-list-created so far
%#2 restore-list
%#3 {hook}{prepend}
\ifx\relax#3\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
{#1}{%
\prependtorestorehooksprependtohooksb#3{#1}{#2}%
}%
}%
\long\def\prependtorestorehooksprependtohooksb#1{%
\expandafter\prependtorestorehooksprependtohooksc\expandafter{\the#1}{#1}%
}%
\long\def\prependtorestorehooksprependtohooksc#1#2#3#4#5{%
\prependtorestorehooksprependtohooks{#4#2={#3#5#1}}{#5}%
}%
%------------------------------------------------------------------------------------
\newbox\MyBox
\newif\ifleadingbox
\newif\ifintestbox\intestboxfalse
\newif\ifhookdone\hookdonefalse
\def\firstindent{}%
\long\def\setifleadingboxandfirstindent#1{%
\begingroup
\ifintestbox\else\global\hookdonefalse\global\leadingboxfalse\fi
\setbox\MyBox=\vbox{%
\intestboxtrue
\prependtorestorehooks{%
{{\everypar}{\ifhookdone\else\setbox\MyBox=\lastbox\xdef\firstindent{\the\wd\MyBox}\box\MyBox\global\hookdonetrue\fi}}%
{{\everyhbox}{\ifhookdone\else\global\leadingboxtrue\global\hookdonetrue\fi}}%
{{\everyvbox}{\ifhookdone\else\global\leadingboxtrue\global\hookdonetrue\fi}}%
}%
#1%
}%
\endgroup
}%
\long\def\Command#1#2{%
\par
\setifleadingboxandfirstindent{#1}%
\prependtorestorehooks{{{\everypar}{\setbox\MyBox\lastbox\llap{#2}\box\MyBox}}}%
\ifleadingbox\leavevmode\else\noindent\hbox to\firstindent{\hfill}\fi#1%
}%
\leavevmode
\kern-1in
\noindent test \hfill test \hfill test
\setifleadingboxandfirstindent{a}%
\ifleadingbox some \else no \fi leading h-or vbox.
\ifleadingbox\else Paragraph is indented by: \firstindent\fi
\smallskip\hrule\smallskip
\setifleadingboxandfirstindent{\hbox{a}}%
\ifleadingbox some \else no \fi leading h-or vbox.
\ifleadingbox\else Paragraph is indented by: \firstindent\fi
\smallskip\hrule\smallskip
\setifleadingboxandfirstindent{\vbox{a}}%
\ifleadingbox some \else no \fi leading h-or vbox.
\ifleadingbox\else Paragraph is indented by: \firstindent\fi
\smallskip\hrule\smallskip
\setifleadingboxandfirstindent{\noindent\vbox{a}}%
\ifleadingbox some \else no \fi leading h-or vbox.
\ifleadingbox\else Paragraph is indented by: \firstindent\fi
\smallskip\hrule\smallskip
\noindent {\bf Test 1:}
\Command{The text of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 2:}
\Command{\noindent The text of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 3:}
\Command{\hbox to 5cm{The\hfill wide\hfill text} of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 4:}
\Command{\noindent\hbox to 5cm{The\hfill wide\hfill text} of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 5:}
\Command{\vtop{\hbox to 5cm{The\hfill wide\hfill text}\hbox to 5cm{The\hfill wide\hfill text}} of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 6:}
\Command{\noindent\vtop{\hbox to 5cm{The\hfill wide\hfill text}\hbox to 5cm{The\hfill wide\hfill text}} of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 7:}
\Command{\vbox{\hbox to 5cm{The\hfill wide\hfill text}\hbox to 5cm{The\hfill wide\hfill text}} of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 8:}
\Command{\noindent\vbox{\hbox to 5cm{The\hfill wide\hfill text}\hbox to 5cm{The\hfill wide\hfill text}} of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 9:}
\newdimen\MyDimen
\setbox\MyBox=\hbox{Left justified?}
\MyDimen=\wd\MyBox
\Command{\noindent\kern\MyDimen The text of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 10:}
\Command{\leavevmode\kern\MyDimen The text of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 11:}
\Command{\noindent\kern\MyDimen \hbox{\vbox{\advance\hsize-\MyDimen\Command{\noindent The text of the paragraph.}{Left justified?}}}}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 12:}
\Command{\noindent\kern\MyDimen \hbox{\vbox{\advance\hsize-\MyDimen\Command{The text of the paragraph.}{Left justified?}}}}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 13:}
\Command{\leavevmode\kern\MyDimen \hbox{\vbox{\advance\hsize-\MyDimen\advance\hsize-\parindent\Command{\noindent The text of the paragraph.}{Left justified?}}}}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 14:}
\Command{\leavevmode\kern\MyDimen \hbox{\vbox{\advance\hsize-\MyDimen\advance\hsize-\parindent\Command{The text of the paragraph.}{Left justified?}}}}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 15:}
\Command{\kern\MyDimen The text of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 16:}
% `\Command` starts with `\par`, i.e., by resorting to (restricted) vertical mode. Thus \kerns at the beginning of \Command's first argument in any case are vertical.
\Command{\kern\MyDimen\noindent The text of the paragraph.}{Left justified?}
\smallskip\hrule\smallskip
\noindent {\bf Test 17:}
% `\Command` starts with `\par`, i.e., by resorting to (restricted) vertical mode. Thus \kerns at the beginning of \Command's first argument in any case are vertical.
\Command{\kern\MyDimen\hbox{T}he text of the paragraph.}{Left justified?}
\smallskip\hrule\bigskip
\noindent {\bf Test 18:}
\Command{The text of the paragraph. \par The text of the paragraph. \par The text of the paragraph.\Command{\noindent The text of the paragraph. \par The text of the paragraph. \par The text of the paragraph.}{Left justified?}}{Left justified?}
\smallskip\hrule\bigskip
\noindent{\bf !!!! But: !!!}
\bigskip
\noindent {\bf Test 19:}
\Command{\setbox\MyBox=\hbox{Something to trigger the every-hook}\noindent This text is indented although it should not be indented. The reason is the triggering of {\tt\string\everyhbox} by {\tt\string\setbox...} right at the beginning of {\tt\string\Command}'s first argument.}{Left justified?}
\bye
Para ser sincero:
No sé por qué es necesario todo esto. En el manual de \Command
simplemente diga que TeX cambia al modo vertical antes de procesar #1
. El usuario puede decidir por sí mismo si es explícito \leavevmode
o \noindent
si es necesario cambiar al modo horizontal.