aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/syntax_highlighting/injector.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-01-07 22:39:02 +0000
committerAleksey Kladov <[email protected]>2021-01-08 20:47:35 +0000
commite30c1c3fbf8f70336d985b2b73e5b0f45f3b95f5 (patch)
treea3cdc2d2f667ab5a122758152eb338a654d387cd /crates/ide/src/syntax_highlighting/injector.rs
parent981a0d708ec352969f9ca075a3e0e50c6da48197 (diff)
Simplify highlighting infra
This also fixes the killer whale bug
Diffstat (limited to 'crates/ide/src/syntax_highlighting/injector.rs')
-rw-r--r--crates/ide/src/syntax_highlighting/injector.rs83
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.
3use std::ops::{self, Sub};
4
5use stdx::equal_range_by;
6use syntax::{TextRange, TextSize};
7
8use super::highlights::ordering;
9
10#[derive(Default)]
11pub(super) struct Injector {
12 buf: String,
13 ranges: Vec<(TextRange, Option<Delta<TextSize>>)>,
14}
15
16impl 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)]
48enum Delta<T> {
49 Add(T),
50 Sub(T),
51}
52
53impl<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
66impl 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
77impl 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}