aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs129
1 files changed, 64 insertions, 65 deletions
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 5f11b091c..e8ca7d652 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -46,93 +46,92 @@ fn is_control_keyword(kind: SyntaxKind) -> bool {
46pub(crate) fn highlight( 46pub(crate) fn highlight(
47 db: &RootDatabase, 47 db: &RootDatabase,
48 file_id: FileId, 48 file_id: FileId,
49 range: Option<TextRange>, 49 range_to_highlight: Option<TextRange>,
50) -> Vec<HighlightedRange> { 50) -> Vec<HighlightedRange> {
51 let _p = profile("highlight"); 51 let _p = profile("highlight");
52 let sema = Semantics::new(db); 52 let sema = Semantics::new(db);
53 let root = sema.parse(file_id).syntax().clone(); 53
54 // Determine the root based on the given range.
55 let (root, range_to_highlight) = {
56 let source_file = sema.parse(file_id);
57 match range_to_highlight {
58 Some(range) => {
59 let node = match source_file.syntax().covering_element(range) {
60 NodeOrToken::Node(it) => it,
61 NodeOrToken::Token(it) => it.parent(),
62 };
63 (node, range)
64 }
65 None => (source_file.syntax().clone(), source_file.syntax().text_range()),
66 }
67 };
54 68
55 let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); 69 let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
56 let mut res = Vec::new(); 70 let mut res = Vec::new();
57 71
58 let mut in_macro_call = None; 72 let mut current_macro_call: Option<ast::MacroCall> = None;
59 73
60 // Determine the root based on the given range. 74 for event in root.preorder_with_tokens() {
61 let (root, highlight_range) = if let Some(range) = range { 75 let event_range = match &event {
62 let root = match root.covering_element(range) { 76 WalkEvent::Enter(it) => it.text_range(),
63 NodeOrToken::Node(node) => node, 77 WalkEvent::Leave(it) => it.text_range(),
64 NodeOrToken::Token(token) => token.parent(),
65 }; 78 };
66 (root, range)
67 } else {
68 (root.clone(), root.text_range())
69 };
70 79
71 for event in root.preorder_with_tokens() { 80 if event_range.intersection(&range_to_highlight).is_none() {
72 match event { 81 continue;
73 WalkEvent::Enter(node) => { 82 }
74 if node.text_range().intersection(&highlight_range).is_none() {
75 continue;
76 }
77 83
78 match node.kind() { 84 match event.clone().map(|it| it.into_node().and_then(ast::MacroCall::cast)) {
79 MACRO_CALL => { 85 WalkEvent::Enter(Some(mc)) => {
80 in_macro_call = Some(node.clone()); 86 current_macro_call = Some(mc.clone());
81 if let Some(range) = highlight_macro(node) { 87 if let Some(range) = highlight_macro(&mc) {
82 res.push(HighlightedRange { 88 res.push(HighlightedRange {
83 range, 89 range,
84 highlight: HighlightTag::Macro.into(), 90 highlight: HighlightTag::Macro.into(),
85 binding_hash: None, 91 binding_hash: None,
86 }); 92 });
87 }
88 }
89 _ if in_macro_call.is_some() => {
90 if let Some(token) = node.as_token() {
91 if let Some((highlight, binding_hash)) = highlight_token_tree(
92 &sema,
93 &mut bindings_shadow_count,
94 token.clone(),
95 ) {
96 res.push(HighlightedRange {
97 range: node.text_range(),
98 highlight,
99 binding_hash,
100 });
101 }
102 }
103 }
104 _ => {
105 if let Some((highlight, binding_hash)) =
106 highlight_node(&sema, &mut bindings_shadow_count, node.clone())
107 {
108 res.push(HighlightedRange {
109 range: node.text_range(),
110 highlight,
111 binding_hash,
112 });
113 }
114 }
115 } 93 }
94 continue;
116 } 95 }
117 WalkEvent::Leave(node) => { 96 WalkEvent::Leave(Some(mc)) => {
118 if node.text_range().intersection(&highlight_range).is_none() { 97 assert!(current_macro_call == Some(mc));
119 continue; 98 current_macro_call = None;
120 } 99 continue;
100 }
101 _ => (),
102 }
121 103
122 if let Some(m) = in_macro_call.as_ref() { 104 let node = match event {
123 if *m == node { 105 WalkEvent::Enter(it) => it,
124 in_macro_call = None; 106 WalkEvent::Leave(_) => continue,
125 } 107 };
108
109 if current_macro_call.is_some() {
110 if let Some(token) = node.into_token() {
111 if let Some((highlight, binding_hash)) =
112 highlight_token_tree(&sema, &mut bindings_shadow_count, token.clone())
113 {
114 res.push(HighlightedRange {
115 range: token.text_range(),
116 highlight,
117 binding_hash,
118 });
126 } 119 }
127 } 120 }
121 continue;
122 }
123
124 if let Some((highlight, binding_hash)) =
125 highlight_node(&sema, &mut bindings_shadow_count, node.clone())
126 {
127 res.push(HighlightedRange { range: node.text_range(), highlight, binding_hash });
128 } 128 }
129 } 129 }
130 130
131 res 131 res
132} 132}
133 133
134fn highlight_macro(node: SyntaxElement) -> Option<TextRange> { 134fn highlight_macro(macro_call: &ast::MacroCall) -> Option<TextRange> {
135 let macro_call = ast::MacroCall::cast(node.as_node()?.clone())?;
136 let path = macro_call.path()?; 135 let path = macro_call.path()?;
137 let name_ref = path.segment()?.name_ref()?; 136 let name_ref = path.segment()?.name_ref()?;
138 137