Faça com que o xparse não engula o caractere de fim de linha no argumento opcional

Faça com que o xparse não engula o caractere de fim de linha no argumento opcional

Ao usar xparsepara definir um novo ambiente com um argumento opcional O{}, o primeiro caractere de fim de linha é engolido, como pode ser visto no documento de exemplo a seguir:

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

quais saídas

abcX

onde eu esperaria

XabcX

Já existeessa questãoque é semelhante, mas não faz uso de caracteres ativos. Além disso, os comentários nessa pergunta não ajudam aqui. Nem prefixar o especificador de argumento está !funcionando nem está funcionando em uma xparseversão mais recente (minha versão é xparse 2019-05-28).

Existe uma maneira de contornar esse problema?


EDITAR:Meu caso de uso é ter um ambiente literal especial com alguma configuração opcional no início. O problema é que preciso ler adiante até encontrar o final da primeira linha/a primeira ^^Mpara descartar qualquer coisa que esteja nessa linha (geralmente está vazia). Isso funciona bem se um argumento opcional estiver presente, mas sem um argumento opcional, a primeira linha real do código é considerada a linha a ser descartada, o que é indesejado.

Responder1

Conforme solicitado, meu rápido modelo como resposta. Você desejará primeiro alterar os códigos de categoria antes de verificar a presença do argumento opcional e, em seguida, alterná-lo novamente para a captura do argumento e redefinir os códigos de gato para o ambiente real.

O exemplo a seguir faz uma captura bastante simples do argumento opcional, como é feito no LaTeX2e, mas isso é inferior a um O{}argumento from xparse, pois não haverá balanceamento de colchetes. Você pode contornar isso fazendo um \NewDocumentCommand \__mycode_parse_arg:w { !O{} } { ... }, mas \NewDocumentCommandnão deve ser usado para macros em nível de código (daí o nome).

Eu configurei o argumento opcional de forma que ele altere a definição de \__mycode_end_of_line:, apenas para mostrar que está funcionando.

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

insira a descrição da imagem aqui

informação relacionada