Почему здесь не работает unskip?

Почему здесь не работает unskip?

Я пытаюсь определить макрос, который будет использоваться следующим образом:

\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.
}

Проблема в том, что \unskipне поглощает последний перенос строки. Если я добавляю комментарий (например as in XKCD 1285.%), то он работает как и ожидалось, но разве это не то, что \unskipдолжно быть?

Начальный пробел поглощается правильно. Без \ignorespacesесть подчеркнутый пробел в начале, но \ignorespacesудаляет его. \unskipПредполагается, что он удаляет подчеркнутое утверждение в конце, но не удаляет.

Я понимаю, что это \unskipчто-то вроде \ignorepreviousspace. Это правильно?

МВЭ:

\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}

решение1

\ulineразбирает свой аргумент, чтобы разделить текст на слова. Разобранное слово помещается в рамку, чтобы измерить его ширину и наложить на него маркировку (линия, двойная линия, волна, ...). Поэтому \unskipидет в начале нового слова в начало рамки. Нет места для удаления. Таким образом, это не имеет эффекта.

Помещение\unskip после \uline{...}лучше, потому что он удаляет клей. Но \ulineвставкидваиз них на месте пробела. Первый — подчеркнутый пробел ( \leaders), второй — небольшой отрицательный пробел (-1/300 дюйма), вероятно, добавленный для лучшего перекрытия сегментов подчеркивания.

Добавляем только один \unskipпосле \ulineвдругой, теперь удаленный ответ(видимо только для пользователей 10К+), если конец строки после \thesisудален комментарием, работает случайно. В конце абзаца TeX удаляет последний пробел неявным \unskip.

Решение с двумя\unskip

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

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

Результат

Решение с пакетомtrimspaces

Следующий пример использует package trimspacesдля удаления пробелов перед передачей текста в \uline. Это делает решение более независимым от реализации \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}

решение2

Хайко дал полное описание того, как решить проблему, поэтому я ограничусь комментарием по подвопросу.

Я понимаю, что это \unskipчто-то вроде \ignorepreviousspace. Это правильно?

По сути нет, такое понимание неверно. \unskip и \ignorespacesработают на совершенно разных уровнях (и %до переноса строки снова работают на другом уровне).

Если немного упростить, TeX считывает последовательностьперсонажииз файла, превращаясь затем вжетоны(либо путем считывания группы символов как имени команды, либо путем назначения значений catcode токенам символов) Затем эти списки токенов обрабатываются и в конечном итоге могут создавать горизонтальные или вертикальныеспискинаборных коробок и клея.

%работает на уровнеперсонажи. Если %виден символ a, то остальные символы в этой строке и перенос строки в конце строки пропускаются и вообще не превращаются в токены.

\ignorespacesработает на уровнежетоны. После того, как \ignorespacesвсе пробельные токены (которые обычно игнорируются в вертикальном режиме или добавляют межсловную склейку в горизонтальном режиме) игнорируются до тех пор, пока не будет виден первый не пробельный токен, когда действие команд заканчивается.

\unskipработает на уровнесписки. Если предыдущий элемент, добавленный в текущий горизонтальный список (будь то из пробела или из явного или неявного списка \vskip, \hskipудален из текущего списка и отброшен. (За исключением основного вертикального списка на странице, где вы не можете удалить элементы после добавления, и \unskipэто пустая операция).

Помимо того, что они работают с разными структурами, обратите внимание (что имеет отношение к обработке в конце абзаца в этом вопросе), что \ignorespacesигнорирует любое количество последовательных пробелов, но \unskipудаляет только один узел склеивания. Обычно, конечно, \ignorespacesвидит только один токен пробела для игнорирования, поскольку вам нужно поработать, чтобы получить два последовательных токена как последовательный пробелперсонажитокенизированы как один пробельный токен. Но, например, \ignorespaces\space\spaceбудет игнорировать оба.

Связанный контент