Por que cancelar o salto não está funcionando aqui?

Por que cancelar o salto não está funcionando aqui?

Estou tentando definir uma macro para ser usada da seguinte forma:

\usepackage[normalem]{ulem}
\newcommand{\thesis}[1]{\uline{\ignorespaces #1\unskip}}
% underlining required by school - I know, I know

% later...

\thesis{
  This is the beginning of a multi-line thesis statement.
  I use one sentence on each line throughout my document.
  Thus, the thesis is broken as in XKCD 1285.
}

O problema é que \unskipnão engole a quebra de linha final. Se eu adicionar um comentário (como as in XKCD 1285.%), ele funcionará conforme o esperado, mas não é isso que \unskipdeveria ser feito?

O espaço inicial é engolido corretamente. Sem \ignorespaceshá um espaço sublinhado no início, mas \ignorespacesremove-o. O \unskipdeveria remover a instrução sublinhada no final, mas não o faz.

Meu entendimento é que \unskipé mais ou menos assim \ignorepreviousspace. Isso está correto?

MWE:

\documentclass{article}
\usepackage[normalem]{ulem}
\newcommand{\thesis}[1]{\uline{\ignorespaces #1\unskip}}
\begin{document}
\thesis{
  Foo.
  Bar.
  Baz.
} % comment at end of previous line gives desired output
\end{document}

Responder1

\ulineanalisa seu argumento para dividir o texto em palavras. Uma palavra analisada é colocada em uma caixa para medir sua largura e sobrepô-la com as marcações (linha, linha dupla, onda, ...). Portanto, \unskipvai do início de uma nova palavra ao início de uma caixa. Não há espaço para remover. Portanto, não tem efeito.

Colocando\unskip depois \uline{...}é melhor porque remove a cola. Mas \ulineinserçõesdoisdeles no lugar de um espaço. O primeiro é o espaço sublinhado ( \leaders), o segundo é um pequeno espaço negativo (-1/300 pol.), provavelmente adicionado para obter uma melhor sobreposição dos segmentos sublinhados.

Adicionando apenas um \unskipdepois \ulinenooutra resposta agora excluída(visível apenas para usuários com mais de 10 mil usuários), se o final da linha após \thesisfor removido por um comentário, funciona por acidente. No final de um parágrafo, o TeX remove o último espaço por um \unskip.

Solução com dois\unskip

\documentclass{article}
\usepackage[normalem]{ulem}
\newcommand*{\thesis}[1]{%
  \uline{\ignorespaces #1}%
  \unskip\unskip
}

\begin{document}
Before. \thesis{
  Foo.
  Bar.
  Baz.
} After.
\end{document}

Resultado

Solução com pacotetrimspaces

O próximo exemplo usa package trimspacespara remover os espaços antes de passar o texto para \uline. Isso torna a solução mais independente da implementação do \uline.

\documentclass{article}
\usepackage[normalem]{ulem}
\usepackage{trimspaces}
\makeatletter
\newcommand*{\thesis}[1]{%
  \def\thesis@text{#1}%
  \trim@spaces@in\thesis@text
  \expandafter\uline\expandafter{\thesis@text}%
}
\makeatother

\begin{document}
Before. \thesis{
  Foo.
  Bar.
  Baz.
} After.
\end{document}

Responder2

Heiko deu uma descrição completa de como resolver o problema, então vou me restringir a comentar a subquestão

Meu entendimento é que \unskipé mais ou menos assim \ignorepreviousspace. Isso está correto?

Basicamente não, esse entendimento não está correto. \unskip e \ignorespacestrabalhar em níveis completamente diferentes (e %antes que uma quebra de linha funcione novamente em outro nível).

Um pouco simplificado, o TeX lê uma sequência depersonagensdo arquivo, transformando-o então emfichas(seja lendo um grupo de caracteres como um nome de comando ou atribuindo valores de catcode a tokens de caracteres). Em seguida, essas listas de tokens são processadas e podem eventualmente produzirlistasde caixas compostas e cola.

%funciona ao nívelpersonagens. Se a %for visto, o restante dos caracteres nessa linha e a quebra de linha no final da linha serão ignorados e não serão transformados em tokens.

\ignorespacesfunciona ao nívelfichas. Depois que \ignorespacestodos os tokens de espaço (que normalmente são ignorados no modo vertical ou adicionam cola entre palavras no modo horizontal) são ignorados até que o primeiro token que não seja de espaço seja visto quando os comandos afetam as extremidades.

\unskipfunciona ao nívellistas. Se o item anterior adicionado à lista horizontal atual (seja proveniente de um espaço ou de um explícito ou implícito \vskipou \hskipfor removido da lista atual e descartado. (Exceto na lista vertical principal da página onde você não pode remover itens depois de adicionados , e \unskipé autônomo).

Além do fato de estarem operando em estruturas diferentes, observe (o que é relevante para o processamento no final de um parágrafo nesta questão) que \ignorespacesignora qualquer número de espaços consecutivos, mas \unskipremove apenas um nó de cola. Normalmente, é claro, \ignorespacessó há um token de espaço para ignorar, pois você precisa trabalhar para obter dois tokens consecutivos como espaço consecutivopersonagenssão tokenizados como um token de espaço único. Mas, por exemplo, \ignorespaces\space\spaceignoraria ambos.

informação relacionada