# Literating in listings with and without star at the same time

I am currently writing a language definition with the listings package. My language should be colored in the following way:

• all comments are supposed to be completely green without any exception
• all strings are supposed to be completely red without any exception
• all keywords are supposed to be blue (keywords may contain numbers)
• identifiers are supposed to be black (indentifiers may contain numbers)
• numbers are supposed to be magenta (but not those in keywords or identifiers)
• mathematical operators, brackets, etc are supposed to be cyan

Colouring my language exactly that way is actually not difficult. I managed that by setting basicstyle to magenta, keywordstyle to blue, commentstyle to green, stringstyle to red and then using the * version of literate to color the mathematical operators with cyan. Everything works like a charm. However my language definition must also make it possible to have German umlauts like "ü" in strings or comments. As we know this is a little tricky since listings and the utf8 encoding causes some trouble, but it can in general be achieved by using the literate version without the star.

And here comes the problem. As you can see I must literate a few things with the * version while at the same time literating other things without the star. I have seen that this can be theoretically done like it was done here: How to apply the star (*) to only a few of the literates in listings environment?

This works, but not in all cases. I get into trouble trying to literate the = sign as well as trying to literate the . The problem seems to be that the delimiter for my comments contains a = and that within strings itself the " is excaped by \". Any idea how to fix this?

I have created a MWE and made three outputs, accodring to the comments in the MWE:

\documentclass{standalone}
\usepackage[utf8]{inputenc}
\usepackage{xcolor}
\usepackage{listings}

\lstdefinelanguage{testlang}{
morekeywords={int32,string},
morecomment=[l]{\#},
morecomment=[n]{\#=}{=\#},
morestring=[b]{"}

\makeatletter
\newcommand{\jPm}[1]{%
\ifnum\lst@mode=\lst@Pmode\relax%
{\color{cyan}#1}%
\else%
#1%
\fi%
}
\begin{document}

% defining the colors
\lstset{basicstyle={\color{magenta}\ttfamily}, keywordstyle={\color{blue}\bfseries},
% defining the literals
\lstset{extendedchars=true}
\lstset{literate={ü}{{\"u}}{1} {+}{{{\jPm{+}}}}{1} % the first result does not use the next two lines
%{\\}{{{\jPm{\textbackslash{}}}}}{1} % the second result does not use the next line
%{=}{{{\jPm{=}}}}{1} % the third result also uses this line
}
\lstset{language=testlang}

\begin{lstlisting}
#= A comment that is longer than one line,
and that contains the German word "Blüte". =#

# Single comment: We will calculate 5 + 2 \ 8

string mystr = "An \"escaped string\", a Blüte and 1 + 1 = 2."
int32 my2ndvar = 8
int32 myres = 5 + 2 \ my2ndvar
\end{lstlisting}

\end{document}


Output when only ü and + are literated:

Output when ü, + and \ are literated:

Output when ü, +, \ and = are literated:

After trying out a lot of different things, looking at the documentation and source code of the listings package as well as searching the internet I have finally found a solution myself which of course I want to share with you for those who have the same problem. It might not be the easiest solution, but it works like a charm.

What I have basically done is that I have looked at the source code of the listings package, figured out which commands definine the literate attribute, copied them to my sourcecode and modified them to create a new opliterate attribute, which does the same as the literate attribute. Now I can use the literate attribute to literate wihtout the star and the opliterate attribute to literate with the star.

Here is the code:

\documentclass{standalone}
\usepackage[utf8]{inputenc}
\usepackage{xcolor}
\usepackage{listings}

\lstdefinelanguage{testlang}{
morekeywords={int32,string},
morecomment=[l]{\#},
morecomment=[n]{\#=}{=\#},
morestring=[b]{"}

\makeatletter
\def\lst@OpLiteratekey#1\@nil@{\let\lst@ifxopliterate\lst@if
\def\lst@opliterate{#1}}
\lst@Key{opliterate}{}{\@ifstar{\lst@true \lst@OpLiteratekey}
{\lst@false\lst@OpLiteratekey}#1\@nil@}
{\ifx\lst@opliterate\@empty\else
\expandafter\lst@OpLiterate\lst@opliterate{}\relax\z@
\fi}
\def\lst@OpLiterate#1#2#3{%
\ifx\relax#2\@empty\else
\lst@CArgX #1\relax\lst@CDef
{}
{\let\lst@next\@empty
\lst@ifxopliterate
\lst@ifmode \let\lst@next\lst@CArgEmpty \fi
\fi
\ifx\lst@next\@empty
\ifx\lst@OutputBox\@gobble\else
\lst@XPrintToken \let\lst@scanmode\lst@scan@m
\lst@token{#2}\lst@length#3\relax
\lst@XPrintToken
\fi
\let\lst@next\lst@CArgEmptyGobble
\fi
\lst@next}%
\@empty
\expandafter\lst@OpLiterate
\fi}

\begin{document}

% defining the colors
\lstset{basicstyle={\color{magenta}\ttfamily}, keywordstyle={\color{blue}\bfseries},
% defining the literals
\lstset{extendedchars=true}
\lstset{literate={ü}{{\"u}}{1}}
\lstset{opliterate=*{+}{{{\color{cyan}+}}}{1} {\\}{{{\color{cyan}\lstum@backslash}}}{1} {=}{{{\color{cyan}=}}}{1}}
\lstset{language=testlang}

\begin{lstlisting}
#= A comment that is longer than one line,
and that contains the German word "Blüte". =#

# Single comment: We will calculate 5 + 2 \ 8

string mystr = "An \"escaped string\", a Blüte and 1 + 1 = 2."
int32 my2ndvar = 8
int32 myres = 5 + 2 \ my2ndvar
\end{lstlisting}

\end{document}


And the output looks like:

• +1 That's just ace! Nicely opliterated a problem I've been having trying to replace tilde and carets. – Tom Carpenter Oct 11 at 19:36