aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/syntax_highlighting/injection.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/syntax_highlighting/injection.rs')
-rw-r--r--crates/ide/src/syntax_highlighting/injection.rs105
1 files changed, 39 insertions, 66 deletions
diff --git a/crates/ide/src/syntax_highlighting/injection.rs b/crates/ide/src/syntax_highlighting/injection.rs
index 98ee03e0d..008d5ce24 100644
--- a/crates/ide/src/syntax_highlighting/injection.rs
+++ b/crates/ide/src/syntax_highlighting/injection.rs
@@ -7,12 +7,12 @@ use ide_db::call_info::ActiveParameter;
7use itertools::Itertools; 7use itertools::Itertools;
8use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; 8use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize};
9 9
10use crate::{Analysis, HighlightModifier, HighlightTag, HighlightedRange, RootDatabase}; 10use crate::{Analysis, HlMod, HlRange, HlTag, RootDatabase};
11 11
12use super::{highlights::Highlights, injector::Injector}; 12use super::{highlights::Highlights, injector::Injector};
13 13
14pub(super) fn highlight_injection( 14pub(super) fn highlight_injection(
15 acc: &mut Highlights, 15 hl: &mut Highlights,
16 sema: &Semantics<RootDatabase>, 16 sema: &Semantics<RootDatabase>,
17 literal: ast::String, 17 literal: ast::String,
18 expanded: SyntaxToken, 18 expanded: SyntaxToken,
@@ -22,80 +22,53 @@ pub(super) fn highlight_injection(
22 return None; 22 return None;
23 } 23 }
24 let value = literal.value()?; 24 let value = literal.value()?;
25 let marker_info = MarkerInfo::new(&*value);
26 let (analysis, tmp_file_id) = Analysis::from_single_file(marker_info.cleaned_text.clone());
27 25
28 if let Some(range) = literal.open_quote_text_range() { 26 if let Some(range) = literal.open_quote_text_range() {
29 acc.add(HighlightedRange { 27 hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None })
30 range,
31 highlight: HighlightTag::StringLiteral.into(),
32 binding_hash: None,
33 })
34 } 28 }
35 29
36 for mut h in analysis.highlight(tmp_file_id).unwrap() { 30 let mut inj = Injector::default();
37 let range = marker_info.map_range_up(h.range);
38 if let Some(range) = literal.map_range_up(range) {
39 h.range = range;
40 acc.add(h);
41 }
42 }
43 31
44 if let Some(range) = literal.close_quote_text_range() { 32 let mut text = &*value;
45 acc.add(HighlightedRange { 33 let mut offset: TextSize = 0.into();
46 range,
47 highlight: HighlightTag::StringLiteral.into(),
48 binding_hash: None,
49 })
50 }
51 34
52 Some(()) 35 while !text.is_empty() {
53} 36 let marker = "$0";
37 let idx = text.find(marker).unwrap_or(text.len());
38 let (chunk, next) = text.split_at(idx);
39 inj.add(chunk, TextRange::at(offset, TextSize::of(chunk)));
54 40
55/// Data to remove `$0` from string and map ranges 41 text = next;
56#[derive(Default, Debug)] 42 offset += TextSize::of(chunk);
57struct MarkerInfo {
58 cleaned_text: String,
59 markers: Vec<TextRange>,
60}
61 43
62impl MarkerInfo { 44 if let Some(next) = text.strip_prefix(marker) {
63 fn new(mut text: &str) -> Self { 45 if let Some(range) = literal.map_range_up(TextRange::at(offset, TextSize::of(marker))) {
64 let marker = "$0"; 46 hl.add(HlRange { range, highlight: HlTag::Keyword.into(), binding_hash: None });
47 }
65 48
66 let mut res = MarkerInfo::default();
67 let mut offset: TextSize = 0.into();
68 while !text.is_empty() {
69 let idx = text.find(marker).unwrap_or(text.len());
70 let (chunk, next) = text.split_at(idx);
71 text = next; 49 text = next;
72 res.cleaned_text.push_str(chunk);
73 offset += TextSize::of(chunk);
74
75 if let Some(next) = text.strip_prefix(marker) {
76 text = next;
77 50
78 let marker_len = TextSize::of(marker); 51 let marker_len = TextSize::of(marker);
79 res.markers.push(TextRange::at(offset, marker_len)); 52 offset += marker_len;
80 offset += marker_len;
81 }
82 } 53 }
83 res
84 } 54 }
85 fn map_range_up(&self, range: TextRange) -> TextRange { 55
86 TextRange::new( 56 let (analysis, tmp_file_id) = Analysis::from_single_file(inj.text().to_string());
87 self.map_offset_up(range.start(), true), 57
88 self.map_offset_up(range.end(), false), 58 for mut hl_range in analysis.highlight(tmp_file_id).unwrap() {
89 ) 59 for range in inj.map_range_up(hl_range.range) {
90 } 60 if let Some(range) = literal.map_range_up(range) {
91 fn map_offset_up(&self, mut offset: TextSize, start: bool) -> TextSize { 61 hl_range.range = range;
92 for r in &self.markers { 62 hl.add(hl_range.clone());
93 if r.start() < offset || (start && r.start() == offset) {
94 offset += r.len()
95 } 63 }
96 } 64 }
97 offset
98 } 65 }
66
67 if let Some(range) = literal.close_quote_text_range() {
68 hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None })
69 }
70
71 Some(())
99} 72}
100 73
101const RUSTDOC_FENCE: &'static str = "```"; 74const RUSTDOC_FENCE: &'static str = "```";
@@ -116,7 +89,7 @@ const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[
116/// Lastly, a vector of new comment highlight ranges (spanning only the 89/// Lastly, a vector of new comment highlight ranges (spanning only the
117/// comment prefix) is returned which is used in the syntax highlighting 90/// comment prefix) is returned which is used in the syntax highlighting
118/// injection to replace the previous (line-spanning) comment ranges. 91/// injection to replace the previous (line-spanning) comment ranges.
119pub(super) fn extract_doc_comments(node: &SyntaxNode) -> Option<(Vec<HighlightedRange>, Injector)> { 92pub(super) fn extract_doc_comments(node: &SyntaxNode) -> Option<(Vec<HlRange>, Injector)> {
120 let mut inj = Injector::default(); 93 let mut inj = Injector::default();
121 // wrap the doctest into function body to get correct syntax highlighting 94 // wrap the doctest into function body to get correct syntax highlighting
122 let prefix = "fn doctest() {\n"; 95 let prefix = "fn doctest() {\n";
@@ -166,12 +139,12 @@ pub(super) fn extract_doc_comments(node: &SyntaxNode) -> Option<(Vec<Highlighted
166 pos 139 pos
167 }; 140 };
168 141
169 new_comments.push(HighlightedRange { 142 new_comments.push(HlRange {
170 range: TextRange::new( 143 range: TextRange::new(
171 range.start(), 144 range.start(),
172 range.start() + TextSize::try_from(pos).unwrap(), 145 range.start() + TextSize::try_from(pos).unwrap(),
173 ), 146 ),
174 highlight: HighlightTag::Comment | HighlightModifier::Documentation, 147 highlight: HlTag::Comment | HlMod::Documentation,
175 binding_hash: None, 148 binding_hash: None,
176 }); 149 });
177 line_start += range.len() - TextSize::try_from(pos).unwrap(); 150 line_start += range.len() - TextSize::try_from(pos).unwrap();
@@ -196,7 +169,7 @@ pub(super) fn extract_doc_comments(node: &SyntaxNode) -> Option<(Vec<Highlighted
196 169
197/// Injection of syntax highlighting of doctests. 170/// Injection of syntax highlighting of doctests.
198pub(super) fn highlight_doc_comment( 171pub(super) fn highlight_doc_comment(
199 new_comments: Vec<HighlightedRange>, 172 new_comments: Vec<HlRange>,
200 inj: Injector, 173 inj: Injector,
201 stack: &mut Highlights, 174 stack: &mut Highlights,
202) { 175) {
@@ -207,9 +180,9 @@ pub(super) fn highlight_doc_comment(
207 180
208 for h in analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() { 181 for h in analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() {
209 for r in inj.map_range_up(h.range) { 182 for r in inj.map_range_up(h.range) {
210 stack.add(HighlightedRange { 183 stack.add(HlRange {
211 range: r, 184 range: r,
212 highlight: h.highlight | HighlightModifier::Injected, 185 highlight: h.highlight | HlMod::Injected,
213 binding_hash: h.binding_hash, 186 binding_hash: h.binding_hash,
214 }); 187 });
215 } 188 }