![添加 enumitem 键以嵌套基于 lualatex 的环境,该环境可自动对列表进行标点](https://linux22.com/image/443063/%E6%B7%BB%E5%8A%A0%20enumitem%20%E9%94%AE%E4%BB%A5%E5%B5%8C%E5%A5%97%E5%9F%BA%E4%BA%8E%20lualatex%20%E7%9A%84%E7%8E%AF%E5%A2%83%EF%BC%8C%E8%AF%A5%E7%8E%AF%E5%A2%83%E5%8F%AF%E8%87%AA%E5%8A%A8%E5%AF%B9%E5%88%97%E8%A1%A8%E8%BF%9B%E8%A1%8C%E6%A0%87%E7%82%B9.png)
我编写了一个基于 lua 的函数来自动对分项列表进行标点,如下所示:
- 一
;
- 二
; and
- 三
.
etc会自动添加。我可以将其作为or环境;
内的命令或环境应用。但我更希望将其作为键传递给 enumitem 提供的可选 key-val 参数。例如。请参阅下面的 MWE。我收到的错误是itemize
enumerate
autopunc
\begin{itemize}[autopunc]
Error: You can't use \spacefactor' after \advance.\@->\spacefactor
PS 我愿意听取关于如何更好地实现自动标点列表的建议。基于 Lua 的想法更受欢迎。
\documentclass{scrartcl}
\usepackage{luacode}
\usepackage{enumitem}
\begin{luacode*}
function AutoPuncItems(s, btwn, seclast, last) -- add btwn and sec and last options
local it = '\\item'
local s_item = '%s*'..it
btwn = btwn or ';'
btwn = btwn..' '..it
seclast = seclast or '; and'
seclast = seclast..' '..it
last = last or '.'
local _, n_matches = string.gsub(s, s_item, "") -- find num items
s, _ = string.gsub(s, s_item, seclast, n_matches) -- replace all items with second last type
s, _ = string.gsub(s, seclast, btwn, n_matches-1) --replace all but last(ie second last) with the between
s, _ = string.gsub(s, '%s*xxxENDxxx', last) -- add the final char
s = string.sub(s, #btwn-#it+1, #s)
tex.print(s)
end
\end{luacode*}
\NewDocumentCommand{\AutoPuncItems}{ O{;} O{; and} O{.} m }{
\luadirect{AutoPuncItems(
\luastringN{#4xxxENDxxx},
\luastringN{#1},
\luastringN{#2},
\luastringN{#3}
)}
}
\NewDocumentEnvironment{AutoPuncItemize}{ O{;} O{; and} O{.} +b }{
\AutoPuncItems[#1][#2][#3]{#4}
}{}
%%%
\SetEnumitemKey{autopunc}{% trying these don't seem to work
% first*=\begin{AutoPuncItemize},
before*=\begin{AutoPuncItemize},
after=\end{AutoPuncItemize},
%% last=\end{AutoPuncItemize} % not a valid key, but this WOULD be nice
}
\begin{document}
Works as desired
\begin{itemize}
\AutoPuncItems{
\item one
\item two
\item three
}
\end{itemize}
Works as desired
\begin{itemize}
\begin{AutoPuncItemize}
\item one
\item two
\item three
\end{AutoPuncItemize}
\end{itemize}
This is what I'm trying to get, desired interface
\begin{itemize}[autopunc]
\item one
\item two
\item three
\end{itemize}
\end{document}
答案1
通过打印 Lua 函数接收到的字符串AutoPuncItems
,我看到\fi \item one \item two \item threexxxENDxxx
;似乎\fi
传递了一个未预测的内容。
我通过简单地\fi
用空白替换解决了这个问题;这是因为第一行是AutoPuncItems
:s = string.gsub(s, "\\fi ", "")
。
似乎没有问题。我唯一担心的是这可能会产生一些不必要的影响。我看到一个警告:
Warning:(67) (\end occurred when \ifnum on line 67 was incomplete)
,这是有道理的,因为我正在删除一个我假设 \ifnum 使用的 \fi。放置\fi
在环境之后可以解决这个问题。所以,为了安全起见,我做了以下事情:
\usepackage{etoolbox}
\newtoggle{autopunc}
\SetEnumitemKey{autopunc}{
before*=\toggletrue{autopunc},
first*=\AutoPuncItemize,
after=\endAutoPuncItemize,
}
\AfterEndEnvironment{itemize}{\iftoggle{autopunc}{\fi\togglefalse{autopunc}}{}}
要重新使用我的 MWE:
\documentclass{scrartcl}
\usepackage{luacode}
\usepackage{enumitem}
\begin{luacode*}
function AutoPuncItems(s, btwn, seclast, last) -- add btwn and sec and last options
--texio.write_nl('VVVVV \n'..s) -- troubleshooting
s = string.gsub(s, "\\fi ", "") -- for some reason this is injected by enumitem
local it = '\\item '
local s_item = '%s*'..it
btwn = btwn or ';'
btwn = btwn..' '..it
seclast = seclast or '; and'
seclast = seclast..' '..it
last = last or '.'
local _, n_matches = string.gsub(s, s_item, "") -- find num items
s, _ = string.gsub(s, s_item, seclast, n_matches) -- replace all 'item' with second last type
s, _ = string.gsub(s, seclast, btwn, n_matches-1) -- replace all 'item' EXCEPT the last with the between
-- (all but second lines affected)
s, _ = string.gsub(s, '%s*xxxENDxxx', last) -- add the final char
s = string.sub(s, #btwn-#it+1, #s) -- remove added stuff on very first item
tex.print(s)
end
\end{luacode*}
\NewDocumentCommand{\AutoPuncItems}{ O{;} O{; and} O{.} m }{
\luadirect{AutoPuncItems(
\luastringN{#4xxxENDxxx},
\luastringN{#1},
\luastringN{#2},
\luastringN{#3}
)}
}
\NewDocumentEnvironment{AutoPuncItemize}{ O{;} O{; and} O{.} +b }{
\AutoPuncItems[;][; and][.]{#4}
}{}
\usepackage{etoolbox}
\newtoggle{autopunc}
\SetEnumitemKey{autopunc}{
before*=\toggletrue{autopunc},
first*=\AutoPuncItemize,
after=\endAutoPuncItemize,
}
\AfterEndEnvironment{itemize}{\iftoggle{autopunc}{\fi\togglefalse{autopunc}}{}}
\begin{document}
Works as desired
\begin{itemize}
\AutoPuncItems{
\item one
\item two
\item three
}
\end{itemize}
%
Works as desired
\begin{itemize}
\begin{AutoPuncItemize}
\item one % funck
\item two
\item three
\end{AutoPuncItemize}
\end{itemize}
This is what I'm trying to get, desired interface
\begin{itemize}[autopunc]
\item one
\item two
\item three
\end{itemize}
\fi
\begin{itemize}
\item one
\item two
\item three
\end{itemize}
\end{document}