在 中lstlisting
我可以使用\^^M
来表示行的结束morecomment
。是否有类似的字符来查找行的开头?
答案1
下面定义了一个宏\collectverbenv
,您可以在环境定义的开始部分使用它。此宏将开始逐字抓取内容,直到\end
达到(具有相同的环境名称)。该宏支持单个可选参数(必须紧跟在后面,\begin{<env>}
没有空格!
该宏支持指定应在每行开头和结尾添加的内容。对于结尾,以下示例使用\char_generate:nn \endlinechar { 12 }
(这是正确重建带有换行符的列表所必需的),对于开头,它使用AA
。您可以指定任何需要的内容来获取行首。
这在自定义环境中使用mylstlisting
。为此,可选参数将存储在标记列表中,然后作为可选参数转发到嵌套lstlisting
环境。然后使用一点 TeX magic ( \scantokens
) 来lstlisting
收集主体本身及其自己的 catcode 和内容。瞧,您可以检测到一行的开头(因为您可以在那里注入任意标记)。
看这个例子(正如已经说过的,只AA
在每行的开头注入):
\documentclass[]{article}
\usepackage{listings}
\ExplSyntaxOn
\cs_new_eq:NN \__collectverbenv_processor:n \q_nil
\keys_define:nn { collectverbenv }
{
process .code:n = \cs_set:Npn \__collectverbenv_processor:n ##1 {#1}
,bol .tl_set:N = \l__collectverbenv_bol_tl
,eol .tl_set:N = \l__collectverbenv_eol_tl
,optional .tl_set:N = \l__collectverbenv_opt_arg_tl
,ignore .int_set:N = \l__collectverbenv_ignore_int
,no-process .code:n = \cs_set_eq:NN \__collectverbenv_processor:n \q_nil
,no-process .value_forbidden:n = true
}
\NewDocumentCommand \collectverbenvstore { +m }
{
\tl_put_right:Nx \l__collectverbenv_body_tl
{
\exp_not:o \l__collectverbenv_bol_tl
\exp_not:n {#1}
\exp_not:o \l__collectverbenv_eol_tl
}
}
\NewDocumentCommand \collectverbenvretrieve { m }
{
\cs_set_eq:NN #1 \l__collectverbenv_body_tl
}
\NewDocumentCommand \collectverbenv { +m }
{
\keys_set:nn { collectverbenv } {#1}
\tl_clear:N \l__collectverbenv_body_tl
\group_begin:
\__collectverbenv_set_catcodes:
\tl_if_empty:NTF \l__collectverbenv_opt_arg_tl
\__collectverbenv_collect:w
\__collectverbenv_opt_arg:w
}
\cs_new_protected:Npn \__collectverbenv_set_catcodes:
{
\cs_set_eq:NN \do \char_set_catcode_other:N
\dospecials
\char_set_catcode_active:N \^^M
}
\group_begin:
\char_set_catcode_active:N \^^M
\cs_new_protected:Npn \__collectverbenv_collect:w #1 ^^M
{
\__collectverbenv_collect_check_end:n {#1}
\int_compare:nNnTF \l__collectverbenv_ignore_int > \c_zero_int
{
\int_decr:N \l__collectverbenv_ignore_int
}
{
\cs_if_eq:NNTF \__collectverbenv_processor:n \q_nil
{
\tl_put_right:Nx \l__collectverbenv_body_tl
{
\exp_not:o \l__collectverbenv_bol_tl
#1
\exp_not:o \l__collectverbenv_eol_tl
}
}
{ \__collectverbenv_processor:n {#1} }
}
\__collectverbenv_collect:w
}
\group_end:
\exp_args:NNo
\cs_new_protected:Npn \__collectverbenv_opt_arg:w
{
\use_i_ii:nnn \peek_charcode:NTF []
\__collectverbenv_opt_arg_auxi:w
{
\group_end:
\exp_after:wN \cs_set:Npn \l__collectverbenv_opt_arg_tl {}
\group_begin:
\__collectverbenv_set_catcodes:
\__collectverbenv_collect:w
}
}
\cs_new_protected:Npn \__collectverbenv_opt_arg_auxi:w
{
\group_end:
\__collectverbenv_opt_arg_auxii:w
}
\NewDocumentCommand \__collectverbenv_opt_arg_auxii:w { O{} }
{
\exp_after:wN \tl_set:Nn \l__collectverbenv_opt_arg_tl {#1}
\group_begin:
\__collectverbenv_set_catcodes:
\__collectverbenv_collect:w
}
\cs_new_protected:Npn \__collectverbenv_collect_check_end:n #1
{
\str_set:Nn \l_tmpa_str {#1}
\str_remove_all:Nn \l_tmpa_str { ~ }
\str_if_eq:eeT
\l_tmpa_str
{ \token_to_str:N \end { \use:c { @currenvir } } }
\__collectverbenv_collect_end:w
}
\cs_new:Npn \__collectverbenv_collect_end:w #1 \__collectverbenv_collect:w
{
\exp_args:NNNo
\group_end:
\tl_set:Nn \l__collectverbenv_body_tl \l__collectverbenv_body_tl
\exp_args:Ne \end { \use:c { @currenvir } }
}
\tl_new:N \l__collectverbenv_body_tl
\tl_new:N \l_mylstlisting_opt_tl
\NewDocumentEnvironment { mylstlisting } { }
{
\collectverbenv
{
bol = AA % <- use whatever you need as a marker for a start of the line
,eol = \char_generate:nn \endlinechar { 12 } % <- needed to rebuild the list
,ignore = 1 % <- first line (the one containing \begin) is ignored
,optional = \l_mylstlisting_opt_tl % <- collect an optional argument
}
}
{
\group_begin:
\collectverbenvretrieve \l_tmpa_tl
\everyeof={\noexpand}
\exp_args:Nx \scantokens
{
\token_to_str:N \begin{lstlisting}
[{ \exp_not:o \l_mylstlisting_opt_tl }]
\char_generate:nn { \endlinechar } { 12 }
\l_tmpa_tl
\char_generate:nn { \endlinechar } { 12 }
\token_to_str:N \end{lstlisting}
}
\group_end:
}
\ExplSyntaxOff
\begin{document}
\begin{mylstlisting}
\foo
\bar
\end{mylstlisting}
\end{document}