如何使用 lstlisting 修复多列后的间距?

如何使用 lstlisting 修复多列后的间距?

lstlisting当与或multicols内部结合时, 的垂直间距会发生变化。可以使用 固定顶部间距(请参阅此内容)minipagetcolorboxlstlisting\topskip = 0pt回答(还有一个关于底部间距的问题),但底部的间距大多不正确。对于belowskip = 0pt和偶数行,可以获得最佳近似值。belowskip > 0pt对于每行数,设置都会给出相同的错误间距(这取决于字体大小)。

有没有针对此问题的通用解决方案?如果没有,那么获得一致间距的最佳做法是什么?

例子

在此处输入图片描述

平均能量损失

\documentclass{article}

\usepackage{listings}
\usepackage{multicol}

% Simplified tcolorbox
\newenvironment{mybox}{
    \addvspace{\bigskipamount}
    \hrule
    \begin{minipage}{\textwidth}
}{
    \end{minipage}
    \hrule
    \addvspace{\bigskipamount}
}

\parindent = 0pt

\begin{document}
Normal

\verb|belowskip = 0pt|

\begin{mybox}
\begin{lstlisting}[aboveskip = 0pt, belowskip = 0pt]
Ag
\end{lstlisting}
\end{mybox}

\begingroup
\huge
\begin{mybox}
\begin{lstlisting}[aboveskip = 0pt, belowskip = 0pt]
Ag
\end{lstlisting}
\end{mybox}
\endgroup

Multicols

\verb|belowskip = 0pt|

\topskip = 0pt

\begin{mybox}
\begin{multicols}{2}
\begin{lstlisting}[aboveskip = 0pt, belowskip = 0pt]
Ag
Ag
\end{lstlisting}
\end{multicols}
\end{mybox}

\begin{mybox}
\begin{multicols}{2}
\begin{lstlisting}[aboveskip = 0pt, belowskip = 0pt]
Ag
Ag
Ag
\end{lstlisting}
\end{multicols}
\end{mybox}

Multicols with default settings of listings

\verb|belowskip = \medskipamount > 0pt|

\begin{mybox}
\begin{multicols}{2}
\begin{lstlisting}
Ag
Ag
\end{lstlisting}
\end{multicols}
\end{mybox}

\begin{mybox}
\begin{multicols}{2}
\begin{lstlisting}
Ag
Ag
Ag
\end{lstlisting}
\end{multicols}
\end{mybox}

\begingroup
\huge
\begin{mybox}
\begin{multicols}{2}
\begin{lstlisting}
Ag
Ag
\end{lstlisting}
\end{multicols}
\end{mybox}
\endgroup
\end{document}

更新

的正常间距listings由 (hook EveryLine) 引入\lsthk@EveryLine。这可以用 和 来模仿\par\strut添加\vspace类似于belowskip。因此间距行为可以简化为multicol

\documentclass{article}

\usepackage{listings}
\usepackage{multicol}

% Simplified tcolorbox
\newenvironment{mybox}{
    \addvspace{\bigskipamount}
    \hrule
    \begin{minipage}{\textwidth}
}{
    \end{minipage}
    \hrule
    \addvspace{\bigskipamount}
}

\parindent = 0pt

\begin{document}
Normal

\begin{mybox}
\begin{lstlisting}[aboveskip = 0pt, belowskip = 0pt]
Ag
\end{lstlisting}
\end{mybox}

\begin{mybox}
\begin{lstlisting}[aboveskip = 0pt, belowskip = 0pt]
Ag
Ag
\end{lstlisting}
\end{mybox}

Imitation of lstlisting

\begin{mybox}
\par\strut Ag
\end{mybox}

\begin{mybox}
\par\strut Ag
\par\strut Ag
\end{mybox}

Multicols with imitation of lstlisting

\topskip = 0pt

\begin{mybox}
\begin{multicols}{2}
\par\strut Ag
\par\strut Ag
%\vspace{0pt}% no belowskip
\end{multicols}
\end{mybox}

\begin{mybox}
\begin{multicols}{2}
\par\strut Ag
\par\strut Ag
\vspace{0pt}% belowskip --> reduces the deviation to a small value, but the spacing remains incorrect
\end{multicols}
\end{mybox}

\begin{mybox}
\begin{multicols}{2}
\par\strut Ag
\par\strut Ag
\par\strut Ag
\vspace{0pt}% belowskip
\end{multicols}
\end{mybox}
\end{document}

答案1

当行数为奇数时,第一列的底部将与基线齐平。belowskip 是什么并不重要,因为它不会位于列的底部。多列本身可能会正常地添加一些空间,但 minipage 会占用这些空间。(\@minipagefalse更糟。)

不清楚应在基线以下添加多少间隙。 \dp\strutbox太小,又\medskipamount太大。

\documentclass{article}

\usepackage{listings}
\usepackage{multicol}

\parindent = 0pt

\begin{document}
Normal

\verb|belowskip = 0pt|\bigskip

\hrule
\begin{minipage}{\textwidth}
\begin{lstlisting}[aboveskip = 0pt, belowskip = 0pt]
Ag
\end{lstlisting}
\end{minipage}
\hrule
\bigskip

Multicols

\verb|belowskip = 0pt|\bigskip

\topskip = 0pt

\hrule
\begin{minipage}{\textwidth}
\begin{multicols}{2}
\begin{lstlisting}[aboveskip = 0pt, belowskip = 0pt]
Ag
Ag
\end{lstlisting}
\end{multicols}
\end{minipage}
\hrule
\bigskip

\hrule
\begin{minipage}{\textwidth}
\begin{multicols}{2}
\begin{lstlisting}[aboveskip = 0pt, belowskip = 0pt]
Ag
Ag
Ag
\end{lstlisting}
\end{multicols}
\vskip 1ex
\hrule height0pt
\end{minipage}
\hrule

\end{document}

答案2

此修复基于回答@John Kormylo 的另一个问题。每行后面的空格可以通过\hrule height0pt在末尾添加来保护。

\begin{mybox}
\begin{multicols}{2}
\par\strut Ag\hrule height0pt
\par\strut Ag\hrule height0pt
\par\strut Ag\hrule height0pt
\vspace{0pt}% belowskip
\end{multicols}
\end{mybox}

幸运的是,包含执行此任务的listings钩子(参见\lst@AddToHook{EOL}listings-devel.pdf)。请注意,每次调用后都必须清除此钩子,因为每次调用lstlisting时都会添加相同的代码。它还可以防止对其他列表产生不必要的影响(例如)。lstlisting\lstinline{code}

\documentclass{article}

\usepackage{listings}
\usepackage{multicol}

% Simplified tcolorbox
\newenvironment{mybox}{
    \addvspace{\bigskipamount}
    \hrule
    \begin{minipage}{\textwidth}
}{
    \end{minipage}
    \hrule
    \addvspace{\bigskipamount}
}

\makeatletter
% Simplified tcolorbox with multicols
\newenvironment{multibox}[1][2]{
    \topskip = 0pt% remove spacing on top
    \begin{mybox}
    \begin{multicols}{#1}
    \lst@AddToHook{EOL}{\hrule height0pt}% add hrule after each input line
}{
    \end{multicols}
    \end{mybox}
}

% Clear the hook
\AfterEndEnvironment{multibox}{\gdef\lsthk@EOL{}}
\makeatother

% Set the skips of lstlisting to 0pt
\lstset{aboveskip = 0pt, belowskip = 0pt}

\parindent = 0pt

\begin{document}
Normal

\begin{mybox}
\begin{lstlisting}
Ag
\end{lstlisting}
\end{mybox}

\begin{mybox}
\begin{lstlisting}
Ag
Ag
\end{lstlisting}
\end{mybox}

Multicols

\begin{multibox}
\begin{lstlisting}
Ag
\end{lstlisting}
\end{multibox}

\begin{multibox}
\begin{lstlisting}
Ag
Ag
\end{lstlisting}
\end{multibox}

\begin{multibox}
\begin{lstlisting}
Ag
Ag
Ag
\end{lstlisting}
\end{multibox}
\end{document}

在此处输入图片描述

相关内容