Lösung des ursprünglichen Problems mitlistings

Lösung des ursprünglichen Problems mitlistings

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:

Beispielausgabe

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:

leicht falsche Lösung

Wenn Sie die beiden Bilder vergleichen, werden Sie feststellen, dass die maskierten Apostrophe jetzt random wordnicht 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}

Problem mit falschen Schlüsselworthervorhebungen und verschachtelten Anführungszeichen

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 listingsdie 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 listingsder Dokumentation, Abschnitt 3.3.

Anmerkung: sOption bedeutet, dass die Anfangs- und Endtrennzeichen unterschiedlich sind, ddass sie gleich sind. Man muss banstelle 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 \lstseterzeugt 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. listingserlaubt nicht anzugeben, wonach wir in den Strings genau suchen werden, also müssen wir einen anderen Workaround finden.

Jetzt listingsbietet 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,

listingsmacht 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 listingses 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 bfunktioniert 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:

aktualisierter Ruby-Code mit Listings

Alternativer Ansatz: Verwendungminted

mintedmacht 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:

aktualisierter Ruby-Code mit Minted

Der größte Nachteil ist, minteddass es aufPygmentedie Verarbeitung durchzuführen, was bedeutet:

  1. Die Installation kann etwas schwierig sein.

  2. Die Anpassung ist schwieriger. (Wenn wir aber erst einmal wissen, wie es geht, kann es sehr wirkungsvoll sein.)

verwandte Informationen