# Framing two-column listings with a tikz node : “missing \item” error ?

I'm trying to use this answer to put my lstlistings environments inside a tikz node. So I want to define a new listings environment, with \lstnewenvironment.

My final goal, to be precise, is to ensure the proper framing of two-column listings generated through the multicol package using the multicols option of listings (§5.8 of the listings manual). Tikz comes in because 2-columns framing is ugly with the frame argument of listings, see the end of this pdf for an example.

But I also have single-column listings in my document that I'd like to decorate with tikz, and I'd love to have a single command to typeset both 2-columns and single-column listings. Fortunately, the listings manual suggests something: simply copying an optional argument of the new listings environment inside an lstset command (p.41).

That's what I tried to do:

\documentclass{minimal}

\usepackage{listings}
\usepackage{tikz}
\usepackage{multicol}

\tikzstyle{sourcecodebox} = [
fill=white, draw=black, inner sep=1em, rectangle
]

\makeatletter
\lstnewenvironment{lstfigurelisting}[1][]{%
\lstset{frame=none,#1}%
\setbox\@tempboxa=\hbox\bgroup\color@setgroup
}%
{%
\color@endgroup\egroup
\begin{tikzpicture}
\node[sourcecodebox] (box)
{\makebox[.75\linewidth][l]{\box\@tempboxa}};
\end{tikzpicture}
}
\makeatother

\begin{document}

Some code here:
\begin{lstfigurelisting}[multicols=2]
#!/usr/bin/env python
def main():
print "Hello, World!"
if __name__ == '__main__':
main()
\end{lstfigurelisting}

\end{document}


Unfortunately, I get a Something's wrong--perhaps a missing \item pointing at multicols=2.

If I remove that optional argument, or change it to something innocuous (e.g. breaklines=true, everything works (so at least I get the framing for single-column listings). I've read the FAQ on the missing \item error, but I don't understand how this would apply, here. I do understand that the plain TeX \setbox is used to save the whole environment content in a TeX box register, but I don't see how the multi-column environment, specifically, would insert a list inside that box.

Does anybody have an idea of what's going on ? Any other alternatives to suggest as to reaching my final goal (1 and 2-column listings inside a tiks node) ?

-

I don't really know anything about listings or multicol and particularly haven't a clue as to why they complain so much about being put in a box (presumably to do with how multicol works its magic). So I went back to the original specification: to get a listings listing in a columnar setup within a TikZ node. I came up with the following solution. What seemed to be the key was to avoid precisely that situation that your code lands in: that something reads in the listing ahead of time and then resets it somewhere else. Several of the commands that I chose to use had a "read ahead" version, and I found that the code did not work if I chose that one. For example, I had to use a minipage instead of a \parbox.

Anyway, this will need tweaking I'm sure - particularly with regard to line widths - but it does seem to do the basic "put a 2-column listing in a TikZ node".

\documentclass{article}

\usepackage{listings}
\usepackage{tikz}
\usepackage{multicol}

\tikzstyle{sourcecodebox} = [
fill=white, draw=black, inner sep=1em, rectangle
]

\makeatletter
\lstnewenvironment{lstfigurelisting}[1][]{%
\tikzpicture
\node[sourcecodebox] (box)
\bgroup
\minipage{.75\textwidth}
\lstset{frame=none,#1}
}
{
\endminipage
\egroup;
\endtikzpicture
}
\makeatother

\begin{document}

Some code here:

\begin{lstfigurelisting}[multicols=2]
#!/usr/bin/env python
def main():
print "Hello, World!"
if __name__ == '__main__':
main()
\end{lstfigurelisting}
\end{document}


Result:

-
Very insightful, thanks ! – huitseeker Sep 13 '11 at 9:09