I did, egreg! I did it by myself! Best day ever! Well, technically it's night. Anyway. :)
May Konrad Rudolph have mercy on me. :)
The following code is a dirty, dirty hack. But we do love dirty code, don't we?
First things first. This trick relies on the powerful awk
. We can print ranges from a document by using the format 'NR==x,NR==y'
, where x
means "the current line is the x
th line" and y
means "the current line is the y
th line". So awk
will print the interval between them.
We can pipe the awk
output to pygmentize
, which is used by minted
. Then I added two options to minted
:
linestart
: the first line to be printed.
lineend
: the last line to be printed.
First, let's consider the following helloworld.c
sample code (lines added for our convenience):
1. #include <stdio.h>
2.
3. int main(void) {
4. printf("Hello world\n");
5. return 0;
6. }
Now the .tex
code:
\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}
After running it (of course, with --shell-escape
enabled), this is our output:
There we go, minted
with line ranges. :)
Edit: Back to the crafting table. :)
My good friend Marco Daniel pointed out an out-of-the-box solution which is way more appropriate for this case: using firstline
and lastline
options from fancyvrb/minted
themselves. It does exactly what I did in the previous attempt, but without all the dangerous bends I went through:
\documentclass{article}
\usepackage{minted}
\begin{document}
\inputminted[firstline=3,lastline=5]{c}{helloworld.c}
\end{document}
And we shall obtain the very same result. :)
Edit: For the sake of completeness, I decided to try again and print the function scope based on its full qualified name. Here it goes. :)
The following awk
code is taken from How to extract a C function definition from a C source file. According to the author, "the following assumes balanced braces, and that the closing }
for a function
is the last character in its line." I modified it slightly in order to set the function name. The original code had the function to extract hardcoded.
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}
I saved it as extract.awk
and put it in the same directory of my .tex
file. It would be wiser to create an alias or even a shell script to wrap the call to this code and export it to the path. I'm taking the easier route, for obvious reasons. :)
Lets use another helloworld.c
:
#include <stdio.h>
void sayHello() {
printf("Hello world!\n");
}
void sayGoodBye() {
printf("Goodbye world!\n");
}
int main(void) {
sayHello();
sayGoodBye();
return 0;
}
Now, our .tex
code:
\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}
Our new output:
As Konrad mentioned in the comments, this trick is not portable, since it works only with a few range of languages and it relies on certain code standards. Nonetheless, it's a neat feature. :)
Best Answer
2012-02-01: Updated to allow for adjustment of spacing between subsequent lines.
Here is a solution for the first two problems adapted from In listings, how to show referenced linenumbers instead of standard ascending linenumbers.
Syntax:
where:
*
adjust space above current line (optinal)[percentage]
= percentage of\baselineskip
to leave above current line (optional, ignored if*
is not used). If not specified this is defaults to be1.0
meaning the entire spacing above is suppressed.<line number>}
is the line number of which the listing is to be printed<file name>
is the file name of the input fileNotes:
xparse
package to provide the starred version of the command. If you do not want to include an additional package, please see other methods of Defining starred versions of commands (* macro)Code: