
При использовании xparse
для определения новой среды с необязательным аргументом O{}
первый символ конца строки поглощается, как можно увидеть в следующем примере документа:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new_protected:Npn \__my_end_of_line: { X }
\NewDocumentEnvironment{mycode}{ !O{} }{
\char_set_catcode_active:N \^^M
\char_set_active_eq:nN {`\^^M} \__my_end_of_line:
}{}
\ExplSyntaxOff
\begin{document}
\begin{mycode}
abc
\end{mycode}
\end{document}
который выводит
abcX
где я и ожидал
XabcX
Там уже естьэтот вопросчто похоже, но не использует активные символы. Комментарии в этом вопросе также не помогают здесь. Ни префикс спецификатора аргумента с !
не работает, ни это не работает в более новой xparse
версии (моя версия xparse 2019-05-28
).
Есть ли способ обойти эту проблему?
РЕДАКТИРОВАТЬ:Мой вариант использования — иметь специальную среду типа verbatim с некоторой необязательной настройкой в начале. Проблема в том, что мне нужно читать вперед, пока я не найду конец первой строки/первую, ^^M
чтобы отбросить все, что находится на этой строке (обычно она пуста). Это работает нормально, если присутствует необязательный аргумент, но без необязательного аргумента первая фактическая строка кода считается строкой, которая должна быть отброшена, что нежелательно.
решение1
Как и просили, мой быстрый макет в качестве ответа. Сначала вам нужно будет изменить коды категорий, прежде чем проверять наличие необязательного аргумента, затем переключить его обратно на захват аргумента и сбросить коды катов для фактической среды.
Следующий пример делает довольно простой захват для необязательного аргумента, как это сделано в LaTeX2e, но это хуже O{}
аргумента из xparse
, поскольку не будет балансировки скобок. Вы можете обойти это, сделав \NewDocumentCommand \__mycode_parse_arg:w { !O{} } { ... }
, но \NewDocumentCommand
не следует использовать для макросов на уровне кода (отсюда и название).
Я настраиваю необязательный аргумент таким образом, чтобы он изменял определение \__mycode_end_of_line:
, просто чтобы показать, что это работает.
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new_protected:Npn \__mycode_end_of_line: { X }
\cs_new_protected:Npn \__mycode_real_begin:
{
\__mycode_catcode_setup:
\char_set_active_eq:nN { `\^^M } \__mycode_end_of_line:
}
\cs_new_protected:Npn \__mycode_parse_arg:w [ #1 ]
{
% do whatever with the optional argument
\cs_set_protected:Npn \__mycode_end_of_line: { #1 }
\__mycode_real_begin:
}
\cs_new_protected:Npn \__mycode_catcode_setup:
{
\char_set_catcode_active:N \^^M
}
\NewDocumentEnvironment { mycode } {}
{
\group_begin:
\__mycode_catcode_setup:
\peek_meaning:NTF [
{
\group_end:
\__mycode_parse_arg:w
}
{
\group_end:
\__mycode_real_begin:
}
}
{}
\ExplSyntaxOff
\begin{document}
\begin{mycode}
abc
\end{mycode}
\begin{mycode}[Y]
abc
\end{mycode}
\end{document}