[Tex/LaTex] texcl, escapeinside, and single character comments, with listings package

commentslistings

I'm using the excellent listings package to typeset some code in a language very similar to Scheme. The language has one type of comment: when an (un-escaped) semicolon is encountered, the rest of the line (including the semicolon) is ignored (as a comment). While only the single semicolon is necessary to introduce a comment, coding convention uses ;;;, ;;, and ; to designate different levels of comments, as in

;;; Top level comment
(define (foo x)
  ;; within body comment
  (list x x)) ; after line comment

I'd like to use listings texcl option to typeset all comments using LaTeX, and have been able to do that so far. I'd also like to use \label{...} to support later references to particular lines of code. I can do this with the regular comments when texcl is turned on, as in

\documentclass{article}
\usepackage{xcolor,listings}
\usepackage{hyperref}

\begin{document}

\lstset{%
  comment=[l]{;},
  texcl=true,
}
\begin{lstlisting}
  ;;; top level
  (defun foo (x) 
    ;; in body
    (let ((y (+ x 1))) ; on line
      y)) ; \label{code:y}
\end{lstlisting}
Cross-reference to line \ref{code:y}.
\end{document}

which produces

sample of listings

The problem is that the comment with the label, ; \label{code:y} still displays the leading semicolon. listings has an escapeinside option that can be used to escape to LaTeX, as in the sample from the documentation:

\lstset{escapeinside={(*@}{@*)}}
\begin{lstlisting}
for i:=maxint to 0 do
begin
    { comment }(*@\label{comment}@*)
end;
\end{lstlisting}
Line \ref{comment} shows a comment.

The documentation also points out that the closing escape delimiter can be \^^M, to support escapes that are terminated by newlines, as in escapeinside={//*}{\^^M}.

What I'd like to do is use something like escapeinside={;@}{\^^M} to provide LaTeX escapes that are still within a comment in the programming language, e.g., (modified from above):

\lstset{%
  comment=[l]{;},
  texcl=true,
  escapeinside={;@}{\^^M}
}
\begin{lstlisting}
  ;;; top level
  (defun foo (x) 
    ;; in body
    (let ((y (+ x 1))) ; on line
      y)) ;@ \label{code:y}
\end{lstlisting}

but this produces an error (which only occurs while using the texcl option):

! Undefined control sequence.
\lst@next ->\lst@c;1 ;

l.14   ;;
         ; top level

Is there a way to fix this, or another way to get the desired behavior (i.e., comment lines generally set with LaTeX with semicolons displayed, but supporting some escape-to-LaTeX beginning with ; in which the semicolon will not be displayed)?

As a temporary workaround, I can define the standard comment sequence to be ;;, and the escaping-comment sequence to be ;@; this works without a problem, except that I no longer have support for comments beginning with a single semicolon.

Best Answer

You need to use morecomment to add the sequences ;; and ;;;:

Sample output

\documentclass{article}

\usepackage{listings}

\begin{document}

\lstset{%
  comment=[l];,morecomment=[l];;,morecomment=[l];;;,
  texcl=true,
  escapeinside={;@}{\^^M},
  numbers=left
}
\begin{lstlisting}
  ;;; top level \LaTeX
  (defun foo (x) 
    ;; in body
    (let ((y (+ x 1))) ; on line $y=x+1$
      y)) ;@ \label{code:y}
\end{lstlisting}
A reference to line~\ref{code:y}
\end{document}
Related Question