背景:我正在尝试使用一些分布在多个文件中的开放文本中的练习。我重写了输入机制,并使其运行良好。我可以使用multicols
和enumerate
在两列中垂直打印练习集,但想水平打印它们,因此使用tasks
包。问题如下:
问题:当从 更改为 时enumerate
,tasks
我收到missing \item
错误。我认为这是因为\par
在 I/O 操作中包含 时引入了\task
(tasks
软件包文档将此列为环境与 不同的一种方式enumerate
,\par
不允许 )。如果是这种情况,那么我找不到它被引入的位置。如果不是,那么我不知道发生了什么。
梅威瑟:
\documentclass{article}
\usepackage{xparse}
\usepackage{tasks}
\usepackage{filecontents}
\begin{filecontents*}{numbers_20.tex}
{$5 - (2+3)$}
{$0$}
\end{filecontents*}
\begin{filecontents*}{numbers_21.tex}
{$5 - (2-3)$}
{$6$}
\end{filecontents*}
\begin{filecontents*}{numbersset.tex}
\exinput{numbers_20.tex}
\exinput{numbers_21.tex}
\end{filecontents*}
\ExplSyntaxOn
\ior_new:N \l__exread_ior % read exercise
\ior_new:N \l__exsetread_ior % read exercise set
\ior_new:N \l__allread_ior % read all
%Relevant code below
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\NewDocumentCommand{\exinput}{m}{
\ior_open:Nn \l__exread_ior {#1} % open exercise file
\ior_get:NN \l__exread_ior \l_tmpb_tl % get line
\task\l_tmpb_tl % add task
\ior_close:N \l__exread_ior
}
\NewDocumentCommand{\exsetinput}{m}{
\ior_open:Nn \l__exsetread_ior {#1} % open set file
\ior_map_inline:Nn \l__exsetread_ior {\seq_put_right:Nn \l_tmpb_seq {##1}} % put exercises in a sequence
% if following changed to enumerate, and line 31 to item then works as expected.
\begin{tasks}(2) % start tasks
% seq items are "exinput" (above) and should print \task\blah
\seq_use:Nn \l_tmpb_seq {}
\end{tasks}
\ior_close:N \l__exsetread_ior
\seq_clear:N \l_tmpb_seq
}
\ExplSyntaxOff
\begin{document}
\exsetinput{numbersset}
\end{document}
答案1
问题是tasks
环境的工作方式不太像enumerate
。enumerate
是一个“传统”环境,它会逐行执行代码,直到找到其结尾。tasks
它更像一个命令,抓取环境的内容,然后执行其操作。
环境抓取其主体,然后在每次出现标记时将其拆分\task
。但是,在您的代码中没有这样的标记;只有\seq_use:Nn \l_tmpb_seq {}
。
为了使其正常工作,tasks
您需要先读取所有内容并将其与\task
环境主体中的明确标记一起放入,然后启动tasks
环境。
我修改了你的代码来做到这一点。它使用临时序列\l__exread_tmp_seq
(避免使用\l_tmpa_seq
和其他此类变量;它们只用于短期使用,如快速测试)来存储读取的练习。然后它读取文件(numbersset.tex
)而不进行任何特殊处理。此文件应包含要读取的文件名,每行一个。
代码在文件的每一行上进行迭代,并在每一行中使用\__exread_input_one:Nn
(我将其设为私有函数;您不需要在文件的每一行中使用它,代码会为您完成 :-)。此内部函数还在每个文件的每一行上进行迭代,并将该行附加到序列变量。完成所有这些操作后,序列应包含 中列出的所有文件中的所有行numbersset.tex
,每行前面都有一个\task
标记。
完成后,函数会在启动环境之前x
展开。一旦环境启动,一切都会各就各位,并完成其工作:\seq_use:Nn \l__exread_tmp_seq { }
tasks
tasks
代码如下:
\documentclass{article}
\usepackage{xparse}
\usepackage{tasks}
\usepackage{filecontents}
\begin{filecontents*}{numbers_20.tex}
{$5 - (2+3)$}
{$0$}
\end{filecontents*}
\begin{filecontents*}{numbers_21.tex}
{$5 - (2-3)$}
{$6$}
\end{filecontents*}
\begin{filecontents*}{numbersset.tex}
numbers_20.tex
numbers_21.tex
\end{filecontents*}
\ExplSyntaxOn
\ior_new:N \l__exread_all_ior
\ior_new:N \l__exread_one_ior
\seq_new:N \l__exread_tmp_seq
\cs_new_protected:Npn \__exread_input_one:Nn #1 #2
{
\ior_open:Nn \l__exread_one_ior {#2}
\ior_map_inline:Nn \l__exread_one_ior
{ \seq_put_right:Nn #1 { \task ##1 } }
\ior_close:N \l__exread_one_ior
}
\NewDocumentCommand { \exsetinput } { m }
{
\seq_clear:N \l__exread_tmp_seq
\file_if_exist:nTF {#1}
{
\ior_open:Nn \l__exread_all_ior {#1}
\ior_map_inline:Nn \l__exread_all_ior
{ \__exread_input_one:Nn \l__exread_tmp_seq {##1} }
\ior_close:N \l__exread_all_ior
}
{ \msg_error:nnn { exread } { file-not-found } {#1} }
\use:x
{
\exp_not:N \begin{tasks}(2)
\seq_use:Nn \l__exread_tmp_seq { }
\exp_not:N \end{tasks}
}
}
\msg_new:nnn { exread } { file-not-found }
{ File~`#1'~not~found. }
\ExplSyntaxOff
\begin{document}
\exsetinput{numbersset}
\end{document}