如何压缩扩展 \macro 的代码并将其存储在 expl3 序列中?

如何压缩扩展 \macro 的代码并将其存储在 expl3 序列中?

我正在尝试按照正确的规则重写我拥有的一些代码。使用expl3以下代码,我使用 定义了封装包环境的scontents环境。一切正常,我可以按顺序记录内容,然后我可以访问它,主题是我获取它的方式。原始包有宏来运行环境记录的内容,但是,我无法让它为我工作,不得不几乎直接从包中复制定义并以 的形式编写它。像这样:filecontentsdefmacrofilecontentsdefxparse/expl3scontents\filecontentsexecfilecontentsdefmacroexpl3

% Expand \l_scontents_macro_tmp_tl and pass to seq
\cs_new_protected:Nn \_scontents_macro_to_seq:
  {
    \tl_put_right:Nx \l_tmpa_tl
      {
         \tex_newlinechar:D = 13
         \tex_everyeof:D = { \exp_not:N }
         \exp_not:N \scantokens \exp_after:wN { \tl_use:c { l_scontents_macro_tmp_tl } }
         \tex_newlinechar:D = 10 \scan_stop:
       }
    \tl_put_right:Nx \l_tmpb_tl
      {
        \exp_not:N \_scontents_append_contents:nn 
          { 
            \exp_not:V \l_scontents_name_seq_tl 
          } 
          { \exp_not:V \l_tmpa_tl } 
      }
    \l_tmpb_tl % add to seq
  }

问题是我使用(并滥用)这个:D论点,据我所读,它不应该被占用,我的想法是能够使用一些更短的东西,类似于这个:

% Expand \l_scontents_macro_tmp_tl and pass to seq
\cs_new_protected:Nn \_scontents_macro_to_seq:
  {
    \_scontents_append_contents:nn { \l_scontents_name_seq_tl } 
      { 
        \filecontentsexec \exp_after:wN { \tl_use:c { l_scontents_macro_tmp_tl } }
      }
  }

这是完整的示例文件:

\documentclass{article}
\usepackage{filecontentsdef}[2019/04/20]
\usepackage{xparse}
\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_tl,
    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 environment ( wrap \filecontentsdefmacro ) 
% 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:
  }

% Delaying [key=val] for 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 a group for environment
    \use:c { filecontentsdefmacro } { \l_scontents_macro_tmp_tl } ^^M 
  }
\group_end:

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

% Expand \l_scontents_macro_tmp_tl and pass to seq
\cs_new_protected:Nn \_scontents_macro_to_seq:
  {
    \tl_put_right:Nx \l_tmpa_tl
      {
         \tex_newlinechar:D = 13
         \tex_everyeof:D = { \exp_not:N }
         \exp_not:N \scantokens \exp_after:wN { \tl_use:c { l_scontents_macro_tmp_tl } }
         \tex_newlinechar:D = 10 \scan_stop:
       }
    \tl_put_right:Nx \l_tmpb_tl
      {
        \exp_not:N \_scontents_append_contents:nn 
          { 
            \exp_not:V \l_scontents_name_seq_tl 
          } 
          { \exp_not:V \l_tmpa_tl } 
      }
    \l_tmpb_tl % add to seq
  }

% Execution of the code after finishing the scontent environment 
\cs_new_protected:Nn \scontents_atend_environment:
  {
    \_scontents_macro_to_seq:
    \bool_if:NT \l_scontents_show_env_tl
      {
        \_scontents_getfrom_seq:nn { -1 }{ \l_scontents_name_seq_tl }
      }
    \cs_undefine:N \l_scontents_macro_tmp_tl
  }
\ExplSyntaxOff
\setlength{\parindent}{0pt} % just for the example
\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 !!}

\begin{verbatim}
      (A) verbatim environment
\end{verbatim}
\end{scontents}

Test \verb+\begin{scontents}[save-env=other]+\par

\begin{scontents}[save-env=other]
Using \verb+scontents+ env with \verb+[save-env=other]+, save in  
\verb+other+ with index 1.

\begin{verbatim*}
      (B) verbatim environment
\end{verbatim*}
\end{scontents}

\section*{Show stored contents}
\getstored[1]{other}
\getstored[1]{contents}

\end{document}

我已尝试遵循“规则”(以及我在论坛中学到的知识)编写代码,如果写得不好(与expansion或相关cs),请相应地纠正我。

问候。

答案1

据我所知,您不能使用\filecontentsexec这种方式。您想要的是将该宏的处理结果传递给\_scontents_append_contents:nn。由于\filecontentsexec不是完全可扩展的,所以这行不通。您只能在正常执行模式下使用此宏,而不是将其作为标记列表操作的一部分。

但是,您可以\_scontents_macro_to_seq:稍微缩短宏,因为第一个版本中的材料\l_tmpa_tl是可扩展的。那么就不需要使用临时变量了,您可以直接将扩展结果传递给\_scontents_append_contents:nn

% Expand \l_scontents_macro_tmp_tl and pass to seq
\cs_gset_protected:Nn \_scontents_macro_to_seq:
  {
    \exp_args:NNx \_scontents_append_contents:nn \l_scontents_name_seq_tl 
      {
        \tex_newlinechar:D = 13
        \tex_everyeof:D = { \exp_not:N }
        \exp_not:N \scantokens \exp_after:wN { \tl_use:c { l_scontents_macro_tmp_tl } }
        \tex_newlinechar:D = 10 \scan_stop:
      }
  }

(如果您不熟悉,\exp_args:函数集\exp_args:NNx \A \B \C等同于\A \B {<full expansion of \C>}。)

相关内容