mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-08 11:18:48 +00:00
81 lines
2.2 KiB
Rust
81 lines
2.2 KiB
Rust
//! 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 take_text(&mut self) -> String {
|
|
std::mem::take(&mut 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())
|
|
}
|
|
}
|