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