当 \obeylines 生效时,Xparse 宏不起作用

当 \obeylines 生效时,Xparse 宏不起作用

这是我在 latex 中遇到的最奇怪和最难调试的情况。当\obeylines生效时,似乎 xparse 定义的带有可选参数的宏会遇到一些问题。以下 MWE 证明了这一点(我尽力将其精简,但它仍然很长,抱歉……尽管如此,它的结构很简单。请参阅编辑部分以获得完整解释):

\documentclass[fontsize=22pt]{scrreprt}

\usepackage{etoolbox}

\usepackage{geometry,calc}
\geometry{paperwidth=1280pt,paperheight=3840pt,margin=25pt}

\usepackage{tcolorbox}
\usepackage{xparse}

\usepackage[titles]{tocloft}
\addtocounter{tocdepth}{1}

\NewDocumentCommand\mypart{m D--{n}}{
  \printtocentry{#1}{#2}{part}
  \item[]
}

\newcommand*{\mychapname}{}
\NewDocumentCommand\mychap{m D--{n}}{
  \item[]
  \end{notes}
  \vspace{-8ex}
  \printtocentry{#1}{#2}{chapter}
  \begingroup\let\clearpage\relax
  \chapter*{\large\sffamily#1}
  \endgroup
  \renewcommand*{\mychapname}{#1}
  \vspace{-12ex}
  \begin{notes}
  \item[]
}

\NewDocumentCommand\printtocentry{m m m o}{
  \refstepcounter{#3}
  \def\mynumberline{\protect\numberline{\csname the#3\endcsname}}
  \IfNoValueF{#4}{\def\mynumberline{\relax}}
  \ifstrequal{#2}{t}{
    \addcontentsline{toc}{#3}{\mynumberline\colorbox{yellow}{#1}}
  }{}
  \ifstrequal{#2}{d}{
    \addcontentsline{toc}{#3}{\mynumberline\colorbox{green}{#1}}
  }{}
  \ifstrequal{#2}{n}{
    \addcontentsline{toc}{#3}{\mynumberline#1}
  }{}
}

\NewDocumentCommand\mysec{m D--{n}}{
  \printtocentry{#1}{#2}{section}
  \item[]\hfill
  {[~\mychapname~\textbf{--}~#1~]}
}

\NewDocumentCommand\mysubsec{m D--{n}}{
  \vspace{3ex}
  \printtocentry{#1}{#2}{subsection}
  \item[(#1)]\hfill
}

\def\removespecial{
  \catcode`\_=12
  \catcode`\^=12
  \catcode`\$=12
  %\catcode`\%=12
  \catcode`\#=12
  \catcode`\&=12
  \catcode`\~=12
}

% the second argument is used to highlight toc entries, I think this is where the bug is
\NewDocumentCommand\myitem{O{} D--{n}}{
  \vspace{1ex}
  \ifstrempty{#1}{}{
    \printtocentry{#1}{#2}{subsubsection}[NoNumberLine]
  }
  \item[#1]
  %%% this line is the source of problem, \obeylines changes the catcode of ^^M
  \obeylines
  \obeyspaces
  \removespecial
}

\renewcommand*{\\}{\textbackslash}

\usepackage[Sonny]{fncychap}
\renewcommand*{\DOCH}{}
\ChTitleVar{\large}

\usepackage[inline]{enumitem}
\newlist{notes}{description}{1}
\setlist[notes]{
  leftmargin=0.3\linewidth,labelsep=2em,
  itemsep=1.5ex,style=multiline,font=\normalfont
}

\begin{document}
\tableofcontents
\begin{notes}

\mypart{Part One}

% this chapter works, because \obeylines is not yet in effect
\mychap{Chap One}

\mysubsec{Subsec One}

\myitem[Item One]
...some content...

\myitem[Item Two]
...some content...

% this chapter does not work
% uncomment the next line would make it to work
%\catcode\endlinechar = 5
\mychap{Chap Two}

\mysubsec{Subsec Two}% disappear

\myitem[Item Three]% disappear
...some content...

\myitem[Item Four]% disappear
...some content...

% however, this chapter works:
\mychap{Chap Three}-d-

\mysubsec{Subsec Three}

\myitem[Item Five]
...some content...

\myitem[Item Six]
...some content...

\end{notes}
\end{document}

% vim: filetype=tex

部分结果如下:

平均能量损失

第二章是观察问题的地方,你可以看到所有项目都消失了,只剩下项目的内容。然而,它的结构应该与第一章完全相同。

我花了很多时间尝试调试这个问题,但徒劳无功。而且我对纯文本不太了解。我想我已经确定问题出在\obeylinesxparse 定义的宏上。我还发现\catcode\endlinechar = 5在前面添加\mychap{}似乎可以解决问题。有人能 1) 解释这个问题和 2) 告诉我如何让它工作吗?谢谢。

编辑:我将介绍一些 MWE 的背景知识,并阐明我在这里想要实现的目标。上面的 MWE 改编自一个名为 mynotes.sty 的自定义类,正如其名称所暗示的那样,我通常用它来做笔记。它为笔记提供了一个类似书本的结构,主要部分是一个列表。如果没有这个类,它可以这样做:

\usepackage[inline]{enumitem}
\newlist{notes}{description}{1}

\part{...}
\chapter{...}
\section{...}
\begin{notes}
\item[]...
\end{notes}
\section{...}
\begin{notes}
\item[]...
\end{notes}
...

显然那里有太多了\begin{notes}...\end{notes}。所以为了美观和节省类型,我定义了\mychap\myitem等等。此外,还添加了一个功能:突出显示目录中的条目的能力。这是通过将这些D--{n}可选参数添加到\NewDocumentCommands 来实现的。所以现在它的工作方式如下:

\mychap{...}         % normal entry, no toc coloring
\mychap{...}-n-      % the same as above, because n is the default value
\mychap{...}-d-      % toc entry colored green
\mysec{...}-t-       % toc entry colored yellow

历史说得够多了。现在来看看相关部分:在该类的原始实现中,缺少以下三行:

\obeylines
\obeyspaces
\removespecial

并且它很好地实现了其设计目的。直到最近,我必须记录一些主题,这使得逐字记录式的环境成为必要。同样,这可能会奏效:

\myitem[...]
\begin{verbatim}...\end{verbatim}
\myitem[...]
\begin{alltt}...\end{alltt}

但输入太多了。另外,将的功能alltt分成三个部分具有更大的灵活性。所以我决定添加这三行来尝试模拟:

\myitem[...]
{\obeylines\obeyspaces\removespecial ...}
\myitem[...]
{\obeylines\obeyspaces\removespecial ...}
% could not figure out how to add the parentheses
% so in fact it is like:
\myitem[...]
\obeylines\obeyspaces\removespecial ...

但是,这三行破坏了原始格式,这就是上面的 MWE 所显示的。在上面的 MWE 的输出中,三个部分(第一章、第二章和第三章)的格式应该看起来完全相同,除了目录条目的颜色。添加这三行(更准确地说,只有行\obeylines)使第二章的一部分偏离了左边缘(正如 Joseph 指出的那样)。从我的角度来看,原因是这样的:

% NOT working example
\myitem[...]
...
% \obeylines is in effect here! for some reason which I don't
% understand it breaks the following \mychap:
\mychap{Chap Two}

尝试减轻 \obeylines 的影响将使其再次按预期工作:

% working example
\myitem[...]
...
\catcode\endlinechar = 5
\mychap{Chap Two}
% works again, those three lines not causing trouble any more

更令人困惑的是,这也有效:

% working example
\myitem[...]
...
\mychap{Chap Two}-d-

这让我产生了一种错觉,认为 xparse 中可选参数的处理存在一些问题。这就是完整的故事。非常感谢你的阅读和帮助!:)

\item[]哦是的,这里对代码中的那些空的 s 有一个解释:那是因为enumitem需要\begin{notes}...\end{notes}至少有一个\item[]内部。

答案1

这是对问题的解释而不是完整的解决方案。

正如约瑟夫·赖特所言,这个问题如果用适当的最小工作示例。事实上,如果你把 MWE 简化,那么问题就很明显了:正如人们可能怀疑的那样,解析包裹是完全无辜的。

这里 (接近) 是一个 MWE。为了节省空间,我稍微压缩了一下,不幸的是可读性会受到影响,但影响不大...:

\documentclass{scrreprt} \usepackage{xparse}
\NewDocumentCommand\mychap{m D--{n}}{
  \item[]\end{notes} \textbf{#1} \begin{notes}\item[] }
\NewDocumentCommand\myitem{O{} D--{n}}{\item[#1]\obeylines}
\usepackage[inline]{enumitem}
\newlist{notes}{description}{1}
\setlist[notes]{nosep,leftmargin=0.3\linewidth}% Note the LEFTMARGIN !!!

\begin{document} \begin{notes}
  % this chapter works, because \obeylines is not yet in effect
  \mychap{Chap One} \myitem[Item Two] ...some content...

  % this chapter does not work: uncommenting the next line makes it work
  %\catcode\endlinechar = 5
  \mychap{Chap Two}
  \myitem[Item Four] ...some content...

  % however, this chapter works:
  \mychap{Chap Three}-d- \myitem[Item Six] ...some content...
\end{notes} \end{document}

此 MWE 比 OP 提供的 MWE 短得多。这产生:

在此处输入图片描述

正如问题所示,在这个精简版中,第二项的位置是错误的

正如 OP 所说,设置\catcode\endlinechar = 5问题就消失了,但这并不奇怪,因为这实际上撤消了前一个\obeylines命令。

leftmargin=0.3\linewidth正如我在 MWE 中的评论所指出的那样,问题的真正原因是环境规范notes和命令的结合\obeylines:使用 obelines 实际上枚举项软件包很难将左边距设置到合适的位置。如果您设置,leftmargin=0问题就会消失。当然,这可能不是 OP 想要的。

在努力理解 OP 的代码后,我认为简单地缩进一个块enumitem(即notes)似乎有点过分。如果我想做这样的事情,我想我会选择使用编辑器快捷键(即 vim 中的代码片段)和一些自定义环境的组合。

相关内容