1 //! Renders a bit of code as HTML.
3 use ra_db::SourceDatabase;
4 use ra_syntax::AstNode;
6 use crate::{FileId, HighlightedRange, RootDatabase};
10 pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String {
11 let parse = db.parse(file_id);
13 fn rainbowify(seed: u64) -> String {
15 let mut rng = SmallRng::seed_from_u64(seed);
18 h = rng.gen_range::<u16, _, _>(0, 361),
19 s = rng.gen_range::<u16, _, _>(42, 99),
20 l = rng.gen_range::<u16, _, _>(40, 91),
24 let mut ranges = highlight(db, file_id, None);
25 ranges.sort_by_key(|it| it.range.start());
26 // quick non-optimal heuristic to intersect token ranges and highlighted ranges
28 let mut could_intersect: Vec<&HighlightedRange> = Vec::new();
30 let mut buf = String::new();
32 buf.push_str("<pre><code>");
33 let tokens = parse.tree().syntax().descendants_with_tokens().filter_map(|it| it.into_token());
35 could_intersect.retain(|it| token.text_range().start() <= it.range.end());
36 while let Some(r) = ranges.get(frontier) {
37 if r.range.start() <= token.text_range().end() {
38 could_intersect.push(r);
44 let text = html_escape(&token.text());
45 let ranges = could_intersect
47 .filter(|it| token.text_range().is_subrange(&it.range))
49 if ranges.is_empty() {
54 .map(|it| it.highlight.to_string().replace('.', " "))
57 let binding_hash = ranges.first().and_then(|x| x.binding_hash);
58 let color = match (rainbow, binding_hash) {
59 (true, Some(hash)) => format!(
60 " data-binding-hash=\"{}\" style=\"color: {};\"",
66 buf.push_str(&format!("<span class=\"{}\"{}>{}</span>", classes, color, text));
69 buf.push_str("</code></pre>");
73 //FIXME: like, real html escaping
74 fn html_escape(text: &str) -> String {
75 text.replace("<", "<").replace(">", ">")
81 pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
84 .comment { color: #7F9F7F; }
85 .struct, .enum { color: #7CB8BB; }
86 .enum_variant { color: #BDE0F3; }
87 .string_literal { color: #CC9393; }
88 .field { color: #94BFF3; }
89 .function { color: #93E0E3; }
90 .parameter { color: #94BFF3; }
91 .text { color: #DCDCCC; }
92 .type { color: #7CB8BB; }
93 .builtin_type { color: #8CD0D3; }
94 .type_param { color: #DFAF8F; }
95 .attribute { color: #94BFF3; }
96 .numeric_literal { color: #BFEBBF; }
97 .macro { color: #94BFF3; }
98 .module { color: #AFD8AF; }
99 .variable { color: #DCDCCC; }
100 .mutable { text-decoration: underline; }
102 .keyword { color: #F0DFAF; font-weight: bold; }
103 .keyword.unsafe { color: #BC8383; font-weight: bold; }
104 .control { font-style: italic; }