添加 enumitem 键以嵌套基于 lualatex 的环境,该环境可自动对列表进行标点

添加 enumitem 键以嵌套基于 lualatex 的环境,该环境可自动对列表进行标点

我编写了一个基于 lua 的函数来自动对分项列表进行标点,如下所示:

  1. ;
  2. ; and
  3. .

etc会自动添加。我可以将其作为or环境;内的命令或环境应用。但我更希望将其作为键传递给 enumitem 提供的可选 key-val 参数。例如。请参阅下面的 MWE。我收到的错误是itemizeenumerateautopunc\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用空白替换解决了这个问题;这是因为第一行是AutoPuncItemss = 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}

相关内容