[Tex/LaTex] Wrapping code (listings, verbatim, or other method) inside a newcommand

macrosverbatim

For some teaching I've been doing, I'd like to have code from two different languages side-by-side. To do so, I hacked together a newcommand which uses a tabular environment to arrange two verb environments, but the problems are myriad:

  • Indentation can only be accomplished by changing spaces to ~'s

  • Any math symbols have to be escaped with \, which requires knowing which ones to escape and which ones not to (can't escape the <'s for instance, otherwise it complains)

  • The <- assignment operator gets changed into an upside down !- when compiled.

The listings environment doesn't work either. Error message is:

Runaway argument?
! Forbidden control sequence found while scanning use of \lst@next.
<inserted text> 
                \par 
l.23 \codeListing{x <- y}{f(g(x))}

Here's some code to reproduce the problem:

\documentclass[english]{article}
\usepackage[latin9]{inputenc}
\usepackage{geometry}
\begin{document}

\newcommand{\codeListing}[2]{
\begin{tabular}{p{8cm} p{8cm}}
\begin{lstlisting}
#1
\end{lstlisting}
&
#2\tabularnewline
\end{tabular}
}

\section{verbatim test}
\begin{verbatim}
logLik <- function(x) { 
  y <<- x^2+2
  return(sum(sqrt(y+7)))
}
\end{verbatim}

\section{codeListing test}
\codeListing{}{
logLik <- function(x) \{ 

~~y <<- x\^2+2

~~return(sum(sqrt(y+7)))

\}

}

\end{document}

Is there any way to make a newcommand wrap parameter-passed code? It doesn't have to be keyword-highlighted or do any of the other tricks that the fancier packages do; it just has to preserve whitespace and no interpret code as latex commands.

Best Answer

We recently considered adding some support for verbatim arguments to xparse. Starting from roughly 15/08/2011 (on the svn, not yet on CTAN), you can define a command with any combination of optional, mandatory and verbatim arguments. Each command defined with xparse has an argument signature which indicates what kind of argument it expects (the most common are m for normal mandatory argument, o for optional, s, for an optional star). With the new argument type, for instance, \verb would have a signature {sv}: an optional star followed by a verbatim argument.

For your case, I think a good idea is to give the signature { O{} +v O{} +v } to \codeListing:

  • #1, optional argument = options given to the first listing (default empty);
  • #2, verbatim argument = contents of the first listing;
  • #3, optional argument = options given to the second listing (default empty);
  • #4, verbatim argument = contents of the second listing;

The + mean that the next argument is "long". For non-verbatim arguments, this means that they may contain more than one paragraph. For verbatim arguments, it currently means that they may contain line-breaks, contrarily to the normal \verb command.

[Apart from the use of xparse, I based the example on Mike Renfro's answer.]

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand {\codeListing} { O{} +v O{} +v }
  {
    \begin{table}[h]\centering
      \begin{tabular}[width=\textwidth]{ll}
        \newlinechar=\endlinechar
        \exp_args:Nx \scantokens
          {
            \string\begin{lstlisting}[\unexpanded{#1}]
              #2
            \string\end{lstlisting}
            &
            \string\begin{lstlisting}[\unexpanded{#3}]
              #4
            \string\end{lstlisting}
          }
      \end{tabular}
    \end{table}
  }
\ExplSyntaxOff
\usepackage[a4paper,margin=2cm]{geometry}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{lipsum}
\begin{document}
\lipsum[1]

\codeListing[language=C,backgroundcolor=\color{yellow!30}]$
#include <stdio.h>

int main(void)
{
  printf("Hello world\n");
  return 0;
}
$[language=C++,backgroundcolor=\color{red!20}]$
#include <iostream>

using namespace std;
int main()
{
  cout << "Hello World!" << endl;
  return 0;
}
$

\lipsum[2]

\end{document}