aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/syntax_highlighting.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/syntax_highlighting.rs')
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs129
1 files changed, 85 insertions, 44 deletions
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 9a3e4c82f..0228ee7e9 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -2,7 +2,7 @@
2 2
3use rustc_hash::{FxHashMap, FxHashSet}; 3use rustc_hash::{FxHashMap, FxHashSet};
4 4
5use hir::{Name, Source}; 5use hir::{InFile, Name};
6use ra_db::SourceDatabase; 6use ra_db::SourceDatabase;
7use ra_prof::profile; 7use ra_prof::profile;
8use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T}; 8use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T};
@@ -16,6 +16,34 @@ use crate::{
16 FileId, 16 FileId,
17}; 17};
18 18
19pub mod tags {
20 pub(crate) const FIELD: &str = "field";
21 pub(crate) const FUNCTION: &str = "function";
22 pub(crate) const MODULE: &str = "module";
23 pub(crate) const TYPE: &str = "type";
24 pub(crate) const CONSTANT: &str = "constant";
25 pub(crate) const MACRO: &str = "macro";
26 pub(crate) const VARIABLE: &str = "variable";
27 pub(crate) const VARIABLE_MUT: &str = "variable.mut";
28 pub(crate) const TEXT: &str = "text";
29
30 pub(crate) const TYPE_BUILTIN: &str = "type.builtin";
31 pub(crate) const TYPE_SELF: &str = "type.self";
32 pub(crate) const TYPE_PARAM: &str = "type.param";
33 pub(crate) const TYPE_LIFETIME: &str = "type.lifetime";
34
35 pub(crate) const LITERAL_BYTE: &str = "literal.byte";
36 pub(crate) const LITERAL_NUMERIC: &str = "literal.numeric";
37 pub(crate) const LITERAL_CHAR: &str = "literal.char";
38 pub(crate) const LITERAL_COMMENT: &str = "comment";
39 pub(crate) const LITERAL_STRING: &str = "string";
40 pub(crate) const LITERAL_ATTRIBUTE: &str = "attribute";
41
42 pub(crate) const KEYWORD_UNSAFE: &str = "keyword.unsafe";
43 pub(crate) const KEYWORD_CONTROL: &str = "keyword.control";
44 pub(crate) const KEYWORD: &str = "keyword";
45}
46
19#[derive(Debug)] 47#[derive(Debug)]
20pub struct HighlightedRange { 48pub struct HighlightedRange {
21 pub range: TextRange, 49 pub range: TextRange,
@@ -71,17 +99,16 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
71 bindings_shadow_count.clear(); 99 bindings_shadow_count.clear();
72 continue; 100 continue;
73 } 101 }
74 COMMENT => "comment", 102 COMMENT => tags::LITERAL_COMMENT,
75 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string", 103 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => tags::LITERAL_STRING,
76 ATTR => "attribute", 104 ATTR => tags::LITERAL_ATTRIBUTE,
105 // Special-case field init shorthand
106 NAME_REF if node.parent().and_then(ast::RecordField::cast).is_some() => tags::FIELD,
107 NAME_REF if node.ancestors().any(|it| it.kind() == ATTR) => continue,
77 NAME_REF => { 108 NAME_REF => {
78 if node.ancestors().any(|it| it.kind() == ATTR) {
79 continue;
80 }
81
82 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); 109 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
83 let name_kind = 110 let name_kind =
84 classify_name_ref(db, Source::new(file_id.into(), &name_ref)).map(|d| d.kind); 111 classify_name_ref(db, InFile::new(file_id.into(), &name_ref)).map(|d| d.kind);
85 112
86 if let Some(Local(local)) = &name_kind { 113 if let Some(Local(local)) = &name_kind {
87 if let Some(name) = local.name(db) { 114 if let Some(name) = local.name(db) {
@@ -90,12 +117,12 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
90 } 117 }
91 }; 118 };
92 119
93 name_kind.map_or("text", |it| highlight_name(db, it)) 120 name_kind.map_or(tags::TEXT, |it| highlight_name(db, it))
94 } 121 }
95 NAME => { 122 NAME => {
96 let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); 123 let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap();
97 let name_kind = 124 let name_kind =
98 classify_name(db, Source::new(file_id.into(), &name)).map(|d| d.kind); 125 classify_name(db, InFile::new(file_id.into(), &name)).map(|d| d.kind);
99 126
100 if let Some(Local(local)) = &name_kind { 127 if let Some(Local(local)) = &name_kind {
101 if let Some(name) = local.name(db) { 128 if let Some(name) = local.name(db) {
@@ -107,18 +134,21 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
107 134
108 match name_kind { 135 match name_kind {
109 Some(name_kind) => highlight_name(db, name_kind), 136 Some(name_kind) => highlight_name(db, name_kind),
110 None => name.syntax().parent().map_or("function", |x| match x.kind() { 137 None => name.syntax().parent().map_or(tags::FUNCTION, |x| match x.kind() {
111 TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type", 138 STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => tags::TYPE,
112 RECORD_FIELD_DEF => "field", 139 TYPE_PARAM => tags::TYPE_PARAM,
113 _ => "function", 140 RECORD_FIELD_DEF => tags::FIELD,
141 _ => tags::FUNCTION,
114 }), 142 }),
115 } 143 }
116 } 144 }
117 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", 145 INT_NUMBER | FLOAT_NUMBER => tags::LITERAL_NUMERIC,
118 LIFETIME => "parameter", 146 BYTE => tags::LITERAL_BYTE,
119 T![unsafe] => "keyword.unsafe", 147 CHAR => tags::LITERAL_CHAR,
120 k if is_control_keyword(k) => "keyword.control", 148 LIFETIME => tags::TYPE_LIFETIME,
121 k if k.is_keyword() => "keyword", 149 T![unsafe] => tags::KEYWORD_UNSAFE,
150 k if is_control_keyword(k) => tags::KEYWORD_CONTROL,
151 k if k.is_keyword() => tags::KEYWORD,
122 _ => { 152 _ => {
123 if let Some(macro_call) = node.as_node().cloned().and_then(ast::MacroCall::cast) { 153 if let Some(macro_call) = node.as_node().cloned().and_then(ast::MacroCall::cast) {
124 if let Some(path) = macro_call.path() { 154 if let Some(path) = macro_call.path() {
@@ -135,7 +165,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
135 } 165 }
136 res.push(HighlightedRange { 166 res.push(HighlightedRange {
137 range: TextRange::from_to(range_start, range_end), 167 range: TextRange::from_to(range_start, range_end),
138 tag: "macro", 168 tag: tags::MACRO,
139 binding_hash: None, 169 binding_hash: None,
140 }) 170 })
141 } 171 }
@@ -211,29 +241,27 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
211 241
212fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str { 242fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str {
213 match name_kind { 243 match name_kind {
214 Macro(_) => "macro", 244 Macro(_) => tags::MACRO,
215 Field(_) => "field", 245 Field(_) => tags::FIELD,
216 AssocItem(hir::AssocItem::Function(_)) => "function", 246 AssocItem(hir::AssocItem::Function(_)) => tags::FUNCTION,
217 AssocItem(hir::AssocItem::Const(_)) => "constant", 247 AssocItem(hir::AssocItem::Const(_)) => tags::CONSTANT,
218 AssocItem(hir::AssocItem::TypeAlias(_)) => "type", 248 AssocItem(hir::AssocItem::TypeAlias(_)) => tags::TYPE,
219 Def(hir::ModuleDef::Module(_)) => "module", 249 Def(hir::ModuleDef::Module(_)) => tags::MODULE,
220 Def(hir::ModuleDef::Function(_)) => "function", 250 Def(hir::ModuleDef::Function(_)) => tags::FUNCTION,
221 Def(hir::ModuleDef::Adt(_)) => "type", 251 Def(hir::ModuleDef::Adt(_)) => tags::TYPE,
222 Def(hir::ModuleDef::EnumVariant(_)) => "constant", 252 Def(hir::ModuleDef::EnumVariant(_)) => tags::CONSTANT,
223 Def(hir::ModuleDef::Const(_)) => "constant", 253 Def(hir::ModuleDef::Const(_)) => tags::CONSTANT,
224 Def(hir::ModuleDef::Static(_)) => "constant", 254 Def(hir::ModuleDef::Static(_)) => tags::CONSTANT,
225 Def(hir::ModuleDef::Trait(_)) => "type", 255 Def(hir::ModuleDef::Trait(_)) => tags::TYPE,
226 Def(hir::ModuleDef::TypeAlias(_)) => "type", 256 Def(hir::ModuleDef::TypeAlias(_)) => tags::TYPE,
227 Def(hir::ModuleDef::BuiltinType(_)) => "type", 257 Def(hir::ModuleDef::BuiltinType(_)) => tags::TYPE_BUILTIN,
228 SelfType(_) => "type", 258 SelfType(_) => tags::TYPE_SELF,
229 GenericParam(_) => "type", 259 TypeParam(_) => tags::TYPE_PARAM,
230 Local(local) => { 260 Local(local) => {
231 if local.is_mut(db) { 261 if local.is_mut(db) || local.ty(db).is_mutable_reference() {
232 "variable.mut" 262 tags::VARIABLE_MUT
233 } else if local.ty(db).is_mutable_reference() {
234 "variable.mut"
235 } else { 263 } else {
236 "variable" 264 tags::VARIABLE
237 } 265 }
238 } 266 }
239 } 267 }
@@ -251,12 +279,16 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
251 279
252.comment { color: #7F9F7F; } 280.comment { color: #7F9F7F; }
253.string { color: #CC9393; } 281.string { color: #CC9393; }
282.field { color: #94BFF3; }
254.function { color: #93E0E3; } 283.function { color: #93E0E3; }
255.parameter { color: #94BFF3; } 284.parameter { color: #94BFF3; }
256.builtin { color: #DD6718; }
257.text { color: #DCDCCC; } 285.text { color: #DCDCCC; }
286.type { color: #7CB8BB; }
287.type\\.builtin { color: #8CD0D3; }
288.type\\.param { color: #20999D; }
258.attribute { color: #94BFF3; } 289.attribute { color: #94BFF3; }
259.literal { color: #BFEBBF; } 290.literal { color: #BFEBBF; }
291.literal\\.numeric { color: #6A8759; }
260.macro { color: #94BFF3; } 292.macro { color: #94BFF3; }
261.variable { color: #DCDCCC; } 293.variable { color: #DCDCCC; }
262.variable\\.mut { color: #DCDCCC; text-decoration: underline; } 294.variable\\.mut { color: #DCDCCC; text-decoration: underline; }
@@ -293,7 +325,8 @@ fn main() {
293 325
294 let mut vec = Vec::new(); 326 let mut vec = Vec::new();
295 if true { 327 if true {
296 vec.push(Foo { x: 0, y: 1 }); 328 let x = 92;
329 vec.push(Foo { x, y: 1 });
297 } 330 }
298 unsafe { vec.set_len(0); } 331 unsafe { vec.set_len(0); }
299 332
@@ -303,6 +336,14 @@ fn main() {
303 336
304 y; 337 y;
305} 338}
339
340enum E<X> {
341 V(X)
342}
343
344impl<X> E<X> {
345 fn new<T>() -> E<T> {}
346}
306"# 347"#
307 .trim(), 348 .trim(),
308 ); 349 );