5

this query is related to How to pass an optional argument to an environment with verbatim content? (whose solution did not work in my case) and with Emulating @ifnextchar in expl3 (which is the one I'm trying to adapt).

I have defined an environment (listcontents) using xparse which encapsulates \filecontentsdef (which is verbatim plus \macro) using the argument !O{} and [key = val] which works well if ALWAYS pass the optional argument.

My idea is to be able to write the environment without having to use an empty optional argument [], this is where I am lost, I have read the documentation of \peek_meaning:NF but I do not understand it at all (the \catcodes is confusing for me).

It works correctly if use:

\begin{listcontents}[]
\begin{listcontents}[key=val]
\begin{listcontents}[
                    key=val
                    ]

and I would like to do it in the following way:

\begin{listcontents}
\begin{listcontents}
[not key = value, only a bracket whit text]

that is, if you do not find [key = val] right after }, insert a line ending \^^M and [not key = value, just a square bracket with text] would be recorded by the environment. The package xsim (which is written only usingexpl3) works similar to filecontents, has a code to solve this problem, but, it is very complicated to adapt for me.

This is my sample file:

\documentclass{article}
\usepackage{fancyvrb,filecontentsdef,xparse}
\pagestyle{empty}
\begin{document}
\makeatletter
\ExplSyntaxOn
\keys_define:nn { listcontents }
  {
    save-env   .tl_set:N         = \l_env_save_tl,
    save-env   .initial:n        = content,
    show-env   .bool_set:N       = \l_env_show_tl,
    show-env   .initial:n        = true,
    name-tmp   .tl_set:N         = \l_tmp_name_tl,
    name-tmp   .initial:n        = \jobname.tsc,
  }

\NewDocumentEnvironment{ listcontents }{ !O{} }
  {
  \group_begin:
  \IfNoValueF { #1 } { \keys_set:nn { listcontents } { #1 } }
  %\peek_meaning_ignore_spaces:NF [ { \char_set_catcode_active:N \^^M \char_set_catcode_end_line:N \^^M  \\ }
  %\peek_meaning:NF \c_space_tl { \char_set_catcode_active:N \^^M \char_set_catcode_end_line:N \^^M  \^^M  }
  % Acording a doc of v1.4 this its a correct line 
   \csname filecontentsdef*\endcsname{ \l_tmp_name_tl }{ \l_tmpa_tl }
   }
  {
  \endfilecontentsdef
  \group_end:
  \group_begin:
  \IfNoValueF { #1 } { \keys_set:nn { listcontents } { #1 } }
  \IfBooleanT{ \l_env_show_tl } { \filecontentsexec\l_tmpa_tl }
  \group_end:
  }
\ExplSyntaxOff
\makeatother
\section{[not key = value, just a square bracket with text]}
\begin{listcontents} 
[not key = value, just a square bracket with text]
This is correct for key=val, but space between letters in [...] disappeared
% some comented lines
\begin{verbatim*}
\begin{listcontents}
[not key = value, just a square bracket with text]
\end{verbatim*}
and \verb+[not key = value, just a square bracket with text]+ its not save 
in \verb+\jobname.tsc+ and \verb+\l_tmpa_tl+.
\end{listcontents}

The \textbf{file generate} is:
\VerbatimInput[frame=single]{\jobname.tsc}

\section{Omit a [optional argument] after begin\{listcontents\} }
\begin{listcontents}
This is what I want to happen when omit []
% some comented lines
\begin{verbatim*}
\begin{listcontents}
This is what I want to happen when omit []
% some comented lines
\end{verbatim*}
if ommit \verb*+[ ]+ the first lines and and space between 
letters disappeared, the contents of environments not save 
in \verb+\jobname.tsc+ and \verb+\l_tmpa_tl+.
\end{listcontents}

The \textbf{file generate} is:
\VerbatimInput[frame=single]{\jobname.tsc}
\end{document}

The output looks like this:

output looks Can this be done using xparse/expl3?

regards

  • I think that you just want \NewDocumentEnvironment{ listcontents }{o} and then continue with \IfNoValueF { #1 }{...} in the environment definition. Now both \begin{listcontents}...\end{listcontents} and \begin{listcontents}[show-env=true]...\end{listcontents} are valid. –  Apr 23 '19 at 13:14
  • @Andrew: Thanks, it was the first thing I tried, but using {o} is not enough for what I want. – Pablo González L Apr 23 '19 at 20:27
  • Possibly related: https://tex.stackexchange.com/questions/108897/verbatim-like-environment-with-optional-arguments-poorly-behaved and this https://tex.stackexchange.com/questions/109030/optional-arguments-in-verbatim-environments – Steven B. Segletes Apr 25 '19 at 17:17
  • I still don't understand what you want to do. Does {o!} give what you want? Certainly using {O{}} followed by \IfNoValueF{#1}{...} makes no sense because O sets #1 to {} if no argument is given so \IfNoValueF{#1}{...} will always execute {...}. –  Apr 26 '19 at 03:06
  • @Andrew Have you tried ?, I only get ! LaTeX3 Error: The key 'listcontents / just a square bracket with text' – Pablo González L Apr 26 '19 at 03:13
  • Sorry, it should be {!o}. This works for me and, as far as I understand it, does something that might be what you want - but, as I said, I'm not sure what you want. In any case, your MWE compiles when using {!o}. –  Apr 26 '19 at 03:20
  • @Andrew : I use TeXLive 2019 (fedora / win10) and the MWE does not work as expected...any ideas? – Pablo González L Apr 26 '19 at 03:26
  • 1
    \filecontentsdef juggles with the category code of the endline character; when no optional argument is used, it's too late because the endline character after \begin{listcontents} has already been scanned and converted to a space, which has the effect of not including the following line in the contents; the text is typeset that way because of how \filecontentsdef sets things up. – egreg Apr 26 '19 at 10:07
  • @egreg Ok, I understand, is there no way to "skip" this problem? – Pablo González L Apr 26 '19 at 11:10

1 Answers1

5

You have to delay the search for the optional argument, because otherwise the endline character after \begin{listcontent} is subject to tokenization and converted to a space before \filecontentsdef can act

\documentclass{article}
\usepackage{fancyvrb,filecontentsdef,xparse}
\pagestyle{empty}

\makeatletter
\ExplSyntaxOn
\keys_define:nn { listcontents }
  {
    save-env   .tl_set:N         = \l_env_save_tl,
    save-env   .initial:n        = content,
    show-env   .bool_set:N       = \l_env_show_bool,
    show-env   .initial:n        = true,
    name-tmp   .tl_set:N         = \l_tmp_name_tl,
    name-tmp   .initial:n        = \c_sys_jobname_str.tsc,
    save-macro .bool_set:N       = \l_save_macro_bool,
    save-macro .initial:n        = true,
  }

\NewDocumentEnvironment{ listcontents }{}
  {
   \char_set_catcode_active:N \^^M
   \pedro_start_listcontents:w
  }
  {
   \endfilecontentsdef
   \group_end:
   \IfBooleanT{ \l_env_show_bool } { \filecontentsexec\l_tmpa_tl }
  }

\cs_new_protected:Npn \pedro_listcontents_set:w [#1]
 {
  \keys_set:nn { listcontents } { #1 }
 }

\group_begin:
\char_set_catcode_active:N \^^M
\cs_new_protected:Npn \pedro_start_listcontents:w #1 ^^M
 {
  \tl_if_blank:nF { #1 } { \pedro_listcontents_set:w #1 }
  \group_begin:
  \use:c { filecontentsdef* } { \l_tmp_name_tl } { \l_tmpa_tl } ^^M
  }
\group_end:
\ExplSyntaxOff
\makeatother

\begin{document}

\section{No optional argument}
\begin{listcontents}
[text in brackets]
Some text
% a comment
\begin{verbatim*}
\foo
\end{verbatim*}
Some text
\end{listcontents}

The \textbf{generated file} is:
\VerbatimInput[frame=single]{\jobname.tsc}

\section{Optional argument}
\begin{listcontents}[name-tmp=\jobname-2.tsc]
Some text
% a comment
\begin{verbatim*}
\foo
\end{verbatim*}
Some text
\end{listcontents}

The \textbf{generated file} is:
\VerbatimInput[frame=single]{\jobname-2.tsc}
\end{document}

enter image description here

egreg
  • 1,121,712
  • Thank you very much, it works perfectly, I almost achieved something by copying the xsim code, but yours is much more readable and has allowed me to finish with my project. You can look at this question (https://tex.stackexchange.com/q/487828/7832) related to this topic?...Saludos y Gracias Totales :) – Pablo González L Apr 26 '19 at 21:29
  • egreg: If you have some time, you could place an alternative response that accept {listcontents}[key val whit vertical space]. Greetings. – Pablo González L Jul 02 '19 at 00:47