diff options
author | Benjamin Coenen <[email protected]> | 2020-04-09 08:39:17 +0100 |
---|---|---|
committer | Benjamin Coenen <[email protected]> | 2020-04-09 08:53:53 +0100 |
commit | 585bb83e2aec9c79dae8c2e031e9165f40937003 (patch) | |
tree | 3dda062f3deb768b211e7e091dd5b29b9b6fae84 /crates/ra_ide/src/syntax_highlighting | |
parent | 8f1dba6f9ae1d8d314dd9d007e4c582ed1403e8d (diff) | |
parent | 080c983498afcac3eb54028af5c9f8bfe7f2c826 (diff) |
feat: add attributes support on struct fields and method #3870
Signed-off-by: Benjamin Coenen <[email protected]>
Diffstat (limited to 'crates/ra_ide/src/syntax_highlighting')
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting/html.rs | 66 | ||||
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting/tests.rs | 25 |
2 files changed, 50 insertions, 41 deletions
diff --git a/crates/ra_ide/src/syntax_highlighting/html.rs b/crates/ra_ide/src/syntax_highlighting/html.rs index e13766c9d..4496529a1 100644 --- a/crates/ra_ide/src/syntax_highlighting/html.rs +++ b/crates/ra_ide/src/syntax_highlighting/html.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | //! Renders a bit of code as HTML. | 1 | //! Renders a bit of code as HTML. |
2 | 2 | ||
3 | use ra_db::SourceDatabase; | 3 | use ra_db::SourceDatabase; |
4 | use ra_syntax::AstNode; | 4 | use ra_syntax::{AstNode, TextUnit}; |
5 | 5 | ||
6 | use crate::{FileId, HighlightedRange, RootDatabase}; | 6 | use crate::{FileId, RootDatabase}; |
7 | 7 | ||
8 | use super::highlight; | 8 | use super::highlight; |
9 | 9 | ||
@@ -21,51 +21,35 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo | |||
21 | ) | 21 | ) |
22 | } | 22 | } |
23 | 23 | ||
24 | let mut ranges = highlight(db, file_id, None); | 24 | let ranges = highlight(db, file_id, None); |
25 | ranges.sort_by_key(|it| it.range.start()); | 25 | let text = parse.tree().syntax().to_string(); |
26 | // quick non-optimal heuristic to intersect token ranges and highlighted ranges | 26 | let mut prev_pos = TextUnit::from(0); |
27 | let mut frontier = 0; | ||
28 | let mut could_intersect: Vec<&HighlightedRange> = Vec::new(); | ||
29 | |||
30 | let mut buf = String::new(); | 27 | let mut buf = String::new(); |
31 | buf.push_str(&STYLE); | 28 | buf.push_str(&STYLE); |
32 | buf.push_str("<pre><code>"); | 29 | buf.push_str("<pre><code>"); |
33 | let tokens = parse.tree().syntax().descendants_with_tokens().filter_map(|it| it.into_token()); | 30 | for range in &ranges { |
34 | for token in tokens { | 31 | if range.range.start() > prev_pos { |
35 | could_intersect.retain(|it| token.text_range().start() <= it.range.end()); | 32 | let curr = &text[prev_pos.to_usize()..range.range.start().to_usize()]; |
36 | while let Some(r) = ranges.get(frontier) { | 33 | let text = html_escape(curr); |
37 | if r.range.start() <= token.text_range().end() { | ||
38 | could_intersect.push(r); | ||
39 | frontier += 1; | ||
40 | } else { | ||
41 | break; | ||
42 | } | ||
43 | } | ||
44 | let text = html_escape(&token.text()); | ||
45 | let ranges = could_intersect | ||
46 | .iter() | ||
47 | .filter(|it| token.text_range().is_subrange(&it.range)) | ||
48 | .collect::<Vec<_>>(); | ||
49 | if ranges.is_empty() { | ||
50 | buf.push_str(&text); | 34 | buf.push_str(&text); |
51 | } else { | ||
52 | let classes = ranges | ||
53 | .iter() | ||
54 | .map(|it| it.highlight.to_string().replace('.', " ")) | ||
55 | .collect::<Vec<_>>() | ||
56 | .join(" "); | ||
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: {};\"", | ||
61 | hash, | ||
62 | rainbowify(hash) | ||
63 | ), | ||
64 | _ => "".into(), | ||
65 | }; | ||
66 | buf.push_str(&format!("<span class=\"{}\"{}>{}</span>", classes, color, text)); | ||
67 | } | 35 | } |
36 | let curr = &text[range.range.start().to_usize()..range.range.end().to_usize()]; | ||
37 | |||
38 | let class = range.highlight.to_string().replace('.', " "); | ||
39 | let color = match (rainbow, range.binding_hash) { | ||
40 | (true, Some(hash)) => { | ||
41 | format!(" data-binding-hash=\"{}\" style=\"color: {};\"", hash, rainbowify(hash)) | ||
42 | } | ||
43 | _ => "".into(), | ||
44 | }; | ||
45 | buf.push_str(&format!("<span class=\"{}\"{}>{}</span>", class, color, html_escape(curr))); | ||
46 | |||
47 | prev_pos = range.range.end(); | ||
68 | } | 48 | } |
49 | // Add the remaining (non-highlighted) text | ||
50 | let curr = &text[prev_pos.to_usize()..]; | ||
51 | let text = html_escape(curr); | ||
52 | buf.push_str(&text); | ||
69 | buf.push_str("</code></pre>"); | 53 | buf.push_str("</code></pre>"); |
70 | buf | 54 | buf |
71 | } | 55 | } |
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index 98c030791..110887c2a 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs | |||
@@ -131,3 +131,28 @@ fn test_ranges() { | |||
131 | 131 | ||
132 | assert_eq!(&highlights[0].highlight.to_string(), "field.declaration"); | 132 | assert_eq!(&highlights[0].highlight.to_string(), "field.declaration"); |
133 | } | 133 | } |
134 | |||
135 | #[test] | ||
136 | fn test_flattening() { | ||
137 | let (analysis, file_id) = single_file( | ||
138 | r##" | ||
139 | fn fixture(ra_fixture: &str) {} | ||
140 | |||
141 | fn main() { | ||
142 | fixture(r#" | ||
143 | trait Foo { | ||
144 | fn foo() { | ||
145 | println!("2 + 2 = {}", 4); | ||
146 | } | ||
147 | }"# | ||
148 | ); | ||
149 | }"## | ||
150 | .trim(), | ||
151 | ); | ||
152 | |||
153 | let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlight_injection.html"); | ||
154 | let actual_html = &analysis.highlight_as_html(file_id, false).unwrap(); | ||
155 | let expected_html = &read_text(&dst_file); | ||
156 | fs::write(dst_file, &actual_html).unwrap(); | ||
157 | assert_eq_text!(expected_html, actual_html); | ||
158 | } | ||