这是lstinputlisting
环境中的第一个行号.考虑 MWE:
\documentclass{article}
%\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\usepackage{filecontents,listings}% http://ctan.org/pkg/{filecontents,listings}
\lstset{
numbers=left,
basicstyle=\ttfamily\footnotesize
}
\begin{filecontents*}{mycode.txt}
Line 1
Line 2
Line 3
Line 4
Line 5
\end{filecontents*}
\makeatletter
% https://tex.stackexchange.com/q/26828/5764
%\patchcmd{\lst@GLI@}% <command>
% {\def\lst@firstline{#1\relax}}% <search>
% {\def\lst@firstline{#1\relax}\def\lst@firstnumber{#1\relax}}% <replace>
% {\typeout{listings firstnumber=firstline}}% <success>
% {\typeout{listings firstnumber not set}}% <failure>
\makeatother
\begin{document}
\lstinputlisting[linerange={1-3}]{mycode.txt}
\lstinputlisting[linerange={2-4}]{mycode.txt}
\lstinputlisting[linerange={2-2,4-5}]{mycode.txt}
\end{document}
没有的援助etoolbox
patch(或默认值),输出看起来像最左边的列。和借助补丁(“firstnumber
校正”),输出看起来像中间一侧的输出。但是,我希望输出看起来像最右边一列的输出。
也就是说,最终输出的行号应该与规范相符linerange
。
我希望避免的简单解决方案是\lstinputlisting
为每个范围包含单独的 s,并进行适当的垂直调整-2\medskipamount
(包含列表上方/下方的默认空间)。这就是首先获得最右边列的方法。
答案1
我之前的解决方案在空白行编号方面存在问题。我添加了一个新的解决方案,并将旧解决方案保留在更下方。
新解决方案
lstnumber
真正需要做的是在每个范围的开头重置计数器。要实现这一点,需要挂接到内部命令\lst@SkipToFirst
。一种方法是定义一个matchrangestart
初始化为 false 的新键,方法是通过
\lst@Key{matchrangestart}{f}{\lstKV@SetIf{#1}\lst@ifmatchrangestart}
然后在开头添加以下测试\lst@SkiptoFirst
:
\lst@ifmatchrangestart\c@lstnumber=\numexpr-1+\lst@firstline\fi
listings
这是设置具有真/假值的键的一般方法以及它如何处理计数器lstnumber
。此代码表示,如果matchrangestart
键为真,则在跳转到范围的开头时,将其设置lstnumber
为比范围的第一个行号小一。打印行时,此数字会在打印前递增,这样我们就得到了所需的输出。
\documentclass{article}
\usepackage{filecontents,listings}
\lstset{
basicstyle=\ttfamily\footnotesize
}
\begin{filecontents*}{mycode.txt}
Line 1
Line 2
Line 3
Line 6
Line 7
Line 9
Line 10
\end{filecontents*}
\makeatletter
\lst@Key{matchrangestart}{f}{\lstKV@SetIf{#1}\lst@ifmatchrangestart}
\def\lst@SkipToFirst{%
\lst@ifmatchrangestart\c@lstnumber=\numexpr-1+\lst@firstline\fi
\ifnum \lst@lineno<\lst@firstline
\def\lst@next{\lst@BeginDropInput\lst@Pmode
\lst@Let{13}\lst@MSkipToFirst
\lst@Let{10}\lst@MSkipToFirst}%
\expandafter\lst@next
\else
\expandafter\lst@BOLGobble
\fi}
\makeatother
\begin{document}
\begin{minipage}{0.45\linewidth}
Standard
\lstset{numbers=left}
\lstinputlisting[linerange={1-3}]{mycode.txt}
\lstinputlisting[linerange={2-6}]{mycode.txt}
\lstinputlisting[linerange={2-2,4-6,8-9}]{mycode.txt}
\end{minipage}
\begin{minipage}{0.45\linewidth}
Literal
\lstset{numbers=left,matchrangestart=t}
\lstinputlisting[linerange={1-3}]{mycode.txt}
\lstinputlisting[linerange={2-6}]{mycode.txt}
\lstinputlisting[linerange={2-2,4-6,8-9}]{mycode.txt}
\end{minipage}
\end{document}
旧解决方案
这会将错误的数字放在空白行上
该listings
包有一个内部计数器,\lst@lineno
用于保存您要查找的行号。现在numbers=left
选项运行代码
\def\lst@PlaceNumber{\llap{\normalfont
\lst@numberstyle{\thelstnumber}\kern\lst@numbersep}}
所以我们需要做的就是采用此代码并将打印的乳胶计数器替换\thelstnumber
为\the\list@lineno
:
\documentclass{article}
\usepackage{filecontents,listings}
\lstset{
basicstyle=\ttfamily\footnotesize
}
\begin{filecontents*}{mycode.txt}
Line 1
Line 2
Line 3
Line 4
Line 5
\end{filecontents*}
\makeatletter
\def\lst@PlaceNumber{\llap{\normalfont
\lst@numberstyle{\the\lst@lineno}\kern\lst@numbersep}}
\makeatother
\begin{document}
\lstinputlisting[linerange={1-3}]{mycode.txt}
\lstinputlisting[linerange={2-4}]{mycode.txt}
\lstinputlisting[linerange={2-2,4-5}]{mycode.txt}
\end{document}
上述代码全局设置了此样式。如果您希望有本地开关,则可以扩展选项listings
的定义numbers
,添加leftliteral
类型,如下所示:
\documentclass{article}
\usepackage{filecontents,listings}
\makeatletter
\lst@Key{numbers}{none}{%
\let\lst@PlaceNumber\@empty
\lstKV@SwitchCases{#1}%
{none&\\%
left&\def\lst@PlaceNumber{\llap{\normalfont
\lst@numberstyle{\thelstnumber}\kern\lst@numbersep}}\\%
leftliteral&\def\lst@PlaceNumber{\llap{\normalfont
\lst@numberstyle{\the\lst@lineno}\kern\lst@numbersep}}\\%
right&\def\lst@PlaceNumber{\rlap{\normalfont
\kern\linewidth \kern\lst@numbersep
\lst@numberstyle{\thelstnumber}}}%
}{\PackageError{Listings}{Numbers #1 unknown}\@ehc}}
\makeatother
\lstset{
basicstyle=\ttfamily\footnotesize
}
\begin{filecontents*}{mycode.txt}
Line 1
Line 2
Line 3
Line 4
Line 5
\end{filecontents*}
\begin{document}
\begin{minipage}{0.3\linewidth}
Standard
\lstset{numbers=left}
\lstinputlisting[linerange={1-3}]{mycode.txt}
\lstinputlisting[linerange={2-4}]{mycode.txt}
\lstinputlisting[linerange={2-2,4-5}]{mycode.txt}
\end{minipage}
\begin{minipage}{0.3\linewidth}
Literal
\lstset{numbers=leftliteral}
\lstinputlisting[linerange={1-3}]{mycode.txt}
\lstinputlisting[linerange={2-4}]{mycode.txt}
\lstinputlisting[linerange={2-2,4-5}]{mycode.txt}
\end{minipage}
\begin{minipage}{0.3\linewidth}
Standard
\lstset{numbers=left}
\lstinputlisting[linerange={1-3}]{mycode.txt}
\lstinputlisting[linerange={2-4}]{mycode.txt}
\lstinputlisting[linerange={2-2,4-5}]{mycode.txt}
\end{minipage}
\end{document}
答案2
根据安德鲁的回答我发现这更符合这个问题:
\makeatletter
\def\lst@MSkipToFirst{%
\global\advance\lst@lineno\@ne
\ifnum \lst@lineno=\lst@firstline
\def\lst@next{\lst@LeaveMode \global\lst@newlines\z@
\lst@OnceAtEOL \global\let\lst@OnceAtEOL\@empty
\lst@InitLstNumber % Added to work with modified \lsthk@PreInit.
\lsthk@InitVarsBOL
\c@lstnumber=\numexpr-1+\lst@lineno % this enforces the displayed line numbers to always be the input line numbers
\lst@BOLGobble}%
\expandafter\lst@next
\fi}
\makeatother
与他的答案相比,它的优点在于它正确支持多范围构造,而无需引入键。这是通过覆盖实际上负责范围跳过并已包含新范围第一行钩子的方法来实现的。
针对清单 1.6 进行测试(2015/06/04)。与往常一样,在覆盖函数时,请注意包源的更改(应该不难,因为只添加了一行)。
奖金:
行块之间有 2mm 的空白:
\makeatletter
\def\lst@MSkipToFirst{%
\global\advance\lst@lineno\@ne
\ifnum \lst@lineno=\lst@firstline
\def\lst@next{\lst@LeaveMode \global\lst@newlines\z@
\lst@OnceAtEOL \global\let\lst@OnceAtEOL\@empty
\ifnum \c@lstnumber>0
\vspace{2 mm}
\fi
\lst@InitLstNumber % Added to work with modified \lsthk@PreInit.
\lsthk@InitVarsBOL
\c@lstnumber=\numexpr-1+\lst@lineno % this enforces the displayed line numbers to always be the input line numbers
\lst@BOLGobble}%
\expandafter\lst@next
\fi}
\makeatother