Я пытаюсь определить макрос, который будет использоваться следующим образом:
\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
будет игнорировать оба.