Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

A user of my menukeys package found a strange error an if don’t have any idea what’s the cause and all the more how to fix it …

The following example make the bullet move to the right inside the text if there is a \menu including \lstinline right behind \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}

strange result

The user found out the an \mbox can help but this should’t be the only way to fix this – I hope …

share|improve this question
1  
Supplying \lstinline (or any verbatim content) as an argument to a macro is a problem. Look at how the formatting differs from item 3 (correct) and that inside \menu. For small inline verbatim content, boxing before passing as an argument is almost always an option. –  Werner Sep 16 '12 at 16:09
1  
The problem disappears if \leavevmode is put at the beginning of the definition of \menu. This shouldn't be a problem, because the all the "menu" commands are to start a new paragraph. –  egreg Sep 16 '12 at 16:18
    
Finally fixed in version 1.2, which will be available on CTAN soon. –  Tobi Jul 23 '13 at 11:15
add comment

1 Answer 1

up vote 4 down vote accepted

LaTeX's \item of environment itemize delays the setting of its label by using \everypar. The label is stored in a box, printed at the start of the paragraph to the left (\parindent is 0pt) and the box is void afterwards.

\menu of menukeys uses \tikz. That stores the contents in a box first and afterwards the box is set. Very simplified:

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

The contents of \menu/\tikz contains \lstinline. It calls \leavevmode right at the beginning. This explains, why \lstinline right after \item works. Inside an \hbox \leavevmode does not start a paragraph. \lstinline calls \lst@Init, an excerpt from its definition:

\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
  ...
}

Default for \lst@boxpos is b, thus \noindent starts a paragraph inside a \vbox. At the begin of the paragraph \everytoks is executed and the label is set. Afterwards the label box is void (by \box, up to the group level of \item). This explains the label inside the menu item.

Then the menu item that has been stored in a box is set as entry in the itemize environment, correctly using \leavevmode. But it is too late now, the label is already set and is not repeated, the label box is void.

Fix suggestions:

  • As egreg already said, \menu (and the other similar macros) should call \leavevmode right at the beginning. Anyway \menu will print material that will start a paragraph.

    Manually it can be redefined:

    \makeatletter
    \newcommand*{\org@menu}{}
    \let\org@menu\menu
    \protected\def\menu{\leavevmode\org@menu}% or
    % \renewcommand*{\menu}{\leavevmode\org@menu}
    \makeatother
    
  • \lst@Init uses the hook \lsthk@BoxUnsafe if a vertical box is used. \everypar can be cleared there:

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

Both ways fix the issue:

Result

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.