Code colors: Rust, JavaScript, Ruby, Haskell, Erlang presets; TOML and CMake comments follow code (Ely R2.12)

This commit is contained in:
ZacharyZhang-NY committed 2026-10-09 07:29:53 -04:00
1 parent c77124812d
commit b0dbfd429c
2 files changed
+134 -157

No files matched your search

+106 -157
View File
@@ -11,182 +11,134 @@ pub(crate) struct Syntax {
pub constants: &'static [&'static str],
}
/// C, Rust, JavaScript, Go, Java, Swift and kin.
pub(crate) const C_LIKE: Syntax = Syntax {
comment: "//",
word_comment: false,
keywords: &[
"as",
"async",
"await",
"break",
"case",
"catch",
"class",
"const",
"continue",
"do",
"else",
"enum",
"export",
"extends",
"fn",
"for",
"from",
"func",
"function",
"if",
"impl",
"import",
"in",
"interface",
"let",
"match",
"mut",
"new",
"package",
"pub",
"return",
"static",
"struct",
"switch",
"throw",
"trait",
"try",
"type",
"use",
"var",
"where",
"while",
"yield",
],
constants: &[
"false",
"nil",
"null",
"self",
"Self",
"this",
"true",
"undefined",
"None",
"Some",
],
};
impl Syntax {
const fn new(
comment: &'static str,
keywords: &'static [&'static str],
constants: &'static [&'static str],
) -> Self {
Self {
comment,
word_comment: false,
keywords,
constants,
}
}
}
const PYTHON: Syntax = Syntax {
comment: "#",
word_comment: false,
keywords: &[
"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",
],
constants: &["True", "False", "None", "self"],
};
#[rustfmt::skip]
const RUST: Syntax = Syntax::new("//", &[
"as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern",
"fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref",
"return", "static", "struct", "super", "trait", "type", "unsafe", "use", "where", "while",
], &["true", "false", "self", "Self", "None", "Some", "Ok", "Err"]);
const SHELL: Syntax = Syntax {
comment: "#",
#[rustfmt::skip]
const SCRIPT: Syntax = Syntax::new("//", &[
"as", "async", "await", "break", "case", "catch", "class", "const", "continue", "default",
"delete", "do", "else", "export", "extends", "finally", "for", "from", "function", "if",
"import", "in", "instanceof", "interface", "let", "new", "of", "return", "static", "switch",
"throw", "try", "type", "typeof", "var", "void", "while", "yield",
], &["true", "false", "null", "undefined", "this", "NaN"]);
/// C, C++, Java, Go, Swift, Kotlin, C# and kin.
#[rustfmt::skip]
pub(crate) const C_LIKE: Syntax = Syntax::new("//", &[
"break", "case", "catch", "class", "const", "continue", "default", "defer", "do", "else",
"enum", "extends", "final", "for", "func", "fun", "go", "if", "implements", "import",
"interface", "let", "namespace", "new", "package", "private", "protected", "public", "return",
"static", "struct", "switch", "throw", "try", "typedef", "union", "using", "val", "var",
"void", "while",
], &["true", "false", "null", "nil", "nullptr", "this", "self"]);
#[rustfmt::skip]
const PYTHON: Syntax = Syntax::new("#", &[
"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",
], &["True", "False", "None", "self"]);
#[rustfmt::skip]
const RUBY: Syntax = Syntax::new("#", &[
"alias", "and", "begin", "break", "case", "class", "def", "do", "else", "elsif", "end",
"ensure", "for", "if", "in", "module", "next", "not", "or", "redo", "rescue", "retry",
"return", "then", "unless", "until", "when", "while", "yield",
], &["true", "false", "nil", "self"]);
#[rustfmt::skip]
const SHELL: Syntax = Syntax { word_comment: true, ..Syntax::new("#", &[
"case", "do", "done", "elif", "else", "esac", "export", "fi", "for", "function", "if", "in",
"local", "return", "then", "until", "while",
], &["true", "false"]) };
/// `#` languages, CMake and Make: no word list.
const HASH: Syntax = Syntax::new("#", &[], &["true", "false"]);
/// YAML, whose `#` starts a comment only after a space.
const YAML: Syntax = Syntax {
word_comment: true,
keywords: &[
"case", "do", "done", "elif", "else", "esac", "export", "fi", "for", "function", "if",
"in", "local", "return", "then", "until", "while",
],
constants: &["true", "false"],
..Syntax::new("#", &[], &["true", "false", "null", "yes", "no"])
};
/// TOML, YAML, INI and other settings: keys are not words.
const SETTINGS: Syntax = Syntax {
comment: "#",
word_comment: true,
keywords: &[],
constants: &["true", "false", "null", "yes", "no", "on", "off"],
};
const INI: Syntax = Syntax::new(";", &[], &["true", "false", "yes", "no", "on", "off"]);
const INI: Syntax = Syntax {
comment: ";",
..SETTINGS
};
#[rustfmt::skip]
const SQL: Syntax = Syntax::new("--", &[
"SELECT", "FROM", "WHERE", "JOIN", "LEFT", "RIGHT", "INNER", "OUTER", "ON", "AND", "OR",
"NOT", "AS", "GROUP", "BY", "ORDER", "HAVING", "LIMIT", "OFFSET", "INSERT", "INTO", "VALUES",
"UPDATE", "SET", "DELETE", "CREATE", "TABLE", "INDEX", "DROP", "ALTER", "DESC", "ASC",
"DISTINCT", "UNION", "WITH", "CASE", "WHEN", "THEN", "ELSE", "END", "IS", "IN", "LIKE",
"BETWEEN", "EXISTS",
], &["NULL", "TRUE", "FALSE"]);
const SQL: Syntax = Syntax {
comment: "--",
word_comment: false,
keywords: &[
"SELECT", "FROM", "WHERE", "JOIN", "LEFT", "RIGHT", "INNER", "OUTER", "ON", "AND", "OR",
"NOT", "AS", "GROUP", "BY", "ORDER", "HAVING", "LIMIT", "OFFSET", "INSERT", "INTO",
"VALUES", "UPDATE", "SET", "DELETE", "CREATE", "TABLE", "INDEX", "DROP", "ALTER", "DESC",
"ASC", "DISTINCT", "UNION", "WITH", "CASE", "WHEN", "THEN", "ELSE", "END", "IS", "IN",
"LIKE", "BETWEEN", "EXISTS",
],
constants: &["NULL", "TRUE", "FALSE"],
};
#[rustfmt::skip]
const LUA: Syntax = Syntax::new("--", &[
"and", "break", "do", "else", "elseif", "end", "for", "function", "goto", "if", "in", "local",
"not", "or", "repeat", "return", "then", "until", "while",
], &["true", "false", "nil"]);
const LUA: Syntax = Syntax {
comment: "--",
word_comment: false,
keywords: &[
"and", "break", "do", "else", "elseif", "end", "for", "function", "goto", "if", "in",
"local", "not", "or", "repeat", "return", "then", "until", "while",
],
constants: &["true", "false", "nil"],
};
#[rustfmt::skip]
const HASKELL: Syntax = Syntax::new("--", &[
"case", "class", "data", "deriving", "do", "else", "if", "import", "in", "instance", "let",
"module", "newtype", "of", "then", "type", "where",
], &["True", "False"]);
const LISP: Syntax = Syntax {
comment: ";",
word_comment: false,
keywords: &[
"defun", "defn", "define", "lambda", "let", "if", "cond", "quote",
],
constants: &["nil", "t", "true", "false"],
};
#[rustfmt::skip]
const LISP: Syntax = Syntax::new(";", &[
"defun", "defn", "define", "lambda", "let", "if", "cond",
], &["nil", "t"]);
/// Ruby, Perl, CMake and other `#` languages.
const HASH: Syntax = Syntax {
comment: "#",
..C_LIKE
};
#[rustfmt::skip]
const ERLANG: Syntax = Syntax::new("%", &[
"after", "begin", "case", "catch", "end", "fun", "if", "of", "receive", "try", "when",
], &["true", "false"]);
const TEX: Syntax = Syntax {
comment: "%",
word_comment: false,
keywords: &[],
constants: &[],
};
const TEX: Syntax = Syntax::new("%", &[], &[]);
/// Extensions of prose and plain text, which read plain.
#[rustfmt::skip]
const PROSE: &[&str] = &[
"md", "markdown", "mdown", "mkd", "txt", "text", "rst", "adoc", "asciidoc", "org", "csv",
"tsv", "log",
"md", "markdown", "mdown", "mkd", "txt", "text", "rst", "adoc", "asciidoc", "org", "csv", "tsv",
"log",
];
/// Languages by extension; any other code reads C-like.
#[rustfmt::skip]
const BY_EXTENSION: &[(&Syntax, &[&str])] = &[
(&RUST, &["rs"]),
(&SCRIPT, &["js", "mjs", "cjs", "jsx", "ts", "tsx", "mts"]),
(&PYTHON, &["py", "pyi", "pyw"]),
(&RUBY, &["rb", "rake", "gemspec"]),
(&SHELL, &["sh", "bash", "zsh", "fish", "ksh"]),
(
&HASH,
&[
"rb", "pl", "r", "cmake", "mk", "nix", "ex", "exs", "jl", "nim", "cr", "tcl", "ps1",
],
),
(
&SETTINGS,
&[
"toml",
"yaml",
"yml",
"conf",
"cfg",
"gitignore",
"env",
"properties",
],
),
(&HASH, &["pl", "r", "cmake", "mk", "nix", "ex", "exs", "jl", "nim", "cr", "tcl", "ps1",
"toml", "conf", "cfg", "gitignore", "env", "properties"]),
(&YAML, &["yaml", "yml"]),
(&INI, &["ini"]),
(&SQL, &["sql"]),
(&LUA, &["lua"]),
(&HASKELL, &["hs", "lhs", "elm"]),
(&LISP, &["clj", "cljs", "lisp", "el", "scm"]),
(&ERLANG, &["erl", "hrl"]),
(&TEX, &["tex", "sty", "bib"]),
];
@@ -195,13 +147,10 @@ pub(crate) fn syntax_of(path: &str) -> Option<&'static Syntax> {
let name = path.rsplit_once('/').map_or(path, |(_, name)| name);
// Named files first: CMakeLists.txt is not prose.
match name {
"Makefile" | "GNUmakefile" | "Dockerfile" | "CMakeLists.txt" => return Some(&SHELL),
"Makefile" | "GNUmakefile" | "Dockerfile" | "CMakeLists.txt" => return Some(&HASH),
_ => {}
}
let ext = match name.rsplit_once('.') {
Some((_, ext)) => ext.to_ascii_lowercase(),
None => return None,
};
let ext = name.rsplit_once('.')?.1.to_ascii_lowercase();
if PROSE.contains(&ext.as_str()) {
return None;
}
+28
View File
@@ -184,6 +184,34 @@ mod tests {
Some(syntax.keyword),
"a TOML key"
);
// Words belong to their own language.
assert_ne!(
color("let from = 42;", "main.rs", cx)[1].1,
Some(syntax.keyword),
"Rust's from"
);
assert_eq!(
color("def hello", "a.rb", cx)[0].1,
Some(syntax.keyword),
"Ruby's def"
);
assert_eq!(
color("-- return 42", "Main.hs", cx),
[(0..12, Some(syntax.comment))]
);
assert_eq!(
color("% return 42", "main.erl", cx),
[(0..11, Some(syntax.comment))]
);
// A comment may follow code at once outside Shell.
assert_eq!(
color("answer = 42# return 99", "config.toml", cx).last(),
Some(&(11..22, Some(syntax.comment)))
);
assert_eq!(
color("set(x 1)# return 42", "CMakeLists.txt", cx).last(),
Some(&(8..19, Some(syntax.comment)))
);
// Shell comments start words only.
let shell = color("echo foo#bar 42", "run.sh", cx);
assert!(