我想像 Visual Studio 一样为我的 C# 代码列表着色。但是,到目前为止,我发现的所有语言定义都只为关键字着色,而不是为用户类型着色。我理解这需要解析代码,并且 listings 包可能不支持,因此我准备自己指定每个单词的颜色。例如,如下所示:
\definecolor{usertype}{rgb}{0.17,0.57,0.68}
\begin{lstlisting}[language=C#]
public interface {\color{usertype}IEntity}
{
{\color{usertype}Guid} Guid { get; }
{\color{usertype}ICollection}<{\color{usertype}IComponent}> Components { get; }
{\color{usertype}IComponent} this[string componentName] { get; }
event {\color{usertype}EventHandler}<{\color{usertype}ComponentEventArgs}> CreatedComponent;
event {\color{usertype}EventHandler}<{\color{usertype}ChangedAttributeEventArgs}> ChangedAttribute;
}
\end{lstlisting}
请注意,某些条目(例如)Guid
既用作类型又用作标识符。不幸的是,这不起作用,因为条目(例如){\color{usertype}...}
实际上被写入输出中。我如何指定列表中单个单词或代码片段的颜色?或者有比这更好的包吗lstlisting
?
更新:我曾尝试使用\texttt
,但它会忽略行首的空格,要求\\
在每行末尾强制换行,并且诸如{
和之类的字符}
必须转义为\{
和\}
。
如果我可以通过某些特殊符号将某些词标记为属于特定类别,那就更好了,例如这样:
\begin{lstlisting}[language=C#]
public interface @IEntity
{
@Guid Guid { get; }
@ICollection<@IComponent> Components { get; }
@IComponent this[string componentName] { get; }
event @EventHandler<@ComponentEventArgs> CreatedComponent;
event @EventHandler<@ChangedAttributeEventArgs> ChangedAttribute;
}
\end{lstlisting}
更新2:尝试使用minted
包。它解析代码,因此能够更好地突出显示它,但仍然没有突出显示用户类型。
答案1
只有当你处于自杀监视之中时……
这里的示例代码相对较短,因此如果您有勇气,您可以执行临时语法突出显示。但是,随着代码长度的增加,手动修改列表以获得所需的语法突出显示变得越来越麻烦。想象一下,如果您拥有的不仅仅是文件中的简短示例代码.tex
,而是大量的源文件;如果您必须修改其中的每一个,以便它们在导入 LaTeX 文档时按所需方式排版,您会很痛苦。
幸运的是,你可以将很多重复的工作委托给listings
。它的词法分析能力有限,但你仍然可以想出一些让你的生活更轻松的变通方法。
具有一定自动化的解决方案
我的理解是,您想要获得单词所需的语法突出显示Guid
,根据上下文,可以是类型或标识符。如果您不使用任何卑鄙的伎俩,listings
则只会对给定“单词”的每次出现使用相同的样式。但是,您可以通过实现一个简单的有限状态机来实现上下文感知;这是一种使用开关和's和键的listings
可能性。listings
emph
\emphstyle
定义Guid
为特殊标识符类(emph=[2]{Guid}
),并使用仅由一个布尔状态(即\ifGuidAlreadyUsed
switch)组成的有限状态机。后者用于跟踪Guid
当前行上是否已经发生。\ProcessGuid
然后,宏突出显示每行上第一次出现的Guid
,但不突出显示该行上后续出现的Guid
(如果有)。
在以下假设下,这应该会产生您想要的语法突出显示:没有多次出现Guid
类型在同一条线上。
此外,如果
- 还有其他“词”既可以是类型或标识符在你的代码中,
- 你手边正好有这些单词的列表,并且
- 这个清单并不太长,
那么您就可以毫不费力地将上面解释的策略扩展到这些单词。
笔记:选择 对应的预定义语言C#
,需要将 值传递[Sharp]C
给language
键;如果传递C#
,则会出错。
\documentclass{article}
\usepackage{xcolor}
\usepackage{listings}
\definecolor{usertype}{rgb}{0.17,0.57,0.68}
\makeatletter
\lstdefinestyle{SergiyCsharp} % define custom style
{
language = [Sharp]C,
basicstyle = \ttfamily,
emph =[1] % basic user types
{
ChangedAttributeEventArgs,
ComponentEventArgs,
EventHandler,
ICollection,
IComponent,
IEntity,
},
emphstyle =[1]\color{usertype},
emph =[2]{Guid}, % Guid user type
emphstyle =[2]\ProcessGuid,
}
% Boolean state of a state machine dedicated to keep track of whether
% Guid has already occured on the current line or not
\newif\ifGuidAlreadyUsed
\GuidAlreadyUsedfalse % initialised as false
% Highlight Guid if it is the first occurence on the current line;
% Do not highlight it otherwise.
\newcommand\ProcessGuid
{%
\ifGuidAlreadyUsed%
\else%
\global\GuidAlreadyUsedtrue%
\color{usertype}%
\fi%
}
% At the end of each line, reset the state to false
\lst@AddToHook{EOL}{\global\GuidAlreadyUsedfalse}
\makeatother
\begin{document}
\begin{lstlisting}[style=SergiyCsharp]
public interface IEntity
{
Guid Guid { get; }
ICollection<IComponent> Components { get; }
IComponent this[string componentName] { get; }
event EventHandler<ComponentEventArgs> CreatedComponent;
event EventHandler<ChangedAttributeEventArgs> ChangedAttribute;
}
\end{lstlisting}
\end{document}