diff options
Diffstat (limited to 'crates/ide/src/syntax_highlighting/injector.rs')
-rw-r--r-- | crates/ide/src/syntax_highlighting/injector.rs | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/crates/ide/src/syntax_highlighting/injector.rs b/crates/ide/src/syntax_highlighting/injector.rs new file mode 100644 index 000000000..fd4025694 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/injector.rs | |||
@@ -0,0 +1,80 @@ | |||
1 | //! Extracts a subsequence of a text document, remembering the mapping of ranges | ||
2 | //! between original and extracted texts. | ||
3 | use std::ops::{self, Sub}; | ||
4 | |||
5 | use stdx::equal_range_by; | ||
6 | use syntax::{TextRange, TextSize}; | ||
7 | |||
8 | use super::highlights::ordering; | ||
9 | |||
10 | #[derive(Default)] | ||
11 | pub(super) struct Injector { | ||
12 | buf: String, | ||
13 | ranges: Vec<(TextRange, Option<Delta<TextSize>>)>, | ||
14 | } | ||
15 | |||
16 | impl Injector { | ||
17 | pub(super) fn add(&mut self, text: &str, source_range: TextRange) { | ||
18 | let len = TextSize::of(text); | ||
19 | assert_eq!(len, source_range.len()); | ||
20 | self.add_impl(text, Some(source_range.start())); | ||
21 | } | ||
22 | pub(super) fn add_unmapped(&mut self, text: &str) { | ||
23 | self.add_impl(text, None); | ||
24 | } | ||
25 | fn add_impl(&mut self, text: &str, source: Option<TextSize>) { | ||
26 | let len = TextSize::of(text); | ||
27 | let target_range = TextRange::at(TextSize::of(&self.buf), len); | ||
28 | self.ranges.push((target_range, source.map(|it| Delta::new(target_range.start(), it)))); | ||
29 | self.buf.push_str(text); | ||
30 | } | ||
31 | |||
32 | pub(super) fn text(&self) -> &str { | ||
33 | &self.buf | ||
34 | } | ||
35 | pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { | ||
36 | equal_range_by(&self.ranges, |&(r, _)| ordering(r, range)).filter_map(move |i| { | ||
37 | let (target_range, delta) = self.ranges[i]; | ||
38 | let intersection = target_range.intersect(range).unwrap(); | ||
39 | Some(intersection + delta?) | ||
40 | }) | ||
41 | } | ||
42 | } | ||
43 | |||
44 | #[derive(Clone, Copy)] | ||
45 | enum Delta<T> { | ||
46 | Add(T), | ||
47 | Sub(T), | ||
48 | } | ||
49 | |||
50 | impl<T> Delta<T> { | ||
51 | fn new(from: T, to: T) -> Delta<T> | ||
52 | where | ||
53 | T: Ord + Sub<Output = T>, | ||
54 | { | ||
55 | if to >= from { | ||
56 | Delta::Add(to - from) | ||
57 | } else { | ||
58 | Delta::Sub(from - to) | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | |||
63 | impl ops::Add<Delta<TextSize>> for TextSize { | ||
64 | type Output = TextSize; | ||
65 | |||
66 | fn add(self, rhs: Delta<TextSize>) -> TextSize { | ||
67 | match rhs { | ||
68 | Delta::Add(it) => self + it, | ||
69 | Delta::Sub(it) => self - it, | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | impl ops::Add<Delta<TextSize>> for TextRange { | ||
75 | type Output = TextRange; | ||
76 | |||
77 | fn add(self, rhs: Delta<TextSize>) -> TextRange { | ||
78 | TextRange::at(self.start() + rhs, self.len()) | ||
79 | } | ||
80 | } | ||