diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-01-08 20:48:30 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-01-08 20:48:30 +0000 |
commit | 056cabf25d3ef7a96220f9f3a6f904b2841feab6 (patch) | |
tree | f2c780887fb41f87ef0872308501b09775275667 /crates/ide/src/syntax_highlighting/injector.rs | |
parent | 903d1f89a51254b92ae6d1776d118a32a38acdf6 (diff) | |
parent | e30c1c3fbf8f70336d985b2b73e5b0f45f3b95f5 (diff) |
Merge #7212
7212: Simplify highlighting r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ide/src/syntax_highlighting/injector.rs')
-rw-r--r-- | crates/ide/src/syntax_highlighting/injector.rs | 83 |
1 files changed, 83 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..0513a9fd6 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/injector.rs | |||
@@ -0,0 +1,83 @@ | |||
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 | |||
21 | let target_range = TextRange::at(TextSize::of(&self.buf), len); | ||
22 | self.ranges | ||
23 | .push((target_range, Some(Delta::new(target_range.start(), source_range.start())))); | ||
24 | self.buf.push_str(text); | ||
25 | } | ||
26 | pub(super) fn add_unmapped(&mut self, text: &str) { | ||
27 | let len = TextSize::of(text); | ||
28 | |||
29 | let target_range = TextRange::at(TextSize::of(&self.buf), len); | ||
30 | self.ranges.push((target_range, None)); | ||
31 | self.buf.push_str(text); | ||
32 | } | ||
33 | |||
34 | pub(super) fn text(&self) -> &str { | ||
35 | &self.buf | ||
36 | } | ||
37 | pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { | ||
38 | let (start, len) = equal_range_by(&self.ranges, |&(r, _)| ordering(r, range)); | ||
39 | (start..start + len).filter_map(move |i| { | ||
40 | let (target_range, delta) = self.ranges[i]; | ||
41 | let intersection = target_range.intersect(range).unwrap(); | ||
42 | Some(intersection + delta?) | ||
43 | }) | ||
44 | } | ||
45 | } | ||
46 | |||
47 | #[derive(Clone, Copy)] | ||
48 | enum Delta<T> { | ||
49 | Add(T), | ||
50 | Sub(T), | ||
51 | } | ||
52 | |||
53 | impl<T> Delta<T> { | ||
54 | fn new(from: T, to: T) -> Delta<T> | ||
55 | where | ||
56 | T: Ord + Sub<Output = T>, | ||
57 | { | ||
58 | if to >= from { | ||
59 | Delta::Add(to - from) | ||
60 | } else { | ||
61 | Delta::Sub(from - to) | ||
62 | } | ||
63 | } | ||
64 | } | ||
65 | |||
66 | impl ops::Add<Delta<TextSize>> for TextSize { | ||
67 | type Output = TextSize; | ||
68 | |||
69 | fn add(self, rhs: Delta<TextSize>) -> TextSize { | ||
70 | match rhs { | ||
71 | Delta::Add(it) => self + it, | ||
72 | Delta::Sub(it) => self - it, | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | |||
77 | impl ops::Add<Delta<TextSize>> for TextRange { | ||
78 | type Output = TextRange; | ||
79 | |||
80 | fn add(self, rhs: Delta<TextSize>) -> TextRange { | ||
81 | TextRange::at(self.start() + rhs, self.len()) | ||
82 | } | ||
83 | } | ||