19

I'm looking for an easy and robust way to strip all the comments from a listing. My approach (passing \@gobble to the commentstyle key) correctly removes all the one-line comments and block comments. However, the white space left behind by by block comments remains, creating useless gaps in my listing. See the screenshot below (the red rectangle is my emphasis). Any idea?

enter image description here

\documentclass{article}

\usepackage{xcolor}
\usepackage[T1]{fontenc}
\renewcommand{\ttdefault}{pcr}
\usepackage{listings}

\makeatletter
\lstset%
{%
  basicstyle   = \ttfamily,
  morecomment  = [l]{//},
  morecomment  = [s]{/*}{*/},
  frame        = single,
  commentstyle = \itshape\color[gray]{.5},
  rulecolor    = \color{black},
  breaklines,
}
\makeatother

\usepackage{filecontents}
\begin{filecontents*}{sample.c}
#include <stdio.h> 
/*
 block comment taking up white space
*/
main()
{
    float fahr, celsius;
    float lower, upper, step;
    lower   = 0;    /* lower limit of temperature scale */
    upper   = 300;  /* upper limit */
    step    = 20;   /* step size */
    celsius = lower;
    printf("\nCelsius\tFahr\n");
    while (celsius <= upper)   
    {
        fahr = (9.0/5.0) * celsius+32.0;
        printf("%3.0f\t%6.1f\n", celsius, fahr);
        celsius = celsius + step;
    }
}
\end{filecontents*}

\begin{document}
\makeatletter
\lstinputlisting[caption={with comments}]{sample.c}
\lstinputlisting[caption={without comments},commentstyle={\@gobble}]{sample.c}
\makeatother
\end{document} 
  • I would just go for a code beautifier avoid using tex/latex for this one. – user2485710 Feb 13 '14 at 20:40
  • @user2485710 Thanks, but this question is specifically about LaTeX and the listings package. But if you know of a code beautifier that allows for typesetting code in LaTeX and switch the comments off with a flip of a switch, I'm interested... – jub0bs Feb 13 '14 at 21:17
  • Does this answer help you? tex.stackexchange.com/questions/5625/… – aganders3 Feb 13 '14 at 21:34
  • @aganders3 No. My feeling is the same as expressed in the first comment on the answer: I don't want any blank space left behind block comments. – jub0bs Feb 13 '14 at 22:42
13
+150

First version

Below I defined two list styles, where the first is loaded by the second, and then the first comment definitions are overwritten. For block comments the invisible variant is used. This does not work for line comments, though (more on this at bottom of this answer). But you can add the command you already used as second optional argument, what works fine:

\documentclass{article}

\usepackage{xcolor}
\definecolor{commentcolor}{gray}{.5}
\definecolor{rulecolor}{named}{black}

\usepackage[T1]{fontenc}
\renewcommand{\ttdefault}{pcr}

\usepackage{listings}
\lstdefinestyle{c_with_comments}%
{
  basicstyle   = \ttfamily,
  language=c,
  morecomment  = [l]{//},
  morecomment  = [s]{/*}{*/},
  frame        = single,
  commentstyle = \itshape\color{commentcolor},
  rulecolor    = \color{rulecolor},
  breaklines,
}
\makeatletter
\lstdefinestyle{c_without_comments}%
{
  style=c_with_comments,
  morecomment  = [l][\@gobble]{//},
  morecomment  = [is]{/*}{*/},
}
\makeatother

\usepackage{filecontents}
\begin{filecontents*}{sample.c}
#include <stdio.h> 
/*
 block comment taking up white space
*/
main()
{
    float fahr, celsius;
    float lower, upper, step;
    lower   = 0;    /* lower limit of temperature scale */
    upper   = 300;  // upper limit
    step    = 20;   // step size
    celsius = lower;
    printf("\nCelsius\tFahr\n");
    while (celsius <= upper)   
    {
        fahr = (9.0/5.0) * celsius+32.0;
        printf("%3.0f\t%6.1f\n", celsius, fahr);
        celsius = celsius + step;
    }
}
\end{filecontents*}

\begin{document}
\lstinputlisting[caption={with comments},style=c_with_comments]{sample.c}
\lstinputlisting[caption={without comments},style=c_without_comments]{sample.c}
\end{document}

screenshot of example output

Second version

The second version differs in only one line. The output is the same, but this version is quite probably safer (thanks @tohecz for the hint, cf. his comment below this answer). Replace \@gobble with \nullfont:

  morecomment  = [l][\nullfont]{//},

\@gobble is defined in a way, that it needs one argument, and there may be situations, that not the whole line after // is considered as such.


Unfortunately the quite simple approach (using the invisible variant) does only work with block comments. For line comments the output is cut until the end of the whole listing! Confer wrong code and output in edit revision 3 of this answer.

I darkly remembered and had to search for again, but here a cite from listings documentation:

Eventually, you might want to use the prefix i on any comment type. Then the comment is not only invisible, it is completely discarded from the output!

No warning for one line comments. Looks like a bug in listings, at least this must be documented.

  • For line comments, depending on whether you want to just hide them or avoid people accessing them, you can print them white. – yo' Feb 14 '14 at 17:26
  • @tohecz: But only when the background is white, too. It becomes an impossible task, when the background is shaded. – Speravir Feb 14 '14 at 17:54
  • Well ... I dunno ... locallz changing to a null font? I think it's described somewhere in the TeXbook how to achieve that, but I really really don't know – yo' Feb 14 '14 at 17:56
  • Thanks for your answer. That's a start. I see two problems: 1) the block comments still leaves a blank line behind (because of the newline right after the closing delimiter), but there may be a way to gobble that; and 2) you have to redefine the morecomment with the i modifier, which kind of lacks automation. I'm not going to award you with the bounty just yet, because I want to see if a more satisfactory solution can be devised... – jub0bs Feb 17 '14 at 10:16
  • Actually, your answer is not bad at all. The fact that one line is left behind block comments is actually quite desirable, and you can automate the removal of comments by defining a new key: \lst@Key{turncommentsoff}{false}[t]{\lst@CommentKey\@empty{[l][\nullfont]{//}}\lst@CommentKey\relax{[is]{/*}{*/}}}. Feel free to add that to your answer, if you want. – jub0bs Feb 17 '14 at 11:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.