[Tex/LaTex] lstlisting environment: applying syntax typesetting to escaped code

codelistings

The lstlisting environment provided by the listings package allows you to escape out of the environment and insert arbitrary LaTeX code which is evaluated using the usual (non-verbatim) rules. What I am interested in is whether it is possible to insert text into an lstlisting environment using a macro that is then still parsed by the lstlisting environment.

The motivation for wanting to do this is the following. I am working on a project with lots of lstlisting environments and we want to provide macros for certain code snippets that frequently occur so that (i) it enforces standardization across the document, and (ii) if we want to change the snippets then we only have to do it in one place.

The MWE below hopefully demonstrates what I'm trying to achieve. This isn't a very realistic example of the kind of situation that we would use this for, but hopefully makes for a clear example. The goal of the MWE would be to have the lstlisting environment recognize the text inserted by the macro as a comment and consequently typeset it using a bold font. An image of the compiled example is shown at the very bottom.

Also notice that the macro is inserting an extra space for some reason in the second code block.

\documentclass{article}

\usepackage{listings}

\lstset{%
  language=bash,
  basicstyle=\fontfamily{pcr}\selectfont,
  commentstyle=\bfseries,
  escapeinside={(*@}{@*)}
}

\newcommand{\comment}[1]{\# here is a comment: #1}


\begin{document}

This is how the example currently looks after compilation.  Notice that the text
after the pound sign in the second code block isn't typeset using bold font.

\begin{lstlisting}
# here is a comment: hardcoded
echo example 1
\end{lstlisting}

\begin{lstlisting}
(*@\comment{using a macro}@*)
echo example 2
\end{lstlisting}


\end{document}

enter image description here

Best Answer

It seems you want to escape from the lstlisting just to silently re-enter it again for highlighting keywords or other syntax parts in your comment later. So why not just stay in the lstlisting? You can define a new delimited environment with mordelim=**[is] that removes the delimiters from the output but still applies all other styles to the text between them. With that a new comment environment [*@ ... @*] might look like this:

\documentclass{article}

\usepackage{listings}
\usepackage{xcolor}

\lstset{%
  language=bash,
  basicstyle=\fontfamily{pcr}\selectfont,
  commentstyle=\bfseries,
  escapeinside={(*@}{@*)},
  moredelim=**[is][\commentstyle]{[*@}{@*]},
  keywordstyle={\color{blue}}
}

\newcommand{\commentstyle}{\frenchspacing \bfseries \# here is a comment: }
\newcommand{\comment}[1]{\# here is a comment: #1}

\begin{document}
This is how the example currently looks after compilation.  Notice that the text
after the pound sign in the second code block isn't typeset using bold font.

\begin{lstlisting}
# here is a comment: hardcoded
echo example 1
\end{lstlisting}

\begin{lstlisting}
(*@\comment{using a macro}@*)
echo example 2
\end{lstlisting}

\begin{lstlisting}
[*@with keywords like echo@*]
echo example 3
\end{lstlisting}
\end{document}

enter image description here