4

I'm using lstnewenvironment to color my SAS datasteps. I'm using emph/emphstyle to add new keywords (as I didn't get to work morekeyword and otherkeyword).

If I use (in=...) after a dataset name the in should be considered as a keyword (in blue)

If I use x in (1,2) then in should not be considered as a keyword.

How can I conditionally assign a color to in when it is followed by an equal sign (or blank + equal sign) and black when it isn't ?

Many thanks in advance for your help.

Right now the only solution I got is to use escapeinside={(*@}{@*)}, and assign manually the color locally.

Here is an example:

\documentclass[a4paper,12pt]{report}

\usepackage{xcolor}
\usepackage{listings}
\usepackage{textcomp}

    \definecolor{sasdarkblue}   {RGB}{0,0,114}      %#000072
    \definecolor{sasblue}       {RGB}{21,23,206}    %#1517CE
    \definecolor{sasviolet}     {RGB}{109,23,110}   %#6D176E

\lstnewenvironment{sasdatastep}{%
\lstset{%
    basicstyle      =\small\ttfamily,%
    language        =SAS,%
    keywordstyle    =\color{sasblue}\ttfamily,%
    escapechar      =|,%
    escapeinside    ={(*@}{@*)},%
    stringstyle     =\color{sasviolet}\ttfamily,%
    showstringspaces=false,%
    keepspaces      =true,%
    sensitive       =false,%
    emph            =[1]{run,data,\%macro,\%mend}, %
    emphstyle       =[1]\color{sasdarkblue}\ttfamily\textbf, %
    emph            =[2]{in,indsname,point,nobs},%
    emphstyle       =[2]\color{sasblue}, %
emph            =[3]{indsname,point,nobs},%
    upquote         =true%
}
}{}

\begin{document}

\begin{sasdatastep}
data new;
    set one (in=_one)
        two (in=_two);
run;

data one;
   set one (where=(x in (1,2)));
run;
\end{sasdatastep}
\end{document}
  • (1) welcome, (2) as always on this site, please post a minimal but complete example that others can copy and test as is. That makes it a lot easier and faster for others to help. – daleif Jan 26 '18 at 11:22
  • (2) I've now added an example in the question. – Véronique Jan 26 '18 at 12:19
  • I don't think that is possible in listings, you'll probably need to use external tools like minted. – daleif Jan 26 '18 at 12:21
1

It's difficult to use this kind of conditionals with listings. To put it simply, listings only reads from left to right (sort of), so when it matches and highlights an in, it doesn't know yet whether a = follows it or not.

It seems that the setting keywordsprefix={in=} does the trick in your example, but it has severe limitations:

  • According to the documentation, keywordsprefix is still buggy. I'm not even sure it's supposed to work in this situation.
  • You can only use one keywordsprefix at a time, so you can't match both in = and in= (with and without space).

The following is a hack which consists in matching all occurences of in= and in =, hiding them, and reinserting them with the correct highlighting. There might be cleaner ways to do this.

\documentclass[a4paper,12pt]{report}

\usepackage{xcolor}
\usepackage{listings}
\usepackage{textcomp}

    \definecolor{sasdarkblue}   {RGB}{0,0,114}      %#000072
    \definecolor{sasblue}       {RGB}{21,23,206}    %#1517CE
    \definecolor{sasviolet}     {RGB}{109,23,110}   %#6D176E

\newcommand{\highlightIn}{%
    \textcolor{sasblue}{in}=%
}
\newcommand{\highlightInWithSpace}{%
    \textcolor{sasblue}{in} =%
}

\lstnewenvironment{sasdatastep}{%
\lstset{%
    basicstyle      =\small\ttfamily,%
    language        =SAS,%
    keywordstyle    =\color{sasblue}\ttfamily,%
    escapechar      =|,%
    escapeinside    ={(*@}{@*)},%
    stringstyle     =\color{sasviolet}\ttfamily,%
    showstringspaces=false,%
    keepspaces      =true,%
    sensitive       =false,%
    emph            =[1]{run,data,\%macro,\%mend}, %
    emphstyle       =[1]\color{sasdarkblue}\ttfamily\textbf, %
    emph            =[2]{indsname,point,nobs},%
    emphstyle       =[2]\color{sasblue}, %
emph            =[3]{indsname,point,nobs},%
    upquote         =true,%
    moredelim=**[il][\highlightIn]{in=}, % `**` is needed so that `in=` is only reinserted once
    moredelim=**[il][\highlightInWithSpace]{in\ =},
    columns=flexible % the replaced text wouldn't fit correctly with fixed columns
}
}{}

\begin{document}

\begin{sasdatastep}
data new;
    set one (in=_one)
        two (in=_two);
run;

data one;
   set one (where=(x in (1,2)));
run;
\end{sasdatastep}
\end{document}

Output:

highlighted code


To expand on daleif's comment, other tools such as minted might be better suited for this. However, in this case, minted/Pygments doesn't take into account the different uses of in, it highlights it every time. One would need a whole new lexer to solve your issue with minted.

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.