1

How can I pass underscore to \newcommand properly? suggests the solution is to use a zero-argument command that changes the catcode of _, before expanding to the actual command.

That's kind of the opposite of why I'd want to use \NewDocumentCommand, as it's kind of awkward, and also obfuscating argument types.

Is there a way to pass strings containing underscores (file names, by the way) without leaving the comfort of my expl3/xparse/\NewDocumentCommand bubble?

I don't want to use v arguments; it should really function like a normal macro, \includechapter{foo_bar} and not like \includechapter!foo_bar!.


My code currently:

%%% Chapter Inclusion Macros
\RequirePackage{expl3}
\ExplSyntaxOn
% Command to include chapter files, if
% either the exclusive chapter list is empty,
% or said chapter is in there
\cs_set:Npn \cel_includechapter:n #1 {
  % Check whether list is empty
  \clist_if_empty:NTF
  \g_cel_enabled_clist % which list
  {\include{#1/#1}} % if empty, just include
  { % else
    % check whether argument in list of enabled chapters
    \clist_if_in:NnTF 
    \g_cel_enabled_clist % in which list
    {#1} % which element to look for
    {\include{#1/#1}} % if in there
    {\chapter{#1~(currently~disabled)}} %if not in there
  }
}
% user-facing command \includechapter
% includes chaptername/chaptername
% if enabled
\NewDocumentCommand{\includechapter}{m}{
  \cel_includechapter:n{#1}
}
\NewDocumentCommand{\enableChapter}{m}{
  \clist_put_right:Nn \g_cel_enabled_clist {#1}
}
\ExplSyntaxOff

The build breaks when reaching

\includechapter{foo_bar}

with

! Missing $ inserted.
<inserted text>
                $
l.147 \includechapter{foo_bar}
  • Use v-type argument or detokenize. (each has its disadvantage, learn TeX for more details) – user202729 May 06 '22 at 14:31
  • Actually... if egreg answer this, consider answering the other question then close this one as duplicate of that instead. Avoid scattering answers everywhere. – user202729 May 06 '22 at 14:32
  • Turns out there's already a comment under that answer you link to for an... alternative approach. Check out if you want. – user202729 May 06 '22 at 14:34
  • @user202729 What I meant with "staying in my bubble" would be to not use "atypical" v-verbatim-style tricks. Clarified in a question edit! Thanks for pointing it out, though. I'm not quite sure what you mean with "detokenize", but if that involves the zero-argument macro trick that I explicitly would like to avoid for the reasong given in my question, I'm afraid it's not a solution. – Marcus Müller May 06 '22 at 14:41
  • 1
    If it's about the interface, v-type in xparse (unlike \verb command) can use {...} too. – user202729 May 06 '22 at 14:42
  • For detokenize, it's a macro defined in TeX... read https://tex.stackexchange.com/questions/20059/what-are-the-exact-semantics-of-detokenize maybe. TeX is a complex programming language. – user202729 May 06 '22 at 14:42
  • hm, usrguide3.pdf says: Thus a v-type argument is read between two identical char- acters, which cannot be any of %, , #, {, } or ␣., so I don't think {foo_bar} would work: not the same character, and not in the allowed set of characters. – Marcus Müller May 06 '22 at 14:43
  • Read the next statement in that same paragraph. Also you can try it out yourself – user202729 May 06 '22 at 14:44
  • 1
    @user202729 My apologies, yes, you're right. Going to try it out! – Marcus Müller May 06 '22 at 14:46
  • Works, but now have to do more workarounds in other places. Interesting! – Marcus Müller May 06 '22 at 14:47

2 Answers2

3

The problem is where you say

{\chapter{#1~(currently~disabled)}} %if not in there

because an underscore in the file name would trigger math mode.

Solution: change into

{\chapter{\tl_to_str:n {#1}~(currently~disabled)}} %if not in there
egreg
  • 1,121,712
0

The solution in this case is to use v-type arguments:

\NewDocumentCommand{\includechapter}{v}{
  \cel_includechapter:n{#1}
}
\NewDocumentCommand{\enableChapter}{v}{
  \clist_put_right:Nn \g_cel_enabled_clist {#1}
}

This still requires more fixing, since the argument passed through needs to get processed before it can be typeset if it contains underscores.

Luckily, I don't want to use this macro as argument to another function (usrguide3.pdf):

v: Reads an argument ‘verbatim’, between the following character and its next occurrence, in a way similar to the argument of the LATEX 2ε command \verb. Thus a v-type argument is read between two identical characters, which cannot be any of %, \, #, {, } or . The verbatim argument can also be enclosed between braces, { and }. A command with a verbatim argument will produce an error when it appears within an argument of another function.