1

I'm trying to create a command that represents the code that is stored in a sequence without executing it (something like \meaning) . When using \cs_log:N \l_scontents_macro_tmp_tl I get in the .log the content recorded in scontents environment before passed to seq.

Can I create a command like \typestored[number]{seqname} that gives me the same result in the document?

Which when run \typestored[1]{contents} take content stored in the sequence and shows in document:

Using \verb+scontents+ env no \verb+[key=val]+, save in \verb+contents+ 
with index $1$\footnote{AND footnotes !!}.%

Prove new \Verb*{ new fvextra whit braces } and environment \verb+Verbatim+

\begin{Verbatim}
(A) verbatim environment                                               %
many space here and percent at end of line                             %
                                many space                   
\end{Verbatim}
No espace after, see \verb+https://tex.stackexchange.com/a/460967/7832+.\par
Use \verb|\relax|.\relax

I've tried to use :

% Fake \meaning
\tl_const:Nn \c_catcode_specials_tl { \  \\ \{ \} \$ \& \# \^ \_ \% \~ }
\cs_new_protected:Npn \_catcode_dospecials:
  {
    \tl_map_inline:Nn \c_catcode_specials_tl
      {
        \char_set_catcode_other:N ##1
      }
  }

\ProvideDocumentCommand{ \typestored }{ O{1} m }
  { 
    \tl_put_right:Nx \l_tmpb_tl
      {
      \_catcode_dospecials:
      \_scontents_getfrom_seq:nn { #1 }{ #2 }
      }
    \tl_show:N \l_tmpb_tl
  }

But it doesn't work, I just want the representation of what's kept in the verbatim style, \l_tmpb_tl does not contain content that is stored in the sequence. This is my MWE.

\documentclass{article}
\usepackage{filecontentsdef}[2019/04/20]
\usepackage{xparse}
\usepackage{fvextra} 
\setlength{\parindent}{0pt} % just for the example
\ExplSyntaxOn
\tl_new:c { l_scontents_macro_tmp_tl }

\keys_define:nn { scontents }
  {
    save-env  .tl_set:N   = \l_scontents_name_seq_tl,
    save-env  .initial:n  = contents,
    show-env  .bool_set:N = \l_scontents_show_env_bool,
    show-env  .initial:n  = false  
  }

% Adapted from https://tex.stackexchange.com/a/215571/7832
\cs_new_protected:Npn \_scontents_append_contents:nn #1 #2
  {
    \seq_if_exist:cF { g_scontents_seq_name_#1_seq }
      {
        \seq_new:c { g_scontents_seq_name_#1_seq }
      }
    \seq_gput_right:cn { g_scontents_seq_name_#1_seq } { #2 }
  }

\cs_new_protected:Npn \_scontents_getfrom_seq:nn #1 #2
  {
    \seq_item:cn { g_scontents_seq_name_#2_seq } { #1 }
  }

\ProvideExpandableDocumentCommand{\getstored}{ O{1} m }
  {
    \_scontents_getfrom_seq:nn { #1 } { #2 }
  }

% Define scontents (wrap \filecontentsdefmacro) whit [key=val] Delaying
% Adapted from https://tex.stackexchange.com/a/487746/7832
\ProvideDocumentEnvironment{ scontents }{}
  {
    \char_set_catcode_active:N \^^M
    \scontents_start_environment:w
  }
  {
    \scontents_stop_environment:
    \scontents_atend_environment:
  }

\cs_new_protected:Npn \scontents_environment_keys:w [#1]
  {
    \keys_set:nn { scontents } { #1 }
  }

% Star environment
\group_begin:
\char_set_catcode_active:N \^^M
\cs_new_protected:Npn \scontents_start_environment:w #1 ^^M
  {
    \tl_if_blank:nF { #1 } { \scontents_environment_keys:w #1 }
    \group_begin: % open group for env
    \use:c { filecontentsdefmacro } { \l_scontents_macro_tmp_tl } ^^M 
  }
\group_end:

% Stop environment
\cs_new_protected:Nn \scontents_stop_environment:
  {
    \endfilecontentsdefmacro 
    \group_end:  % close group for env
  }

% A variant to replace \^^M for \^^J (need by Verb{..} from fvextra)
% https://tex.stackexchange.com/a/8971/7832
\cs_generate_variant:Nn \tl_replace_all:Nnn { Nxx } 

% Expand \l_tmpa_tl and pass to seq
\cs_gset_protected:Nn \_scontents_macro_to_seq:
  { 
    \regex_replace_all:nnN { \^^M } { \^^J } \l_scontents_macro_tmp_tl
    \cs_log:N \l_scontents_macro_tmp_tl
    \exp_args:NNx \_scontents_append_contents:nn \l_scontents_name_seq_tl 
      {
       \exp_not:N \scantokens \exp_after:wN { \tl_use:c { l_scontents_macro_tmp_tl} } %
      }
  }

% Code after scontent environment \seq_item:cn { g_scontents_seq_name_#2_seq } { #1 }
\cs_new_protected:Nn \scontents_atend_environment:
  {
    \_scontents_macro_to_seq:
    \bool_if:NT \l_scontents_show_env_bool
      {
        \_scontents_getfrom_seq:nn { -1 }{ \l_scontents_name_seq_tl }
      }
    \cs_undefine:N \l_scontents_macro_tmp_tl
  }

% Fake \meaning
\tl_const:Nn \c_catcode_specials_tl { \  \\ \{ \} \$ \& \# \^ \_ \% \~ }
\cs_new_protected:Npn \_catcode_dospecials:
  {
    \tl_map_inline:Nn \c_catcode_specials_tl
      {
        \char_set_catcode_other:N ##1
      }
  }

\ProvideDocumentCommand{ \typestored }{ O{1} m }
  { 
    \tl_put_right:Nx \l_tmpb_tl
      {
      \_catcode_dospecials:
      \_scontents_getfrom_seq:nn { #1 }{ #2 }
      }
    %\tl_show:N \l_tmpb_tl
  }

\ExplSyntaxOff
\begin{document}
\section*{Test environment}
Test \verb+\begin{scontents}+ no \verb+[key=val]+\par

\begin{scontents}
Using \verb+scontents+ env no \verb+[key=val]+, save in \verb+contents+ 
with index $1$\footnote{AND footnotes !!}.%

Prove new \Verb*{ new fvextra whit braces } and environment \verb+Verbatim+

\begin{Verbatim}
(A) verbatim environment                                               %
many space here and percent at end of line                             %
                                many space                   
\end{Verbatim}
No espace after, see \verb+https://tex.stackexchange.com/a/460967/7832+.\par
Use \verb|\relax|.\relax
\end{scontents}

\section*{Show stored contents}
XX\getstored[1]{contents}NO space here :)\par

\section*{typestored}
%\typestored[1]{contents} % not work
\end{document}

If I remove the comments from \tl_show:l \l_tmpb_tl and \typestored[1]{contents} I get in log file:

\l_tmpb_tl=\_catcode_dospecials: \_scontents_getfrom_seq:nn {1}{contents}

As @David Carlisle put in his comment, which is not what I want. I hope it contains :

\l_tmpb_tl=Using \verb+scontents+ env no \verb+[key=val]+, save in
\verb+contents+
with index $1$\footnote{AND footnotes !!}.%

Prove new \Verb*{ new fvextra whit braces } and environment \verb+Verbatim+

\begin{Verbatim}
(A) verbatim environment                                               %
many space here and percent at end of line                             %
                                many space
\end{Verbatim}
No espace after, see \verb+https://tex.stackexchange.com/a/460967/7832+.\par
Use \verb|\relax|.\relax

The author of the package provides the macro \filecontentsprint which I try to imitate using the content stored in the sequences. It should look something like this (or similar):

Output Expected

EDIT 1

A first attempt, by defining '\typestored' as follows:

\ProvideDocumentCommand{ \typestored }{ O{1} m }
  { 
    \tl_put_right:Nx \l_tmpb_tl
      {
         \seq_item:cn { g_scontents_seq_name_#2_seq } { #1 }
      }
    \regex_replace_once:nnN { ^ \c{scantokens} } { \c{#2[#1]} } \l_tmpb_tl 
    \tl_show:N \l_tmpb_tl
    \small\texttt{\meaning\l_tmpb_tl}
  }

I get: actual output which is almost exactly what I want, of course, breaks the title of the question (I don't need to modify catcode), I would need to replace Ω and ΩΩ with a regex(I don't know how). I hope this clarifies better what I want (my English is not the best, Spanish is my language).

EDIT 2

Second attempt, I copied the definition of \filecontentsprint from the style file and added the newvbtm package to avoid conflicts with the classic verbatim environment. It's not at all elegant and doesn't follow the line I'm looking for, the code is a bit "obfuscated" for me but it works.

% Fake \meaning, copy direct from filecontensdef package 
% Add \usepackage{newvbtm} to solve conflict whit verbatim nested
\newverbatim{typescverb}{}{}{}{}
\makeatletter
\gdef\filecontentsprint{\filecontentsdef@get\filecontents@print}%
\catcode`\^^M\active%
\gdef\filecontents@print #1{\let\filecontents@print@EOL^^M\let^^M\relax%
\begingroup\toks@\expandafter{#1}\edef\x{\endgroup%
\noexpand\begin{typescverb}^^M%
\the\toks@\@backslashchar end\string{typescverb\string}}\x^^M%
\filecontents@print@resetEOL}%
\gdef\filecontents@print@resetEOL{\let^^M\filecontents@print@EOL}%
\makeatother

\ProvideDocumentCommand{ \typestored }{ O{1} m }
  { 
    \group_begin: 
    \tl_put_right:Nx \l_tmpb_tl
      { 
         \seq_item:cn { g_scontents_seq_name_#2_seq } { #1 }
      }
    \filecontentsprint\l_tmpb_tl
    \group_end:
  }

The output obtained is: output OK

What I was looking for, of course, in doing this you lose the spirit of using expl3 by mixing LaTeX2e code.

Greetings.

  • why can't you just use \meaning that will put essentially the same in the document as \show will show in the log? I must be missing something... – David Carlisle Jun 23 '19 at 18:11
  • I think it's because of the use of \scantokens, the filecontentsdef package plays with catcodes in ways I don't understand and I can't get the result I'm hoping for. – Pablo González L Jun 23 '19 at 18:14
  • it would help if you said what was wrong with the output of \meaning (\meaning returns all characters with catcode 12 or 10 so initial catcodes should not matter) – David Carlisle Jun 23 '19 at 18:16
  • I think I have a problem with concepts, what I hope is that the output looks like the content is inside \begin{verbatim}...\end{verbatim}, I've played a little and get " instead of \, and other symbol... – Pablo González L Jun 23 '19 at 18:25
  • \texttt{\meaning\zzzzz} should be the same except possibly you need to do something about line ends, but that is all. – David Carlisle Jun 23 '19 at 18:26
  • I tried (I had read it from one of your answers) but, it didn't work for me, maybe I have misdeclared \tl_put_right:. – Pablo González L Jun 23 '19 at 18:34
  • how did you make that first log block, if I uncomment the \tl_show:N in your code then it shows a completely different definition \l_tmpb_tl=\_catcode_dospecials: \_scontents_getfrom_seq:nn {1}{contents}. – David Carlisle Jun 23 '19 at 18:51
  • You might also be interested in the functions provided by the l3tl-analysis package – siracusa Jun 24 '19 at 04:53
  • Yes I have read a bit about l3tl-analysis but it's above my level, I think what I want can't be done with sequences. If I understood the documentation, \seq_item: is \exp_not:n, maybe I should switch to l3prop and use \prop_get:cn , but I've never used l3prop. – Pablo González L Jun 24 '19 at 05:37
  • Looking a bit closer at your code, I don't think you can do only with other special characters. You need at least ^^M and spaces to be active to map them to the correct output behavior. Also, {filecontentsdefmacro} should already give you letter-only characters, so the reassignment to other probably isn't necessary. – siracusa Jun 24 '19 at 07:24
  • I'm getting the feeling this is an XY question. You cannot use \scantokens here if you are going to allow verbatim content inside the grabbed content if you then want the grabbed content to be used in normal typesetting: you have to go with the beamer approach of re-reading a temporary file. – Joseph Wright Jun 25 '19 at 07:06
  • I think I got it wrong, I edited the post and tried to clarify the idea. – Pablo González L Jun 25 '19 at 14:34
  • If all you want is the detokenized content, then \seq_get_right:NN \l_my_seq \l_my_tl followed by \tl_to_str:N \l_my_tl will work. I have a feeling you want more than that. – Joseph Wright Jun 26 '19 at 06:51
  • About your last comment, on the spirit of expl3: You are interfacing LaTeX3 code with a 2ε document and using 2ε packages. It's unlikely that you will get away without any 2ε code at all. The LaTeX3 kernel itself uses \@currname, \input@path, \@filelist, \@unexpandable@protect, etc., and that is after the 2ε--3 interface code is already set up. My point is: if the code is doing what you want it to, then you should leave it be. Of course you can do a direct translation of syntax, but you will still need to use \filecontentsdef@get. That or rewrite filecontentsdef in expl3... – Phelype Oleinik Jun 26 '19 at 11:39
  • @PhelypeOleinik : I understand that cannot be completely dispensed with, but, one should try to follow the line proposed by expl3, that is, if something can be written in terms of expl3 it should be done directly. Clearly I should use \filecontentsdef@get , I can try to make translation, something like cs_gset_eq:N\myfcdefget \filecontentsdef@get (which is quite simple), but, the macros used \filecontentsprint are harder to pass through (\edef\x for example), the code would be more readable (and nice). Rewrite filecontentsdef in expl3 is absolutely out of my level :( – Pablo González L Jun 26 '19 at 12:59
  • @PabloGonzálezL Well, a complete rewrite of that bit of code is easy: https://pastebin.com/vppE2uUC. \catcode`\^^M\active becomes \char_set_catcode_active:N \^^M, \edef\x{...}\x becomes \use:x{...}, and a few other changes... I also replaced the \tl_put_right:Nx by \tl_set:Nx because you weren't reusing the contents, so set is better. – Phelype Oleinik Jun 26 '19 at 13:44
  • @PhelypeOleinik : Thank you very much, that's just what I had in mind, if you can turn it into an answer I'd appreciate it (I put a more chord title). I used the newvbtm package because I didn't find a way to use fancyvrb to define a new environment, if you can use this package better, but as it is working perfectly. All this is part of an "idea" I have in mind (https://pastebin.com/1s8tzC22). PD: A macro like a \filecontentsdef@get in expl3 I'd be really pretty. – Pablo González L Jun 26 '19 at 18:17

1 Answers1

3

Since it seems you are keen to follow the expl3 guidelines, I suggest you take a look at “The expl3 package and LaTeX3 programming” (texdoc expl3) and “The LaTeX3 kernel: style guide for code authors” (texdoc l3styleguide). These are two short documents introducing the basic concepts of expl3 and a preferable coding style.

That said, I translated the code in your question to expl3 syntax and changed your code a bit to incorporate the guidelines above.


First, the translation of the code.
This answer is more conceptual than code, so I kept the \newverbatim thing as it was already working. As I said in the comment: you are interfacing LaTeX2ε with LaTeX3, so you will eventually have to put some 2ε in there, mainly if that code comes from a package. Since you are already using \filecontentsdefmacro, then I guess \newverbatim is fine.

I dropped \makeatletter (that’s yelling “I’m LaTeX2ε c@de!” :-). I made a copy of filecontentsdef@get to be used in expl3 code with \cs_new_eq:Nc, so that you don't need to \makeatletter:

\cs_new_eq:Nc \__scontents_fcdef_get:NN { filecontentsdef@get }

Next, we make ^^M active (inside a group) with:

\group_begin:
  \char_set_catcode_active:N \^^M

Now comes the main macro. First, untangling the code a bit:

\gdef\filecontents@print#1{%
  \let\filecontents@print@EOL^^M%
  \let^^M\relax%
  \begingroup%
    \toks@\expandafter{#1}%
    \edef\x{%
  \endgroup%
    \noexpand\begin{typescverb}^^M%
    \the\toks@%
    \@backslashchar end\string{typescverb\string}%
  }\x^^M%
  \filecontents@print@resetEOL%
}

First the code saves the definition of ^^M and makes it a no-op with \let^^M\relax. We do the same:

  \cs_new_protected:Npn \__scontents_fcdef_print:N #1
    {
      \cs_set_eq:NN \__scontents_fcdef_saved_EOL: ^^M
      \cs_set_eq:NN ^^M \scan_stop:

Notice that the scope of \cs_new_protected: is global, so \gdef is already covered. Also the function contains assignments, so it can't expand in expansion-only contexts, thus you need protected.

Now the code saves the expansion of a macro into \toks@, which is then used in an \edef with \the\toks@. This is used because \the\toks@ expands only once, even inside an \edef, thus it allows one to use something like an ε-TeX \unexpanded in TeX (Actually it's the other way around: \unexpanded{<stuff>} does more or less \toks@{<stuff>}\the\toks@ internally to prevent further expansion of <stuff>). The same can be accomplished with (in the \edef) \unexpanded\expandafter{#1}, without needing the \toks@. Since expl3 (and LaTeX2ε, for that matter) requires ε-TeX anyway, there's no harm in that. A more expl3y version of that is \exp_not:V #1, which retrieves the contents of #1 and prevents further expansion.

This bit of code also uses the \begingroup\edef\x{\endgroup<stuff to be expanded>}\x. This is precisely what an x expansion does in expl3, except that the grouping is not used because a private temporary macro is used. So we can just replace all that by \use:x.

Finally, the \@backslashchar end\string{typescverb\string} is replaced by the expl3 equivalent string. Putting all that together:

      \use:x
        {
          \exp_not:N \begin{typescverb} ^^M
          \exp_not:V #1
          \c_backslash_str end \c_left_brace_str typescverb \c_right_brace_str
        }
        ^^M

Finally we reset ^^M and end the group we started back there:

      \cs_set_eq:NN ^^M \__scontents_fcdef_saved_EOL:
    }
\group_end:

Now, some notes on the code in general.
In expl3 there is a clear distinction of internal, code-level, and user-level functions and variables. User level is code defined with xparse's \NewDocumentCommand and the like, which the final user will use in the document.

Code level functions and variables will be used in the implementation of the user level code and across different modules. These should be documented and they are named \<module>_function_name:<args> for functions and \(l|g|c)_variable_name_<type> for variables. Examples of these are \seq_item:Nn and \l_tmpa_tl, respectively.

Finally, internal code is used in the implementation and gory details of the former level. These functions should never be used outside the module they are defined in. These are named \__<module>_macro_name:<args> and \(l|g|c)__variable_name_<type>. Notice the double underscore in both cases. Examples of these are \__seq_item:wNn and \l__char_tmp_tl.

In your code you used many \_scontents..., which is midway between code-level an internal. You should decide: If you expect other programmers to use that then \scontents..., otherwise it is internal code and should be \__scontents.... The same goes for the variables.

You should also remeber to use the proper \cs_new... function. If the definition is expandable and you need it to be expandable, then you need \cs_new:Npn (or similars). In every other case the function should be defined with \cs_new_protected:Npn (or similar). \__scontents_getfrom_seq:nn uses \seq_item:Nn (which is expandable) to fetch contents from a seq variable. If you expect this function to expand in an x-type expansion you can't define it with \cs_new_protected:Npn, or it won't expand. Use just \cs_new:Npn here.

Remember also to use the proper variants depending on what type of argument you are passing to the function. Suppose you define a function, say, \cs_new:Npn \my_use:n #1 { \use:c { my_#1_command_name: } }, to use as \my_use:n { funny } and get \my_funny_command_name: (sorry for the dumb example), TeX allows you to do \tl_set:Nn \l_my_tl { funny } and then \my_use:n { \l_my_tl } because \use:c (\csname) expands \l_my_tl as it goes. But you should really not do that! In this particular case, no problem occurs. However suppose that now you want to disallow an empty argument to \my_use:n, then you define it with:

\cs_new:Npn \my_use:n #1
  {
    \tl_if_empty:nTF {#1}
      { \msg_error:nn { mymodule } { empty-arg } }
      { \use:c { my_#1_command_name: } }
  }

If you use \my_use:n { } the error message is issued, but if you do \tl_clear:n \l_my_tl and then \my_use:n { \l_my_tl } the error will not show up! The correct way to use \my_use:n with \l_my_tl here would be \exp_args:NV \my_use:n \l_my_tl or simply \my_use:V \l_my_tl with the proper variant definition.

Somewhere you had \cs_undefine:N \l__scontents_macro_tmp_tl. That's very wrong! \cs_undefine:N should be used to make a control sequence undefined, but \l__scontents_macro_tmp_tl is a token list. Yes, it does work, and yes, a token list is, deep down, a control sequence, but it's conceptually wrong. A variable, once allocated with \<type>_new:N should exist “forever” and be reused accordingly. What you want here is probably \tl_clear:N to clear the contents of that token list.

The function \_catcode_dospecials: and the variable \c_catcode_specials_tl should be named \__scontents_catcode_dospecials: and \c_scontents_catcode_specials_tl because the module you are creating is scontents, not catcode. Note also that expl3 defines a seq variable \l_char_special_seq which contains the special characters you need, so you don't need to define the sequence yourself, and can simplify the definition of \__scontents_catcode_dospecials: to:

\cs_new_protected:Npn \__scontents_catcode_dospecials:
  { \seq_map_function:NN \l_char_special_seq \char_set_catcode_ignore:N }

but you aren't using it in the code, so I removed it.

You should only use \ProvideDocumentCommand and \DeclareDocumentCommand only when you have a good reason to. In all other cases you should stick to \NewDocumentCommand (Or \RenewDocumentCommand if redefining) to avoid surprises. Usually the “command already defined” error is helpful.

You should also avoid \l_tmpa_tl and other scratch variables defined by the LaTeX3 kernel. They can, of course, be used, but should be only in temporary code (if you are testing something, for example). If the code goes beyond temporary you should declare a variable and use that instead. This will avoid undesired interaction between packages which use the same scratch variable.

I also changed, in the definition of \typestored, \tl_put_right:Nx to \tl_set:Nx because you don't actually want to add to the existing contents of the token list. This would cause problems in longer stretches of code if you forgot to clear the token list (for example, if some other package code used \l_tmpb_tl and forgot to clear it, their contents would creep in your code).


To allow the usage of fancyvrb instead of newvbtm I had to change the timing of the \scantokens a tad. Apparently a verbatim environment like this:

\begin{typescverb}
\scantokens{<stuff>}
\end{typescverb}

(which is what the code was doing), defined with newvbtm will expand the \scantokens (somehow) and things will go as planned. However the same environment defined with fancyvrb does not, and it thinks the whole thing is just one line of code and typesets it as such. To have it working with fancyvrb you need to change to:

\scantokens{
  \begin{typescverb}
  <stuff>
  \end{typescverb}
}

However, to do that you need to remove the \scantokens from around the <stuff>, so I pass the token list variable to a \__scontents_strip_scantokens:N macro which expands the token list, checks if the first token is \tex_scantokens:D. If it is (that is, the token list is \scantokens{<stuff>}) then it expands to \unexpanded{<stuff>}. Otherwise it returns the token list unchanged.


After all that talking, here's your modified code:

\documentclass{article}
\usepackage{filecontentsdef}[2019/04/20]
\usepackage{xparse}
\usepackage{fvextra}
\setlength{\parindent}{0pt} % just for the example
\ExplSyntaxOn
\tl_new:N \l__scontents_macro_tmp_tl
\tl_new:N \l__scontents_tmpa_tl
\keys_define:nn { scontents }
  {
    save-env  .tl_set:N   = \l__scontents_name_seq_tl,
    save-env  .initial:n  = contents,
    show-env  .bool_set:N = \l__scontents_show_env_bool,
    show-env  .initial:n  = false
  }
% Adapted from https://tex.stackexchange.com/a/215571/7832
\cs_new_protected:Npn \__scontents_append_contents:nn #1#2
  {
    \seq_if_exist:cF { g__scontents_seq_name_#1_seq }
      { \seq_new:c { g__scontents_seq_name_#1_seq } }
    \seq_gput_right:cn { g__scontents_seq_name_#1_seq } {#2}
  }
\cs_new:Npn \__scontents_getfrom_seq:nn #1#2
  { \seq_item:cn { g__scontents_seq_name_#2_seq } {#1} }
\NewExpandableDocumentCommand { \getstored } { O{1} m }
  { \__scontents_getfrom_seq:nn {#1} {#2} }
% Define scontents (wrap \filecontentsdefmacro) whit [key=val] Delaying
% Adapted from https://tex.stackexchange.com/a/487746/7832
\NewDocumentEnvironment { scontents } { }
  {
    \char_set_catcode_active:N \^^M
    \scontents_start_environment:w
  }
  {
    \scontents_stop_environment:
    \scontents_atend_environment:
  }
\cs_new_protected:Npn \scontents_environment_keys:w [ #1 ]
  { \keys_set:nn { scontents } {#1} }
\group_begin:
  \char_set_catcode_active:N \^^M
  \cs_new_protected:Npn \scontents_start_environment:w #1 ^^M
    {
      \tl_if_blank:nF {#1} { \scontents_environment_keys:w #1 }
      \group_begin: % open group for env
        \filecontentsdefmacro { \l__scontents_macro_tmp_tl } ^^M
    }
  \cs_new_protected:Nn \scontents_stop_environment:
    {
        \endfilecontentsdefmacro
      \group_end: % close group for env
    }
\group_end:
\exp_args_generate:n { Vx }
\cs_gset_protected:Nn \__scontents_macro_to_seq:
  {
    \regex_replace_all:nnN { \^^M } { \^^J } \l__scontents_macro_tmp_tl
    \cs_log:N \l__scontents_macro_tmp_tl
    \exp_args:NVx \__scontents_append_contents:nn \l__scontents_name_seq_tl
      { \exp_not:N \tex_scantokens:D { \tl_use:N \l__scontents_macro_tmp_tl } }
  }
% Code after scontent environment \seq_item:cn { g__scontents_seq_name_#2_seq } { #1 }
\cs_new_protected:Nn \scontents_atend_environment:
  {
    \__scontents_macro_to_seq:
    \bool_if:NT \l__scontents_show_env_bool
      { \exp_args:NnV \__scontents_getfrom_seq:nn { -1 } { \l__scontents_name_seq_tl } }
    \tl_clear:N \l__scontents_macro_tmp_tl
  }
\DefineVerbatimEnvironment{typescverb}{Verbatim}{}
\cs_new_eq:Nc \__scontents_fcdef_get:NN { filecontentsdef@get }
\quark_new:N \q__scontents_strip_quark
\cs_new:Npn \__scontents_strip_scantokens:N #1
  { \exp_args:NV \__scontents_strip_scantokens:n #1 }
\cs_new:Npn \__scontents_strip_scantokens:n #1
  {
    \tl_if_head_is_N_type:nTF {#1}
      {
        \__scontents_if_scantokens:NwTF #1 \q__scontents_strip_quark
          { \exp_not:o { \use_ii:nn #1 } }
          { \exp_not:n {#1} }
      }
      { \exp_not:n {#1} }
  }
\prg_new_conditional:Npnn \__scontents_if_scantokens:Nw
  #1 #2 \q__scontents_strip_quark { TF }
  {
    \token_if_eq_meaning:NNTF \tex_scantokens:D #1
      { \prg_return_true: }
      { \prg_return_false: }
  }
\group_begin:
  \char_set_catcode_active:N \^^M
  \cs_new_protected:Npn \__scontents_fcdef_print:N #1
    {
      \cs_set_eq:NN \__scontents_fcdef_saved_EOL: ^^M
      \cs_set_eq:NN ^^M \scan_stop:
      \use:x
        {
          \exp_not:N \tex_scantokens:D
            {
              \exp_not:N \begin{typescverb} ^^M
              \__scontents_strip_scantokens:N #1
              \c_backslash_str end \c_left_brace_str typescverb \c_right_brace_str ^^M
            }
        }
      \cs_set_eq:NN ^^M \__scontents_fcdef_saved_EOL:
    }
\group_end:
\NewDocumentCommand { \typestored } { O{1} m }
  {
    \group_begin:
      \tl_set:Nx \l__scontents_tmpa_tl
        { \seq_item:cn { g__scontents_seq_name_#2_seq } {#1} }
      \__scontents_fcdef_get:NN \__scontents_fcdef_print:N \l__scontents_tmpa_tl
    \group_end:
  }
\ExplSyntaxOff
\begin{document}

\section*{Test environment}
Test \verb+\begin{scontents}+ no \verb+[key=val]+\par

\begin{scontents}
Using \verb+scontents+ env no \verb+[key=val]+, save in \verb+contents+ 
with index $1$\footnote{AND footnotes !!}.%

Prove new \Verb*{ new fvextra whit braces } and environment \verb+Verbatim+

\begin{Verbatim}
(A) verbatim environment                                               %
many space here and percent at end of line                             %
                                many space                   
\end{Verbatim}
No espace after, see \verb+https://tex.stackexchange.com/a/460967/7832+.\par
Use \verb|\relax|.\relax
\end{scontents}

\section*{Show stored contents}
XX\getstored[1]{contents}NO space here :)\par

\section*{typestored}
\typestored[1]{contents} % not work
\end{document}
  • Thank you so much for the response and clarification of concepts, in my mind \l__scontents_macro_tmp_tl became \cs as I went through \filecontentsdefmacro. Now I will be able to adapt it to the idea I have in mind, which is to put together a small package (that's why \ProvideDocumentCommand) for a future feature request to the LaTeX3 team. Greetings – Pablo González L Jun 27 '19 at 12:51
  • @PabloGonzálezL As I said, deep down a tl is just a macro. Roughly speaking \tl_set:Nn \l__my_tl {hello} does \def\l__my_tl{hello}, so \cs_undefine:N does what it advertises and it works in \filecontentsdefmacro. And that's one of the problems with interfacing stuff: trying not to mess up data types. However the whole purpose of variables is to be declared once and used throughout the code for the same data type, akin to a variable in other programming languages, so you should never undefine them, only clear. Good luck with your package! – Phelype Oleinik Jun 27 '19 at 13:55
  • With this answer, I think I can finish with my idea, I think I have clarified all my doubts and I can finish writing a package with dignity :). I will read with more attention l3styleguide. Greetings – Pablo González L Jun 27 '19 at 18:26
  • Hi, I tried to adapt your answer using fancyvrb package (which I use in a regular way) by placing \DefineVerbatimEnvironment{typescverb}{Verbatim}{}, but don't respect ^^M and keep looking [opt arg] and you can't prevent the error. If you have some time, could you extend your answer by adding this? Greetings – Pablo González L Jun 29 '19 at 20:18
  • @PabloGonzálezL Hello, Pablo. Sorry for the delay, I could only look at it now. I changed the code a bit to make it work with fancyvrb. Apparently fanvyvrb does things in a different order than newvbtm and the \scantokens stored in the token list doesn't get expanded. I changed the code to remove the \scantokens initially used for typesetting, and then inserted an outer \scantokens that goes around the entire verbatim environment and it seems to work. See if it works; if it does I'll change the answer. Here it is: https://pastebin.com/Cx6Jvg4X – Phelype Oleinik Jun 30 '19 at 22:00
  • It works perfectly, I can even use \fvset{numbers=left}' . You can explain how the__scontents_strip_scantokens:` (apparently that's the magic line) – Pablo González L Jul 01 '19 at 13:04
  • @PabloGonzálezL \__scontents_strip_scantokens:N just removes the \tex_scantokens:D from the token list so that it doesn't appear twice. I edited the answer. – Phelype Oleinik Jul 01 '19 at 16:50
  • The query was for the following, when using \__scontents_strip_scantokens:N this assumes that the content being extracted from the sequence starts with \tex_scantokens:D which is correct when using the {scontents} env, but in my original project I have a command like \ProvideDocumentCommand{ \Scontents }{ +m } { \__scontents_append_to_seq:nn { \l__scontents_name_seq_cmd_tl } {#1} } which doesn't need \tex_scantokens:D. Can \__scontents_strip_scantokens: be modified to work in this case? (Promise this is the last query). Once again thank you for the time invested. – Pablo González L Jul 02 '19 at 01:07
  • @PabloGonzálezL The code actually tested if the first token in #1 was \tex_scantokens:D. However it was a bit of a lazy code and would have undesired side effects in certain circumstances (if #1 contained only one token it would break, if #1 was something like {some}{thing} it would strip braces: something, and a couple other issues). I adopted a more conservative approach and the code will only act (I hope) if the token list is \scantokens{<stuff>}. All other cases it remains as is. I didn't test because I don't have that macro, but if it doesn't work, call me! :-) – Phelype Oleinik Jul 02 '19 at 19:27
  • Thanks Phelype, I tried your solution but it doesn't work with my version, the strange thing is that in your first answer with the newverb package if I could do it, I leave the example code here (https://pastebin.com/bBTJ8uAd) so you can check it when you have some time. Greetings – Pablo González L Jul 02 '19 at 20:22
  • @PabloGonzálezL Here you go: https://pastebin.com/NzgBZy05 I put some comments in the file (I marked them with my name so that you can find them easily). There were a couple of problems, most notably the value of save-cmd being empty (then you got an empty verbatim error), and a missing ^^M which would make one-line contents break. I think it's all working fine now :-) I also added a few more notes to my answer. – Phelype Oleinik Jul 03 '19 at 00:08
  • Hi, sorry to bother you again, but, I have a new question (it's a bit confusing and the code very long) related to the same code. I'm trying to pass a macro given by Ulrich Diez at (https://tex.stackexchange.com/a/472044/7832) but it's written in pure TeX and I don't know how to adapt it to expl3. The current code is (https://gist.github.com/pablgonz/678c3d16909078cc6603946409458f81), it is quite long for the test as it is the complete idea I had in mind. If you have time and give me a hand with this, I would appreciate it very much. Greetings once again. – Pablo González L Jul 15 '19 at 21:31
  • @PabloGonzálezL Hello Pablo! Sorry for the delay: I'm at my parents' since Thursday, and only today I got some time left to check on TeX.SX. Here's your code: https://pastebin.com/yckpyPH1. Most of the code is a direct 2e->l3 translation, so it's rather straightforward. I put some comments in the source for you. I haven't got the time yet to carefully read the code to see what it does: I think it can be optimized using expl3's features. Again, I'm deeply sorry for the delay (you can find my email in the source of my EoTeX class (the link is in my profile), if you want to call me there :-). – Phelype Oleinik Jul 16 '19 at 23:37
  • Thank you very much for the answer, you can place your macro adaptation in (https://tex.stackexchange.com/q/500270/7832), I thought it was appropriate to ask a new question to confuse the topics. I'll add all the modifications you've given me, for now if you have more optimizations you can add, place them in this post. As soon as I have the complete written idea, I will send an email to know your opinion regarding the package I'm writing, if it can be useful for other users and meets the conditions of being well written could make it public. Saludos – Pablo González L Jul 17 '19 at 00:29
  • @PabloGonzálezL Since Siracusa already posted a very good answer to your question, already with the optimizations I mentioned, I'll refrain to post a downgraded version of his answer; I'm sure you'll understand :-) About making your package public, I say: go for it. There isn't a peer-review system for packages uploaded to CTAN, so you can upload basically anything if you deem it worth it. (This explains some of the dubious packages which are on CTAN, but this is a talk for another day :-). If you want feedback I suggest you the LaTeX-L mailing list: more people will see it! – Phelype Oleinik Jul 17 '19 at 17:30