The problem in your literate
text are the extra braces in the replacement text.
When the second parameter of the literate
key is parsed, each LaTeX token or {...}
-group—let's call them item—is considered a replacement of one character of the output. Thus, {{\color{red}Hello}}
is parsed as a single item and results in the wrong spacing. The 5
at the end only tells it to assume the overall replaced text has a width of 5 times the width of a single character.
So the solution is to split the replacement text over 5 (printable) items:
{\unskip\bgroup\color{red}}Hello{\unskip\egroup}
Note that the first and last items are considered output characters now, too. As the \bgroup\color{red}
and \egroup
parts are not printable, there is no space occupied in the output for them. However, listings
inserts an additional glue before each item, which has to be removed by \unskip
to get the proper overall spacing.
See the difference in output of the following example:
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{\jobname.c}
/*
* Hello World Program
*/
// Hello
#include <stdio.h>
int main (void) {
printf("Hello World!\n");
int Hello = 0;
int hello = 0;
return Hello;
}
\end{filecontents*}
\usepackage{listings,xcolor}
\lstset{
language=C,
}
\begin{document}
\lstinputlisting[literate={Hello}{{{\color{red}Hello}}}5]{\jobname.c}
\lstinputlisting[literate={Hello}{{\unskip\bgroup\color{red}}Hello{\unskip\egroup}}5]{\jobname.c}
\end{document}

I'd like to add a note on why the emph
version didn't work. listings
has different ways to define new delimited parts of the input text. Relevant in your example are the morecomment
and morestring
keys. Each of them is available in a non-starred (morecomment=
) and in a starred (morecomment=*
) version.
When the former version is used, the text between the delimiters is not scanned for other classes like keywords or emphasized words. However, for the starred version, the text is scanned for other classes and appropriate styles are applied. In the case of predefined language styles those delimited classes are defined as the non-starred version. So if you want the text replacement inside them, you have to redefine them as starred version.
Note that it doesn't seem to be possible to choose between class styles that are applied and those that are not applied inside delimited environments. To work around the unwanted side effect of keywords also being highlighted in comments or strings, we can save the currently active style before keyword style is applied and apply it only when outside of special delimited environments:
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{\jobname.c}
/*
* Hello World Program
*/
// Hello
#include <stdio.h>
int main (void) {
printf("Hello World!\n");
int Hello = 0;
int hello = 0;
World greetings;
return Hello;
}
\end{filecontents*}
\usepackage{listings,xcolor}
\makeatletter
\lstset{
language=C,
emph={Hello},
emphstyle=\emphstyle,
morekeywords={World},
keywordstyle=\keywordstyle,
morecomment=*[l][\special@on\color{gray}\itshape]{//},
morecomment=*[s][\special@on\color{gray}\itshape]{/*}{*/},
morestring=*[b][\special@on\color{green}]",
}
\newif\ifspecial@env@
\def\special@on{\global\special@env@true}
\def\special@off{\global\special@env@false}
\lst@AddToHook{DetectKeywords}{%
\global\let\last@lst@thestyle=\lst@thestyle
}
\def\emphstyle{%
\last@lst@thestyle
\aftergroup\special@off
\underbar
}
\def\keywordstyle{%
\ifspecial@env@
\last@lst@thestyle
\else
\color{blue}%
\fi
\aftergroup\special@off
}
\makeatother
\begin{document}
\lstinputlisting{\jobname.c}
\end{document}

Here the World
keyword is only highlighted when outside of comments and strings, while the underline style for the emphasized word Hello
is applied everywhere.
listings
does not adjust the tracking forliterate
. It left the job to you so that you can emphasis the word more freely. Check alsomathescape
and what follows for an alternative approach. By the way, sincelistings
pretends to be an IDE, it should not -- and it did not -- highlight keywords in comments. If a comment is so important that all readers must recognize it, typeset outside thelstlisting
, where you are really free.mathescape
alternative (and the other escaping mechanisms oflistings
), but as I wrote in the question I would prefer to not change the included source code, hence these options are NO alternatives. Thatlistings
understands the comments is correct and indeed part of the problem in this case...listings
itself. How aboutcolumns=fullflexible,keepspaces
? Or you might want to know the default value ofbasewidth
and mimic the behavior.