# Pretty-printing LaTeX syntax with lstlisting environment

I would like this:

\begin{lstlisting}
\mymacro[<optional argument>]{<mandatory argument>}
\end{lstlisting}


to generate output like this:

I've made a couple attempts at this, but haven't succeeded yet.

Here's a complete test document that shows what I've tried so far:

\documentclass{article}

% Macros for the syntax environment
\newcommand*{\cs}[1]{{\ttfamily\char\\#1}}
\newcommand*{\meta}[1]{{\ensuremath{\langle}\rmfamily\itshape#1\/\ensuremath{\rangle}}}
\newcommand*{\oarg}[1]{{\ttfamily[\meta{#1}]}}
\newcommand*{\marg}[1]{{\ttfamily\char\{\meta{#1}\char\}}}
\newenvironment{syntax}{\par\medskip\bgroup\obeyspaces\strut}{\egroup\medskip}

\usepackage{listings}

% Shortcut for verbatim code
\lstMakeShortInline[basicstyle=\ttfamily]|

% First attempt to pretty-print the syntax
\lstdefinestyle{first}{%
columns=fullflexible,
basicstyle=\ttfamily,
moredelim={[is][\meta]{<}{>}},
}

\lstdefinestyle{second}{%
columns=fullflexible,
basicstyle=\ttfamily,
literate=*{<}{{$\langle$\itshape}}{1}{>}{{\/$\rangle$}}{1},
}

\begin{document}

\parindent0pt

\section{The problem}

I would like this:

\begin{lstlisting}
\mymacro[<optional argument>]{<mandatory argument>}
\end{lstlisting}%

to generate output like this:

\begin{syntax}
\cs{mymacro}\oarg{optional argument}\marg{mandatory argument}
\end{syntax}

\section{Partial solutions}

The first attempt uses the |moredelim| key:

\begin{lstlisting}[style=first]
\mymacro[<optional argument>]{<mandatory argument>}
\end{lstlisting}

It looks like the |\meta| macro is applied to each word'' instead of the entire text delimited by |<| and |>|.

\medskip

The second attempt uses the \texttt{literate} key:
\begin{lstlisting}[style=second]
\mymacro[<optional argument>]{<mandatory argument>}
\end{lstlisting}

This successfully replaces the |<| and |>| characters, but doesn't apply the |\itshape| formatting.

Any suggestions? Thanks!

\end{document}

-

It works with delimiters, if you use moredelim with the ** option. In this case, the delimiter macro is invoked not around every single word, but at the begin of the group that is made out of the delimited text. You just have to grab the group's content into a lrbox to typeset the < and > around it:

\documentclass{article}

% Macros for the syntax environment
\newenvironment{syntax}{\par\medskip\bgroup\obeyspaces\strut}{\egroup\medskip}

\makeatletter
\newenvironment{hl@env}
{\begin{lrbox}{\@tempboxa}\rmfamily\itshape}
{\end{lrbox}\ensuremath{\langle}\usebox{\@tempboxa}\kern.3ex\ensuremath{\rangle}}

\newcommand\boxmeta{%
\begin{hl@env}\bgroup\aftergroup\hl@endenv%
}
\def\hl@endenv{%
\end{hl@env}%
\egroup
}
\makeatother

\usepackage{listings}

% Shortcut for verbatim code
\lstMakeShortInline[basicstyle=\ttfamily]|

% First attempt to pretty-print the syntax
\lstdefinestyle{first}{%
columns=fullflexible,
basicstyle=\ttfamily,
moredelim=**[is][\boxmeta]{<}{>},
}

\begin{document}

\parindent0pt

\section{The problem}

I would like this:

\begin{lstlisting}
\mymacro[<optional argument>]{<mandatory argument>}
\end{lstlisting}%

to generate output like this:

\begin{syntax}
\cs{mymacro}\oarg{optional argument}\marg{mandatory argument}
\end{syntax}

\section{Working solution}

The first attempt uses the |moredelim=**| key:

\begin{lstlisting}[style=first]
\mymacro[<optional argument>]{<mandatory argument>}
\end{lstlisting}

This works :-)

\end{document}


-
Can we add the italic correction before the right angle bracket? (Compare $\langle$\itshape optional$rlangle$ with $\langle$\itshape optional\/$\rangle$.) –  godbyk Mar 15 '12 at 22:38
@godbyk: Not directly as the italic content has been boxed, but we could mimic it's effect, e.g. by \kern.3ex. See updated answer. –  Daniel Mar 15 '12 at 22:56

You could try the following but I doubt a bit that it is very robust. I fear that the font changes leak out to places where you don't want them.

\documentclass{article}
\usepackage[formats]{listings}

\lstdefinestyle{first}{%
columns=fullflexible,
basicstyle=\ttfamily,
}

\makeatletter
\lstdefineformat{argument}{%
<=$\langle$\aftergroup\rmfamily\aftergroup\itshape,%
>=$\rangle$\aftergroup\normalfont\aftergroup\lst@basicstyle}%
\makeatother

\begin{document}
\begin{lstlisting}[style=first,format=argument]
\mymacro[<optional argument>]{<mandatory argument>}
\end{lstlisting}

\end{document}

-
I like the succinctness of this solution. Can the spaces at the beginning of the lines be preserved? –  godbyk Mar 15 '12 at 22:14

If you are willing to list the commands as morekeywords, then you could use:

\lstdefinelanguage{MyLanguage}{
showstringspaces=false,
identifierstyle=\color{black}\rmfamily\itshape,
keywordstyle=\color{black}\bfseries,
}

\lstdefinestyle{third}{%
language=MyLanguage,
columns=fullflexible,
basicstyle=\ttfamily,
literate=*{<}{{$\langle$}}{1}{>}{{\/$\rangle$}}{1},
}


which yields:

## Code:

\documentclass{article}
\usepackage{xcolor}

% Macros for the syntax environment
\newcommand*{\cs}[1]{{\ttfamily\char\\#1}}
\newcommand*{\meta}[1]{{\ensuremath{\langle}\rmfamily\itshape#1\/\ensuremath{\rangle}}}
\newcommand*{\oarg}[1]{{\ttfamily[\meta{#1}]}}
\newcommand*{\marg}[1]{{\ttfamily\char\{\meta{#1}\char\}}}
\newenvironment{syntax}{\par\medskip\bgroup\obeyspaces\strut}{\egroup\medskip}

\usepackage{listings}

% Shortcut for verbatim code
\lstMakeShortInline[basicstyle=\ttfamily]|

\lstdefinelanguage{MyLanguage}{
showstringspaces=false,
identifierstyle=\color{black}\rmfamily\itshape,
keywordstyle=\color{black}\bfseries,
}

\lstdefinestyle{third}{%
language=MyLanguage,
columns=fullflexible,
basicstyle=\ttfamily,
literate=*{<}{{$\langle$}}{1}{>}{{\/$\rangle$}}{1},
}

\begin{document}

\parindent0pt

\section{The problem}

I would like this:

\begin{lstlisting}
\mymacro[<optional argument>]{<mandatory argument>}
\end{lstlisting}%

to generate output like this:

\begin{syntax}
\cs{mymacro}\oarg{optional argument}\marg{mandatory argument}
\end{syntax}

\section{The Solution}

\begin{lstlisting}[style=third]
\mymacro[<optional argument>]{<mandatory argument>}
\end{lstlisting}
\end{document}

-
I think listing each macro as a keyword might get a bit tedious. Another example use would be \mymacro{<placeholder>}{verbatim text here should be monospaced}. Your solution prints the verbatim text in italic. Thanks for the idea, though! –  godbyk Mar 15 '12 at 21:37

Apparently, the literate key cannot force listings to print the argument in italics – but we can use the package to determine what are the control sequences, the comments, and the special characters. Hence, I suggest setting the whole thing in italics and then setting everything that's not an argument back upright.

Here is how you do it:

\documentclass{article}

\usepackage{xcolor,listings}

\newcommand{\macrocolor}[1]{\textcolor{violet}{#1}}
\newcommand{\commentcolor}[1]{\textcolor{purple}{#1}}
\newcommand{\literatecolori}[1]{\textcolor{cyan}{#1}}
\newcommand{\literatecolorii}[1]{\textcolor{blue}{#1}}
\newcommand{\literatecoloriii}[1]{\textcolor{orange}{#1}}

\lstset{
basicstyle=\ttfamily\upshape,
identifierstyle=\rmfamily\itshape,
language=[LaTex]TeX,
texcsstyle=*\macrocolor,
literate=   {\{}{{\literatecolori{\{}$\langle$}}{2}
{\}}{{$\rangle$\literatecolori{\}}}}{2}
{[}{{\literatecolorii{[}$\langle$}}{2}
{]}{{$\rangle$\literatecolorii{]}}}{2}
{\$}{{\literatecoloriii{\$}}}{1},
}

\lstnewenvironment{macro}[1][]
{\lstset{texcs=[1]{#1},}}
{}

\begin{document}

\begin{macro}[mymacro]
\mymacro[opt. arg.]{mand. arg.}% Some comment
\end{macro}

\end{document}


I have used colours for clarity, and also because I expect some people might want them – but they are not necessary at all.

Just make sure to write which commands you are using in the optional argument of the environment.

Edit: Looking at Peter Grill's answer, I have just realised that using identifierstyle would be wiser, as it allows to remove all of the then useless font commands everywhere. I have edited my answer accordingly – it does not modify the output in any way – but I want to acknowledge that it was his idea originally.

-
In the case where I want to provide an example use, I might type \mymacro{Verbatim text here} and expect that the verbatim text appear monospaced (i.e., not italic and not surrounded by angle brackets). –  godbyk Mar 15 '12 at 21:40
@godbyk Inserting the angle brackets automatically seemed better as an answer to your question (because I would be lazy to type them) but obviously you should use \lstdefinestyle and create environments accordingly – so you can have several different variants. Having two environments with a semantic distinction (one for explaining macros and one for examples) allows you to modify them separately later if needed. –  ienissei Mar 15 '12 at 21:51