如何将特殊标记嵌入到代码列表中,以使用自定义方案标记要着色的某些代码部分?

如何将特殊标记嵌入到代码列表中,以使用自定义方案标记要着色的某些代码部分?

我想像 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可能性。listingsemph\emphstyle

定义Guid为特殊标识符类(emph=[2]{Guid}),并使用仅由一个布尔状态(即\ifGuidAlreadyUsedswitch)组成的有限状态机。后者用于跟踪Guid当前行上是否已经发生。\ProcessGuid然后,宏突出显示每行上第一次出现的Guid,但不突出显示该行上后续出现的Guid(如果有)。

在以下假设下,这应该会产生您想要的语法突出显示:没有多次出现Guid 类型在同一条线上

此外,如果

  1. 还有其他“词”既可以是类型标识符在你的代码中,
  2. 你手边正好有这些单词的列表,并且
  3. 这个清单并不太长,

那么您就可以毫不费力地将上面解释的策略扩展到这些单词。

笔记:选择 对应的预定义语言C#,需要将 值传递[Sharp]Clanguage键;如果传递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}

相关内容