aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/syntax_highlighting/injector.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/syntax_highlighting/injector.rs')
-rw-r--r--crates/ide/src/syntax_highlighting/injector.rs80
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.
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 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)]
45enum Delta<T> {
46 Add(T),
47 Sub(T),
48}
49
50impl<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
63impl 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
74impl 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}