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
79
80
81
82
83
#[cfg(test)]
#[path = "span_test.rs"]
mod test;
use std::ops::Sub;
use crate::db::FilesGroup;
use crate::ids::FileId;
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TextOffset(pub usize);
impl TextOffset {
pub fn inc(&mut self) {
self.0 += 1;
}
pub fn add(&self, width: usize) -> Self {
TextOffset(self.0 + width)
}
}
impl Sub for TextOffset {
type Output = usize;
fn sub(self, rhs: Self) -> Self::Output {
self.0 - rhs.0
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct TextSpan {
pub start: TextOffset,
pub end: TextOffset,
}
impl TextSpan {
pub fn width(&self) -> u32 {
(self.end - self.start) as u32
}
pub fn contains(&self, other: Self) -> bool {
self.start <= other.start && self.end >= other.end
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TextPosition {
pub line: usize,
pub col: usize,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FileSummary {
pub line_offsets: Vec<TextOffset>,
pub total_length: usize,
}
#[allow(dead_code)]
impl TextOffset {
pub fn get_line_number(&self, db: &dyn FilesGroup, file: FileId) -> Option<usize> {
let summary = db.file_summary(file)?;
assert!(
self.0 <= summary.total_length,
"TextOffset out of range. {} > {}.",
self.0,
summary.total_length
);
Some(summary.line_offsets.binary_search(self).unwrap_or_else(|x| x - 1))
}
pub fn position_in_file(&self, db: &dyn FilesGroup, file: FileId) -> Option<TextPosition> {
let summary = db.file_summary(file)?;
let line_number = self.get_line_number(db, file)?;
let line_offset = summary.line_offsets[line_number];
Some(TextPosition { line: line_number, col: *self - line_offset })
}
}
impl FileSummary {
pub fn line_count(&self) -> usize {
self.line_offsets.len()
}
}