7

I use the listings package to typeset code in my document. I have defined a new environment via \lstnewenvironment in which I use \lstset to set a large number of options through a list of key-values. It looks like the following:

\lstnewenvironment{mycodebox}[1][]                                                                                                                      
{
  \lstset{
     key1=val1,
     key2=val2,
     % some more options are set
     #1 % so that it can accept more options
  }
}{}   

I use this new environment mostly in two variants where in each variant I need to override some existing (or add new) options. For example:

% variant 1
\begin{mycodebox}[newkey=newval, key1=newval]
 % my code
\end{mycodebox}

and

% variant 2
\begin{mycodebox}[anotherkey=newval, key2=newval]
 % my code
\end{mycodebox}

The two variants share a lot of options but they are different. Can I define two macros/commands like \variant1settings and \variant2settigns that can be used in some way like the following?

\begin{mycodebox}[\variant1settings]
 % my code
\end{mycodebox}

I know that I can use \lstset{options...} to do this before using the environment each time but

  1. I don't want the options to run through when I don't specify them before subsequent instances;
  2. I want the options to be in the form of a macro (or similar) so that they can be tweaked from one central position.
3
  • Welcome to TeX.SX! Please help us to help you and add a minimal working example (MWE) that illustrates your problem. It will be much easier for us to reproduce your situation and find out what the issue is when we see compilable code, starting with \documentclass{...} and ending with \end{document}. – user31729 Feb 8 '15 at 8:54
  • You could use \newcommand\variantA{\lstset{...}} and {\variantA\begin{mycodebox}...\end{mycodebox}} in the text, but it is slightly less convenient than the syntax you asked for. – Torbjørn T. Feb 8 '15 at 9:15
  • @TorbjørnT. Yes, this would certainly work in this context. Thanks for bothering to answer this but maybe I'm looking for something more elegant (and general) if possible at all. Can a macro (or something similar) be used inside the square brackets to specify additional options? – Loax Feb 8 '15 at 9:29
7

The expansion of the content of the optional argument #1 has to be postponed, otherwise the macro \optionstocodebox is expanded, letting keyval macros think its content is a complete key name, which isn't, of course.

Using

\begingroup\edef\x{\endgroup\noexpand\lstset{numbers=right,language={C},#1}}\x

will prevent premature expansion and expands it afterwards.

\begingroup...\endgroup is a neat trick to let the redefinition \x be forgotten after it's expanded (which is the case at the end of }}\x.

To be short: the expansion is prevented first for \lstset, then applied afterwards by calling \x.

However, no unexpandable stuff such as \textbf or \textcolor are allowed without fine-tuning. This could be achieved by a brute force \unexpanded{stuff} as a key assignment. The second example \otheroptionstocodebox shows usage with \unexpanded approach.

\documentclass{article}

\usepackage{xcolor}
\usepackage{listings}


\lstnewenvironment{mycodebox}[1][]                                                                                                                      
{
  \begingroup\edef\x{\endgroup\noexpand\lstset{numbers=right,language={C},#1}}\x
}{}   


\begin{document}

\newcommand{\optionstocodebox}{language={Pascal},numbers=left}%



\newcommand{\otheroptionstocodebox}{language={C},numbers=left,stepnumber=3,numberstyle={\unexpanded{\color{red}\tiny}}}%


\begin{mycodebox}[language={C}]
#include<stdio.h>
int main(int argc,char **argv)
{
  printf("Hello World!\n");
}
\end{mycodebox}

\begin{mycodebox}[numbers=left,\optionstocodebox]
program first

BEGIN
WriteLn('Hello World');
END.
\end{mycodebox}


\begin{mycodebox}[language={C},\otheroptionstocodebox]
#include<stdio.h>
int main(int argc,char **argv)
{
  printf("Hello World!\n");
}
\end{mycodebox}


\end{document}

enter image description here

1
  • You provided a good explanation of what's going on (more inline with the title of the question). @TorbjørnT. gave the most elegant way of doing this in the context of listings. A tough call for me as to which one I should choose as an answer. – Loax Feb 8 '15 at 10:01
8

listings allow you to define styles that you can apply to individual listings with style=<stylename>.

\documentclass{article}
\usepackage{listings,xcolor}
\lstdefinestyle{style1}{basicstyle=\ttfamily\color{red}}
\lstdefinestyle{style2}{basicstyle=\scshape\color{blue},frame=single}

\lstnewenvironment{mycodebox}[1][]                                                                                                                      
{
  \lstset{
     basicstyle=\itshape,
     #1
  }
}{}  

\begin{document}
\begin{mycodebox}[style=style1]
This is some text
\end{mycodebox}

\begin{mycodebox}
This is some text
\end{mycodebox}

\begin{mycodebox}[style=style2] 
This is some text
\end{mycodebox}
\end{document}

enter image description here

5
  • I think, the style option is what I 'reinvented' (;-)) by preventing unexpansion. (+1) – user31729 Feb 8 '15 at 9:51
  • This is certainly the most elegant way of doing this in the context of listings. Thanks! – Loax Feb 8 '15 at 10:04
  • Once I have defined an lstdefinestyle{style1}{blabla}, can I use it inside \lstnewenvironment{mycodebox} in combination with lstset{}? Can I write lstset{basicstyle=style1}? If so/not so, perhaps you could comment on that, if you are so inclined. – PatrickT Nov 5 '17 at 10:08
  • @PatrickT If you look at how style1 is defined with \lstdefinestyle, you'll probably see that setting basicstyle=style1 doesn't really make sense. style1 contains basicstyle and any other settings you'd like. But I do say in the first sentence that you select a style with style=<stylename>, and indirectly what happens in the code is \lstset{style=style1}. – Torbjørn T. Nov 5 '17 at 10:21
  • @TorbjørnT. great thanks! I had missed that opening sentence, apologies. – PatrickT Nov 5 '17 at 10:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.