aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_ide_api/src/snapshots/tests__highlighting.snap192
-rw-r--r--crates/ra_ide_api/src/snapshots/tests__sematic_highlighting.snap87
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs101
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs6
-rw-r--r--crates/ra_lsp_server/src/req.rs1
-rw-r--r--crates/ra_syntax/src/syntax_node.rs4
6 files changed, 355 insertions, 36 deletions
diff --git a/crates/ra_ide_api/src/snapshots/tests__highlighting.snap b/crates/ra_ide_api/src/snapshots/tests__highlighting.snap
new file mode 100644
index 000000000..208681f10
--- /dev/null
+++ b/crates/ra_ide_api/src/snapshots/tests__highlighting.snap
@@ -0,0 +1,192 @@
1---
2created: "2019-05-25T10:53:54.439877Z"
3creator: [email protected]
4source: crates/ra_ide_api/src/syntax_highlighting.rs
5expression: result
6---
7Ok(
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 461893210254723387,
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 8312289520117458465,
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 4497542318236667727,
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 4506850079084802999,
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 16968185728268100018,
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 14467718814232352107,
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__sematic_highlighting.snap b/crates/ra_ide_api/src/snapshots/tests__sematic_highlighting.snap
new file mode 100644
index 000000000..3b3fe32e9
--- /dev/null
+++ b/crates/ra_ide_api/src/snapshots/tests__sematic_highlighting.snap
@@ -0,0 +1,87 @@
1---
2created: "2019-05-25T10:25:13.898113Z"
3creator: [email protected]
4source: crates/ra_ide_api/src/syntax_highlighting.rs
5expression: result
6---
7Ok(
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 17119830160611610240,
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 2744494144922727377,
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 10375904121795371996,
48 ),
49 },
50 HighlightedRange {
51 range: [50; 55),
52 tag: "variable",
53 id: Some(
54 2744494144922727377,
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 8228548264153724449,
72 ),
73 },
74 HighlightedRange {
75 range: [81; 86),
76 tag: "variable",
77 id: Some(
78 2744494144922727377,
79 ),
80 },
81 HighlightedRange {
82 range: [87; 96),
83 tag: "text",
84 id: None,
85 },
86 ],
87)
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs
index 87e053364..da000c0c3 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -10,6 +10,7 @@ use crate::{FileId, db::RootDatabase};
10pub struct HighlightedRange { 10pub 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} 14}
14 15
15fn is_control_keyword(kind: SyntaxKind) -> bool { 16fn is_control_keyword(kind: SyntaxKind) -> bool {
@@ -32,6 +33,14 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
32 33
33 let source_file = db.parse(file_id); 34 let source_file = db.parse(file_id);
34 35
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 }
43
35 // Visited nodes to handle highlighting priorities 44 // Visited nodes to handle highlighting priorities
36 let mut highlighted: FxHashSet<SyntaxElement> = FxHashSet::default(); 45 let mut highlighted: FxHashSet<SyntaxElement> = FxHashSet::default();
37 let mut res = Vec::new(); 46 let mut res = Vec::new();
@@ -39,52 +48,59 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
39 if highlighted.contains(&node) { 48 if highlighted.contains(&node) {
40 continue; 49 continue;
41 } 50 }
42 let tag = match node.kind() { 51 let (tag, id) = match node.kind() {
43 COMMENT => "comment", 52 COMMENT => ("comment", None),
44 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string", 53 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => ("string", None),
45 ATTR => "attribute", 54 ATTR => ("attribute", None),
46 NAME_REF => { 55 NAME_REF => {
47 if let Some(name_ref) = node.as_node().and_then(|n| ast::NameRef::cast(n)) { 56 if let Some(name_ref) = node.as_ast_node::<ast::NameRef>() {
48 use crate::name_ref_kind::{classify_name_ref, NameRefKind::*}; 57 use crate::name_ref_kind::{classify_name_ref, NameRefKind::*};
49 use hir::{ModuleDef, ImplItem}; 58 use hir::{ModuleDef, ImplItem};
50 59
51 // FIXME: try to reuse the SourceAnalyzers 60 // FIXME: try to reuse the SourceAnalyzers
52 let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); 61 let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None);
53 match classify_name_ref(db, &analyzer, name_ref) { 62 match classify_name_ref(db, &analyzer, name_ref) {
54 Some(Method(_)) => "function", 63 Some(Method(_)) => ("function", None),
55 Some(Macro(_)) => "macro", 64 Some(Macro(_)) => ("macro", None),
56 Some(FieldAccess(_)) => "field", 65 Some(FieldAccess(_)) => ("field", None),
57 Some(AssocItem(ImplItem::Method(_))) => "function", 66 Some(AssocItem(ImplItem::Method(_))) => ("function", None),
58 Some(AssocItem(ImplItem::Const(_))) => "constant", 67 Some(AssocItem(ImplItem::Const(_))) => ("constant", None),
59 Some(AssocItem(ImplItem::TypeAlias(_))) => "type", 68 Some(AssocItem(ImplItem::TypeAlias(_))) => ("type", None),
60 Some(Def(ModuleDef::Module(_))) => "module", 69 Some(Def(ModuleDef::Module(_))) => ("module", None),
61 Some(Def(ModuleDef::Function(_))) => "function", 70 Some(Def(ModuleDef::Function(_))) => ("function", None),
62 Some(Def(ModuleDef::Struct(_))) => "type", 71 Some(Def(ModuleDef::Struct(_))) => ("type", None),
63 Some(Def(ModuleDef::Union(_))) => "type", 72 Some(Def(ModuleDef::Union(_))) => ("type", None),
64 Some(Def(ModuleDef::Enum(_))) => "type", 73 Some(Def(ModuleDef::Enum(_))) => ("type", None),
65 Some(Def(ModuleDef::EnumVariant(_))) => "constant", 74 Some(Def(ModuleDef::EnumVariant(_))) => ("constant", None),
66 Some(Def(ModuleDef::Const(_))) => "constant", 75 Some(Def(ModuleDef::Const(_))) => ("constant", None),
67 Some(Def(ModuleDef::Static(_))) => "constant", 76 Some(Def(ModuleDef::Static(_))) => ("constant", None),
68 Some(Def(ModuleDef::Trait(_))) => "type", 77 Some(Def(ModuleDef::Trait(_))) => ("type", None),
69 Some(Def(ModuleDef::TypeAlias(_))) => "type", 78 Some(Def(ModuleDef::TypeAlias(_))) => ("type", None),
70 Some(SelfType(_)) => "type", 79 Some(SelfType(_)) => ("type", None),
71 Some(Pat(_)) => "text", 80 Some(Pat(ptr)) => ("variable", Some(hash(ptr.syntax_node_ptr().range()))),
72 Some(SelfParam(_)) => "type", 81 Some(SelfParam(_)) => ("type", None),
73 Some(GenericParam(_)) => "type", 82 Some(GenericParam(_)) => ("type", None),
74 None => "text", 83 None => ("text", None),
75 } 84 }
76 } else { 85 } else {
77 "text" 86 ("text", None)
78 } 87 }
79 } 88 }
80 NAME => "function", 89 NAME => {
81 TYPE_ALIAS_DEF | TYPE_ARG | TYPE_PARAM => "type", 90 if let Some(name) = node.as_ast_node::<ast::Name>() {
82 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", 91 ("variable", Some(hash(name.syntax().range())))
83 LIFETIME => "parameter", 92 } else {
84 T![unsafe] => "keyword.unsafe", 93 ("text", None)
85 k if is_control_keyword(k) => "keyword.control", 94 }
86 k if k.is_keyword() => "keyword", 95 }
96 TYPE_ALIAS_DEF | TYPE_ARG | TYPE_PARAM => ("type", None),
97 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => ("literal", None),
98 LIFETIME => ("parameter", None),
99 T![unsafe] => ("keyword.unsafe", None),
100 k if is_control_keyword(k) => ("keyword.control", None),
101 k if k.is_keyword() => ("keyword", None),
87 _ => { 102 _ => {
103 // let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None);
88 if let Some(macro_call) = node.as_node().and_then(ast::MacroCall::cast) { 104 if let Some(macro_call) = node.as_node().and_then(ast::MacroCall::cast) {
89 if let Some(path) = macro_call.path() { 105 if let Some(path) = macro_call.path() {
90 if let Some(segment) = path.segment() { 106 if let Some(segment) = path.segment() {
@@ -101,6 +117,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
101 res.push(HighlightedRange { 117 res.push(HighlightedRange {
102 range: TextRange::from_to(range_start, range_end), 118 range: TextRange::from_to(range_start, range_end),
103 tag: "macro", 119 tag: "macro",
120 id: None,
104 }) 121 })
105 } 122 }
106 } 123 }
@@ -109,7 +126,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
109 continue; 126 continue;
110 } 127 }
111 }; 128 };
112 res.push(HighlightedRange { range: node.range(), tag }) 129 res.push(HighlightedRange { range: node.range(), tag, id })
113 } 130 }
114 res 131 res
115} 132}
@@ -221,4 +238,18 @@ fn main() {
221 // std::fs::write(dst_file, &actual_html).unwrap(); 238 // std::fs::write(dst_file, &actual_html).unwrap();
222 assert_eq_text!(expected_html, actual_html); 239 assert_eq_text!(expected_html, actual_html);
223 } 240 }
241
242 #[test]
243 fn test_sematic_highlighting() {
244 let (analysis, file_id) = single_file(
245 r#"
246fn main() {
247 let hello = "hello";
248 let x = hello.to_string();
249 let y = hello.to_string();
250}"#,
251 );
252 let result = analysis.highlight(file_id);
253 assert_debug_snapshot_matches!("sematic_highlighting", result);
254 }
224} 255}
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index a82ae696b..5dfd64ed4 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -872,7 +872,11 @@ fn highlight(world: &ServerWorld, file_id: FileId) -> Result<Vec<Decoration>> {
872 .analysis() 872 .analysis()
873 .highlight(file_id)? 873 .highlight(file_id)?
874 .into_iter() 874 .into_iter()
875 .map(|h| Decoration { range: h.range.conv_with(&line_index), tag: h.tag }) 875 .map(|h| Decoration {
876 range: h.range.conv_with(&line_index),
877 tag: h.tag,
878 id: h.id.map(|x| x.to_string()),
879 })
876 .collect(); 880 .collect();
877 Ok(res) 881 Ok(res)
878} 882}
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs
index 6090eb7b9..cea0e6ce7 100644
--- a/crates/ra_lsp_server/src/req.rs
+++ b/crates/ra_lsp_server/src/req.rs
@@ -129,6 +129,7 @@ pub struct PublishDecorationsParams {
129pub struct Decoration { 129pub struct Decoration {
130 pub range: Range, 130 pub range: Range,
131 pub tag: &'static str, 131 pub tag: &'static str,
132 pub id: Option<String>,
132} 133}
133 134
134pub enum ParentModule {} 135pub enum ParentModule {}
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs
index 80054f529..89f92e0b7 100644
--- a/crates/ra_syntax/src/syntax_node.rs
+++ b/crates/ra_syntax/src/syntax_node.rs
@@ -523,6 +523,10 @@ impl<'a> SyntaxElement<'a> {
523 } 523 }
524 } 524 }
525 525
526 pub fn as_ast_node<T: AstNode>(&self) -> Option<&T> {
527 self.as_node().and_then(|x| <T as AstNode>::cast(x))
528 }
529
526 pub fn as_token(&self) -> Option<SyntaxToken<'a>> { 530 pub fn as_token(&self) -> Option<SyntaxToken<'a>> {
527 match self { 531 match self {
528 SyntaxElement::Node(_) => None, 532 SyntaxElement::Node(_) => None,