[Tex/LaTex] How to automatically highlight SuperCollider symbols and environment variables

highlightinglistings

This question led to a new package:
sclang-prettifier

I've been poring over the listings manual, trying to figure out how to get some very specific types of formatting for the SuperCollider language.

I need to highlight words where the opening delimiter is \ and the closing delimiter is any non-alphanumeric character. Background: SC has a normal string type, delimited by double quotes — that's easy. It also has a Symbol type, in single quotes (also easy) — but Symbols that consist only of alphanumeric characters (and underscore) may also be written with a preceding backslash: 'symbol' and \symbol are equivalent.

Note that the answer to How to highlight all identifiers starting by '@'? does not apply because the closing delimiter may be any non-alphanum (frequently a comma or closing paren, in which case it would be ugly to force a space before it).

If listings won't do it, what alternatives do I have? I also looked at the minted manual, but that was even more confusing.

Some sample SuperCollider code:

p.clear;

~grains.addSpec(\tfreq, [1, 40, \exp]);
~grains.addSpec(\overlap, [0.1, 10, \exp]);
~grains.addSpec(\pos, [0, b.duration]);  // 3.43 is nice!
~grains.addSpec(\rate, [0.5, 2, \exp]);
~grains = { |tfreq = 25, overlap = 6, pan = 0, amp = 0.2, pos = 3.43,
   rate = 1|
   var trig = Impulse.ar(tfreq);
   TGrains.ar(2, trig, b, rate, pos, overlap / tfreq, pan, amp)
};
~grains.play;

\exp, \tfreq, \overlap, \pos and \rate need to be highlighted as Symbols. Ideally, environment variables (e.g. ~grains) would also be highlighted in a different color (same rule but with a different opening delimiter).

I have another question, which I will ask separately…

Best Answer

listings can do that, but you have to whisper in its ear :)

First, tell listings to treat backslash and tilde as "letters", thereby allowing them in identifiers. Then, before each identifier gets printed, check the first character of that identifier and apply a different style depending on that character.

For convenience, I've defined keys to easily specify the styles for SuperCollider classes (starting by A-Z), symbols (starting by \), and global variables (starting by ~).

Update: For convenience to SuperCollider users, I've put together a little package called sclang-prettifier, now available on CTAN and, soon, in popular TeX distributions.

enter image description here

\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage[framed,numbered]{sclang-prettifier}

% --- write source code to external file (for this example) ---
\usepackage{filecontents}
\begin{filecontents*}{sample.scd}
p.clear;

~grains.addSpec(\tfreq, [1, 40, \exp]);
~grains.addSpec(\overlap, [0.1, 10, \exp]);
~grains.addSpec(\pos, [0, b.duration]);  // 3.43 is nice!
~grains.addSpec(\rate, [0.5, 2, \exp]);
~grains = { |tfreq = 25, overlap = 6, pan = 0, amp = 0.2, pos = 3.43,
   rate = 1|
   var trig = Impulse.ar(tfreq);
   TGrains.ar(2, trig, b, rate, pos, overlap / tfreq, pan, amp)
};
~grains.play;
\end{filecontents*}

\begin{document}
\lstinputlisting
[
  style      = SuperCollider-IDE,
  basicstyle = \scttfamily\small,
  caption    = {SuperCollider sample}
]{sample.scd}

\begin{lstlisting}[
  frame   = single,
  caption = Some code unrelated to SuperCollider,
]
 c = a
 a = b
 b = c
 discard c
\end{lstlisting}
\end{document}