(40, 91),
)
}
let mut ranges = highlight(db, file_id, None);
ranges.sort_by_key(|it| it.range.start());
// quick non-optimal heuristic to intersect token ranges and highlighted ranges
let mut frontier = 0;
let mut could_intersect: Vec<&HighlightedRange> = Vec::new();
let mut buf = String::new();
buf.push_str(&STYLE);
buf.push_str("");
let tokens = parse.tree().syntax().descendants_with_tokens().filter_map(|it| it.into_token());
for token in tokens {
could_intersect.retain(|it| token.text_range().start() <= it.range.end());
while let Some(r) = ranges.get(frontier) {
if r.range.start() <= token.text_range().end() {
could_intersect.push(r);
frontier += 1;
} else {
break;
}
}
let text = html_escape(&token.text());
let ranges = could_intersect
.iter()
.filter(|it| token.text_range().is_subrange(&it.range))
.collect::>();
if ranges.is_empty() {
buf.push_str(&text);
} else {
let classes = ranges
.iter()
.map(|it| it.highlight.to_string().replace('.', " "))
.collect::>()
.join(" ");
let binding_hash = ranges.first().and_then(|x| x.binding_hash);
let color = match (rainbow, binding_hash) {
(true, Some(hash)) => format!(
" data-binding-hash=\"{}\" style=\"color: {};\"",
hash,
rainbowify(hash)
),
_ => "".into(),
};
buf.push_str(&format!("{}", classes, color, text));
}
}
buf.push_str("
");
buf
}
//FIXME: like, real html escaping
fn html_escape(text: &str) -> String {
text.replace("<", "<").replace(">", ">")
}
const STYLE: &str = "
";