diff options
Diffstat (limited to 'crates/ra_ide_api/src')
-rw-r--r-- | crates/ra_ide_api/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide_api/src/snapshots/highlighting.html | 24 | ||||
-rw-r--r-- | crates/ra_ide_api/src/snapshots/rainbow_highlighting.html | 27 | ||||
-rw-r--r-- | crates/ra_ide_api/src/snapshots/tests__highlighting.snap | 192 | ||||
-rw-r--r-- | crates/ra_ide_api/src/snapshots/tests__rainbow_highlighting.snap | 128 | ||||
-rw-r--r-- | crates/ra_ide_api/src/syntax_highlighting.rs | 185 |
6 files changed, 151 insertions, 407 deletions
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index d3456d5b2..65a3b591a 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs | |||
@@ -464,7 +464,7 @@ impl Analysis { | |||
464 | 464 | ||
465 | /// Computes syntax highlighting for the given file. | 465 | /// Computes syntax highlighting for the given file. |
466 | pub fn highlight_as_html(&self, file_id: FileId) -> Cancelable<String> { | 466 | pub fn highlight_as_html(&self, file_id: FileId) -> Cancelable<String> { |
467 | self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id)) | 467 | self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id, true)) |
468 | } | 468 | } |
469 | 469 | ||
470 | /// Computes completions at the given position. | 470 | /// Computes completions at the given position. |
diff --git a/crates/ra_ide_api/src/snapshots/highlighting.html b/crates/ra_ide_api/src/snapshots/highlighting.html index bfc0a67b1..4f4ed62a1 100644 --- a/crates/ra_ide_api/src/snapshots/highlighting.html +++ b/crates/ra_ide_api/src/snapshots/highlighting.html | |||
@@ -1,10 +1,7 @@ | |||
1 | 1 | ||
2 | <style> | 2 | <style> |
3 | pre { | 3 | body { margin: 0; } |
4 | color: #DCDCCC; | 4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } |
5 | background-color: #3F3F3F; | ||
6 | font-size: 22px; | ||
7 | } | ||
8 | 5 | ||
9 | .comment { color: #7F9F7F; } | 6 | .comment { color: #7F9F7F; } |
10 | .string { color: #CC9393; } | 7 | .string { color: #CC9393; } |
@@ -19,13 +16,11 @@ pre { | |||
19 | .keyword { color: #F0DFAF; } | 16 | .keyword { color: #F0DFAF; } |
20 | .keyword\.unsafe { color: #F0DFAF; font-weight: bold; } | 17 | .keyword\.unsafe { color: #F0DFAF; font-weight: bold; } |
21 | .keyword\.control { color: #DC8CC3; } | 18 | .keyword\.control { color: #DC8CC3; } |
22 | |||
23 | </style> | 19 | </style> |
24 | <pre><code> | 20 | <pre><code><span class="attribute">#</span><span class="attribute">[</span><span class="attribute">derive</span><span class="attribute">(</span><span class="attribute">Clone</span><span class="attribute">,</span><span class="attribute"> </span><span class="attribute">Debug</span><span class="attribute">)</span><span class="attribute">]</span> |
25 | <span class="attribute">#</span><span class="attribute">[</span><span class="attribute">derive</span><span class="attribute">(</span><span class="attribute">Clone</span><span class="attribute">,</span><span class="attribute"> </span><span class="attribute">Debug</span><span class="attribute">)</span><span class="attribute">]</span> | ||
26 | <span class="keyword">struct</span> <span class="function">Foo</span> { | 21 | <span class="keyword">struct</span> <span class="function">Foo</span> { |
27 | <span class="keyword">pub</span> <span class="function">x</span>: <span class="text">i32</span>, | 22 | <span class="keyword">pub</span> <span class="variable" data-binding-hash="12067179602561426350" style="color: hsl(78,84%,47%);">x</span>: <span class="text">i32</span>, |
28 | <span class="keyword">pub</span> <span class="function">y</span>: <span class="text">i32</span>, | 23 | <span class="keyword">pub</span> <span class="variable" data-binding-hash="15562018766631452210" style="color: hsl(318,95%,78%);">y</span>: <span class="text">i32</span>, |
29 | } | 24 | } |
30 | 25 | ||
31 | <span class="keyword">fn</span> <span class="function">foo</span><<span class="type function">T</span>>() -> <span class="type">T</span> { | 26 | <span class="keyword">fn</span> <span class="function">foo</span><<span class="type function">T</span>>() -> <span class="type">T</span> { |
@@ -36,10 +31,9 @@ pre { | |||
36 | <span class="keyword">fn</span> <span class="function">main</span>() { | 31 | <span class="keyword">fn</span> <span class="function">main</span>() { |
37 | <span class="macro">println</span><span class="macro">!</span>(<span class="string">"Hello, {}!"</span>, <span class="literal">92</span>); | 32 | <span class="macro">println</span><span class="macro">!</span>(<span class="string">"Hello, {}!"</span>, <span class="literal">92</span>); |
38 | 33 | ||
39 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="function">vec</span> = <span class="text">Vec</span>::<span class="text">new</span>(); | 34 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable" data-binding-hash="9636295041291189729" style="color: hsl(51,57%,74%);">vec</span> = <span class="text">Vec</span>::<span class="text">new</span>(); |
40 | <span class="keyword.control">if</span> <span class="keyword">true</span> { | 35 | <span class="keyword.control">if</span> <span class="keyword">true</span> { |
41 | <span class="text">vec</span>.<span class="text">push</span>(<span class="type">Foo</span> { <span class="field">x</span>: <span class="literal">0</span>, <span class="field">y</span>: <span class="literal">1</span> }); | 36 | <span class="variable" data-binding-hash="8496027264380925433" style="color: hsl(18,48%,55%);">vec</span>.<span class="text">push</span>(<span class="type">Foo</span> { <span class="field" data-binding-hash="17368948500121423555" style="color: hsl(49,97%,70%);">x</span>: <span class="literal">0</span>, <span class="field" data-binding-hash="13663097548341495469" style="color: hsl(26,51%,46%);">y</span>: <span class="literal">1</span> }); |
42 | } | 37 | } |
43 | <span class="keyword.unsafe">unsafe</span> { <span class="text">vec</span>.<span class="text">set_len</span>(<span class="literal">0</span>); } | 38 | <span class="keyword.unsafe">unsafe</span> { <span class="variable" data-binding-hash="8496027264380925433" style="color: hsl(18,48%,55%);">vec</span>.<span class="text">set_len</span>(<span class="literal">0</span>); } |
44 | } | 39 | }</code></pre> \ No newline at end of file |
45 | </code></pre> \ No newline at end of file | ||
diff --git a/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html b/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html new file mode 100644 index 000000000..729d129d0 --- /dev/null +++ b/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html | |||
@@ -0,0 +1,27 @@ | |||
1 | |||
2 | <style> | ||
3 | body { margin: 0; } | ||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | ||
5 | |||
6 | .comment { color: #7F9F7F; } | ||
7 | .string { color: #CC9393; } | ||
8 | .function { color: #93E0E3; } | ||
9 | .parameter { color: #94BFF3; } | ||
10 | .builtin { color: #DD6718; } | ||
11 | .text { color: #DCDCCC; } | ||
12 | .attribute { color: #BFEBBF; } | ||
13 | .literal { color: #DFAF8F; } | ||
14 | .macro { color: #DFAF8F; } | ||
15 | |||
16 | .keyword { color: #F0DFAF; } | ||
17 | .keyword\.unsafe { color: #F0DFAF; font-weight: bold; } | ||
18 | .keyword\.control { color: #DC8CC3; } | ||
19 | </style> | ||
20 | <pre><code><span class="keyword">fn</span> <span class="function">main</span>() { | ||
21 | <span class="keyword">let</span> <span class="variable" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span> = <span class="string">"hello"</span>; | ||
22 | <span class="keyword">let</span> <span class="variable" data-binding-hash="5695551762718493399" style="color: hsl(272,48%,45%);">x</span> = <span class="variable" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span>.<span class="text">to_string</span>(); | ||
23 | <span class="keyword">let</span> <span class="variable" data-binding-hash="5435401749617022797" style="color: hsl(353,77%,74%);">y</span> = <span class="variable" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span>.<span class="text">to_string</span>(); | ||
24 | |||
25 | <span class="keyword">let</span> <span class="variable" data-binding-hash="1903207544374197704" style="color: hsl(58,61%,61%);">x</span> = <span class="string">"other color please!"</span>; | ||
26 | <span class="keyword">let</span> <span class="variable" data-binding-hash="14878783531007968800" style="color: hsl(265,73%,83%);">y</span> = <span class="variable" data-binding-hash="1903207544374197704" style="color: hsl(58,61%,61%);">x</span>.<span class="text">to_string</span>(); | ||
27 | }</code></pre> \ No newline at end of file | ||
diff --git a/crates/ra_ide_api/src/snapshots/tests__highlighting.snap b/crates/ra_ide_api/src/snapshots/tests__highlighting.snap deleted file mode 100644 index e50003b3c..000000000 --- a/crates/ra_ide_api/src/snapshots/tests__highlighting.snap +++ /dev/null | |||
@@ -1,192 +0,0 @@ | |||
1 | --- | ||
2 | created: "2019-05-25T11:24:53.486036Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_ide_api/src/syntax_highlighting.rs | ||
5 | expression: result | ||
6 | --- | ||
7 | Ok( | ||
8 | [ | ||
9 | HighlightedRange { | ||
10 | range: [1; 24), | ||
11 | tag: "attribute", | ||
12 | id: None, | ||
13 | }, | ||
14 | HighlightedRange { | ||
15 | range: [25; 31), | ||
16 | tag: "keyword", | ||
17 | id: None, | ||
18 | }, | ||
19 | HighlightedRange { | ||
20 | range: [32; 35), | ||
21 | tag: "variable", | ||
22 | id: Some( | ||
23 | 8465336196764640996, | ||
24 | ), | ||
25 | }, | ||
26 | HighlightedRange { | ||
27 | range: [42; 45), | ||
28 | tag: "keyword", | ||
29 | id: None, | ||
30 | }, | ||
31 | HighlightedRange { | ||
32 | range: [46; 47), | ||
33 | tag: "variable", | ||
34 | id: Some( | ||
35 | 176272420896316891, | ||
36 | ), | ||
37 | }, | ||
38 | HighlightedRange { | ||
39 | range: [49; 52), | ||
40 | tag: "text", | ||
41 | id: None, | ||
42 | }, | ||
43 | HighlightedRange { | ||
44 | range: [58; 61), | ||
45 | tag: "keyword", | ||
46 | id: None, | ||
47 | }, | ||
48 | HighlightedRange { | ||
49 | range: [62; 63), | ||
50 | tag: "variable", | ||
51 | id: Some( | ||
52 | 15061637676198917049, | ||
53 | ), | ||
54 | }, | ||
55 | HighlightedRange { | ||
56 | range: [65; 68), | ||
57 | tag: "text", | ||
58 | id: None, | ||
59 | }, | ||
60 | HighlightedRange { | ||
61 | range: [73; 75), | ||
62 | tag: "keyword", | ||
63 | id: None, | ||
64 | }, | ||
65 | HighlightedRange { | ||
66 | range: [76; 79), | ||
67 | tag: "variable", | ||
68 | id: Some( | ||
69 | 14077410872302487760, | ||
70 | ), | ||
71 | }, | ||
72 | HighlightedRange { | ||
73 | range: [80; 81), | ||
74 | tag: "type", | ||
75 | id: None, | ||
76 | }, | ||
77 | HighlightedRange { | ||
78 | range: [80; 81), | ||
79 | tag: "variable", | ||
80 | id: Some( | ||
81 | 8379786015941272633, | ||
82 | ), | ||
83 | }, | ||
84 | HighlightedRange { | ||
85 | range: [88; 89), | ||
86 | tag: "type", | ||
87 | id: None, | ||
88 | }, | ||
89 | HighlightedRange { | ||
90 | range: [96; 110), | ||
91 | tag: "macro", | ||
92 | id: None, | ||
93 | }, | ||
94 | HighlightedRange { | ||
95 | range: [117; 127), | ||
96 | tag: "comment", | ||
97 | id: None, | ||
98 | }, | ||
99 | HighlightedRange { | ||
100 | range: [128; 130), | ||
101 | tag: "keyword", | ||
102 | id: None, | ||
103 | }, | ||
104 | HighlightedRange { | ||
105 | range: [131; 135), | ||
106 | tag: "variable", | ||
107 | id: Some( | ||
108 | 5766414492220109266, | ||
109 | ), | ||
110 | }, | ||
111 | HighlightedRange { | ||
112 | range: [145; 153), | ||
113 | tag: "macro", | ||
114 | id: None, | ||
115 | }, | ||
116 | HighlightedRange { | ||
117 | range: [154; 166), | ||
118 | tag: "string", | ||
119 | id: None, | ||
120 | }, | ||
121 | HighlightedRange { | ||
122 | range: [168; 170), | ||
123 | tag: "literal", | ||
124 | id: None, | ||
125 | }, | ||
126 | HighlightedRange { | ||
127 | range: [178; 181), | ||
128 | tag: "keyword", | ||
129 | id: None, | ||
130 | }, | ||
131 | HighlightedRange { | ||
132 | range: [182; 185), | ||
133 | tag: "keyword", | ||
134 | id: None, | ||
135 | }, | ||
136 | HighlightedRange { | ||
137 | range: [186; 189), | ||
138 | tag: "macro", | ||
139 | id: None, | ||
140 | }, | ||
141 | HighlightedRange { | ||
142 | range: [197; 200), | ||
143 | tag: "macro", | ||
144 | id: None, | ||
145 | }, | ||
146 | HighlightedRange { | ||
147 | range: [192; 195), | ||
148 | tag: "text", | ||
149 | id: None, | ||
150 | }, | ||
151 | HighlightedRange { | ||
152 | range: [208; 211), | ||
153 | tag: "macro", | ||
154 | id: None, | ||
155 | }, | ||
156 | HighlightedRange { | ||
157 | range: [212; 216), | ||
158 | tag: "macro", | ||
159 | id: None, | ||
160 | }, | ||
161 | HighlightedRange { | ||
162 | range: [226; 227), | ||
163 | tag: "literal", | ||
164 | id: None, | ||
165 | }, | ||
166 | HighlightedRange { | ||
167 | range: [232; 233), | ||
168 | tag: "literal", | ||
169 | id: None, | ||
170 | }, | ||
171 | HighlightedRange { | ||
172 | range: [242; 248), | ||
173 | tag: "keyword.unsafe", | ||
174 | id: None, | ||
175 | }, | ||
176 | HighlightedRange { | ||
177 | range: [251; 254), | ||
178 | tag: "text", | ||
179 | id: None, | ||
180 | }, | ||
181 | HighlightedRange { | ||
182 | range: [255; 262), | ||
183 | tag: "text", | ||
184 | id: None, | ||
185 | }, | ||
186 | HighlightedRange { | ||
187 | range: [263; 264), | ||
188 | tag: "literal", | ||
189 | id: None, | ||
190 | }, | ||
191 | ], | ||
192 | ) | ||
diff --git a/crates/ra_ide_api/src/snapshots/tests__rainbow_highlighting.snap b/crates/ra_ide_api/src/snapshots/tests__rainbow_highlighting.snap deleted file mode 100644 index 84cd521a2..000000000 --- a/crates/ra_ide_api/src/snapshots/tests__rainbow_highlighting.snap +++ /dev/null | |||
@@ -1,128 +0,0 @@ | |||
1 | --- | ||
2 | created: "2019-05-25T11:21:56.117898Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_ide_api/src/syntax_highlighting.rs | ||
5 | expression: result | ||
6 | --- | ||
7 | Ok( | ||
8 | [ | ||
9 | HighlightedRange { | ||
10 | range: [1; 3), | ||
11 | tag: "keyword", | ||
12 | id: None, | ||
13 | }, | ||
14 | HighlightedRange { | ||
15 | range: [4; 8), | ||
16 | tag: "variable", | ||
17 | id: Some( | ||
18 | 5766414492220109266, | ||
19 | ), | ||
20 | }, | ||
21 | HighlightedRange { | ||
22 | range: [17; 20), | ||
23 | tag: "keyword", | ||
24 | id: None, | ||
25 | }, | ||
26 | HighlightedRange { | ||
27 | range: [21; 26), | ||
28 | tag: "variable", | ||
29 | id: Some( | ||
30 | 15975256018338854530, | ||
31 | ), | ||
32 | }, | ||
33 | HighlightedRange { | ||
34 | range: [29; 36), | ||
35 | tag: "string", | ||
36 | id: None, | ||
37 | }, | ||
38 | HighlightedRange { | ||
39 | range: [42; 45), | ||
40 | tag: "keyword", | ||
41 | id: None, | ||
42 | }, | ||
43 | HighlightedRange { | ||
44 | range: [46; 47), | ||
45 | tag: "variable", | ||
46 | id: Some( | ||
47 | 176272420896316891, | ||
48 | ), | ||
49 | }, | ||
50 | HighlightedRange { | ||
51 | range: [50; 55), | ||
52 | tag: "variable", | ||
53 | id: Some( | ||
54 | 15975256018338854530, | ||
55 | ), | ||
56 | }, | ||
57 | HighlightedRange { | ||
58 | range: [56; 65), | ||
59 | tag: "text", | ||
60 | id: None, | ||
61 | }, | ||
62 | HighlightedRange { | ||
63 | range: [73; 76), | ||
64 | tag: "keyword", | ||
65 | id: None, | ||
66 | }, | ||
67 | HighlightedRange { | ||
68 | range: [77; 78), | ||
69 | tag: "variable", | ||
70 | id: Some( | ||
71 | 15061637676198917049, | ||
72 | ), | ||
73 | }, | ||
74 | HighlightedRange { | ||
75 | range: [81; 86), | ||
76 | tag: "variable", | ||
77 | id: Some( | ||
78 | 15975256018338854530, | ||
79 | ), | ||
80 | }, | ||
81 | HighlightedRange { | ||
82 | range: [87; 96), | ||
83 | tag: "text", | ||
84 | id: None, | ||
85 | }, | ||
86 | HighlightedRange { | ||
87 | range: [105; 108), | ||
88 | tag: "keyword", | ||
89 | id: None, | ||
90 | }, | ||
91 | HighlightedRange { | ||
92 | range: [109; 110), | ||
93 | tag: "variable", | ||
94 | id: Some( | ||
95 | 1714508680417729339, | ||
96 | ), | ||
97 | }, | ||
98 | HighlightedRange { | ||
99 | range: [113; 134), | ||
100 | tag: "string", | ||
101 | id: None, | ||
102 | }, | ||
103 | HighlightedRange { | ||
104 | range: [140; 143), | ||
105 | tag: "keyword", | ||
106 | id: None, | ||
107 | }, | ||
108 | HighlightedRange { | ||
109 | range: [144; 145), | ||
110 | tag: "variable", | ||
111 | id: Some( | ||
112 | 15953336624848413466, | ||
113 | ), | ||
114 | }, | ||
115 | HighlightedRange { | ||
116 | range: [148; 149), | ||
117 | tag: "variable", | ||
118 | id: Some( | ||
119 | 1714508680417729339, | ||
120 | ), | ||
121 | }, | ||
122 | HighlightedRange { | ||
123 | range: [150; 159), | ||
124 | tag: "text", | ||
125 | id: None, | ||
126 | }, | ||
127 | ], | ||
128 | ) | ||
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index 407fcda4a..8981c85e6 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs | |||
@@ -10,7 +10,7 @@ use crate::{FileId, db::RootDatabase}; | |||
10 | pub struct HighlightedRange { | 10 | pub struct HighlightedRange { |
11 | pub range: TextRange, | 11 | pub range: TextRange, |
12 | pub tag: &'static str, | 12 | pub tag: &'static str, |
13 | pub id: Option<u64>, | 13 | pub binding_hash: Option<u64>, |
14 | } | 14 | } |
15 | 15 | ||
16 | fn is_control_keyword(kind: SyntaxKind) -> bool { | 16 | fn is_control_keyword(kind: SyntaxKind) -> bool { |
@@ -30,15 +30,18 @@ fn is_control_keyword(kind: SyntaxKind) -> bool { | |||
30 | 30 | ||
31 | pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> { | 31 | pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> { |
32 | let _p = profile("highlight"); | 32 | let _p = profile("highlight"); |
33 | |||
34 | let source_file = db.parse(file_id); | 33 | let source_file = db.parse(file_id); |
35 | 34 | ||
36 | fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 { | 35 | fn calc_binding_hash(file_id: FileId, text: &SmolStr, shadow_count: u32) -> u64 { |
37 | use std::{collections::hash_map::DefaultHasher, hash::Hasher}; | 36 | fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 { |
37 | use std::{collections::hash_map::DefaultHasher, hash::Hasher}; | ||
38 | |||
39 | let mut hasher = DefaultHasher::new(); | ||
40 | x.hash(&mut hasher); | ||
41 | hasher.finish() | ||
42 | } | ||
38 | 43 | ||
39 | let mut hasher = DefaultHasher::new(); | 44 | hash((file_id, text, shadow_count)) |
40 | x.hash(&mut hasher); | ||
41 | hasher.finish() | ||
42 | } | 45 | } |
43 | 46 | ||
44 | // Visited nodes to handle highlighting priorities | 47 | // Visited nodes to handle highlighting priorities |
@@ -50,66 +53,92 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa | |||
50 | if highlighted.contains(&node) { | 53 | if highlighted.contains(&node) { |
51 | continue; | 54 | continue; |
52 | } | 55 | } |
53 | let (tag, id) = match node.kind() { | 56 | let mut binding_hash = None; |
54 | COMMENT => ("comment", None), | 57 | let tag = match node.kind() { |
55 | STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => ("string", None), | 58 | COMMENT => "comment", |
56 | ATTR => ("attribute", None), | 59 | STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string", |
60 | ATTR => "attribute", | ||
57 | NAME_REF => { | 61 | NAME_REF => { |
58 | if let Some(name_ref) = node.as_ast_node::<ast::NameRef>() { | 62 | if let Some(name_ref) = node.as_node().and_then(ast::NameRef::cast) { |
59 | use crate::name_ref_kind::{classify_name_ref, NameRefKind::*}; | 63 | use crate::name_ref_kind::{classify_name_ref, NameRefKind::*}; |
60 | use hir::{ModuleDef, ImplItem}; | 64 | use hir::{ModuleDef, ImplItem}; |
61 | 65 | ||
62 | // FIXME: try to reuse the SourceAnalyzers | 66 | // FIXME: try to reuse the SourceAnalyzers |
63 | let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); | 67 | let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); |
64 | match classify_name_ref(db, &analyzer, name_ref) { | 68 | match classify_name_ref(db, &analyzer, name_ref) { |
65 | Some(Method(_)) => ("function", None), | 69 | Some(Method(_)) => "function", |
66 | Some(Macro(_)) => ("macro", None), | 70 | Some(Macro(_)) => "macro", |
67 | Some(FieldAccess(_)) => ("field", None), | 71 | Some(FieldAccess(field)) => { |
68 | Some(AssocItem(ImplItem::Method(_))) => ("function", None), | 72 | let (hir_file_id, src) = field.source(db); |
69 | Some(AssocItem(ImplItem::Const(_))) => ("constant", None), | 73 | if let hir::FieldSource::Named(name) = src { |
70 | Some(AssocItem(ImplItem::TypeAlias(_))) => ("type", None), | 74 | let text = name.syntax().text().to_smol_string(); |
71 | Some(Def(ModuleDef::Module(_))) => ("module", None), | 75 | let shadow_count = 0; // potentially even from different file |
72 | Some(Def(ModuleDef::Function(_))) => ("function", None), | 76 | binding_hash = Some(calc_binding_hash(hir_file_id.original_file(db), &text, shadow_count)); |
73 | Some(Def(ModuleDef::Struct(_))) => ("type", None), | 77 | } |
74 | Some(Def(ModuleDef::Union(_))) => ("type", None), | 78 | |
75 | Some(Def(ModuleDef::Enum(_))) => ("type", None), | 79 | "field" |
76 | Some(Def(ModuleDef::EnumVariant(_))) => ("constant", None), | 80 | }, |
77 | Some(Def(ModuleDef::Const(_))) => ("constant", None), | 81 | Some(AssocItem(ImplItem::Method(_))) => "function", |
78 | Some(Def(ModuleDef::Static(_))) => ("constant", None), | 82 | Some(AssocItem(ImplItem::Const(_))) => "constant", |
79 | Some(Def(ModuleDef::Trait(_))) => ("type", None), | 83 | Some(AssocItem(ImplItem::TypeAlias(_))) => "type", |
80 | Some(Def(ModuleDef::TypeAlias(_))) => ("type", None), | 84 | Some(Def(ModuleDef::Module(_))) => "module", |
81 | Some(SelfType(_)) => ("type", None), | 85 | Some(Def(ModuleDef::Function(_))) => "function", |
82 | Some(Pat(ptr)) => ("variable", Some(hash({ | 86 | Some(Def(ModuleDef::Struct(_))) => "type", |
83 | let text = ptr.syntax_node_ptr().to_node(&source_file.syntax()).text().to_smol_string(); | 87 | Some(Def(ModuleDef::Union(_))) => "type", |
84 | let shadow_count = bindings_shadow_count.entry(text.clone()).or_default(); | 88 | Some(Def(ModuleDef::Enum(_))) => "type", |
85 | (text, shadow_count) | 89 | Some(Def(ModuleDef::EnumVariant(_))) => "constant", |
86 | }))), | 90 | Some(Def(ModuleDef::Const(_))) => "constant", |
87 | Some(SelfParam(_)) => ("type", None), | 91 | Some(Def(ModuleDef::Static(_))) => "constant", |
88 | Some(GenericParam(_)) => ("type", None), | 92 | Some(Def(ModuleDef::Trait(_))) => "type", |
89 | None => ("text", None), | 93 | Some(Def(ModuleDef::TypeAlias(_))) => "type", |
94 | Some(SelfType(_)) => "type", | ||
95 | Some(Pat(ptr)) => { | ||
96 | binding_hash = Some({ | ||
97 | let text = ptr.syntax_node_ptr().to_node(&source_file.syntax()).text().to_smol_string(); | ||
98 | let shadow_count = bindings_shadow_count.entry(text.clone()).or_default(); | ||
99 | calc_binding_hash(file_id, &text, *shadow_count) | ||
100 | }); | ||
101 | |||
102 | "variable" | ||
103 | }, | ||
104 | Some(SelfParam(_)) => "type", | ||
105 | Some(GenericParam(_)) => "type", | ||
106 | None => "text", | ||
90 | } | 107 | } |
91 | } else { | 108 | } else { |
92 | ("text", None) | 109 | "text" |
93 | } | 110 | } |
94 | } | 111 | } |
95 | NAME => { | 112 | NAME => { |
96 | if let Some(name) = node.as_ast_node::<ast::Name>() { | 113 | if let Some(name) = node.as_node().and_then(ast::Name::cast) { |
97 | ("variable", Some(hash({ | 114 | if name.syntax().ancestors().any(|x| ast::BindPat::cast(x).is_some()) { |
98 | let text = name.syntax().text().to_smol_string(); | 115 | binding_hash = Some({ |
99 | let shadow_count = bindings_shadow_count.entry(text.clone()).or_insert(1); | 116 | let text = name.syntax().text().to_smol_string(); |
100 | *shadow_count += 1; | 117 | let shadow_count = bindings_shadow_count.entry(text.clone()).or_insert(0); |
101 | (text, shadow_count) | 118 | *shadow_count += 1; |
102 | }))) | 119 | calc_binding_hash(file_id, &text, *shadow_count) |
120 | }); | ||
121 | "variable" | ||
122 | } else if name.syntax().ancestors().any(|x| ast::NamedFieldDef::cast(x).is_some()) { | ||
123 | binding_hash = Some({ | ||
124 | let text = name.syntax().text().to_smol_string(); | ||
125 | let shadow_count = 0; | ||
126 | calc_binding_hash(file_id, &text, shadow_count) | ||
127 | }); | ||
128 | "variable" | ||
129 | } else { | ||
130 | "function" | ||
131 | } | ||
103 | } else { | 132 | } else { |
104 | ("text", None) | 133 | "text" |
105 | } | 134 | } |
106 | } | 135 | } |
107 | TYPE_ALIAS_DEF | TYPE_ARG | TYPE_PARAM => ("type", None), | 136 | TYPE_ALIAS_DEF | TYPE_ARG | TYPE_PARAM => "type", |
108 | INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => ("literal", None), | 137 | INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", |
109 | LIFETIME => ("parameter", None), | 138 | LIFETIME => "parameter", |
110 | T![unsafe] => ("keyword.unsafe", None), | 139 | T![unsafe] => "keyword.unsafe", |
111 | k if is_control_keyword(k) => ("keyword.control", None), | 140 | k if is_control_keyword(k) => "keyword.control", |
112 | k if k.is_keyword() => ("keyword", None), | 141 | k if k.is_keyword() => "keyword", |
113 | _ => { | 142 | _ => { |
114 | // let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); | 143 | // let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); |
115 | if let Some(macro_call) = node.as_node().and_then(ast::MacroCall::cast) { | 144 | if let Some(macro_call) = node.as_node().and_then(ast::MacroCall::cast) { |
@@ -128,7 +157,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa | |||
128 | res.push(HighlightedRange { | 157 | res.push(HighlightedRange { |
129 | range: TextRange::from_to(range_start, range_end), | 158 | range: TextRange::from_to(range_start, range_end), |
130 | tag: "macro", | 159 | tag: "macro", |
131 | id: None, | 160 | binding_hash: None, |
132 | }) | 161 | }) |
133 | } | 162 | } |
134 | } | 163 | } |
@@ -137,14 +166,24 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa | |||
137 | continue; | 166 | continue; |
138 | } | 167 | } |
139 | }; | 168 | }; |
140 | res.push(HighlightedRange { range: node.range(), tag, id }) | 169 | res.push(HighlightedRange { range: node.range(), tag, binding_hash }) |
141 | } | 170 | } |
142 | res | 171 | res |
143 | } | 172 | } |
144 | 173 | ||
145 | pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId) -> String { | 174 | pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String { |
146 | let source_file = db.parse(file_id); | 175 | let source_file = db.parse(file_id); |
147 | 176 | ||
177 | fn rainbowify(seed: u64) -> String { | ||
178 | use rand::prelude::*; | ||
179 | let mut rng = SmallRng::seed_from_u64(seed); | ||
180 | format!("hsl({h},{s}%,{l}%)", | ||
181 | h = rng.gen_range::<u16, _, _>(0, 361), | ||
182 | s = rng.gen_range::<u16, _, _>(42, 99), | ||
183 | l = rng.gen_range::<u16, _, _>(40, 91), | ||
184 | ) | ||
185 | } | ||
186 | |||
148 | let mut ranges = highlight(db, file_id); | 187 | let mut ranges = highlight(db, file_id); |
149 | ranges.sort_by_key(|it| it.range.start()); | 188 | ranges.sort_by_key(|it| it.range.start()); |
150 | // quick non-optimal heuristic to intersect token ranges and highlighted ranges | 189 | // quick non-optimal heuristic to intersect token ranges and highlighted ranges |
@@ -166,16 +205,20 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId) -> String { | |||
166 | } | 205 | } |
167 | } | 206 | } |
168 | let text = html_escape(&token.text()); | 207 | let text = html_escape(&token.text()); |
169 | let classes = could_intersect | 208 | let ranges = could_intersect |
170 | .iter() | 209 | .iter() |
171 | .filter(|it| token.range().is_subrange(&it.range)) | 210 | .filter(|it| token.range().is_subrange(&it.range)) |
172 | .map(|it| it.tag) | ||
173 | .collect::<Vec<_>>(); | 211 | .collect::<Vec<_>>(); |
174 | if classes.is_empty() { | 212 | if ranges.is_empty() { |
175 | buf.push_str(&text); | 213 | buf.push_str(&text); |
176 | } else { | 214 | } else { |
177 | let classes = classes.join(" "); | 215 | let classes = ranges.iter().map(|x| x.tag).collect::<Vec<_>>().join(" "); |
178 | buf.push_str(&format!("<span class=\"{}\">{}</span>", classes, text)); | 216 | let binding_hash = ranges.first().and_then(|x| x.binding_hash); |
217 | let color = match (rainbow, binding_hash) { | ||
218 | (true, Some(hash)) => format!(" data-binding-hash=\"{}\" style=\"color: {};\"", hash, rainbowify(hash)), | ||
219 | _ => "".into() | ||
220 | }; | ||
221 | buf.push_str(&format!("<span class=\"{}\"{}>{}</span>", classes, color, text)); | ||
179 | } | 222 | } |
180 | } | 223 | } |
181 | buf.push_str("</code></pre>"); | 224 | buf.push_str("</code></pre>"); |
@@ -189,11 +232,8 @@ fn html_escape(text: &str) -> String { | |||
189 | 232 | ||
190 | const STYLE: &str = " | 233 | const STYLE: &str = " |
191 | <style> | 234 | <style> |
192 | pre { | 235 | body { margin: 0; } |
193 | color: #DCDCCC; | 236 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } |
194 | background-color: #3F3F3F; | ||
195 | font-size: 22px; | ||
196 | } | ||
197 | 237 | ||
198 | .comment { color: #7F9F7F; } | 238 | .comment { color: #7F9F7F; } |
199 | .string { color: #CC9393; } | 239 | .string { color: #CC9393; } |
@@ -208,7 +248,6 @@ pre { | |||
208 | .keyword { color: #F0DFAF; } | 248 | .keyword { color: #F0DFAF; } |
209 | .keyword\\.unsafe { color: #F0DFAF; font-weight: bold; } | 249 | .keyword\\.unsafe { color: #F0DFAF; font-weight: bold; } |
210 | .keyword\\.control { color: #DC8CC3; } | 250 | .keyword\\.control { color: #DC8CC3; } |
211 | |||
212 | </style> | 251 | </style> |
213 | "; | 252 | "; |
214 | 253 | ||
@@ -241,12 +280,12 @@ fn main() { | |||
241 | } | 280 | } |
242 | unsafe { vec.set_len(0); } | 281 | unsafe { vec.set_len(0); } |
243 | } | 282 | } |
244 | "#, | 283 | "#.trim(), |
245 | ); | 284 | ); |
246 | let dst_file = project_dir().join("crates/ra_ide_api/src/snapshots/highlighting.html"); | 285 | let dst_file = project_dir().join("crates/ra_ide_api/src/snapshots/highlighting.html"); |
247 | let actual_html = &analysis.highlight_as_html(file_id).unwrap(); | 286 | let actual_html = &analysis.highlight_as_html(file_id).unwrap(); |
248 | let expected_html = &read_text(&dst_file); | 287 | let expected_html = &read_text(&dst_file); |
249 | // std::fs::write(dst_file, &actual_html).unwrap(); | 288 | std::fs::write(dst_file, &actual_html).unwrap(); |
250 | assert_eq_text!(expected_html, actual_html); | 289 | assert_eq_text!(expected_html, actual_html); |
251 | } | 290 | } |
252 | 291 | ||
@@ -261,9 +300,13 @@ fn main() { | |||
261 | 300 | ||
262 | let x = "other color please!"; | 301 | let x = "other color please!"; |
263 | let y = x.to_string(); | 302 | let y = x.to_string(); |
264 | }"#, | 303 | } |
304 | "#.trim(), | ||
265 | ); | 305 | ); |
266 | let result = analysis.highlight(file_id); | 306 | let dst_file = project_dir().join("crates/ra_ide_api/src/snapshots/rainbow_highlighting.html"); |
267 | assert_debug_snapshot_matches!("rainbow_highlighting", result); | 307 | let actual_html = &analysis.highlight_as_html(file_id).unwrap(); |
308 | let expected_html = &read_text(&dst_file); | ||
309 | std::fs::write(dst_file, &actual_html).unwrap(); | ||
310 | assert_eq_text!(expected_html, actual_html); | ||
268 | } | 311 | } |
269 | } | 312 | } |