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.

6
  • 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
    Commented Aug 18, 2019 at 13:03
  • What is your suggestion if I want special catcodes in the environment's body but not for the optional argument?
    – siracusa
    Commented Aug 18, 2019 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
    Commented Aug 18, 2019 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
    Commented Aug 18, 2019 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
    Commented Aug 19, 2019 at 14:30

1 Answer 1

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

2
  • 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: tex.stackexchange.com/q/546846
    – antshar
    Commented Jun 3, 2020 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
    Commented Jun 4, 2020 at 18:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .