aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-02-26 16:08:15 +0000
committerAleksey Kladov <[email protected]>2020-02-26 16:17:15 +0000
commitf38bac48e5cc193d88aaea17bfb4234f64f1ded0 (patch)
treeedd6cef6d68d06efebbcd667074af262e099940b /crates/ra_ide/src
parent640ede4ade02e6caae57532506409370c5ca63c9 (diff)
More type safety for highlighting
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r--crates/ra_ide/src/lib.rs2
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs107
-rw-r--r--crates/ra_ide/src/syntax_highlighting/highlight_tag.rs43
3 files changed, 85 insertions, 67 deletions
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index f31d3c295..d74d32453 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -74,7 +74,7 @@ pub use crate::{
74 runnables::{Runnable, RunnableKind, TestId}, 74 runnables::{Runnable, RunnableKind, TestId},
75 source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, 75 source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
76 ssr::SsrError, 76 ssr::SsrError,
77 syntax_highlighting::{tags, HighlightedRange}, 77 syntax_highlighting::{HighlightTag, HighlightedRange},
78}; 78};
79 79
80pub use hir::Documentation; 80pub use hir::Documentation;
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 987476d2c..d422930bf 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -1,5 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3mod highlight_tag;
4
3use hir::{Name, Semantics}; 5use hir::{Name, Semantics};
4use ra_db::SourceDatabase; 6use ra_db::SourceDatabase;
5use ra_ide_db::{ 7use ra_ide_db::{
@@ -15,39 +17,12 @@ use rustc_hash::FxHashMap;
15 17
16use crate::{references::classify_name_ref, FileId}; 18use crate::{references::classify_name_ref, FileId};
17 19
18pub mod tags { 20pub use highlight_tag::HighlightTag;
19 pub const FIELD: &str = "field";
20 pub const FUNCTION: &str = "function";
21 pub const MODULE: &str = "module";
22 pub const CONSTANT: &str = "constant";
23 pub const MACRO: &str = "macro";
24
25 pub const VARIABLE: &str = "variable";
26 pub const VARIABLE_MUT: &str = "variable.mut";
27
28 pub const TYPE: &str = "type";
29 pub const TYPE_BUILTIN: &str = "type.builtin";
30 pub const TYPE_SELF: &str = "type.self";
31 pub const TYPE_PARAM: &str = "type.param";
32 pub const TYPE_LIFETIME: &str = "type.lifetime";
33
34 pub const LITERAL_BYTE: &str = "literal.byte";
35 pub const LITERAL_NUMERIC: &str = "literal.numeric";
36 pub const LITERAL_CHAR: &str = "literal.char";
37
38 pub const LITERAL_COMMENT: &str = "comment";
39 pub const LITERAL_STRING: &str = "string";
40 pub const LITERAL_ATTRIBUTE: &str = "attribute";
41
42 pub const KEYWORD: &str = "keyword";
43 pub const KEYWORD_UNSAFE: &str = "keyword.unsafe";
44 pub const KEYWORD_CONTROL: &str = "keyword.control";
45}
46 21
47#[derive(Debug)] 22#[derive(Debug)]
48pub struct HighlightedRange { 23pub struct HighlightedRange {
49 pub range: TextRange, 24 pub range: TextRange,
50 pub tag: &'static str, 25 pub tag: HighlightTag,
51 pub binding_hash: Option<u64>, 26 pub binding_hash: Option<u64>,
52} 27}
53 28
@@ -104,7 +79,7 @@ pub(crate) fn highlight(
104 if let Some(range) = highlight_macro(node) { 79 if let Some(range) = highlight_macro(node) {
105 res.push(HighlightedRange { 80 res.push(HighlightedRange {
106 range, 81 range,
107 tag: tags::MACRO, 82 tag: HighlightTag::MACRO,
108 binding_hash: None, 83 binding_hash: None,
109 }); 84 });
110 } 85 }
@@ -175,7 +150,7 @@ fn highlight_token_tree(
175 sema: &Semantics<RootDatabase>, 150 sema: &Semantics<RootDatabase>,
176 bindings_shadow_count: &mut FxHashMap<Name, u32>, 151 bindings_shadow_count: &mut FxHashMap<Name, u32>,
177 token: SyntaxToken, 152 token: SyntaxToken,
178) -> Option<(&'static str, Option<u64>)> { 153) -> Option<(HighlightTag, Option<u64>)> {
179 if token.parent().kind() != TOKEN_TREE { 154 if token.parent().kind() != TOKEN_TREE {
180 return None; 155 return None;
181 } 156 }
@@ -196,7 +171,7 @@ fn highlight_node(
196 sema: &Semantics<RootDatabase>, 171 sema: &Semantics<RootDatabase>,
197 bindings_shadow_count: &mut FxHashMap<Name, u32>, 172 bindings_shadow_count: &mut FxHashMap<Name, u32>,
198 node: SyntaxElement, 173 node: SyntaxElement,
199) -> Option<(&'static str, Option<u64>)> { 174) -> Option<(HighlightTag, Option<u64>)> {
200 let db = sema.db; 175 let db = sema.db;
201 let mut binding_hash = None; 176 let mut binding_hash = None;
202 let tag = match node.kind() { 177 let tag = match node.kind() {
@@ -204,11 +179,11 @@ fn highlight_node(
204 bindings_shadow_count.clear(); 179 bindings_shadow_count.clear();
205 return None; 180 return None;
206 } 181 }
207 COMMENT => tags::LITERAL_COMMENT, 182 COMMENT => HighlightTag::LITERAL_COMMENT,
208 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => tags::LITERAL_STRING, 183 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => HighlightTag::LITERAL_STRING,
209 ATTR => tags::LITERAL_ATTRIBUTE, 184 ATTR => HighlightTag::LITERAL_ATTRIBUTE,
210 // Special-case field init shorthand 185 // Special-case field init shorthand
211 NAME_REF if node.parent().and_then(ast::RecordField::cast).is_some() => tags::FIELD, 186 NAME_REF if node.parent().and_then(ast::RecordField::cast).is_some() => HighlightTag::FIELD,
212 NAME_REF if node.ancestors().any(|it| it.kind() == ATTR) => return None, 187 NAME_REF if node.ancestors().any(|it| it.kind() == ATTR) => return None,
213 NAME_REF => { 188 NAME_REF => {
214 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); 189 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
@@ -242,21 +217,21 @@ fn highlight_node(
242 217
243 match name_kind { 218 match name_kind {
244 Some(name_kind) => highlight_name(db, name_kind), 219 Some(name_kind) => highlight_name(db, name_kind),
245 None => name.syntax().parent().map_or(tags::FUNCTION, |x| match x.kind() { 220 None => name.syntax().parent().map_or(HighlightTag::FUNCTION, |x| match x.kind() {
246 STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => tags::TYPE, 221 STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => HighlightTag::TYPE,
247 TYPE_PARAM => tags::TYPE_PARAM, 222 TYPE_PARAM => HighlightTag::TYPE_PARAM,
248 RECORD_FIELD_DEF => tags::FIELD, 223 RECORD_FIELD_DEF => HighlightTag::FIELD,
249 _ => tags::FUNCTION, 224 _ => HighlightTag::FUNCTION,
250 }), 225 }),
251 } 226 }
252 } 227 }
253 INT_NUMBER | FLOAT_NUMBER => tags::LITERAL_NUMERIC, 228 INT_NUMBER | FLOAT_NUMBER => HighlightTag::LITERAL_NUMERIC,
254 BYTE => tags::LITERAL_BYTE, 229 BYTE => HighlightTag::LITERAL_BYTE,
255 CHAR => tags::LITERAL_CHAR, 230 CHAR => HighlightTag::LITERAL_CHAR,
256 LIFETIME => tags::TYPE_LIFETIME, 231 LIFETIME => HighlightTag::TYPE_LIFETIME,
257 T![unsafe] => tags::KEYWORD_UNSAFE, 232 T![unsafe] => HighlightTag::KEYWORD_UNSAFE,
258 k if is_control_keyword(k) => tags::KEYWORD_CONTROL, 233 k if is_control_keyword(k) => HighlightTag::KEYWORD_CONTROL,
259 k if k.is_keyword() => tags::KEYWORD, 234 k if k.is_keyword() => HighlightTag::KEYWORD,
260 235
261 _ => return None, 236 _ => return None,
262 }; 237 };
@@ -318,7 +293,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
318 if ranges.is_empty() { 293 if ranges.is_empty() {
319 buf.push_str(&text); 294 buf.push_str(&text);
320 } else { 295 } else {
321 let classes = ranges.iter().map(|x| x.tag).collect::<Vec<_>>().join(" "); 296 let classes = ranges.iter().map(|x| x.tag.to_string()).collect::<Vec<_>>().join(" ");
322 let binding_hash = ranges.first().and_then(|x| x.binding_hash); 297 let binding_hash = ranges.first().and_then(|x| x.binding_hash);
323 let color = match (rainbow, binding_hash) { 298 let color = match (rainbow, binding_hash) {
324 (true, Some(hash)) => format!( 299 (true, Some(hash)) => format!(
@@ -335,26 +310,26 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
335 buf 310 buf
336} 311}
337 312
338fn highlight_name(db: &RootDatabase, def: NameDefinition) -> &'static str { 313fn highlight_name(db: &RootDatabase, def: NameDefinition) -> HighlightTag {
339 match def { 314 match def {
340 NameDefinition::Macro(_) => tags::MACRO, 315 NameDefinition::Macro(_) => HighlightTag::MACRO,
341 NameDefinition::StructField(_) => tags::FIELD, 316 NameDefinition::StructField(_) => HighlightTag::FIELD,
342 NameDefinition::ModuleDef(hir::ModuleDef::Module(_)) => tags::MODULE, 317 NameDefinition::ModuleDef(hir::ModuleDef::Module(_)) => HighlightTag::MODULE,
343 NameDefinition::ModuleDef(hir::ModuleDef::Function(_)) => tags::FUNCTION, 318 NameDefinition::ModuleDef(hir::ModuleDef::Function(_)) => HighlightTag::FUNCTION,
344 NameDefinition::ModuleDef(hir::ModuleDef::Adt(_)) => tags::TYPE, 319 NameDefinition::ModuleDef(hir::ModuleDef::Adt(_)) => HighlightTag::TYPE,
345 NameDefinition::ModuleDef(hir::ModuleDef::EnumVariant(_)) => tags::CONSTANT, 320 NameDefinition::ModuleDef(hir::ModuleDef::EnumVariant(_)) => HighlightTag::CONSTANT,
346 NameDefinition::ModuleDef(hir::ModuleDef::Const(_)) => tags::CONSTANT, 321 NameDefinition::ModuleDef(hir::ModuleDef::Const(_)) => HighlightTag::CONSTANT,
347 NameDefinition::ModuleDef(hir::ModuleDef::Static(_)) => tags::CONSTANT, 322 NameDefinition::ModuleDef(hir::ModuleDef::Static(_)) => HighlightTag::CONSTANT,
348 NameDefinition::ModuleDef(hir::ModuleDef::Trait(_)) => tags::TYPE, 323 NameDefinition::ModuleDef(hir::ModuleDef::Trait(_)) => HighlightTag::TYPE,
349 NameDefinition::ModuleDef(hir::ModuleDef::TypeAlias(_)) => tags::TYPE, 324 NameDefinition::ModuleDef(hir::ModuleDef::TypeAlias(_)) => HighlightTag::TYPE,
350 NameDefinition::ModuleDef(hir::ModuleDef::BuiltinType(_)) => tags::TYPE_BUILTIN, 325 NameDefinition::ModuleDef(hir::ModuleDef::BuiltinType(_)) => HighlightTag::TYPE_BUILTIN,
351 NameDefinition::SelfType(_) => tags::TYPE_SELF, 326 NameDefinition::SelfType(_) => HighlightTag::TYPE_SELF,
352 NameDefinition::TypeParam(_) => tags::TYPE_PARAM, 327 NameDefinition::TypeParam(_) => HighlightTag::TYPE_PARAM,
353 NameDefinition::Local(local) => { 328 NameDefinition::Local(local) => {
354 if local.is_mut(db) || local.ty(db).is_mutable_reference() { 329 if local.is_mut(db) || local.ty(db).is_mutable_reference() {
355 tags::VARIABLE_MUT 330 HighlightTag::VARIABLE_MUT
356 } else { 331 } else {
357 tags::VARIABLE 332 HighlightTag::VARIABLE
358 } 333 }
359 } 334 }
360 } 335 }
@@ -523,6 +498,6 @@ fn bar() {
523 }) 498 })
524 .unwrap(); 499 .unwrap();
525 500
526 assert_eq!(highlights[0].tag, "field"); 501 assert_eq!(&highlights[0].tag.to_string(), "field");
527 } 502 }
528} 503}
diff --git a/crates/ra_ide/src/syntax_highlighting/highlight_tag.rs b/crates/ra_ide/src/syntax_highlighting/highlight_tag.rs
new file mode 100644
index 000000000..af1ac07b3
--- /dev/null
+++ b/crates/ra_ide/src/syntax_highlighting/highlight_tag.rs
@@ -0,0 +1,43 @@
1//! Defines token tags we use for syntax highlighting.
2//! A tag is not unlike a CSS class.
3
4use std::fmt;
5
6#[derive(Debug, PartialEq, Eq, Clone, Copy)]
7pub struct HighlightTag(&'static str);
8
9impl fmt::Display for HighlightTag {
10 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11 fmt::Display::fmt(self.0, f)
12 }
13}
14
15#[rustfmt::skip]
16impl HighlightTag {
17 pub const FIELD: HighlightTag = HighlightTag("field");
18 pub const FUNCTION: HighlightTag = HighlightTag("function");
19 pub const MODULE: HighlightTag = HighlightTag("module");
20 pub const CONSTANT: HighlightTag = HighlightTag("constant");
21 pub const MACRO: HighlightTag = HighlightTag("macro");
22
23 pub const VARIABLE: HighlightTag = HighlightTag("variable");
24 pub const VARIABLE_MUT: HighlightTag = HighlightTag("variable.mut");
25
26 pub const TYPE: HighlightTag = HighlightTag("type");
27 pub const TYPE_BUILTIN: HighlightTag = HighlightTag("type.builtin");
28 pub const TYPE_SELF: HighlightTag = HighlightTag("type.self");
29 pub const TYPE_PARAM: HighlightTag = HighlightTag("type.param");
30 pub const TYPE_LIFETIME: HighlightTag = HighlightTag("type.lifetime");
31
32 pub const LITERAL_BYTE: HighlightTag = HighlightTag("literal.byte");
33 pub const LITERAL_NUMERIC: HighlightTag = HighlightTag("literal.numeric");
34 pub const LITERAL_CHAR: HighlightTag = HighlightTag("literal.char");
35
36 pub const LITERAL_COMMENT: HighlightTag = HighlightTag("comment");
37 pub const LITERAL_STRING: HighlightTag = HighlightTag("string");
38 pub const LITERAL_ATTRIBUTE: HighlightTag = HighlightTag("attribute");
39
40 pub const KEYWORD: HighlightTag = HighlightTag("keyword");
41 pub const KEYWORD_UNSAFE: HighlightTag = HighlightTag("keyword.unsafe");
42 pub const KEYWORD_CONTROL: HighlightTag = HighlightTag("keyword.control");
43}