如何在 lstings 环境中设置选项 frame=tb 和 multicols=2,以便它们同时正常工作

如何在 lstings 环境中设置选项 frame=tb 和 multicols=2,以便它们同时正常工作

我的最小示例如下:

\documentclass{article}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{multicol}

\lstdefinelanguage{Cpp}{
    keywords={auto, double, int, struct, break, else, long,
    switch, case, enum, register, typedef, char, extern,
    return, union, continue, for, signed, void, do, if, static,
    while, default, goto, sizeof, volatile, const, float, short, unsigned, NULL, \#include, \#define},
    sensitive=true,
    alsoletter = {\#},
    comment=[l]{//},
    morecomment=[s]{/*}{*/},
    morestring=[b]',
    morestring=[b]"
}

\lstdefinestyle{mystyle}{
% Basic design
    basicstyle=\ttfamily\linespread{1}\small,
  frame=t,
    multicols=2,
%framesep=5pt,
    framerule=.5pt,
    rulecolor=\color{violet},
    abovecaptionskip=0pt,
    belowcaptionskip=5pt,
% Code design
    keywordstyle=\color{codecolorkeywords},
    commentstyle=\color{codecolorcomments},
    stringstyle=\color{codecolorstrings},
    numberstyle=\small\color{gray},
    breakatwhitespace=false,
    breaklines=true,
    captionpos=t,
    keepspaces=true,
% Line numbers
    numbers=left,
    numbersep=2pt,
    xleftmargin=.5em,
    stepnumber=1,
    firstnumber=1,
    numberfirstline=true,
% Code
    tabsize=4,
    showspaces=false,
    showstringspaces=false,
    showtabs=false,
    breaklines=true,
}
\lstset{style=mystyle}

\begin{document}
    \lstset{language=Cpp}

    \begin{lstlisting}[frame=tb, caption={caption}]
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>

    void swap(int *q, int a, int b) {
        int tmp = q[a];
        q[a] = q[b];
        q[b] = tmp;
    }

    void quick_sort(int *q, int l, int r)
        {
        if (l >= r) {
            return;
        }
        int x = q[(l + r) >> 1];
        int i = l - 1;
        int j = r + 1;
        while (i < j) {
            do i++; while (q[i] < x);
            do j--; while (q[j] > x);
            if (i < j) {
                swap(q, i, j);
            }
        }
        quick_sort(q, l, j);
        quick_sort(q, j + 1, r);
    }
    \end{lstlisting}
\end{document}

上述代码将生成如下所示的内容。 生成这样的 pdf

但我希望得到从左到右的多列框架线,而不是文本宽度的一半。并且多列环境的第二列将向下移动,以避免与扩展框架线重叠。

任何答案都会有帮助。非常感谢。

答案1

环境multicols被添加到 和InitDeInit的钩子中listings。标题和框架被添加到相同的钩子中,但在 multicol 代码之后,因此标题和框架最终位于列内。

您可以将 multicol 代码移至InitVarsExitVars钩子,它们分别在 之后Init和 之前执行DeInit。参见清单开发人员指南所有钩子的准确顺序。

实现这一点的快速方法是从选项multicols中删除键lstset,而是对钩子中的列数进行硬编码。

请注意,multicols 出现在 Init 和 DeInit 中以及标题之前可能是有原因的,因此这种修改在某些时候可能会导致问题。

OP 指出的一个问题是\lstinline片段现在也是多列的。一个快速的解决方法是引入一个新的 if 并使多列以这个 if 为条件。这需要\applymulticoltrue在代码之前有一个明确的语句,说明您希望它分为两列,并\applymulticolfalse在内联代码(或单列常规列表)之前有一个语句。这是一个开关,因此您只需设置一次,然后它将应用于所有后续列表,直到您更改该值。

梅威瑟:

\documentclass{article}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{multicol}
\colorlet{codecolorkeywords}{black}
\colorlet{codecolorcomments}{black}
\colorlet{codecolorstrings}{black}
\lstdefinelanguage{Cpp}{
    keywords={auto, double, int, struct, break, else, long,
    switch, case, enum, register, typedef, char, extern,
    return, union, continue, for, signed, void, do, if, static,
    while, default, goto, sizeof, volatile, const, float, short, unsigned, NULL, \#include, \#define},
    sensitive=true,
    alsoletter = {\#},
    comment=[l]{//},
    morecomment=[s]{/*}{*/},
    morestring=[b]',
    morestring=[b]"
}

\lstdefinestyle{mystyle}{
% Basic design
    basicstyle=\ttfamily\linespread{1}\small,
  frame=t,
    %multicols=2,
%framesep=5pt,
    framerule=.5pt,
    rulecolor=\color{violet},
    abovecaptionskip=0pt,
    belowcaptionskip=5pt,
% Code design
    keywordstyle=\color{codecolorkeywords},
    commentstyle=\color{codecolorcomments},
    stringstyle=\color{codecolorstrings},
    numberstyle=\small\color{gray},
    breakatwhitespace=false,
    breaklines=true,
    captionpos=t,
    keepspaces=true,
% Line numbers
    numbers=left,
    numbersep=2pt,
    xleftmargin=.5em,
    stepnumber=1,
    firstnumber=1,
    numberfirstline=true,
% Code
    tabsize=4,
    showspaces=false,
    showstringspaces=false,
    showtabs=false,
    breaklines=true,
}
\lstset{style=mystyle}
\newif\ifapplymulticol
\makeatletter
\lst@AddToHook{InitVars}{\ifapplymulticol\edef\lst@next{\noexpand\multicols{2}}\expandafter\lst@next\fi}
\lst@AddToHook{ExitVars}{\ifapplymulticol\def\lst@next{\global\let\@checkend\@gobble
                      \endmulticols
                      \global\let\@checkend\lst@@checkend}
        \expandafter\lst@next\fi}
\makeatother


\begin{document}
    \lstset{language=Cpp}
    \applymulticoltrue
    \begin{lstlisting}[frame=tb, caption={caption}]
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>

    void swap(int *q, int a, int b) {
        int tmp = q[a];
        q[a] = q[b];
        q[b] = tmp;
    }

    void quick_sort(int *q, int l, int r)
        {
        if (l >= r) {
            return;
        }
        int x = q[(l + r) >> 1];
        int i = l - 1;
        int j = r + 1;
        while (i < j) {
            do i++; while (q[i] < x);
            do j--; while (q[j] > x);
            if (i < j) {
                swap(q, i, j);
            }
        }
        quick_sort(q, l, j);
        quick_sort(q, j + 1, r);
    }
    \end{lstlisting}

\applymulticolfalse
Some text with inline listing \lstinline{i = i + 1;} in a sentence

Some text with inline listing \lstinline{do i++; while (q[i] < x); do j--; while (q[j] > x);} in a longer sentence

\end{document}

结果:

在此处输入图片描述

相关内容