想要在coffin
(后续要用此coffin与其它coffin组合)中构建一个能够保留空格且将每一行都作为一个段落的环境(用命令实现l3doc文档中syntax环境的操作),代码大致如下:
\ExplSyntaxOn
\NewDocumentCommand{\test}{ O{\linewidth} +m }
{
\coffin_clear:N \l_tmpa_coffin
\vcoffin_set:Nnn \l_tmpa_coffin {#1}
{
\small \ttfamily
\obeyspaces
\obeylines
#2
\ignorespacesafterend
}
\coffin_typeset:Nnnnn \l_tmpa_coffin {H}{l}{0pt}{0pt}
}
\ExplSyntaxOff
其中
\obeyspaces
表示:保留其后文本中的空格(其定义为:\def\obeyspaces{\catcode'\ \active}
);\obeylines
表示将其后每一行都作为一个段落(其定义为:\gdef\obeylines{\catcode'\^^M\active \let^^M\par}
)。想要实现的效果为:
\test{ha ha
hahahha
}
ha ha
hahahha
但实际输出却是:
ha ha hahahha
\obeyspaces
与\obeylines
命令似乎并没生效。
请问大佬,我需要怎样改进代码才能完成想要实现的效果?
TeX 在获取命令的参数时,参数的 catcode 已经固定了,多个空格合并为一个,行结束符(一般是换行符)转为空格。所以再使用修改 catcode 的命令(比如 \obeyspaces
)已经无效了。
要么用环境,且不能用 b
参数,要么原样获取参数,然后重新扫描(使用 \scantokens
或 \tl_rescan:nn
及类似命令)。
\documentclass{article}
\begin{document}
\ExplSyntaxOn
\NewDocumentCommand{\test}{ O{\linewidth} +v }
{
\coffin_clear:N \l_tmpa_coffin
\vcoffin_set:Nnn \l_tmpa_coffin {#1}
{ % 注意如果 \parindent>0pt 这里会有缩进
\small \ttfamily
\obeyspaces
\obeylines
\scantokens{#2}
\ignorespacesafterend
}
\coffin_typeset:Nnnnn \l_tmpa_coffin {H}{l}{0pt}{0pt}
}
\ExplSyntaxOff
\noindent % 移除段首缩进
\test{ha ha
hahahha
}
\end{document}
当然也还有其它办法,不过比这个略微复杂。
PS:使用 varwidth
还能有不一样的效果:
\documentclass{article}
\usepackage{varwidth}
\begin{document}
\ExplSyntaxOn
\NewDocumentCommand{\testa}{ O{\linewidth} +v }
{
\coffin_clear:N \l_tmpa_coffin
\hcoffin_set:Nn \l_tmpa_coffin
{
\varwidth [b] { \dim_eval:n {#1} }
\dim_set:Nn \parindent { \c_zero_dim }
\small \ttfamily
\obeyspaces
\obeylines
\scantokens{#2}
\endvarwidth
}
% \coffin_typeset:Nnnnn \l_tmpa_coffin {H}{l}{0pt}{0pt}
\coffin_display_handles:Nn \l_tmpa_coffin { blue }
}
\NewDocumentCommand{\testb}{ O{\linewidth} +v }
{
\coffin_clear:N \l_tmpa_coffin
\vcoffin_set:Nnn \l_tmpa_coffin {#1}
{
\dim_set:Nn \parindent { \c_zero_dim }
\small \ttfamily
\obeyspaces
\obeylines
\scantokens{#2}
\ignorespacesafterend
}
% \coffin_typeset:Nnnnn \l_tmpa_coffin {H}{l}{0pt}{0pt}
\coffin_display_handles:Nn \l_tmpa_coffin { red }
}
\ExplSyntaxOff
\noindent
\testa{ha ha
hahahha
}
\vspace{1cm}
\noindent
\testb{ha ha
hahahha
}
\end{document}
谢谢雾月大佬,我又学到了新知识,没想到还有
\scantokens
这种命令,还能这么操作。另外对于
varwidth
宏包,得到的竟是内容在垂直模式下的自然宽度,太妙了,前几天问的问题:获取逗号分隔列表中空间长度最大的元素,早知道有这个宏包也就不用写这么复杂了,当时我第一想到的就是创建一个获取内容自然宽度的垂直盒子(可是找到的要么是给定宽度的垂直盒子,如\parbox
,要么是默认文本宽,如\vbox
),属实是才疏学浅了