Highlighted code blocks inside the app (#1153)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-11-04 07:58:57 +01:00
1 parent 0b42c0288e
commit f4a86c2fb8
60 files changed
+2550 -41

No files matched your search

@@ -0,0 +1,42 @@
namespace AIStudio.Tools.CodeHighlighting.Languages;
/// <summary>
/// How C and C++ code looks to the tokenizer. C++ knows all the words of C, so both share one set of
/// rules.
/// </summary>
/// <remarks>
/// A directive of the preprocessor, such as #include, runs to the end of its line. A raw string of C++,
/// such as R"(…)", reads like any other string, which differs only when it holds a quotation mark.
/// </remarks>
public static class CppCodeRules
{
public static readonly CodeLanguageRules RULES = new()
{
Keywords = CodeLanguageRules.Words(
"alignas", "alignof", "asm", "auto", "break", "case", "catch", "class", "co_await", "co_return", "co_yield",
"concept", "const", "const_cast", "consteval", "constexpr", "constinit", "continue", "decltype", "default",
"delete", "do", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "for", "friend", "goto", "if",
"inline", "mutable", "namespace", "new", "noexcept", "operator", "private", "protected", "public", "register",
"reinterpret_cast", "requires", "return", "sizeof", "static", "static_assert", "static_cast", "struct",
"switch", "template", "this", "thread_local", "throw", "try", "typedef", "typeid", "typename", "union", "using",
"virtual", "volatile", "while"),
Types = CodeLanguageRules.Words(
"bool", "char", "char8_t", "char16_t", "char32_t", "double", "float", "int", "int8_t", "int16_t", "int32_t",
"int64_t", "intptr_t", "long", "ptrdiff_t", "short", "signed", "size_t", "uint8_t", "uint16_t", "uint32_t",
"uint64_t", "uintptr_t", "unsigned", "void", "wchar_t"),
Literals = CodeLanguageRules.Words("true", "false", "nullptr", "NULL"),
TypeDeclarations = CodeLanguageRules.Words("class", "enum", "struct", "union"),
LineComments = ["//"],
BlockComments = [new("/*", "*/")],
Strings =
[
new("\"", "\""),
new("'", "'"),
],
StringPrefixes = CodeLanguageRules.Words("L", "u", "U", "u8", "R", "LR", "uR", "UR", "u8R"),
HasPreprocessor = true,
};
}
@@ -0,0 +1,26 @@
namespace AIStudio.Tools.CodeHighlighting.Languages;
/// <summary>
/// How a style sheet in CSS looks to the tokenizer.
/// </summary>
/// <remarks>
/// A style sheet has no statements: it has selectors, such as .card or #main, and blocks of properties
/// with their values. The tokenizer tells them apart by the braces. At-rules, such as @media, and
/// !important get the color of keywords, and a function, such as var(), that of functions.
/// </remarks>
public static class CssCodeRules
{
public static readonly CodeLanguageRules RULES = new()
{
IsStyleSheet = true,
BlockComments = [new("/*", "*/")],
Strings =
[
new("\"", "\""),
new("'", "'"),
],
WordStartCharacters = "-",
WordCharacters = "-",
};
}
@@ -0,0 +1,37 @@
namespace AIStudio.Tools.CodeHighlighting.Languages;
/// <summary>
/// How Java code looks to the tokenizer.
/// </summary>
/// <remarks>
/// Java names its classes in PascalCase, such as String or ArrayList, so such a name is a type, and a
/// constant in capitals, such as MAX_SIZE, is none. A text block in three quotation marks may run over
/// several lines.
/// </remarks>
public static class JavaCodeRules
{
public static readonly CodeLanguageRules RULES = new()
{
Keywords = CodeLanguageRules.Words(
"abstract", "assert", "break", "case", "catch", "class", "const", "continue", "default", "do", "else", "enum",
"extends", "final", "finally", "for", "goto", "if", "implements", "import", "instanceof", "interface", "native",
"new", "package", "permits", "private", "protected", "public", "record", "return", "sealed", "static",
"strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "try", "var",
"volatile", "while", "yield"),
Types = CodeLanguageRules.Words("boolean", "byte", "char", "double", "float", "int", "long", "short", "void"),
Literals = CodeLanguageRules.Words("true", "false", "null"),
TypeDeclarations = CodeLanguageRules.Words("class", "enum", "interface", "record"),
LineComments = ["//"],
BlockComments = [new("/*", "*/")],
Strings =
[
new("\"\"\"", "\"\"\"", IsMultiline: true),
new("\"", "\""),
new("'", "'"),
],
AnnotationPrefix = '@',
HighlightPascalCaseTypes = true,
};
}
@@ -0,0 +1,51 @@
namespace AIStudio.Tools.CodeHighlighting.Languages;
/// <summary>
/// How JavaScript code looks to the tokenizer, JSX included, whose tags stay plain.
/// </summary>
/// <remarks>
/// A template literal stays one string, including the expressions within it. A regular expression
/// literal stays plain: telling it from a division needs the grammar of the language.
/// </remarks>
public static class JavaScriptCodeRules
{
/// <summary>
/// The keywords of JavaScript, which TypeScript has, too.
/// </summary>
internal static readonly string[] KEYWORDS =
[
"async", "await", "break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete", "do",
"else", "export", "extends", "finally", "for", "from", "function", "if", "import", "in", "instanceof", "let",
"new", "of", "return", "static", "super", "switch", "this", "throw", "try", "typeof", "var", "void", "while",
"with", "yield",
];
/// <summary>
/// The words of JavaScript which stand for a value, which TypeScript has, too.
/// </summary>
internal static readonly string[] LITERALS = ["true", "false", "null", "undefined", "NaN", "Infinity"];
/// <summary>
/// The strings of JavaScript, which TypeScript has, too.
/// </summary>
internal static readonly IReadOnlyList<CodeStringRule> STRINGS =
[
new("`", "`", IsMultiline: true),
new("\"", "\""),
new("'", "'"),
];
public static readonly CodeLanguageRules RULES = new()
{
Keywords = CodeLanguageRules.Words(KEYWORDS),
Literals = CodeLanguageRules.Words(LITERALS),
FunctionDeclarations = CodeLanguageRules.Words("function"),
TypeDeclarations = CodeLanguageRules.Words("class"),
LineComments = ["//"],
BlockComments = [new("/*", "*/")],
Strings = STRINGS,
AnnotationPrefix = '@',
WordStartCharacters = "$",
WordCharacters = "$",
};
}
@@ -0,0 +1,27 @@
namespace AIStudio.Tools.CodeHighlighting.Languages;
/// <summary>
/// How Lua code looks to the tokenizer, the language of the plugins of AI Studio, too.
/// </summary>
/// <remarks>
/// Lua writes long strings and comments in brackets, such as [[ … ]] and --[==[ … ]==].
/// </remarks>
public static class LuaCodeRules
{
public static readonly CodeLanguageRules RULES = new()
{
Keywords = CodeLanguageRules.Words(
"and", "break", "do", "else", "elseif", "end", "for", "function", "goto", "if", "in", "local", "not", "or",
"repeat", "return", "then", "until", "while"),
Literals = CodeLanguageRules.Words("nil", "true", "false"),
FunctionDeclarations = CodeLanguageRules.Words("function"),
LineComments = ["--"],
HasLongBrackets = true,
Strings =
[
new("\"", "\""),
new("'", "'"),
],
};
}
@@ -0,0 +1,46 @@
namespace AIStudio.Tools.CodeHighlighting.Languages;
/// <summary>
/// How a PowerShell script looks to the tokenizer.
/// </summary>
/// <remarks>
/// PowerShell ignores the case of its keywords and operators. A command such as Get-ChildItem has the
/// form Verb-Noun, an operator such as -eq is a word after a hyphen, and a type stands in square
/// brackets, as in [string]. The backtick escapes within double quotation marks; two apostrophes stand
/// for one within single ones.
/// </remarks>
public static class PowerShellCodeRules
{
public static readonly CodeLanguageRules RULES = new()
{
Keywords = CodeLanguageRules.WordsInAnyCase(
"begin", "break", "catch", "class", "continue", "do", "dynamicparam", "else", "elseif", "end", "enum", "exit",
"filter", "finally", "for", "foreach", "function", "if", "in", "param", "process", "return", "switch", "throw",
"trap", "try", "until", "using", "while"),
FunctionDeclarations = CodeLanguageRules.WordsInAnyCase("function", "filter"),
TypeDeclarations = CodeLanguageRules.WordsInAnyCase("class", "enum"),
LineComments = ["#"],
LineCommentsNeedSeparator = true,
BlockComments = [new("<#", "#>")],
Strings =
[
new("@\"", "\"@", Escape: '`', IsMultiline: true),
new("@'", "'@", Escape: null, IsMultiline: true),
new("\"", "\"", Escape: '`', IsMultiline: true),
new("'", "'", Escape: null, IsMultiline: true, DoubledCloseIsLiteral: true),
],
VariablePrefix = '$',
VariableNameCharacters = ":",
WordCharacters = "-",
HighlightCommandNames = true,
HyphenOperators = CodeLanguageRules.WordsInAnyCase(
"and", "as", "band", "bnot", "bor", "bxor", "ceq", "clike", "cmatch", "cne", "contains", "creplace", "eq", "f",
"ge", "gt", "ieq", "ilike", "imatch", "in", "ine", "ireplace", "is", "isnot", "join", "le", "like", "lt",
"match", "ne", "not", "notcontains", "notin", "notlike", "notmatch", "or", "replace", "shl", "shr", "split",
"xor"),
HasBracketTypes = true,
};
}
@@ -0,0 +1,34 @@
namespace AIStudio.Tools.CodeHighlighting.Languages;
/// <summary>
/// How Python code looks to the tokenizer.
/// </summary>
/// <remarks>
/// The soft keywords match, case, and type stay out: they are names everywhere else, as in re.match.
/// </remarks>
public static class PythonCodeRules
{
public static readonly CodeLanguageRules RULES = new()
{
Keywords = CodeLanguageRules.Words(
"and", "as", "assert", "async", "await", "break", "class", "continue", "def", "del", "elif", "else", "except",
"finally", "for", "from", "global", "if", "import", "in", "is", "lambda", "nonlocal", "not", "or", "pass",
"raise", "return", "try", "while", "with", "yield"),
Types = CodeLanguageRules.Words("bool", "bytearray", "bytes", "complex", "dict", "float", "frozenset", "int", "list", "object", "set", "str", "tuple"),
Literals = CodeLanguageRules.Words("True", "False", "None"),
FunctionDeclarations = CodeLanguageRules.Words("def"),
TypeDeclarations = CodeLanguageRules.Words("class"),
LineComments = ["#"],
Strings =
[
new("\"\"\"", "\"\"\"", IsMultiline: true),
new("'''", "'''", IsMultiline: true),
new("\"", "\""),
new("'", "'"),
],
StringPrefixes = CodeLanguageRules.WordsInAnyCase("r", "u", "b", "f", "t", "rb", "br", "fr", "rf", "tr", "rt"),
AnnotationPrefix = '@',
};
}
@@ -0,0 +1,30 @@
namespace AIStudio.Tools.CodeHighlighting.Languages;
/// <summary>
/// How a script of a Unix shell, such as Bash, looks to the tokenizer.
/// </summary>
/// <remarks>
/// A # starts a comment only at the start of a word, so $# and ${#list[@]} stay variables. Strings may
/// run over several lines, and the variables within double quotation marks stay a part of the string.
/// </remarks>
public static class ShellCodeRules
{
public static readonly CodeLanguageRules RULES = new()
{
Keywords = CodeLanguageRules.Words(
"break", "case", "continue", "declare", "do", "done", "elif", "else", "esac", "exit", "export", "fi", "for",
"function", "if", "in", "local", "readonly", "return", "select", "source", "then", "time", "until", "unset",
"while"),
FunctionDeclarations = CodeLanguageRules.Words("function"),
LineComments = ["#"],
LineCommentsNeedSeparator = true,
Strings =
[
new("\"", "\"", IsMultiline: true),
new("'", "'", Escape: null, IsMultiline: true),
],
VariablePrefix = '$',
};
}
@@ -0,0 +1,40 @@
namespace AIStudio.Tools.CodeHighlighting.Languages;
/// <summary>
/// How SQL looks to the tokenizer, across its dialects, such as PostgreSQL, MySQL, or T-SQL.
/// </summary>
/// <remarks>
/// SQL ignores the case of its keywords. A string stands in apostrophes, two of which stand for one. A
/// name in quotation marks, backticks, or square brackets, such as "order", stays plain, so that no
/// keyword within it gets a color.
/// </remarks>
public static class SqlCodeRules
{
public static readonly CodeLanguageRules RULES = new()
{
Keywords = CodeLanguageRules.WordsInAnyCase(
"add", "all", "alter", "and", "as", "asc", "begin", "between", "by", "case", "cast", "check", "column", "commit",
"constraint", "create", "cross", "database", "default", "delete", "desc", "distinct", "drop", "else", "end",
"exists", "foreign", "from", "full", "group", "having", "if", "in", "index", "inner", "insert", "into", "is",
"join", "key", "left", "like", "limit", "not", "offset", "on", "or", "order", "outer", "over", "partition",
"primary", "references", "replace", "returning", "right", "rollback", "select", "set", "table", "then", "top",
"transaction", "trigger", "truncate", "union", "unique", "update", "using", "values", "view", "when", "where",
"with"),
Types = CodeLanguageRules.WordsInAnyCase(
"bigint", "binary", "bit", "blob", "boolean", "char", "date", "datetime", "decimal", "double", "float", "int",
"integer", "interval", "json", "jsonb", "money", "nchar", "numeric", "nvarchar", "real", "serial", "smallint",
"text", "time", "timestamp", "tinyint", "uuid", "varbinary", "varchar"),
Literals = CodeLanguageRules.WordsInAnyCase("null", "true", "false"),
LineComments = ["--"],
BlockComments = [new("/*", "*/")],
Strings = [new("'", "'", Escape: null, IsMultiline: true, DoubledCloseIsLiteral: true)],
QuotedNames =
[
new("\"", "\"", Escape: null, DoubledCloseIsLiteral: true),
new("`", "`", Escape: null),
new("[", "]", Escape: null),
],
};
}
@@ -0,0 +1,33 @@
namespace AIStudio.Tools.CodeHighlighting.Languages;
/// <summary>
/// How TypeScript code looks to the tokenizer, TSX included: JavaScript with types.
/// </summary>
/// <remarks>
/// TypeScript names its own types in PascalCase, such as Promise or User, so a name in PascalCase is a
/// type here, unlike in JavaScript.
/// </remarks>
public static class TypeScriptCodeRules
{
public static readonly CodeLanguageRules RULES = new()
{
Keywords = CodeLanguageRules.Words(
[
..JavaScriptCodeRules.KEYWORDS,
"abstract", "as", "declare", "enum", "implements", "infer", "interface", "is", "keyof", "namespace", "override",
"private", "protected", "public", "readonly", "satisfies", "type",
]),
Types = CodeLanguageRules.Words("any", "bigint", "boolean", "never", "number", "object", "string", "symbol", "unknown"),
Literals = CodeLanguageRules.Words(JavaScriptCodeRules.LITERALS),
FunctionDeclarations = CodeLanguageRules.Words("function"),
TypeDeclarations = CodeLanguageRules.Words("class", "enum", "interface", "type"),
LineComments = ["//"],
BlockComments = [new("/*", "*/")],
Strings = JavaScriptCodeRules.STRINGS,
AnnotationPrefix = '@',
WordStartCharacters = "$",
WordCharacters = "$",
HighlightPascalCaseTypes = true,
};
}