Ich verwende es listings
, um Ruby-Code mit Hervorhebung anzuzeigen. Ich habe das folgende Testdokument:
\documentclass{article}
\usepackage{xcolor}
\usepackage{listings}
\definecolor{dkgreen}{rgb}{0,0.6,0}
\definecolor{mauve}{rgb}{0.58,0,0.82}
\lstdefinestyle{Ruby} {
aboveskip=3mm,
belowskip=3mm,
showstringspaces=false,
columns=flexible,
basicstyle={\footnotesize\ttfamily},
numberstyle={\tiny},
numbers=left,
keywordstyle=\color{blue},
commentstyle=\color{dkgreen},
stringstyle=\color{mauve},
breaklines=true,
breakatwhitespace=true,
tabsize=2,
sensitive = true
}
\lstset{language=Ruby}
\begin{document}
\begin{lstlisting}[style=Ruby,float=ht,caption={...},label={lst:sourcecode},captionpos=b]
def some_function
File.open(filename, 'w+') do |f|
[...]
# a comment
f.puts "whatever #{some_variable} another string part"
f.puts 'this string contains apostrophes: \'random word\''
[...]
end
end
\end{lstlisting}
\end{document}
Und das sieht so aus:
Natürlich #{some_variable}
wird in Lila/Malve hervorgehoben, weil ich es als Stringstil festgelegt habe, aber das ist nicht ganz richtig, da die Syntax #{}
den Inhalt ausführt, anstatt diesen Block als String zu interpretieren (nur wenn innerhalb von " "
, nicht mit ' '
, aber ich wäre bereit, diese Feinheit zu ignorieren).
Meine Frage lautet: Gibt es eine Möglichkeit, die Hervorhebung so zu konfigurieren, dass dies richtig dargestellt wird, sodass #{some_variable}
die Standardfarbe verwendet wird?
EDIT: mit der von SDF präsentierten Antwort sieht es nun so aus:
Wenn Sie die beiden Bilder vergleichen, werden Sie feststellen, dass die maskierten Apostrophe jetzt random word
nicht mehr wie zuvor ignoriert werden (was das richtige Verhalten war).
EDIT 2: Obwohl ich dieses Problem durch Weglassen von lösen konnte string=[d]{'},
, sind mir zwei weitere Probleme aufgefallen. Das Beispiel sieht nun folgendermaßen aus:
\documentclass{article}
\usepackage{xcolor}
\usepackage[procnames]{listings}
\definecolor{dkgreen}{rgb}{0,0.6,0}
\definecolor{gray}{rgb}{0.5,0.5,0.5}
\definecolor{mauve}{rgb}{0.58,0,0.82}
\definecolor{light-gray}{gray}{0.25}
\lstdefinestyle{Ruby} {
aboveskip=3mm,
belowskip=3mm,
showstringspaces=false,
columns=flexible,
basicstyle={\footnotesize\ttfamily},
numberstyle={\tiny},
numbers=left,
keywordstyle=\color{blue},
commentstyle=\color{dkgreen},
stringstyle=\color{mauve},
breaklines=true,
breakatwhitespace=true,
tabsize=2,
sensitive = true,
morestring=*[d]{"},
morestring=[s][]{\#\{}{\}},
procnamekeys={def},
procnamestyle=\color{red},
}
\lstset{language=Ruby}
\begin{document}
\begin{lstlisting}[style=Ruby,float=ht,caption={...},label={lst:sourcecode},captionpos=b]
def some_function
File.open(filename, 'w+') do |f|
[...]
# a comment
f.puts "whatever #{some_variable} another string part"
f.puts 'this string contains apostrophes: \'random word\''
f.puts 'i do love keywords like class'
f.puts "i do love keywords like class"
f.puts "now single quotes 'inside #{double quotes}'"
[...]
end
end
\end{lstlisting}
\end{document}
Schlüsselwörter in doppelten Anführungszeichen werden jetzt hervorgehoben und auch einfache Anführungszeichen in doppelten Anführungszeichen führen dazu, dass das ursprüngliche Problem erneut auftritt.
Das gerät langsam außer Kontrolle... Vielleicht sollte ich wirklich auf Minted umsteigen.
Antwort1
Notiz:
Ich habe die gesamte Antwort aktualisiert, um die beiden Änderungen zu berücksichtigen. Es gibt viele kleine Hacks, aber ich fürchte, je präziser wir mit sein wollen listings
, desto mehr Hacks müssen wir hinzufügen. Eine alternative Lösung mit finden Sie am Ende der Antwort minted
.
Lösung des ursprünglichen Problems mitlistings
Sie können listings
die Erkennung von Trennzeichen innerhalb eines anderen Trennzeichens zulassen, indem Sie *
in seiner Definition Folgendes hinzufügen:
morestring=*[d]{"}
Dann definieren wir #{
und }
als spezielle Trennzeichen. Wir geben ihnen ihren eigenen Stil, indem wir ein zweites Paar eckiger Klammern hinzufügen:
morestring=[s][]{\#\{}{\}}
Hier fügen wir leere Klammern hinzu, was bedeutet, dass der Standardstil verwendet wird. Vergessen Sie auch nicht, Sonderzeichen wie #
, {
, usw. zu maskieren. Ausführlichere Erklärungen finden Sie in listings
der Dokumentation, Abschnitt 3.3.
Anmerkung:
s
Option bedeutet, dass die Anfangs- und Endtrennzeichen unterschiedlich sind, d
dass sie gleich sind. Man muss b
anstelle von verwenden d
, um das Escapen des Backslashs zu aktivieren. Diesen Fehler habe ich in meiner ursprünglichen Antwort gemacht. Es ist auch erwähnenswert, dass Ruby, wie die meisten Sprachen, bereits eine grundlegende Definition hat, die die meisten Zeichenfolgen enthält, sodass es nicht nötig ist, alles neu zu definieren (es sei denn, wir möchten es überschreiben, und das werden wir).
Dies \lstset
erzeugt die Ausgabe, die in der ersten Bearbeitung des OP zu sehen ist:
\lstdefinestyle{Ruby} {
aboveskip=3mm,
belowskip=3mm,
showstringspaces=false,
columns=flexible,
basicstyle={\footnotesize\ttfamily},
numberstyle={\tiny},
numbers=left,
keywordstyle=\color{blue},
commentstyle=\color{dkgreen},
stringstyle=\color{mauve},
breaklines=true,
breakatwhitespace=true,
tabsize=2,
morestring=[d]{'}, % wrong: should be [b]
morestring=*[d]{"},
morestring=[s][]{\#\{}{\}},
}
Lösen zusätzlicher Probleme
Schlüsselwörter in Zeichenfolgen werden hervorgehoben
Wie Daniel in einem Kommentar sagte, morestring=*[d]{"}
bewirkt der Stern in, dass es weiter nach weiteren Saiten suchtUndSchlüsselwörter. Das ist, was wir in Bezug auf „-Strings“ wollen #{
, }
aber es passiert auch bei Schlüsselwörtern.
listings
erlaubt nicht anzugeben, wonach wir in den Strings genau suchen werden, also müssen wir einen anderen Workaround finden.
Jetzt listings
bietet sich eine **
Option an, mit der die Stile der Zeichenfolge und deren spezieller Inhalt kumuliert werden können. Wenn wir beispielsweise Folgendes tun:
morestring=**[d][\color{mauve}]{"},
keywordstyle=\bfseries,
listings
macht Schlüsselwörter in Anführungszeichen fettUndMauve. Die Sache ist, wir müssen Farben „kumulieren“.
morestring=**[d][\color{mauve}]{"},
keywordstyle=\color{blue},
In diesem Fall werden Schlüsselwörter in Zeichenfolgen mit verarbeitet \color{mauve} \color{blue}
, und das ist schlecht: Der Schlüsselwortstil überschreibt den Zeichenfolgenstil. Mein Hack bestand darin, den Schlüsselwortstil durch einen neuen Befehl zu ersetzen, der die aktuelle Farbe überprüft und sie auf Blau setzt, wenn sie nicht bereits Mauve ist:
\def\bluecolorifnotalreadymauve{%
\extractcolorspec{.}\currentcolor
\extractcolorspec{mauve}\stringcolor
\ifx\currentcolor\stringcolor\else
\color{blue}%
\fi
}
(Dank andiese Antwortfür die Lösung.)
Jetzt verlieren wir auch unsere ursprüngliche #{}
Korrektur, da ihr (leerer) Stil mit dem \color{mauve}
from "kumuliert" ist ""
. Kumulieren wir es zurück:
morestring=[s][\color{black}]{\#\{}{\}},
Einfache Anführungszeichen führen dazu, dass das #{}
Problem erneut auftritt
Genau wie Schlüsselwörter werden Zeichenfolgen in einfachen Anführungszeichen in Zeichenfolgen in doppelten Anführungszeichen erneut verarbeitet. Und listings
es wurde nicht gesagt, dass Zeichenfolgen in einfachen Anführungszeichen nachsehen sollen, also müssen wir sie auf die gleiche Weise ändern:
morestring=**[d]{'},
Und jetzt geht das Backslash-Escape verloren. Aus einem unbekannten Grund b
funktioniert die Option nicht gut mit **
. Nun, wenn wir schon dabei sind …
morestring=[d]{\\'},
Vollständig aktualisiertes MWE
\documentclass{article}
\usepackage{xcolor}
\usepackage[procnames]{listings}
\definecolor{dkgreen}{rgb}{0,0.6,0}
\definecolor{gray}{rgb}{0.5,0.5,0.5}
\definecolor{mauve}{rgb}{0.58,0,0.82}
\definecolor{light-gray}{gray}{0.25}
\def\bluecolorifnotalreadymauve{%
\extractcolorspec{.}\currentcolor
\extractcolorspec{mauve}\stringcolor
\ifx\currentcolor\stringcolor\else
\color{blue}%
\fi
}
\lstdefinestyle{Ruby} {
aboveskip=3mm,
belowskip=3mm,
showstringspaces=false,
columns=flexible,
basicstyle=\footnotesize\ttfamily,
numberstyle=\tiny,
numbers=left,
keywordstyle=\bluecolorifnotalreadymauve,
commentstyle=\color{dkgreen},
stringstyle=\color{mauve},
breaklines=true,
breakatwhitespace=true,
tabsize=2,
moredelim=[s][\color{black}]{\#\{}{\}}, % same as morestring in this case
morestring=**[d]{'},
morestring=[d]{\\'},
morestring=**[d]{"},
procnamekeys={def}, % bonus, for function names
procnamestyle=\color{red},
}
\lstset{language=Ruby}
\begin{document}
\begin{lstlisting}[style=Ruby,float=ht,caption={...},label={lst:sourcecode},captionpos=b]
def some_function
File.open(filename, 'w+') do |f|
[...]
# a comment
f.puts "whatever #{some_variable} another string part"
f.puts 'this string contains apostrophes: \'random word\''
f.puts 'i do love keywords like class'
f.puts "i do love keywords like class"
f.puts "now single quotes 'inside #{double quotes}'"
[...]
end
end
\end{lstlisting}
\end{document}
Ausgabe:
Alternativer Ansatz: Verwendungminted
minted
macht bereits alles, was Sie wollen, und noch viel mehr! Hier ist ein MWE:
\documentclass{article}
\usepackage{minted}
\begin{document}
\begin{listing}[H]
\begin{minted}[fontsize=\footnotesize, linenos]{Ruby}
def some_function
File.open(filename, 'w+') do |f|
[...]
# a comment
f.puts "whatever #{some_variable} another string part"
f.puts 'this string contains apostrophes: \'random word\''
f.puts 'i do love keywords like class'
f.puts "i do love keywords like class"
f.puts "now single quotes 'inside #{double quotes}'"
[...]
end
end
\end{minted}
\caption{...}
\end{listing}
\end{document}
Dies ist die Ausgabe im Standardstil:
Der größte Nachteil ist, minted
dass es aufPygmentedie Verarbeitung durchzuführen, was bedeutet:
Die Installation kann etwas schwierig sein.
Die Anpassung ist schwieriger. (Wenn wir aber erst einmal wissen, wie es geht, kann es sehr wirkungsvoll sein.)