package_json_lsp/
document.rs1use tower_lsp::lsp_types::{Position, Range, TextDocumentContentChangeEvent, Url};
2
3#[derive(Clone, Debug)]
4pub struct Document {
5 pub uri: Url,
6 pub version: i32,
7 text: String,
8}
9
10impl Document {
11 pub fn new(uri: Url, version: i32, text: String) -> Self {
12 Self { uri, version, text }
13 }
14
15 pub fn text(&self) -> &str {
16 &self.text
17 }
18
19 pub fn apply_changes(&mut self, changes: Vec<TextDocumentContentChangeEvent>) {
20 for change in changes {
21 if let Some(range) = change.range {
22 let start = self.offset_at(range.start);
23 let end = self.offset_at(range.end);
24 if start <= end && end <= self.text.len() {
25 self.text.replace_range(start..end, &change.text);
26 }
27 } else {
28 self.text = change.text;
29 }
30 }
31 }
32
33 pub fn range_from_byte_range(&self, start: usize, end: usize) -> Range {
34 Range {
35 start: self.position_at(start),
36 end: self.position_at(end),
37 }
38 }
39
40 pub fn position_at(&self, offset: usize) -> Position {
41 let target = offset.min(self.text.len());
42 let mut line = 0_u32;
43 let mut character = 0_u32;
44
45 for (idx, ch) in self.text.char_indices() {
46 if idx >= target {
47 break;
48 }
49 if ch == '\n' {
50 line += 1;
51 character = 0;
52 } else {
53 character += ch.len_utf16() as u32;
54 }
55 }
56
57 Position { line, character }
58 }
59
60 pub fn offset_at(&self, position: Position) -> usize {
61 let mut line = 0_u32;
62 let mut character = 0_u32;
63
64 for (idx, ch) in self.text.char_indices() {
65 if line == position.line && character >= position.character {
66 return idx;
67 }
68 if ch == '\n' {
69 if line == position.line {
70 return idx;
71 }
72 line += 1;
73 character = 0;
74 } else {
75 character += ch.len_utf16() as u32;
76 }
77 }
78
79 self.text.len()
80 }
81}
82
83pub fn position_in_range(position: Position, range: Range) -> bool {
84 if position.line < range.start.line || position.line > range.end.line {
85 return false;
86 }
87 if position.line == range.start.line && position.character < range.start.character {
88 return false;
89 }
90 if position.line == range.end.line && position.character > range.end.character {
91 return false;
92 }
93 true
94}