使用解決最初的問題listings

使用解決最初的問題listings

我用來listings突出顯示 ruby​​ 代碼。我有以下測試文件:

\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}

看起來像這樣:

範例輸出

當然,#{some_variable}以紫色/紫紅色突出顯示,因為我將其設為字串樣式,但這並不是真正正確的,因為語法#{}將執行內容而不是將此區塊解釋為字串(僅當 inside " ",而不是 with ' ',但我會願意忽略這種微妙之處)。

我的問題是,有沒有辦法配置突出顯示以正確表示這一點,以便#{some_variable}具有預設顏色?

編輯:根據 SDF 提出的答案,現在看起來像這樣:

稍微錯誤的解決方案

如果您比較這兩張圖片,您會發現現在轉義的撇號random word不再像以前那樣被忽略(這是正確的行為)。

編輯2:雖然我能夠透過省略來解決這個問題string=[d]{'},,但我注意到另外兩個問題。該範例現在如下所示:

\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}

Wearg 關鍵字突出顯示和巢狀參考問題

雙引號內的關鍵字現在被反白顯示,雙引號內的單引號也會導致原來的問題再次出現。

這正在慢慢失去控制......也許我真的應該改用鑄幣。

答案1

筆記: 我更新了整個答案以考慮這兩個編輯。有很多小技巧,但恐怕我們想要使用的越精確listings,我們需要添加的技巧就越多。請參閱答案末尾的替代解決方案,使用minted.

使用解決最初的問題listings

您可以透過在定義中listings新增 a 來允許偵測另一個分隔符號內的分隔符號:*

morestring=*[d]{"}

然後我們將#{and定義}為特殊分隔符號。我們透過添加第二個對方括號來賦予它們自己的風格:

morestring=[s][]{\#\{}{\}}

在這裡,我們添加空括號,這意味著將使用預設樣式。另外,不要忘記轉義特殊字符,例如#{等。listings

評論: s選項意味著開始和結束分隔符號不同,d它們是相同的。必須使用b而不是d啟用反斜線轉義。我在原來的答案中犯了這個錯誤。另外值得注意的是,Ruby 與大多數語言一樣,已經有一個基本定義,其中包括大多數字串,因此無需重新定義所有內容(除非我們想要覆蓋它,我們會的)。

這是\lstset產生在OP的第一次編輯中看到的輸出的:

\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][]{\#\{}{\}},
}

解決其他問題

字串內的關鍵字突出顯示

正如丹尼爾在評論中所說,星號morestring=*[d]{"}導致它進一步尋找更多字串關鍵字。這就是我們想要的“ #{-}字串”,但它也發生在關鍵字上。 listings不允許指定我們要在字串中尋找的內容,因此我們將找到另一種解決方法。

現在,listings提供了一個**選項,可以累積字串的樣式及其特殊內容。例如,當我們這樣做時:

morestring=**[d][\color{mauve}]{"},
keywordstyle=\bfseries,

listings將使雙引號內的關鍵字加粗淡紫色。問題是,我們需要「累積」顏色。

morestring=**[d][\color{mauve}]{"},
keywordstyle=\color{blue},

在這種情況下,字串內的關鍵字將使用 進行處理\color{mauve} \color{blue},這很糟糕:關鍵字樣式會覆蓋字串樣式。我的技巧是用一個新命令替換關鍵字樣式,該命令檢查當前顏色並將其設為藍色(如果它還不是紫紅色):

\def\bluecolorifnotalreadymauve{%
    \extractcolorspec{.}\currentcolor
    \extractcolorspec{mauve}\stringcolor
    \ifx\currentcolor\stringcolor\else
        \color{blue}%
    \fi
}

(謝謝這個答案以獲得解決方案。

現在我們也失去了原來的#{}修復,因為它的(空)樣式是與\color{mauve}from一起「累積」的""。讓我們把它累積回來:

morestring=[s][\color{black}]{\#\{}{\}},

單引號導致#{}問題再次出現

就像關鍵字一樣,單引號字串在雙引號字串內重新處理。並且listings沒有被告知要查看單引號字串,因此我們必須以相同的方式更改它們:

morestring=**[d]{'},

現在我們失去了反斜線轉義。由於未知原因,b該選項不能很好地與**.好吧,當我們這樣做的時候…

morestring=[d]{\\'},

全面更新的 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}

輸出:

使用清單更新了 Ruby 程式碼

替代方法:使用minted

minted已經完成了您想要的一切,甚至更多!這是一個 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}

這是預設樣式的輸出:

使用 minted 更新了 Ruby 程式碼

主要缺點minted是它依賴於皮格門斯進行處理,這意味著:

  1. 安裝起來可能有點棘手。

  2. 客製化更難。 (但是一旦我們知道如何做,它就會非常強大。)

相關內容