use std::collections::HashSet;
use super::{Markers, MatchKind, Model, Scope, TokenGroup};
pub const MARKERS: Markers = Markers {
begin: "\" >>> rossi gen-grammars (generated, do not edit)",
end: "\" <<< rossi gen-grammars",
};
fn vim_group(scope: Scope) -> (&'static str, &'static str) {
match scope {
Scope::KeywordControl => ("eventbKeyword", "Keyword"),
Scope::KeywordOther => ("eventbStatusKeyword", "Keyword"),
Scope::ConstantLanguage => ("eventbConstant", "Constant"),
Scope::SupportFunction => ("eventbBuiltin", "Function"),
Scope::KeywordOperator => ("eventbOperator", "Operator"),
}
}
pub fn render(model: &Model) -> String {
let mut out = String::new();
out.push_str("syn case ignore\n");
for group in &model.groups {
if group.kind == MatchKind::Word && group.case_insensitive {
let (name, _) = vim_group(group.scope);
out.push_str(&format!("syn keyword {name} {}\n", group.members.join(" ")));
}
}
out.push_str("syn case match\n");
for group in &model.groups {
if group.kind == MatchKind::Word && !group.case_insensitive {
let (name, _) = vim_group(group.scope);
out.push_str(&format!("syn keyword {name} {}\n", group.members.join(" ")));
}
}
out.push('\n');
for group in &model.groups {
if group.kind == MatchKind::Symbol {
let (name, _) = vim_group(group.scope);
out.push_str(&format!(
"syn match {name} \"{}\"\n",
vim_alternation(group)
));
}
}
out.push('\n');
out.push_str("syn match eventbNumber \"\\<\\d\\+\\>\"\n");
out.push_str("syn region eventbString start='\"' end='\"' contains=eventbEscape\n");
out.push_str("syn match eventbEscape \"\\\\[nrt\\\\\\\"]\" contained\n");
out.push_str("syn match eventbComment \"//.*$\"\n");
out.push_str("syn region eventbComment start=\"/\\*\" end=\"\\*/\"\n");
out.push_str("syn match eventbLabel \"@[A-Za-z0-9_]\\+\"\n");
out.push_str("syn match eventbIdentifier \"\\<[a-zA-Z_][a-zA-Z0-9_]*\\>\"\n");
out.push_str("syn match eventbDelimiter \"[(){}\\[\\]]\"\n");
out.push('\n');
let mut links: Vec<(&str, &str)> = Vec::new();
let mut seen: HashSet<&str> = HashSet::new();
for group in &model.groups {
let link = vim_group(group.scope);
if seen.insert(link.0) {
links.push(link);
}
}
links.extend([
("eventbNumber", "Number"),
("eventbString", "String"),
("eventbEscape", "SpecialChar"),
("eventbComment", "Comment"),
("eventbLabel", "Label"),
("eventbIdentifier", "Identifier"),
("eventbDelimiter", "Delimiter"),
]);
for (name, target) in links {
out.push_str(&format!("hi def link {name} {target}\n"));
}
out
}
fn vim_alternation(group: &TokenGroup) -> String {
group
.members
.iter()
.map(|m| vim_escape(m))
.collect::<Vec<_>>()
.join("\\|")
}
fn vim_escape(s: &str) -> String {
let mut out = String::with_capacity(s.len());
for c in s.chars() {
if matches!(c, '.' | '*' | '[' | ']' | '^' | '$' | '~' | '\\') {
out.push('\\');
}
out.push(c);
}
out
}