Заставить xparse не поглощать символ конца строки в необязательном аргументе

Заставить xparse не поглощать символ конца строки в необязательном аргументе

При использовании 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}

введите описание изображения здесь

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