5

I have many Verbatim environments in my document, which contain source code with different characters inside, including {, (, [, <. I'm trying to find a way of attaching labels to some lines inside these environments. This looks clumsy, since I have to replace all { with \{ and all } with \} thus making Java code way less readable (for me, the editor of the document):

\documentclass{article}
\usepackage{fancyvrb}
\begin{document}
\begin{Verbatim}[commandchars=\\\{\}]
void main() \{
  print("Hello!"); \label{foo}
\}
\end{Verbatim}
\end{document}

Something like this would be much better:

\documentclass{article}
\usepackage{fancyvrb}
\begin{document}
\begin{Verbatim}
void main() {
  print("Hello!"); !foo
}
\end{Verbatim}
\end{document}

Is it somehow possible, to make fancyvrb interpret !foo as \label{foo}? (it's OK if a "hack" of fancyvrb would be necessary)

yegor256
  • 12,021
  • 2
    Are you sure you're using the right approach? Possibly minted or listings would be better. – egreg Jan 10 '24 at 10:14
  • In your last example, how do you want to distinguish the ! in the code and the ! as beginning of the label? And how to do so, if you change print("Hello!") into print("Hello!Hello!")? – cabohah Jan 10 '24 at 10:15
  • 2
    Unfortunately, the piton package does not yet support the Java language. – projetmbc Jan 10 '24 at 11:38

2 Answers2

4

You can use different group chars, not used in the code, e.g.

\documentclass{article}
\usepackage{fancyvrb}
\begin{document}
\begin{Verbatim}[{commandchars=\\[]}]
void main() {
  print("Hello!"); \label[foo]
}
\end{Verbatim}
\end{document}

or

\documentclass{article}
\usepackage{fancyvrb}
\begin{document}
\begin{Verbatim}[{commandchars=\\$/}]
void main() {
  print("Hello!"); \label$foo/
}
\end{Verbatim}
\end{document}

fancyvrb

Note: With PDFLaTeX you cannot use UTF8 characters as value of commandchars. But with an UTF8 engine, e.g., LuaLaTeX also something like:

% This is a LuaLaTeX example!
\documentclass{article}
\usepackage{fancyvrb}
\begin{document}
\begin{Verbatim}[{commandchars=§«»}]
void main() {
  print("Hello!"); §label«foo»
}
\end{Verbatim}
\end{document}

can be used.


Another alternative would be to use package listings instead of fancyvrb. In this case, you would need only one escape character, e.g.:

\documentclass{article}
\usepackage{listings}
\begin{document}
\begin{lstlisting}[escapechar=~]
void main() {
  print("Hello!"); ~\label{foo}~
}
\end{lstlisting}
\end{document}

or even:

\documentclass{article}
\usepackage{listings}
\begin{document}
\begin{lstlisting}[escapechar=¡]
void main() {
  print("Hello!"); ¡\label{foo}¡
}
\end{lstlisting}
\end{document}

listings

or

\documentclass{article}
\usepackage{xcolor}
\usepackage{listings}
\lstset{columns=flexible,basicstyle=\ttfamily,identifierstyle=\color{blue}}
\begin{document}
\begin{lstlisting}[language=Java,escapechar=¡]
void main() {
  print("Hello!"); ¡\label{foo}¡
}
\end{lstlisting}
\end{document}

Java code with color

See also section 8 of the listings manual for more hints and an alternative to reference line numbers even if you need all characters to be usable in the code.


If you really insist in using ! as \label inside code but only if it is not followed by ", I would recommend to also delimit the foo with an additional !:

\documentclass{article}
\usepackage{fancyvrb}
\makeatletter
\let\!!
\begingroup
\catcode`\!=\active
\gdef!{\@ifnextchar"{\!}{\labeltill}}
\gdef\labeltill#1!{\label{#1}}
\endgroup
\makeatother
\begin{document}
\begin{Verbatim}[codes*={\catcode`\!\active}]
void main() {
  print("Hello!"); !foo!
}
\end{Verbatim}
\end{document}

However using a character, that is never used as part of the code would be a better idea:

\documentclass{article}
\usepackage{fancyvrb}
\begingroup
\catcode`\^=\active
\gdef^#1^{\label{#1}}
\endgroup
\begin{document}
\begin{Verbatim}[codes*={\catcode`\^\active}}
void main() {
  print("Hello!"); ^foo^
}
\end{Verbatim}
\end{document}

Nevertheless, I don't like this solution because I think it can go wrong too easily. And with every case in which one of the last two solutions fails, the complexity of the code increases. In contrast, changing the character in the listings examples is a trifle.

cabohah
  • 11,455
  • It's Java code, all of them are used there: [, (, {, <, etc. Moreover, I only need to attach labels: "occupying" three characters for them is an overkill. – yegor256 Jan 10 '24 at 09:28
  • 1
    @yegor256 See my alternative using LuaLaTeX or listings. – cabohah Jan 10 '24 at 09:37
  • 1
    rather than redefining \FV@CommandChars in your last example you can use \begin{Verbatim}[codes*={\catcode`\^\active}]. – user691586 Jan 10 '24 at 15:01
  • @user691586 Good point! Nevertheless, I don't like this solution because I think it can go wrong too easily. I've added it only to show, that it is not so nice as it may seem. – cabohah Jan 10 '24 at 15:28
3

You can set ! to be active with a suitable definition: it will look for alphanumeric characters and pass them as argument to \label.

\documentclass{article}
\usepackage{fancyvrb}

\ExplSyntaxOn

\cs_new_protected:Nn __yegor_verbatim_label: { \peek_regex_replace_once:nn { [[:alnum:]]* } { \c{label}\cB{\0\cE} } } \char_set_active_eq:nN { `! } __yegor_verbatim_label:

\ExplSyntaxOff

\begin{document}

\begin{Verbatim}[codes={\catcode`!=\active}] void main() { print("Hello!"); !foo } \end{Verbatim}

\end{document}

Here's what you'll find in the .aux file:

\newlabel{foo}{{2}{1}{}{}{}}
egreg
  • 1,121,712