Justifique a caixa na margem esquerda mantendo \parindent cola/obedecendo \noindent se presente

Justifique a caixa na margem esquerda mantendo \parindent cola/obedecendo \noindent se presente

Como definir um comando que recebe dois argumentos e a partir do primeiro argumento cria um novo parágrafo onde a margem direita de uma caixa contendo o segundo argumento é justificada na margem esquerda desse parágrafo com o ponto de referência dessa caixa verticalmente no linha de base da primeira linha do texto desse parágrafo?

Se eu fizer

\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

, então (como esperado) \noindentnão tem efeito e a margem direita da caixa contém a frase "Justificado à esquerda?" não é justificado na margem esquerda do parágrafo, mas é justificado à esquerda da letra T.

Se em vez de \leavevmodeI do \noindent, então a margem direita da caixa contendo a frase "Justificado à esquerda?" é justificado tanto na margem esquerda do parágrafo quanto à esquerda da letra, Tmas não haverá \parindent-glue antes da letra, Ta menos que você adicione "à mão" como parte do \Commandprimeiro 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

Então, depois de passar dias analisando frases ambíguas e inescrutáveis ​​do TeXbook, só encontrei maneiras de não alcançar o que desejo e só aprendi por que minhas tentativas não funcionam.

Alguém poderia apontar uma maneira quefaztrabalhar?

Responder1

insira a descrição da imagem aqui

Acho que você quis dizer isso, não totalmente claro:

\long\def\Command#1#2{%
\everypar{\setbox0\lastbox\llap{#2}\box0\everypar{}}#1}

\Command{The text of the paragraph.}{Left justified?}

\Command{\noindent The text of the paragraph.}{Left justified?}

\bye

Responder2

peguei seu comentário

Quase. Obrigado. \Command{\hbox{This box should be part of the paragraph, too} text text}{Left justified?}não dá certo...

sobreA resposta de David Carlisleem conta:

A caixa horizontal de largura \parindentno início do modo horizontal é produzida e colocada sem realizar o gancho \everyhbox.

Assim, você pode criar um mecanismo para definir um \if...-switch caso \everyhbox/ \everyvboxseja acionado antes \everypar:

Crie uma caixa vertical temporária a partir \Commanddo primeiro argumento de.

Ao criar aquela caixa vertical temporária, acrescente aos ganchos \everyhbox/ \everyvboxum token de macro que define globalmente um \if...-switch.
Anexe a cada um dos ganchos \everyhbox/ \everyvboxe \everyparuma diretiva para restaurar todos esses ganchos.

Efeito:

Caso \everyparseja executado antes de \everyvboxou \everyhbox, os ganchos serão restaurados e, portanto, a diretiva para alterar o \if..-switch anexado a \everyhbox/ \everyvboxdesaparece e nunca será executada.

No caso \everyvboxde ou \everyhboxser executado antes \everypar, a diretiva para definir o \if-switch é executada uma vez e todos os ganchos são restaurados.

Como três ganchos ( \everypar, \everyvbox, \everyhbox) estão envolvidos, defini uma rotina recursiva \prependtorestorehooksonde você pode fornecer uma lista de tuplas, o primeiro componente denotando um gancho, o segundo componente denotando tokens para este gancho entregar antes de restaurar todos os ganchos na lista de tuplas e entregar os tokens que o gancho também entregou antes da redefinição.

Você também precisa de alguns cuidados caso o mecanismo \Commandesteja aninhado.

Ressalvas:

  • Anexar a ganchos/restaurar ganchos só funciona enquanto os próprios ganchos não contiverem \outer-tokens. Por exemplo, o código a seguir gera uma mensagem de erro ! 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é acionado ao criar um \hbox/ \vboxnão importa se essa caixa entra no arquivo de saída ou vai para um registro de caixa cujo conteúdo nunca entrará no arquivo de saída. Assim, o mecanismo pode ser enganado colocando, por exemplo, um \setbox-assignment no início do \Commandargumento de '.

  • Um temporário \vboxé criado a partir \Commanddo primeiro argumento de para definir o \if...-switch caso \everyhbox/ \everyvboxseja acionado antes \everypar. Assim, o material do \Commandprimeiro argumento de é processado duas vezes: Uma vez para criar a caixa temporária. Uma vez para criar o parágrafo que deve ir para o arquivo de saída. Pode haver coisas \immediate\writeque você não gostaria de fazer duas vezes. Infelizmente não existe um modo "get-box-properties"/"box-measuring" onde tais coisas possam ser desligadas.

 

\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

insira a descrição da imagem aqui

Para ser honesto:

Não sei por que tudo isso é necessário. No manual \Commandapenas informamos que o TeX muda para o modo vertical antes do processamento #1. O usuário pode decidir por si mesmo se é explícito \leavevmodeou \noindentnecessário para mudar para o modo horizontal.

informação relacionada