6

The project I'm working on right now is a general template for documents that will contain code from an arbitrary programming language. Specifically, I'm trying to make a nice layout for code in the documents using the lstlistings package. However, I'm running into some trouble with the placement of the asterisks in the layout.

Bad asterisks

Specifically the problem I have is the fact that the typewriter font families tend to place the asterisk vertically centered, whereas most other fonts place theirs up near the top of the line.

My ideal solution, derived from Highlight asterisk in lstlisting, is basically to replace the font used to render the asterisk.

I tried to imitate this method and expand on it. Specifically, I'm using the key-value pair literate=\*{\*}{\normalfont{\*}}1 in the \lstset command. (literate is a form of string replace. More info: listings docs, page 50). The basic idea is to for every asterisk to be the default font instead of the typewriter font.

This solution works well for most of the document, but as the top answer says, the solution presented there works "only in listings normal mode, not within strings, comments, and other delimited stuff." which is exactly what's giving me such a problem. In most programming languages, the delimiters /* ... */ define a multi-line comment. However, the above solution causes lots of problems when you start playing with substrings of delimiters.

There is an optional star you can leave off of the literate command (i.e. literate={\*}{\normalfont{\*}}1 instead of literate=\*{\*}{\normalfont{\*}}1") which "indicates that literate replacements should be made in strings, comments, and other delimited text" which one would think would solve the problem, but upon replacing the text, it stops behaving well.

Bad parsing

As you can see in this screenshot, the pink multi-line comment color extends well past the ending delimiter.

One of the strange things is that this behavior occurs even when you use literate simply to replace the asterisk with another identical asterisk (literate={\*}{\*}1).

Other solutions I've imagined:

  • Deal with it
  • Somehow preprocess/preformat the code to replace all occurrences of /* and */ with some other delimiter.
  • Preform some kind of really messy conditional string replacement on each token in the comment (When the comment is parsed, it seems as though essentially each token is given the style instead of the whole comment as one piece of text)

I haven't dismissed the idea of using the fontenc package to use a typewriter font that has a better asterisk, but for some reason, loading the fontenc package makes compilation time incredibly long, so I'd like to stick to using the default fonts for now.

Relevant code:

Main.tex:

\usepackage{listings} 
\usepackage{color} 
\definecolor{stringColor}{RGB}{42,0.0,255}
\definecolor{keyword1Color}{RGB}{63,127,95}
\definecolor{keyword2Color}{RGB}{63,127,200}
\definecolor{singleLineCommentColor}{RGB}{127,0,85}
\definecolor{multiLineCommentColor}{RGB}{200,0,127}

\lstdefinelanguage{test}{
    basicstyle=\linespread{0.83}\small\ttfamily, % Global Code Style
    literate=*{*}{\normalfont{*}}1,
    morecomment=[l][\color{singleLineCommentColor}]{//}, 
    morecomment=[s][\color{multiLineCommentColor}]{/*}{*/},
    morestring=[b]",
    morestring=[b]',
    commentstyle=\color{commentColor}, 
    keywordstyle=[1]{\bfseries\color{keyword1Color}}, 
    keywordstyle=[2]{\bfseries\color{keyword2Color}}, 
    stringstyle=\color{stringColor}, 
    %...
}

\begin{document}
\lstinputlisting[language=test]{code1.txt}
\end{document}

code1.txt (test code)

import math

def hi():
    print "Hello!"
    print "This is a test!"
    print 'This is a test!'
    print "This is a 'single 'quote within 'a double quote 'string" 
    one two three four five six seven eight nine
    //Comment 1
    /* Bad asterisk placement! */ 
    $t=0$ //Disable math parsing
def f(x):
    return x**2 //Good asterisk placement

Any advice would be greatly appreciated. I've been working on this for several hours now without much success (though it has been pretty useful for my goal of learning more about how TeX works) If I've left out any relevant information let me know and I'll update the post asap.

  • I don't recall this being an issue in the font I used, which was Latin modern tt condensed. But I didn't use block comments or any adjustments. I've just checked and they're higher than in your bad case but lower than you'd like. – Chris H Apr 10 '16 at 7:52
5

You can change the command listings use when processing the asterisk:

\documentclass{scrbook}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{listings}

\usepackage{color}
\definecolor{stringColor}{RGB}{42,0.0,255}
\definecolor{keyword1Color}{RGB}{63,127,95}
\definecolor{keyword2Color}{RGB}{63,127,200}
\definecolor{singleLineCommentColor}{RGB}{127,0,85}
\definecolor{multiLineCommentColor}{RGB}{200,0,127}

\lstdefinelanguage{test}{
    basicstyle=\linespread{0.83}\small\ttfamily, % Global Code Style
    %literate=*{*}{\normalfont{*}}1,
    morecomment=[l][\color{singleLineCommentColor}]{//},
    morecomment=[s][\color{multiLineCommentColor}]{/*}{*/},
    morestring=[b]",
    morestring=[b]',
    commentstyle=\color{commentColor},
    keywordstyle=[1]{\bfseries\color{keyword1Color}},
    keywordstyle=[2]{\bfseries\color{keyword2Color}},
    stringstyle=\color{stringColor},
    %...
}



\begin{document}
\begin{lstlisting}[language=test]
    /* Bad asterisk placement! */
x**3
\end{lstlisting}    

\makeatletter
\lst@CCPutMacro
    \lst@ProcessOther {"2A}{%
      \lst@ttfamily 
         {\raisebox{2pt}{*}}% used with ttfamily
         \textasteriskcentered}% used with other fonts
    \@empty\z@\@empty
\makeatother  

\begin{lstlisting}[language=test]
    /* good asterisk placement! */
x**3
\end{lstlisting}

\end{document}

enter image description here

  • This is beautiful. Thank you. Do you have any recommended resource on how to figure things like this out on my own when I come across them? I find TeX to be rather arcane in this sense. – exyphrius Apr 19 '16 at 5:55
  • You have to look in the code to find out such things. – Ulrike Fischer Apr 19 '16 at 6:25

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.