使用 menukeys 和 \lstinline 进行 itemize 时出现奇怪错误

使用 menukeys 和 \lstinline 进行 itemize 时出现奇怪错误

我的一个用户menukeys包发现了一个奇怪的错误,如果不知道原因是什么以及如何修复它……

以下示例如果后面有\menu包括right则使项目符号在文本内向右移动。\lstinline\item

\documentclass{article}
\usepackage{listings}
\usepackage{menukeys}

\begin{document}
\begin{itemize}
    \item Test
    \item \menu{Test \lstinline|test|}
    \item \lstinline|test|
    \item \menu{Test}
    \item \mbox{}\menu{Test \lstinline|test|}
\end{itemize}
\end{document}

奇怪的结果

用户发现这个\mbox可以提供帮助,但这不应该是解决这个问题的唯一方法——我希望……

答案1

LaTeX 的\itemof 环境itemize使用 来延迟其标签的设置\everypar。标签存储在一个框中,打印在左侧段落的开头(\parindent0pt),之后该框无效。

\menu用途。首先将内容存储在盒子中menukeys\tikz然后设置盒子。非常简单:

\setbox0=\hbox{...}%
\leavevmode\box0

\menu/的内容\tikz包含\lstinline。它\leavevmode在开头就调用 。这解释了为什么\lstinline紧接着\item它起作用。在 中,\hbox \leavevmode并不开始一个段落。\lstinline调用\lst@Init,其定义摘录如下:

\def\lst@Init#1{%
  ...
  \ifhmode\ifinner \lst@boxtrue \fi\fi
  \lst@ifbox
    \lsthk@BoxUnsafe
    \hbox to\z@\bgroup
      $\if t\lst@boxpos \vtop
    \else \if b\lst@boxpos \vbox
    \else \vcenter \fi\fi
    \bgroup \par\noindent
  \else
  ...
}

的默认值为\lst@boxposb因此\noindent在 内开始一个段落\vbox。在段落的开头\everytoks执行 并设置标签。之后标签框无效(由\box,直到 的组级别\item)。这解释了菜单项内的标签。

然后将存储在框中的菜单项设置为环境中的条目itemize,正确使用\leavevmode。但现在为时已晚,标签已经设置并且没有重复,标签框无效。

修复建议:

  • 正如 egreg 所说,\menu(和其他类似的宏)应该\leavevmode 在开头调用。无论如何\menu都会打印出一个段落的开头材料。

    可以手动重新定义:

    \makeatletter
    \newcommand*{\org@menu}{}
    \let\org@menu\menu
    \protected\def\menu{\leavevmode\org@menu}% or
    % \renewcommand*{\menu}{\leavevmode\org@menu}
    \makeatother
    
  • \lst@Init\lsthk@BoxUnsafe如果使用垂直框则 使用钩子。\everypar可以在那里清除:

    \makeatletter
    \lst@AddToHook{BoxUnsafe}{\everypar{}}%
    \makeatother
    

两种方法都可以解决问题:

结果

相关内容