1

For instance this solution for macros with lstlisting inside works well, except if the verbatim text contains a tabulation (as shown by the following MCE). Why?

\documentclass{article}
\usepackage{listings}
\usepackage{xparse}

\ExplSyntaxOn \NewDocumentCommand{\code}{m +v}{ \exp_args:Nx \scantokens { \string\begin{lstlisting}[\unexpanded{language=#1,numbers=none,xleftmargin=0.35cm,framesep=0mm}] #2 \string\end{lstlisting} } } \ExplSyntaxOff

\begin{document} \section{Works well}

\code{C}{ Foo bar }

\section{Fails}

\code{C}{ Foo bar } \end{document}

Denis Bitouzé
  • 9,652
  • 4
  • 27
  • 85
  • 1
    Joseph said "it's not a priority" https://chat.stackexchange.com/transcript/message/60060617#60060617 ... although if you make pull request to https://github.com/latex3/latex3/pulls it might be accepted. No guarantee though – user202729 Apr 09 '22 at 12:44
  • 1
    By the way it's possible to include literal tab character in SE post (
    	
    ), however it's quite messy -- if I definitely need it I would probably go to https://tio.run/ pick any language, then use its "generate code" feature.
    – user202729 Apr 09 '22 at 12:46
  • @user202729 (Off topic) I can't see the point of tio.run but that's not a big deal :) – Denis Bitouzé Apr 09 '22 at 14:10
  • (also off topic) I mean, so that you don't have to manually (/with a regex) replace every tab with &#9; and every < with &lt;, in case you want to include a tab character in the code. It's not the main purpose of the site but can be (ab) used to do that – user202729 Apr 10 '22 at 03:34

2 Answers2

2

\dospecials, which sets the special catcodes for verbatim environments, doesn't include a tab character (^^I). TeX then treats the tab as a regular space, and upon seeing that, the verbatim scanner complains. You can add \do\^^I to \dospecials to make it work (in the code below I added it in a group so it has no effect outside your command):

\documentclass{article}
\usepackage{listings}
\usepackage{xparse}

\ExplSyntaxOn \NewDocumentCommand \code { } { \group_begin: \tl_put_right:Nn \dospecials { \do ^^I } \code_aux:nw } \NewDocumentCommand \code_aux:nw { m +v } { \exp_args:Nx \scantokens { \string\begin{lstlisting}[\unexpanded {language=#1,numbers=none,xleftmargin=0.35cm,framesep=0mm}] #2 \string\end{lstlisting} } \group_end: } \ExplSyntaxOff

\begin{document} \section{Works well}

\code{C}{ Foo bar }

\section{Fails (a tabulation is supposed to be between "Foo" and "bar")}

\code{C}{ Foo bar } \end{document}

  • P.S.: Don't use tabs :) – Phelype Oleinik Apr 09 '22 at 12:22
  • Hm I notice you posted an answer there, I think it's better to encloses as duplicate though – you get list of cross-links to relevant questions on the main one (right sidebar) & if there's something new people don't have to copy paste answer on every question & etc. (basically every reason why duplicate feature was created on SO) – user202729 Apr 09 '22 at 12:50
  • @PhelypeOleinik You cannot guarantee users of your macros won't use tabs ;) – Denis Bitouzé Apr 09 '22 at 14:11
  • @user202729 Yes, good that you found a suitable duplicate (and I don't object closing), but not always people remember/find a duplicate before posting an answer (and I definitely didn't remember to look at the sidebar :) – Phelype Oleinik Apr 09 '22 at 22:01
  • @DenisBitouzé Unfortunately, indeed! ;-) That was more of a rant than a serious comment :) – Phelype Oleinik Apr 09 '22 at 22:04
  • Well maybe it's just me who spends extraordinary effort to look for duplicate before writing an answer... but then writing answer isn't free of cost too && you get better linking ↑ – user202729 Apr 10 '22 at 03:33
1

Besides the circumstance that +v-preprocessing of arguments does not take care of the character code of the horizontal tab-character (^^I in TeX's ^^-notation), so that horizontal tabs even with v/+v-type-arguments usually are tokenized as explicit space-tokens of category 10(space) and character code 32 while v/+v-arguments deliberately are implemented to trigger error-messages in case of containing explicit space-tokens, I suggest not to use \exp_args:Nx because that might lead to unwanted expansion of active characters in case of using inputenc. Instead you can use a scratch-macro which reads the phrases \begin{lstlistig} and \end{lstlisting} under modified catcode-régime and then defines the non-scratch-variant.

And you might wish to have the \newline-character-mechanism neutralized, by temporarily giving \newlinechar the value of \endlinechar, while \scantokens does its writing of the fake-file—in order to make sure the lstlisting-environment and your \code-command behave in the same way even when someone played around with the \newlinechar-parameter.

\documentclass{article}
\usepackage{listings}
\usepackage{xparse}

\ExplSyntaxOn \NewDocumentCommand{\code}{m}{ \group_begin: \char_set_catcode_other:N ^^I \innercode{#1} } \group_begin: \NewDocumentCommand{\innercode}{mmm}{ \group_end: \NewDocumentCommand{\innercode}{m +v}{ \group_end: \group_begin: % See the subtle difference between \code and the lstlisting-environment % when turning the following line into a comment: \tex_newlinechar:D=\tex_endlinechar:D % \tex_scantokens:D { #3 #1[language=##1,numbers=none,xleftmargin=0.35cm,framesep=0mm]% ##2 #2%<-here \scantokens attaches an endline-chracter=return } } } \use:n{ \char_set_catcode_other:N \ \char_set_catcode_other:N { \char_set_catcode_other:N } \char_set_catcode_group_begin:N [ \char_set_catcode_group_end:N ] \innercode }[\begin{lstlisting}][\end{lstlisting}][\endgroup~]

\ExplSyntaxOff

\begin{document} \section{Works well}

\code{C}{ Foo bar }

\section{A tabulation is supposed to be between "Foo" and "bar"}

\newlinechar=`\A

\code{C}{ Foo bar Foo bar Foo bar Foo barAFoo bar }

\begin{lstlisting}[language=C,numbers=none,xleftmargin=0.35cm,framesep=0mm] Foo bar Foo bar Foo bar Foo barAFoo bar \end{lstlisting}

\end{document}

enter image description here

Ulrich Diez
  • 28,770
  • I couldn't imagine weird stuff as \group_begin: \NewDocumentCommand{\innercode}{mmm}{ \group_end: \NewDocumentCommand{\innercode}{m +v}{ could be possible :) – Denis Bitouzé Apr 09 '22 at 14:16
  • I couldn't any difference between the cases % \tex_newlinechar:D=-1~ and \tex_newlinechar:D=-1~. – Denis Bitouzé Apr 09 '22 at 14:19
  • 1
    @DenisBitouzé Comment/disable both \tex_newlinechar:D=\tex_endlinechar:D and \tex_newlinechar:D=-1~ so that the \newlinechar-mechanism is enabled and you see a difference between what is delivered by the \code-command and what is delvered by the lstlisting-environment: In the one case you get the last line Foo BarAFoo Bar, in the other case the A is not there but the string is split in two lines at this place. – Ulrich Diez Apr 09 '22 at 14:25