]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/injector.rs
Auto merge of #97802 - Enselic:add-no_ignore_sigkill-feature, r=joshtriplett
[rust.git] / src / tools / rust-analyzer / crates / ide / src / syntax_highlighting / injector.rs
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 #[derive(Default)]
9 pub(super) struct Injector {
10     buf: String,
11     ranges: Vec<(TextRange, Option<Delta<TextSize>>)>,
12 }
13
14 impl Injector {
15     pub(super) fn add(&mut self, text: &str, source_range: TextRange) {
16         let len = TextSize::of(text);
17         assert_eq!(len, source_range.len());
18         self.add_impl(text, Some(source_range.start()));
19     }
20
21     pub(super) fn add_unmapped(&mut self, text: &str) {
22         self.add_impl(text, None);
23     }
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 take_text(&mut self) -> String {
33         std::mem::take(&mut self.buf)
34     }
35
36     pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ {
37         equal_range_by(&self.ranges, |&(r, _)| TextRange::ordering(r, range)).filter_map(move |i| {
38             let (target_range, delta) = self.ranges[i];
39             let intersection = target_range.intersect(range).unwrap();
40             Some(intersection + delta?)
41         })
42     }
43 }
44
45 #[derive(Clone, Copy)]
46 enum Delta<T> {
47     Add(T),
48     Sub(T),
49 }
50
51 impl<T> Delta<T> {
52     fn new(from: T, to: T) -> Delta<T>
53     where
54         T: Ord + Sub<Output = T>,
55     {
56         if to >= from {
57             Delta::Add(to - from)
58         } else {
59             Delta::Sub(from - to)
60         }
61     }
62 }
63
64 impl ops::Add<Delta<TextSize>> for TextSize {
65     type Output = TextSize;
66
67     fn add(self, rhs: Delta<TextSize>) -> TextSize {
68         match rhs {
69             Delta::Add(it) => self + it,
70             Delta::Sub(it) => self - it,
71         }
72     }
73 }
74
75 impl ops::Add<Delta<TextSize>> for TextRange {
76     type Output = TextRange;
77
78     fn add(self, rhs: Delta<TextSize>) -> TextRange {
79         TextRange::at(self.start() + rhs, self.len())
80     }
81 }