Code colors: Rust, JavaScript, Ruby, Haskell, Erlang presets; TOML and CMake comments follow code (Ely R2.12)
This commit is contained in:
2 files changed
+134
-157
No files matched your search
+106
-157
@@ -11,182 +11,134 @@ pub(crate) struct Syntax {
|
|||||||
pub constants: &'static [&'static str],
|
pub constants: &'static [&'static str],
|
||||||
}
|
}
|
||||||
|
|
||||||
/// C, Rust, JavaScript, Go, Java, Swift and kin.
|
impl Syntax {
|
||||||
pub(crate) const C_LIKE: Syntax = Syntax {
|
const fn new(
|
||||||
comment: "//",
|
comment: &'static str,
|
||||||
word_comment: false,
|
keywords: &'static [&'static str],
|
||||||
keywords: &[
|
constants: &'static [&'static str],
|
||||||
"as",
|
) -> Self {
|
||||||
"async",
|
Self {
|
||||||
"await",
|
comment,
|
||||||
"break",
|
word_comment: false,
|
||||||
"case",
|
keywords,
|
||||||
"catch",
|
constants,
|
||||||
"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",
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const PYTHON: Syntax = Syntax {
|
#[rustfmt::skip]
|
||||||
comment: "#",
|
const RUST: Syntax = Syntax::new("//", &[
|
||||||
word_comment: false,
|
"as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern",
|
||||||
keywords: &[
|
"fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref",
|
||||||
"and", "as", "assert", "async", "await", "break", "class", "continue", "def", "del",
|
"return", "static", "struct", "super", "trait", "type", "unsafe", "use", "where", "while",
|
||||||
"elif", "else", "except", "finally", "for", "from", "global", "if", "import", "in", "is",
|
], &["true", "false", "self", "Self", "None", "Some", "Ok", "Err"]);
|
||||||
"lambda", "nonlocal", "not", "or", "pass", "raise", "return", "try", "while", "with",
|
|
||||||
"yield",
|
|
||||||
],
|
|
||||||
constants: &["True", "False", "None", "self"],
|
|
||||||
};
|
|
||||||
|
|
||||||
const SHELL: Syntax = Syntax {
|
#[rustfmt::skip]
|
||||||
comment: "#",
|
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,
|
word_comment: true,
|
||||||
keywords: &[
|
..Syntax::new("#", &[], &["true", "false", "null", "yes", "no"])
|
||||||
"case", "do", "done", "elif", "else", "esac", "export", "fi", "for", "function", "if",
|
|
||||||
"in", "local", "return", "then", "until", "while",
|
|
||||||
],
|
|
||||||
constants: &["true", "false"],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// TOML, YAML, INI and other settings: keys are not words.
|
const INI: Syntax = Syntax::new(";", &[], &["true", "false", "yes", "no", "on", "off"]);
|
||||||
const SETTINGS: Syntax = Syntax {
|
|
||||||
comment: "#",
|
|
||||||
word_comment: true,
|
|
||||||
keywords: &[],
|
|
||||||
constants: &["true", "false", "null", "yes", "no", "on", "off"],
|
|
||||||
};
|
|
||||||
|
|
||||||
const INI: Syntax = Syntax {
|
#[rustfmt::skip]
|
||||||
comment: ";",
|
const SQL: Syntax = Syntax::new("--", &[
|
||||||
..SETTINGS
|
"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 {
|
#[rustfmt::skip]
|
||||||
comment: "--",
|
const LUA: Syntax = Syntax::new("--", &[
|
||||||
word_comment: false,
|
"and", "break", "do", "else", "elseif", "end", "for", "function", "goto", "if", "in", "local",
|
||||||
keywords: &[
|
"not", "or", "repeat", "return", "then", "until", "while",
|
||||||
"SELECT", "FROM", "WHERE", "JOIN", "LEFT", "RIGHT", "INNER", "OUTER", "ON", "AND", "OR",
|
], &["true", "false", "nil"]);
|
||||||
"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"],
|
|
||||||
};
|
|
||||||
|
|
||||||
const LUA: Syntax = Syntax {
|
#[rustfmt::skip]
|
||||||
comment: "--",
|
const HASKELL: Syntax = Syntax::new("--", &[
|
||||||
word_comment: false,
|
"case", "class", "data", "deriving", "do", "else", "if", "import", "in", "instance", "let",
|
||||||
keywords: &[
|
"module", "newtype", "of", "then", "type", "where",
|
||||||
"and", "break", "do", "else", "elseif", "end", "for", "function", "goto", "if", "in",
|
], &["True", "False"]);
|
||||||
"local", "not", "or", "repeat", "return", "then", "until", "while",
|
|
||||||
],
|
|
||||||
constants: &["true", "false", "nil"],
|
|
||||||
};
|
|
||||||
|
|
||||||
const LISP: Syntax = Syntax {
|
#[rustfmt::skip]
|
||||||
comment: ";",
|
const LISP: Syntax = Syntax::new(";", &[
|
||||||
word_comment: false,
|
"defun", "defn", "define", "lambda", "let", "if", "cond",
|
||||||
keywords: &[
|
], &["nil", "t"]);
|
||||||
"defun", "defn", "define", "lambda", "let", "if", "cond", "quote",
|
|
||||||
],
|
|
||||||
constants: &["nil", "t", "true", "false"],
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Ruby, Perl, CMake and other `#` languages.
|
#[rustfmt::skip]
|
||||||
const HASH: Syntax = Syntax {
|
const ERLANG: Syntax = Syntax::new("%", &[
|
||||||
comment: "#",
|
"after", "begin", "case", "catch", "end", "fun", "if", "of", "receive", "try", "when",
|
||||||
..C_LIKE
|
], &["true", "false"]);
|
||||||
};
|
|
||||||
|
|
||||||
const TEX: Syntax = Syntax {
|
const TEX: Syntax = Syntax::new("%", &[], &[]);
|
||||||
comment: "%",
|
|
||||||
word_comment: false,
|
|
||||||
keywords: &[],
|
|
||||||
constants: &[],
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Extensions of prose and plain text, which read plain.
|
/// Extensions of prose and plain text, which read plain.
|
||||||
|
#[rustfmt::skip]
|
||||||
const PROSE: &[&str] = &[
|
const PROSE: &[&str] = &[
|
||||||
"md", "markdown", "mdown", "mkd", "txt", "text", "rst", "adoc", "asciidoc", "org", "csv",
|
"md", "markdown", "mdown", "mkd", "txt", "text", "rst", "adoc", "asciidoc", "org", "csv", "tsv",
|
||||||
"tsv", "log",
|
"log",
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Languages by extension; any other code reads C-like.
|
/// Languages by extension; any other code reads C-like.
|
||||||
|
#[rustfmt::skip]
|
||||||
const BY_EXTENSION: &[(&Syntax, &[&str])] = &[
|
const BY_EXTENSION: &[(&Syntax, &[&str])] = &[
|
||||||
|
(&RUST, &["rs"]),
|
||||||
|
(&SCRIPT, &["js", "mjs", "cjs", "jsx", "ts", "tsx", "mts"]),
|
||||||
(&PYTHON, &["py", "pyi", "pyw"]),
|
(&PYTHON, &["py", "pyi", "pyw"]),
|
||||||
|
(&RUBY, &["rb", "rake", "gemspec"]),
|
||||||
(&SHELL, &["sh", "bash", "zsh", "fish", "ksh"]),
|
(&SHELL, &["sh", "bash", "zsh", "fish", "ksh"]),
|
||||||
(
|
(&HASH, &["pl", "r", "cmake", "mk", "nix", "ex", "exs", "jl", "nim", "cr", "tcl", "ps1",
|
||||||
&HASH,
|
"toml", "conf", "cfg", "gitignore", "env", "properties"]),
|
||||||
&[
|
(&YAML, &["yaml", "yml"]),
|
||||||
"rb", "pl", "r", "cmake", "mk", "nix", "ex", "exs", "jl", "nim", "cr", "tcl", "ps1",
|
|
||||||
],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
&SETTINGS,
|
|
||||||
&[
|
|
||||||
"toml",
|
|
||||||
"yaml",
|
|
||||||
"yml",
|
|
||||||
"conf",
|
|
||||||
"cfg",
|
|
||||||
"gitignore",
|
|
||||||
"env",
|
|
||||||
"properties",
|
|
||||||
],
|
|
||||||
),
|
|
||||||
(&INI, &["ini"]),
|
(&INI, &["ini"]),
|
||||||
(&SQL, &["sql"]),
|
(&SQL, &["sql"]),
|
||||||
(&LUA, &["lua"]),
|
(&LUA, &["lua"]),
|
||||||
|
(&HASKELL, &["hs", "lhs", "elm"]),
|
||||||
(&LISP, &["clj", "cljs", "lisp", "el", "scm"]),
|
(&LISP, &["clj", "cljs", "lisp", "el", "scm"]),
|
||||||
|
(&ERLANG, &["erl", "hrl"]),
|
||||||
(&TEX, &["tex", "sty", "bib"]),
|
(&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);
|
let name = path.rsplit_once('/').map_or(path, |(_, name)| name);
|
||||||
// Named files first: CMakeLists.txt is not prose.
|
// Named files first: CMakeLists.txt is not prose.
|
||||||
match name {
|
match name {
|
||||||
"Makefile" | "GNUmakefile" | "Dockerfile" | "CMakeLists.txt" => return Some(&SHELL),
|
"Makefile" | "GNUmakefile" | "Dockerfile" | "CMakeLists.txt" => return Some(&HASH),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
let ext = match name.rsplit_once('.') {
|
let ext = name.rsplit_once('.')?.1.to_ascii_lowercase();
|
||||||
Some((_, ext)) => ext.to_ascii_lowercase(),
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
if PROSE.contains(&ext.as_str()) {
|
if PROSE.contains(&ext.as_str()) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,6 +184,34 @@ mod tests {
|
|||||||
Some(syntax.keyword),
|
Some(syntax.keyword),
|
||||||
"a TOML key"
|
"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.
|
// Shell comments start words only.
|
||||||
let shell = color("echo foo#bar 42", "run.sh", cx);
|
let shell = color("echo foo#bar 42", "run.sh", cx);
|
||||||
assert!(
|
assert!(
|
||||||
|
|||||||
Reference in new issue
Block a user