using System.Collections.Frozen; namespace AIStudio.Tools.CodeHighlighting; /// /// 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. /// /// /// 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. /// public sealed class CodeLanguageRules { private static readonly FrozenSet NO_WORDS = Words(); /// /// The keywords, such as if or return. /// public FrozenSet Keywords { get; init; } = NO_WORDS; /// /// The names of built-in types, such as int. /// public FrozenSet Types { get; init; } = NO_WORDS; /// /// The words which stand for a value, such as true or null. /// public FrozenSet Literals { get; init; } = NO_WORDS; /// /// The keywords after which the name of a function follows, such as def. Each of them has to be one /// of the keywords, too. /// public FrozenSet FunctionDeclarations { get; init; } = NO_WORDS; /// /// The keywords after which the name of a type follows, such as class. Each of them has to be one of /// the keywords, too. /// public FrozenSet TypeDeclarations { get; init; } = NO_WORDS; /// /// What starts a comment to the end of its line, such as //. /// public IReadOnlyList LineComments { get; init; } = []; /// /// 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. /// public bool LineCommentsNeedSeparator { get; init; } /// /// The kinds of block comments, such as /* … */. /// public IReadOnlyList BlockComments { get; init; } = []; /// /// 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. /// public IReadOnlyList Strings { get; init; } = []; /// /// The kinds of quoted names, such as "column" in SQL. They stay plain, but no keyword within them /// gets a color. /// public IReadOnlyList QuotedNames { get; init; } = []; /// /// The words which may stand right before a string and belong to it, such as the f of an f-string in /// Python. /// public FrozenSet StringPrefixes { get; init; } = NO_WORDS; /// /// Whether the language writes long strings and comments in brackets, as Lua does with [[ … ]] and /// --[==[ … ]==]. /// public bool HasLongBrackets { get; init; } /// /// The character which starts the name of a variable, such as $, or null when there is none. /// public char? VariablePrefix { get; init; } /// /// The characters which may appear within the name of a variable beyond letters, digits, and the /// underscore, such as the colon of $env:PATH. /// public string VariableNameCharacters { get; init; } = string.Empty; /// /// The character which starts an annotation or decorator, such as @, or null when there is none. /// public char? AnnotationPrefix { get; init; } /// /// Whether a # at the start of a line begins a directive to the end of the line, as #include does. /// public bool HasPreprocessor { get; init; } /// /// 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. /// public string WordStartCharacters { get; init; } = string.Empty; /// /// The characters which may appear within a word beyond letters, digits, and the underscore, such as /// the hyphen of a CSS property. /// public string WordCharacters { get; init; } = string.Empty; /// /// Whether a name followed directly by an opening parenthesis is a function. /// public bool HighlightFunctionCalls { get; init; } = true; /// /// Whether a name in PascalCase is a type, as in Java. /// public bool HighlightPascalCaseTypes { get; init; } /// /// Whether a word of the form Verb-Noun is a command, as in PowerShell. /// public bool HighlightCommandNames { get; init; } /// /// 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. /// public FrozenSet HyphenOperators { get; init; } = NO_WORDS; /// /// Whether a name in square brackets is a type, as [string] in PowerShell. /// public bool HasBracketTypes { get; init; } /// /// Whether the code is a style sheet: selectors, properties, and values instead of statements. /// public bool IsStyleSheet { get; init; } /// /// A set of words which match exactly as they are written. /// /// The words. /// The set of words. public static FrozenSet Words(params string[] words) => words.ToFrozenSet(StringComparer.Ordinal); /// /// A set of words which match in any case, for the languages which ignore it, such as SQL. /// /// The words. /// The set of words. public static FrozenSet WordsInAnyCase(params string[] words) => words.ToFrozenSet(StringComparer.OrdinalIgnoreCase); }