aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/syntax_highlighting.rs
diff options
context:
space:
mode:
authorLeander Tentrup <[email protected]>2020-06-14 13:43:43 +0100
committerLeander Tentrup <[email protected]>2020-06-15 21:13:53 +0100
commitc4b3db0c2f307d1d782af88ded260e4c6593cae0 (patch)
treedd32c19bf36913db87d0dde84f70e6fd1b4c2e5a /crates/ra_ide/src/syntax_highlighting.rs
parentf4f51171ca6d99b693df2ef6fb71f0347999aa9f (diff)
Syntactic highlighting of NAME_REF for injections
This commit adds a function that tries to determine the syntax highlighting class of NAME_REFs based on the usage. It is used for highlighting injections (such as highlighting of doctests) as the semantic logic will most of the time result in unresolved references. It also adds a color to unresolved references in HTML encoding.
Diffstat (limited to 'crates/ra_ide/src/syntax_highlighting.rs')
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs63
1 files changed, 60 insertions, 3 deletions
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index bbcd52a1c..5a4de450c 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -44,6 +44,7 @@ pub(crate) fn highlight(
44 db: &RootDatabase, 44 db: &RootDatabase,
45 file_id: FileId, 45 file_id: FileId,
46 range_to_highlight: Option<TextRange>, 46 range_to_highlight: Option<TextRange>,
47 syntactic_name_ref_highlighting: bool,
47) -> Vec<HighlightedRange> { 48) -> Vec<HighlightedRange> {
48 let _p = profile("highlight"); 49 let _p = profile("highlight");
49 let sema = Semantics::new(db); 50 let sema = Semantics::new(db);
@@ -104,6 +105,7 @@ pub(crate) fn highlight(
104 if let Some((highlight, binding_hash)) = highlight_element( 105 if let Some((highlight, binding_hash)) = highlight_element(
105 &sema, 106 &sema,
106 &mut bindings_shadow_count, 107 &mut bindings_shadow_count,
108 syntactic_name_ref_highlighting,
107 name.syntax().clone().into(), 109 name.syntax().clone().into(),
108 ) { 110 ) {
109 stack.add(HighlightedRange { 111 stack.add(HighlightedRange {
@@ -200,9 +202,12 @@ pub(crate) fn highlight(
200 202
201 let is_format_string = format_string.as_ref() == Some(&element_to_highlight); 203 let is_format_string = format_string.as_ref() == Some(&element_to_highlight);
202 204
203 if let Some((highlight, binding_hash)) = 205 if let Some((highlight, binding_hash)) = highlight_element(
204 highlight_element(&sema, &mut bindings_shadow_count, element_to_highlight.clone()) 206 &sema,
205 { 207 &mut bindings_shadow_count,
208 syntactic_name_ref_highlighting,
209 element_to_highlight.clone(),
210 ) {
206 stack.add(HighlightedRange { range, highlight, binding_hash }); 211 stack.add(HighlightedRange { range, highlight, binding_hash });
207 if let Some(string) = 212 if let Some(string) =
208 element_to_highlight.as_token().cloned().and_then(ast::String::cast) 213 element_to_highlight.as_token().cloned().and_then(ast::String::cast)
@@ -410,6 +415,7 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> {
410fn highlight_element( 415fn highlight_element(
411 sema: &Semantics<RootDatabase>, 416 sema: &Semantics<RootDatabase>,
412 bindings_shadow_count: &mut FxHashMap<Name, u32>, 417 bindings_shadow_count: &mut FxHashMap<Name, u32>,
418 syntactic_name_ref_highlighting: bool,
413 element: SyntaxElement, 419 element: SyntaxElement,
414) -> Option<(Highlight, Option<u64>)> { 420) -> Option<(Highlight, Option<u64>)> {
415 let db = sema.db; 421 let db = sema.db;
@@ -463,6 +469,7 @@ fn highlight_element(
463 } 469 }
464 NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), 470 NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(),
465 }, 471 },
472 None if syntactic_name_ref_highlighting => highlight_name_ref_by_syntax(name_ref),
466 None => HighlightTag::UnresolvedReference.into(), 473 None => HighlightTag::UnresolvedReference.into(),
467 } 474 }
468 } 475 }
@@ -614,3 +621,53 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
614 621
615 tag.into() 622 tag.into()
616} 623}
624
625fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight {
626 let default = HighlightTag::UnresolvedReference;
627
628 let parent = match name.syntax().parent() {
629 Some(it) => it,
630 _ => return default.into(),
631 };
632
633 let tag = match parent.kind() {
634 METHOD_CALL_EXPR => HighlightTag::Function,
635 FIELD_EXPR => HighlightTag::Field,
636 PATH_SEGMENT => {
637 let path = match parent.parent().and_then(ast::Path::cast) {
638 Some(it) => it,
639 _ => return default.into(),
640 };
641 let expr = match path.syntax().parent().and_then(ast::PathExpr::cast) {
642 Some(it) => it,
643 _ => {
644 // within path, decide whether it is module or adt by checking for uppercase name
645 return if name.text().chars().next().unwrap_or_default().is_uppercase() {
646 HighlightTag::Struct
647 } else {
648 HighlightTag::Module
649 }
650 .into();
651 }
652 };
653 let parent = match expr.syntax().parent() {
654 Some(it) => it,
655 None => return default.into(),
656 };
657
658 match parent.kind() {
659 CALL_EXPR => HighlightTag::Function,
660 _ => {
661 if name.text().chars().next().unwrap_or_default().is_uppercase() {
662 HighlightTag::Struct
663 } else {
664 HighlightTag::Constant
665 }
666 }
667 }
668 }
669 _ => default,
670 };
671
672 tag.into()
673}