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