我可以用 minted 只打印一些函数吗?

我可以用 minted 只打印一些函数吗?

我经常需要打印源代码,但通常只打印项目的一部分。现在我接到一个改进两个功能的任务,我必须打印出我所做的更改。我使用 minted 来打印源代码。

我怎样才能告诉 minted 仅打印给定的函数?

就像是:

\inputminted[functions=helloWorld,functions=abc,
                fontsize=\footnotesize, tabsize=4]{c}{/home/moose/Desktop/RO/blatt02.c} 

如果这不可能的话,我也会接受,如果我可以告诉 minted 打印一些给定的行,例如:

\inputminted[from=12, to=50,
                fontsize=\footnotesize, tabsize=4]{c}{/home/moose/Desktop/RO/blatt02.c} 

这虽然不如功能那么好,但是也可以。

答案1

Method 1

我做到了,天哪!我一个人做到了!这是最棒的一天!好吧,严格来说现在是晚上。无论如何。:)

愿康拉德·鲁道夫怜悯我。:)以下代码是肮脏的黑客代码。但我们确实喜欢肮脏的代码,不是吗?

首先,这个技巧依赖于强大的awk。我们可以使用格式打印文档中的范围'NR==x,NR==y',其中x表示“当前行是x行”,y表示“当前行是第y”。因此awk将打印它们之间的间隔。

我们可以将awk输出通过管道传输到pygmentize,供 所用minted。然后我向 添加了两个选项minted

  • linestart:要打印的第一行。
  • lineend:要打印的最后一行。

首先,让我们考虑以下helloworld.c示例代码(为方便起见添加了行):

1. #include <stdio.h>
2. 
3. int main(void) {
4.     printf("Hello world\n");
5.     return 0;
6. }

现在.tex代码:

\documentclass{article}

\usepackage{minted}

\makeatletter
\minted@define@opt{linestart}{NR==#1}
\minted@define@opt{lineend}{NR==#1}
\renewcommand\minted@pygmentize[2][\jobname.pyg]{%
\ifthenelse{\equal{\minted@opt@linestart}{}}{\def\minted@awk{}}{\def\minted@awk{awk '\minted@opt{linestart},\minted@opt{lineend}' #1 |}}
\ifthenelse{\equal{\minted@opt@linestart}{}}{\def\minted@fromsource{#1}}{\def\minted@fromsource{}}
\def\minted@cmd{\minted@awk pygmentize -l #2 -f latex -F tokenmerge
\minted@opt{gobble} \minted@opt{texcl} \minted@opt{mathescape}
\minted@opt{startinline} \minted@opt{funcnamehighlighting}
\minted@opt{linenos} -P "verboptions=\minted@opt{extra}"
-o \jobname.out.pyg \minted@fromsource}
\immediate\write18{\minted@cmd}
\ifthenelse{\equal{\minted@opt@bgcolor}{}}
{}
{\begin{minted@colorbg}{\minted@opt@bgcolor}}
\input{\jobname.out.pyg}
\ifthenelse{\equal{\minted@opt@bgcolor}{}}
{}
{\end{minted@colorbg}}
\DeleteFile{\jobname.out.pyg}}
\makeatother

\begin{document}
\inputminted[linestart=3,lineend=5]{c}{helloworld.c}
\end{document}

运行之后(当然,--shell-escape启用后),这是我们的输出:

The output

好了,我们minted有了线路范围。:)

Method 2

编辑:回到工作台。:)

我的好朋友马可·丹尼尔指出了一种更适合这种情况的现成解决方案:使用firstlinelastline选项fancyvrb/minted本身。它完全按照我上次尝试的方式进行操作,但没有我经历的所有危险弯路:

\documentclass{article}

\usepackage{minted}

\begin{document}
\inputminted[firstline=3,lastline=5]{c}{helloworld.c}
\end{document}

我们将获得同样的结果。:)

Method 3

编辑:为了完整起见,我决定再试一次,并根据其完整限定名称打印函数范围。就是这样。:)

以下awk代码取自如何从 C 源文件中提取 C 函数定义。根据作者的说法,“以下内容假设括号匹配,并且}函数的结束符是其行中的最后一个字符。”我对其进行了轻微修改,以设置函数名称。原始代码中硬编码了提取函数。

function match_braces() {
s=$0
# how to abuse gsub
op=gsub(/{/,"",s);
cl=gsub(/}/,"",s);
if (op || cl) f=1;
return (op-cl);
}

match($0, v) {ok=1}
ok {n+=match_braces(); print; if ((n==0)&&(f==1)) exit}

我将其另存为extract.awk并放在我的.tex文件的同一目录中。创建一个别名甚至一个 shell 脚本来包装对此代码的调用并将其导出到路径会更明智。出于显而易见的原因,我选择了更简单的方法。:)

让我们使用另一个helloworld.c

#include <stdio.h>

void sayHello() {
    printf("Hello world!\n");
}

void sayGoodBye() {
    printf("Goodbye world!\n");
}

int main(void) {
    sayHello();
    sayGoodBye();
    return 0;
}

现在,我们的.tex代码:

\documentclass{article}

\usepackage{minted}
\usepackage{lipsum}

\makeatletter
\minted@define@opt{function}{#1}
\renewcommand\minted@pygmentize[2][\jobname.pyg]{%
\ifthenelse{\equal{\minted@opt@function}{}}{\def\minted@awk{}}{\def\minted@awk{awk -vv="\minted@opt@function" -f extract.awk #1 |}}
\ifthenelse{\equal{\minted@opt@function}{}}{\def\minted@fromsource{#1}}{\def\minted@fromsource{}}
\def\minted@cmd{\minted@awk pygmentize -l #2 -f latex -F tokenmerge
\minted@opt{gobble} \minted@opt{texcl} \minted@opt{mathescape}
\minted@opt{startinline} \minted@opt{funcnamehighlighting}
\minted@opt{linenos} -P "verboptions=\minted@opt{extra}"
-o \jobname.out.pyg \minted@fromsource}
\immediate\write18{\minted@cmd}
\ifthenelse{\equal{\minted@opt@bgcolor}{}}
{}
{\begin{minted@colorbg}{\minted@opt@bgcolor}}
\input{\jobname.out.pyg}
\ifthenelse{\equal{\minted@opt@bgcolor}{}}
{}
{\end{minted@colorbg}}
\DeleteFile{\jobname.out.pyg}}
\makeatother

\begin{document}

\inputminted[function={int main}]{c}{helloworld.c}

\lipsum[1]

\inputminted[function={void sayHello}]{c}{helloworld.c}

\lipsum[1]

\inputminted[function={void sayGoodBye}]{c}{helloworld.c}

\end{document}

我们的新输出:

Output 5

正如 Konrad 在评论中提到的,这个技巧不可移植,因为它只适用于少数几种语言,并且依赖于某些代码标准。尽管如此,这仍然是一个很棒的功能。:)

答案2

这是一种侵入性较小、略有不同的方法,重新绑定\MintedPygmentize到脚本。我选择使用 和 等明确标记要提取的部分(参见下面的示例//!begin:main//!end:main

文件extract.sh

#!/bin/zsh -f

args=($@)
marker=$args[1]
shift args
file=$args[-1]
args[-1]=()

sed -n "\?//!begin:$marker\$? { :a n; \?//!end:$marker\$?q; p; ba }" $file | \
    grep -v '//!' | \
    pygmentize $args

文件main.tex

\documentclass{article}

\usepackage{minted}
\usepackage{lipsum}

\newcommand{\inputmintedannotated}[4][]{
  \begingroup
  \renewcommand{\MintedPygmentize}{%
    extract.sh\space #2}
  \inputminted[#1]{#3}{#4}%
  \endgroup
}

\begin{document}

\inputmintedannotated{main}{c}{helloworld.c}

Full file:

\inputminted{c}{helloworld.c}

\end{document}

Example

相关内容