2

When using xparse to define a new environment with an optional argument O{}, the first end of line character is gobbled as can be seen in the following example document:

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

which outputs

abcX

where I would expect

XabcX

There already is this question which is similar, but doesn't make use of active characters. Also the comments in that question don't help here. Neither is prefixing the argument specifier with ! working nor is it working in a newer xparse version (my version is xparse 2019-05-28).

Is there a way to work around this problem?


EDIT: My use case is to have a special verbatim-like environment with some optional setup at the beginning. The problem is that I need to read ahead until I find the end of the first line/the first ^^M to discard anything that is on that line (it's usually empty). This works fine if an optional argument is present, but without an optional argument the first actual line of code is considered the line to be discarded, which is unwanted.

siracusa
  • 13,411
  • 2
    Tokenization takes place when looking ahead: if you want to play catcode tricks you've got to do those before even trying to grab arguments – Joseph Wright Aug 18 '19 at 13:03
  • What is your suggestion if I want special catcodes in the environment's body but not for the optional argument? – siracusa Aug 18 '19 at 13:19
  • @siracusa the environment shouldn't grab any arguments, change the catcodes you need to be changed, then execute a macro at the end of the begin block which grabs the arguments. – Skillmon Aug 18 '19 at 13:57
  • @Skillmon As mentioned, I'd get the wrong catcodes in the argument processing then. The only option I see is to temporarily change the catcodes for the short moment the check for the [ occurs, change it back for the option processing, and afterwards set them active again, which seems quite messy. – siracusa Aug 18 '19 at 15:08
  • 1
    \NewDocumentEnvironment { foo } { } { \group_begin: \char_set_catcode_active:N \^^M \peek_meaning_ignore_spaces:NTF [ { \group_end: \parse_opt_arg:w } { \group_end: \dont_parse_opt_arg:w }, doesn't seem that messy. – Skillmon Aug 19 '19 at 14:30
  • @Skillmon Would you like to add this as an answer? – siracusa Oct 09 '19 at 23:38

1 Answers1

1

As requested, my quick mock-up as an answer. You'll want to first change the category codes before you check for the optional argument's present, then switch it back for the argument grabbing and reset the catcodes for the actual environment.

The following example does a pretty simple grab for the optional argument, as it is done in LaTeX2e, but this is inferior to an O{} argument from xparse as there will be no bracket balancing. You might circumvent that by doing a \NewDocumentCommand \__mycode_parse_arg:w { !O{} } { ... }, but \NewDocumentCommand shouldn't be used for code-level macros (hence the name).

I setup the optional argument such that it changes the definition of \__mycode_end_of_line:, just to show that it's working.

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

enter image description here

Skillmon
  • 60,462
  • I find this question very similar to mine, but I would like to do that with a command. I tried to implement your approach to my problem, but failed in tries. I would be really grateful if you could take a look: https://tex.stackexchange.com/q/546846 – antshar Jun 03 '20 at 15:44
  • @antshar sorry, but it really isn't that similar to your question (on which you still not clarified what you're meaning, imho). – Skillmon Jun 04 '20 at 18:57