1

I have been working on the implementation of an environment (which never nests) and a command to save different parts of a document and use them within it later using a expl3 list andxparse. So far everything went fine, it works OK, but, when analyzing the .fls file I noticed that something is not right. When writing auxiliary files and then call them from the list this is loaded twice in memory. The code I own (MWE) is this:

% arara: pdflatex : {action: nonstopmode, options: "-recorder"}
\documentclass{article}
\usepackage{environ,xparse,fvextra,xcolor}%

\ExplSyntaxOn

\cs_new:Npn \elementin #1
 {
    \seq_count:c {l_savecontent_content_#1_seq}%
 }

\cs_new:Npn \clearlist #1
 {
    \seq_clear_new:c {l_savecontent_content_#1_seq}%
 }

\NewDocumentCommand{\addcontent}{m +m}
 {
    \savecontent_add_content:nn { #1 } { #2 }
 }

\DeclareExpandableDocumentCommand{\usecontent}{O{1}m}
 {
    \savecontent_use_content:nn { #1 } { #2 }
 }

\cs_new_protected:Npn \savecontent_add_content:nn #1 #2
 {
 \seq_if_exist:cF { l_savecontent_content_#1_seq }
    { \seq_new:c { l_savecontent_content_#1_seq } }
 \__savecontent_add_content:nn { #1 } { #2 }
 }

\cs_new_protected:Npn \__savecontent_add_content:nn #1 #2
 {
    \tl_map_inline:nn { #2 }
  {
    \seq_gput_right:cn { l_savecontent_content_#1_seq } { ##1 }
  }
 }

\cs_new:Npn \savecontent_use_content:nn #1 #2
 {
    \seq_item:cn { l_savecontent_content_#2_seq } { #1 }
 }

\keys_define:nn { scontent }
 {
    save-cmd .tl_set:N   = \l_scontent_cmd_save_tl,%
    show-cmd .bool_set:N = \l_scontent_cmd_show_tl,% 
    save-env .tl_set:N   = \l_scontent_env_save_tl,%
    show-env .bool_set:N = \l_scontent_env_show_tl,%
    show-inf .bool_set:N = \l_scontent_inf_show_tl,%
    name-tmp .tl_set:N   = \l_scontent_tmp_name_tl,% 
    temp-ext .tl_set:N   = \l_scontent_ext_temp_tl,%
    body-env .bool_set:N = \l_scontent_env_body_tl,%
    verb     .meta:n     = { body-env = false },%
    show-all .meta:n     = { show-env = true , show-cmd = true },%
 }

\keys_set:nn { scontent }
 {
    save-cmd = content,%
    show-cmd = false,%
    save-env = content,%
    show-env = false,%
    name-tmp = \jobname,%
    temp-ext = tsc,%
    show-inf = false,%
    body-env = true,%
 }

\NewDocumentCommand{\Setscontent}{ +m }
 {
    \keys_set:nn { scontent } {#1}
 }

\newrobustcmd{\envtolist}[1]{\addcontent{ \l_scontent_env_save_tl }{{#1}}}

\newcounter{outNr}

\tl_new:N \filetolist

\NewEnviron{SAVEcontent}[1]{}

\NewDocumentEnvironment{scontent}{ !o }
 { 
   \group_begin:
   \IfNoValueF {#1} { \keys_set:nn { scontent } {#1} }
   \IfBooleanTF { \l_scontent_env_body_tl } { \SAVEcontent{#1} } 
    { \stepcounter{outNr} \VerbatimOut{\l_scontent_tmp_name_tl-\theoutNr.\l_scontent_ext_temp_tl}}
 }{
   \IfBooleanTF { \l_scontent_env_body_tl }
    {\endSAVEcontent\expandafter\envtolist\expandafter{\BODY}}
    {\endVerbatimOut
    \tl_put_right:Nx  \filetolist { {\envtolist { \exp_not:N \input { 
    \exp_after:wN \l_scontent_tmp_name_tl-\theoutNr.\l_scontent_ext_temp_tl } } } }
    \filetolist
    }
  \IfBooleanT { \l_scontent_env_show_tl } { \usecontent[-1]{ \l_scontent_env_save_tl} }
  \IfBooleanT { \l_scontent_inf_show_tl } 
    {\marginpar{\scriptsize\ttfamily saved ~ in ~ \l_scontent_env_save_tl, ~ index ~ \elementin{\l_scontent_env_save_tl}}}
  \group_end:
 }

\NewDocumentCommand{\Scontent}{!o +m}
 {
  \group_begin:
  \IfNoValueF {#1} { \keys_set:nn { scontent } {#1} }
  \addcontent{ \l_scontent_cmd_save_tl }{{#2}} % pass direct to list
  \IfBooleanT { \l_scontent_cmd_show_tl } { \usecontent[-1]{ \l_scontent_cmd_save_tl} }
  \IfBooleanT { \l_scontent_inf_show_tl } 
    {\marginpar{\scriptsize\ttfamily saved ~ in ~ \l_scontent_cmd_save_tl, ~ index ~ \elementin{\l_scontent_cmd_save_tl}}}
  \group_end:
 }
\ExplSyntaxOff
\setlength{\parindent}{0pt}
\pagestyle{empty}
\begin{document}
\Setscontent{save-env=test-env, save-cmd=test-cmd}
\section{Test scontent env OK}
The following blocks of text will be stored directly in list or in external files and
then referenced using lists, not shown directly.\par

\begin{scontent}[show-inf]
\textcolor{red}{First Text}....use environ
\end{scontent}

\begin{scontent}[verb]
\textcolor{green}{Second Text}...save in \verb+\jobname-1.tsc+
\end{scontent}

\begin{scontent}[verb]
\textcolor{blue}{Third Text}...save in \verb+\jobname-2.tsc+
\end{scontent}

Now we can see that the number of items saved in the list is \elementin{test-env} and 
we can show them in reverse order whit \verb+\usecontent[...]{test-env}+:\par

\usecontent[3]{test-env}\par\vspace{0.5cm}
\usecontent[2]{test-env}\par\vspace{0.5cm}
\usecontent[1]{test-env}\par\vspace{0.5cm}

\section{Test Scontent comand OK}

\Scontent[show-inf]{using a \textcolor{orange}{\texttt{\textbackslash Scontent}}\ command version}
No \verb+\verb+ supported by environ :( [no problem, use env for this] :)\par
\usecontent{test-cmd}
\end{document}

The output of the .fls file is:

$ cat forum.fls |  grep \.tsc
OUTPUT forum-1.tsc
OUTPUT forum-2.tsc
INPUT forum-2.tsc
INPUT forum-2.tsc
INPUT forum-1.tsc
INPUT forum-1.tsc

and should go out:

OUTPUT forum-1.tsc
OUTPUT forum-2.tsc
INPUT forum-1.tsc
INPUT forum-2.tsc

that is to say when executing \usecontent should show only anINPUT in .fls, i think the problem is in the lines of \filetolist or \addtolist that expands \inputwhen saving. An image of how it works:

pdf image generated by pdflatex (TexLive 2018 up)

I have read the documentation but it is at a level far superior to mine and I have not been able to find the solution to my problem. Saludos

PS: Comments to improve the code are welcome

  • 1
    Too much code. Please post a minimal working example. – Henri Menke Jun 2 '18 at 0:56
  • I have tried to reduce it, what is written in the preamble is the minimum, thousand apologies – Pablo González L Jun 2 '18 at 1:09
  • the duplicates you refer to are omnipresent in the fls file (from recorder option). They probably have nothing to do with the details of your code. Perhaps this is artefact of \InputIfFileExists LaTeX macro. – user4686 Jun 2 '18 at 6:22
  • 1
    There are various things that are not 'standard' expl3 here: none of them relate to the question itself ... – Joseph Wright Jun 2 '18 at 6:41
  • @JosephWright: Sorry, I was a little lost, I thought that when executing \filelist I would read the file at that moment, instead of having saved the line{\input{file-1.tsc} and that's why it appeared twice, hence my wrong idea of the use of \exp_not: N and \exp_after: wN. – Pablo González L Jun 2 '18 at 16:32
3

The phenomenon you observe in the fls file (from -recorder) option has presumably nothing to do with your code. It is an artefact from LaTeX's \input when used in \input{file} form.

Consider this

\documentclass{article}
\usepackage{filecontents}
\begin{filecontents}{\jobname-test}
This is a test file
\end{filecontents}
\begin{filecontents}{\jobname-test2}
This is another test file
\end{filecontents}

\begin{document}
\input{\jobname-test}

\input \jobname-test2
\end{document}

and compile it with pdflatex -recorder. This creates an fls file, due to filecontents there will be multiple references to the test file but extracting the relevant lines I get this

....
INPUT filename.aux
INPUT filename.aux
OUTPUT filename.aux
INPUT filename-test.tex
INPUT filename-test.tex
INPUT filename-test2.tex
OUTPUT filename.pdf
....

As you can see the \input filename form creates only one entry but the \input{filename} creates two.

$ latexdef input

\input:
macro:->\@ifnextchar \bgroup \@iinput \@@input 


$ latexdef @iinput

\@iinput:
macro:#1->\InputIfFileExists {#1}{}{\filename@parse {#1}\edef \reserved@a {\noexpand \@missingfileerror {\filename@area \filename@base }{\ifx \filename@ext \relax tex\else \filename@ext \fi }}\reserved@a }

The \InputIfFileExits will open for reading twice the file, the first one to check existence.

On the other hand \@@input is TeX's primitive, which of course opens only once.

  • Thank you very much for the explanation, changed to \@@ input everything goes perfectly. will it improve the runtime of the file? ....Saludos – Pablo González L Jun 2 '18 at 16:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.