mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-04 17:47:21 +00:00
161 lines
6.1 KiB
C#
161 lines
6.1 KiB
C#
using System.Collections.Frozen;
|
|
|
|
namespace AIStudio.Tools.CodeHighlighting;
|
|
|
|
/// <summary>
|
|
/// How a language looks to the CodeTokenizer: its words, comments, strings, and the few habits of its
|
|
/// own, such as the dollar sign of a shell variable.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The rules describe what a reader recognizes at a glance, not the grammar of the language. Whatever
|
|
/// they leave out stays plain, which is no error.
|
|
/// </remarks>
|
|
public sealed class CodeLanguageRules
|
|
{
|
|
private static readonly FrozenSet<string> NO_WORDS = Words();
|
|
|
|
/// <summary>
|
|
/// The keywords, such as if or return.
|
|
/// </summary>
|
|
public FrozenSet<string> Keywords { get; init; } = NO_WORDS;
|
|
|
|
/// <summary>
|
|
/// The names of built-in types, such as int.
|
|
/// </summary>
|
|
public FrozenSet<string> Types { get; init; } = NO_WORDS;
|
|
|
|
/// <summary>
|
|
/// The words which stand for a value, such as true or null.
|
|
/// </summary>
|
|
public FrozenSet<string> Literals { get; init; } = NO_WORDS;
|
|
|
|
/// <summary>
|
|
/// The keywords after which the name of a function follows, such as def. Each of them has to be one
|
|
/// of the keywords, too.
|
|
/// </summary>
|
|
public FrozenSet<string> FunctionDeclarations { get; init; } = NO_WORDS;
|
|
|
|
/// <summary>
|
|
/// The keywords after which the name of a type follows, such as class. Each of them has to be one of
|
|
/// the keywords, too.
|
|
/// </summary>
|
|
public FrozenSet<string> TypeDeclarations { get; init; } = NO_WORDS;
|
|
|
|
/// <summary>
|
|
/// What starts a comment to the end of its line, such as //.
|
|
/// </summary>
|
|
public IReadOnlyList<string> LineComments { get; init; } = [];
|
|
|
|
/// <summary>
|
|
/// Whether a line comment starts only at the beginning of a word, as the # of a shell does: in $# or
|
|
/// a#b, it starts none.
|
|
/// </summary>
|
|
public bool LineCommentsNeedSeparator { get; init; }
|
|
|
|
/// <summary>
|
|
/// The kinds of block comments, such as /* … */.
|
|
/// </summary>
|
|
public IReadOnlyList<CodeDelimiters> BlockComments { get; init; } = [];
|
|
|
|
/// <summary>
|
|
/// The kinds of strings. The first one whose opening matches wins, so a longer opening, such as three
|
|
/// quotation marks, has to come before a shorter one.
|
|
/// </summary>
|
|
public IReadOnlyList<CodeStringRule> Strings { get; init; } = [];
|
|
|
|
/// <summary>
|
|
/// The kinds of quoted names, such as "column" in SQL. They stay plain, but no keyword within them
|
|
/// gets a color.
|
|
/// </summary>
|
|
public IReadOnlyList<CodeStringRule> QuotedNames { get; init; } = [];
|
|
|
|
/// <summary>
|
|
/// The words which may stand right before a string and belong to it, such as the f of an f-string in
|
|
/// Python.
|
|
/// </summary>
|
|
public FrozenSet<string> StringPrefixes { get; init; } = NO_WORDS;
|
|
|
|
/// <summary>
|
|
/// Whether the language writes long strings and comments in brackets, as Lua does with [[ … ]] and
|
|
/// --[==[ … ]==].
|
|
/// </summary>
|
|
public bool HasLongBrackets { get; init; }
|
|
|
|
/// <summary>
|
|
/// The character which starts the name of a variable, such as $, or null when there is none.
|
|
/// </summary>
|
|
public char? VariablePrefix { get; init; }
|
|
|
|
/// <summary>
|
|
/// The characters which may appear within the name of a variable beyond letters, digits, and the
|
|
/// underscore, such as the colon of $env:PATH.
|
|
/// </summary>
|
|
public string VariableNameCharacters { get; init; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// The character which starts an annotation or decorator, such as @, or null when there is none.
|
|
/// </summary>
|
|
public char? AnnotationPrefix { get; init; }
|
|
|
|
/// <summary>
|
|
/// Whether a # at the start of a line begins a directive to the end of the line, as #include does.
|
|
/// </summary>
|
|
public bool HasPreprocessor { get; init; }
|
|
|
|
/// <summary>
|
|
/// The characters which may start a word beyond letters and the underscore, such as the $ of
|
|
/// JavaScript. A hyphen starts a word only when a letter, an underscore, or another hyphen follows it.
|
|
/// </summary>
|
|
public string WordStartCharacters { get; init; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// The characters which may appear within a word beyond letters, digits, and the underscore, such as
|
|
/// the hyphen of a CSS property.
|
|
/// </summary>
|
|
public string WordCharacters { get; init; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Whether a name followed directly by an opening parenthesis is a function.
|
|
/// </summary>
|
|
public bool HighlightFunctionCalls { get; init; } = true;
|
|
|
|
/// <summary>
|
|
/// Whether a name in PascalCase is a type, as in Java.
|
|
/// </summary>
|
|
public bool HighlightPascalCaseTypes { get; init; }
|
|
|
|
/// <summary>
|
|
/// Whether a word of the form Verb-Noun is a command, as in PowerShell.
|
|
/// </summary>
|
|
public bool HighlightCommandNames { get; init; }
|
|
|
|
/// <summary>
|
|
/// The operators written as a word after a hyphen, such as -eq in PowerShell. Any other word after a
|
|
/// hyphen is the name of a parameter and stays plain.
|
|
/// </summary>
|
|
public FrozenSet<string> HyphenOperators { get; init; } = NO_WORDS;
|
|
|
|
/// <summary>
|
|
/// Whether a name in square brackets is a type, as [string] in PowerShell.
|
|
/// </summary>
|
|
public bool HasBracketTypes { get; init; }
|
|
|
|
/// <summary>
|
|
/// Whether the code is a style sheet: selectors, properties, and values instead of statements.
|
|
/// </summary>
|
|
public bool IsStyleSheet { get; init; }
|
|
|
|
/// <summary>
|
|
/// A set of words which match exactly as they are written.
|
|
/// </summary>
|
|
/// <param name="words">The words.</param>
|
|
/// <returns>The set of words.</returns>
|
|
public static FrozenSet<string> Words(params string[] words) => words.ToFrozenSet(StringComparer.Ordinal);
|
|
|
|
/// <summary>
|
|
/// A set of words which match in any case, for the languages which ignore it, such as SQL.
|
|
/// </summary>
|
|
/// <param name="words">The words.</param>
|
|
/// <returns>The set of words.</returns>
|
|
public static FrozenSet<string> WordsInAnyCase(params string[] words) => words.ToFrozenSet(StringComparer.OrdinalIgnoreCase);
|
|
} |