10

Hi I am using the lstlisting package to format my Prolog code within my tex file. In Prolog all variables begin with an uppercase letter. I would like to emphasize them. Is there a way to for example add all uppercase letters to the keyword list or adjusting their style. I imagine there is something like this:

\lstset{emph={\wordsbeginninguppercase},emphstyle=\bfseries}

I tried

\lstset{identifierstyle=\bfseries}.

That made everything except for strings bold.

The solution should also only apply to the actual programming language, s.t. uppercase words within strings and comments are not changed.

In the following example FoundClass and Message would be emphasized, but Find and Found not since they are either within a comment or a string.

somerule(Message,FoundClass) :-
    %Find property
    look_for_class_with_property(FoundClass),
    atomic_list_concat(['Found class which fulfills property:' ,FoundClass],Message).

Thanks for your help.

2 Answers 2

8

There's nothing quite so simple. However, you can give your own macro as the argument to identifierstyle and that can examine the \lst@token token list to see if the list starts with an uppercase letter. I'm not sure how robust this solution is though.

\lstset{identifierstyle=\idstyle}

\makeatletter
\newcommand*\idstyle{%
        \expandafter\id@style\the\lst@token\relax
}
\def\id@style#1#2\relax{%
        \ifcat#1\relax\else
                \ifnum`#1=\uccode`#1%
                        \bfseries
                \fi
        \fi
}
\makeatother

I only tested it on the QuickSort example on Wikipedia.

This answer is slightly difficult to figure out exactly what it's doing so let me try to explain. The listings package will use the execute the \idstyle macro whenever it is trying to typeset an identifier and the actual text will be in the \lst@token token register. So all \idstyle does is it expands the token register using \the\lst@token and then \id@style will expand.

\is@style has a delimited argument (#2) which will scoop up every thing up to the \relax token. That is, #1 will contain the first token and #2 will contain all of the rest. Then, the category code of #1 will be compared to that of \relax. This is true if #1 is a control sequence and false otherwise. The second if checks that the token matches its own uppercase code; that is, it checks if the token is an uppercase character. If it is, then \bfseries executes.

6
  • Hi TH, thanks for your quick answer. This solution already works but it also highlights uppercase words within strings and comments. Do you know how to escape this macro if the word is within the mentioned environments or how to activate it only when it has to deal with programming logic?
    – LeoR
    Oct 16, 2010 at 19:27
  • @LeoR: Can you provide a sample? That would make it easier to test out. I'm actually sort of surprised that it would treat words in strings as identifiers since it should be using stringstyle for those instead. Same with comments.
    – TH.
    Oct 16, 2010 at 19:30
  • @TH Sure. I originally thought this problem can be abstracted to arbitrary programming languages so I didn't provide a concrete Prolog example.
    – LeoR
    Oct 16, 2010 at 19:47
  • 1
    @LeoR: And sure enough, neither Find nor Found are in boldface. You must be doing something more than you've shown.
    – TH.
    Oct 16, 2010 at 20:22
  • You are right. When I initially used the language setting Prolog, I had a variable called "Name" which was the only one which would be displayed boldface, although I don't know why. So I added \lstdefinelanguage{Prolog} { deletekeywords=[1]{Name} } that removed the boldface presentation of Name but I didn't realize that it also removed the rest of the Prolog related presentation. After I removed that your solution worked fine for me as well. Thanks again.
    – LeoR
    Oct 16, 2010 at 20:42
4

Putting this here because had the same problem, found this question and used code from the accepted answer, but then expanded it; might be useful for somebody else

Here's a variant using LaTeX3's experimental regular expressions. Of course that's overkill for the question, but by matching the token against a regex it's much more powerful. Here I'm using it to differentiate between camelCase and snake_case identifiers.

\documentclass{article}
\usepackage{listings,xparse,l3regex}

\ExplSyntaxOn

% compile the expression
\regex_new:N \l_pascal_camelcase_regex
\regex_set:Nn \l_pascal_camelcase_regex { ^ [a-z]* [A-Z]+ [a-zA-Z]* $ } 

% a variant that expands the input fully
\cs_generate_variant:Nn \regex_match:NnTF {No}

\NewDocumentCommand \ifcamelcase { m m }
{
    % expand to actual underscore
    \cs_set_eq:Nc \__pascal_camelcase_um { lst@um_ }
    \tl_set:cn { lst@um_ } { _ }
    % match the current token
    \regex_match:NoTF \l_pascal_camelcase_regex {\the\use:c{lst@token}} {#1} {#2}
    % reset
    \cs_set_eq:cN { lst@um_ } \__pascal_camelcase_um
}

\ExplSyntaxOff

\lstset{
    alsoletter={?_},
    columns=fullflexible,
    identifierstyle=\ifcamelcase{\bfseries}{\itshape}
}

\begin{document}

\begin{lstlisting}
thisIsCamelCase
UppercaseCamel
this_is_snake_case
Uppercase_Snake
_
\end{lstlisting}

\end{document}

We redefine \lst@um_ before expanding the token to avoid this error:

./snakecase.tex:37: Extra \else.
\lst@PrintToken ...@Output \lst@letterfalse \else 
                                                  \lst@OutputOther \let \lst...
l.37 _

Result:

two bold lines, followed by two italic lines

3
  • Very nice. I took the liberty of improving your coding style to avoid \def and \let, together with \makeatletter. Only \the remains, which is somewhat unavoidable.
    – egreg
    Apr 16, 2015 at 11:00
  • Awesome! This can also be used as a hack to get hexadecimal numbers (e.g. 0xFF) properly highlighted when \identifierstyle differs from \basicstyle (where listings draws 0 as basic and xFF as identifier). To that end, one needs \regex_set:Nn \l_pascal_camelcase_regex {^x[A-F0-9a-f]+$} and set the first color to the same as \otherstyle. Naturally this is not a complete solution because identifiers like xf will not be drawn correctly but it's actually the best solution I could come up for that yet.
    – stefanct
    Sep 9, 2016 at 15:21
  • My regex should be correct, but apparently it does nonetheless not match for some reason. This works better: {x[A-Fa-f01-9]+[^A-Fa-f0-9]*$}. I could not determine what character was trailing the hexadecimals but apparently there is sometimes something before the $.
    – stefanct
    Sep 9, 2016 at 15:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .