lsp_text_document/
document.rs1use lsp_types::{Position, Range, TextDocumentContentChangeEvent, Url};
2#[derive(Clone)]
3pub struct FullTextDocument {
4 pub uri: Url,
5
6 pub language_id: String,
8
9 pub version: i64,
12
13 pub text: String,
15
16 line_offset: Option<Vec<usize>>,
17}
18
19impl FullTextDocument {
20 pub fn new(uri: Url, language_id: String, version: i64, text: String) -> FullTextDocument {
21 FullTextDocument {
23 uri,
24 language_id,
25 version,
26 text,
27 line_offset: None,
28 }
29 }
30
31 pub fn update(&mut self, changes: Vec<TextDocumentContentChangeEvent>, version: i64) {
32 for change in changes {
33 if Self::is_incremental(&change) {
34 let range = get_wellformed_range(change.range.unwrap());
36
37 let start_offset = self.offset_at(range.start);
38 let end_offset = self.offset_at(range.end);
39
40 let (start_byte, end_byte) = self.transform_offset_to_byte_offset(start_offset, end_offset);
41 self.text = self.text[0..start_byte].to_string()
42 + &change.text
43 + &self.text[end_byte..];
44 let start_line = range.start.line as usize;
47 let end_line = range.end.line as usize;
48 let line_offsets = self.get_line_offsets();
49
50 let mut add_line_offsets =
51 compute_line_offsets(&change.text, false, Some(start_offset));
52
53 let add_line_offsets_len = add_line_offsets.len();
54 if end_line - start_line == add_line_offsets.len() {
59 for (i, offset) in add_line_offsets.into_iter().enumerate() {
60 line_offsets[i + start_line + 1] = offset;
61 }
62 } else {
63 *line_offsets = {
64 let mut res =
65 line_offsets[0..=start_line.min(line_offsets.len() - 1)].to_vec();
66 res.append(&mut add_line_offsets);
67 res.extend_from_slice(
68 &line_offsets[end_line.min(line_offsets.len() - 1) + 1..],
69 );
70 res
71 };
72 }
73 let diff: i32 = change.text.len() as i32 - (end_offset - start_offset) as i32;
74 if diff != 0 {
75 for i in start_line + 1 + add_line_offsets_len..line_offsets.len() {
76 line_offsets[i] = (line_offsets[i] as i32 + diff) as usize;
77 }
78 }
79 } else if Self::is_full(&change) {
80 self.text = change.text;
81 self.line_offset = None;
82 }
83 self.version = version;
84 }
85 }
86
87 pub fn transform_offset_to_byte_offset(&self, start_offset: usize, end_offset: usize) -> (usize, usize) {
88 let start_byte = self.text
89 .chars()
90 .take(start_offset)
91 .fold(0, |acc, cur| acc + cur.len_utf8());
92 let end_byte = (&self.text[start_offset..end_offset])
93 .chars()
94 .take(end_offset)
95 .fold(0, |acc, cur| acc + cur.len_utf8())
96 + start_byte;
97 (start_byte, end_byte)
98 }
99 pub fn position_at(&mut self, mut offset: u32) -> Position {
100 offset = offset.min(self.text.len() as u32).max(0);
101
102 let line_offsets = self.get_line_offsets();
103 let mut low = 0usize;
105 let mut high = line_offsets.len();
106 if high == 0 {
107 return Position {
108 line: 0,
109 character: offset,
110 };
111 }
112 while low < high {
113 let mid = low + (high - low) / 2;
114 if line_offsets[mid] as u32 > offset {
115 high = mid;
116 } else {
117 low = mid + 1;
118 }
119 }
120 let line = low as u32 - 1;
121 return Position {
122 line,
123 character: offset - line_offsets[line as usize] as u32,
124 };
125 }
138
139 pub fn line_count(&mut self) -> usize {
140 self.get_line_offsets().len()
141 }
142 pub fn is_incremental(event: &TextDocumentContentChangeEvent) -> bool {
143 event.range.is_some()
144 }
145
146 pub fn is_full(event: &TextDocumentContentChangeEvent) -> bool {
147 !event.range_length.is_some() && !event.range.is_some()
148 }
149
150 pub fn get_line_offsets(&mut self) -> &mut Vec<usize> {
151 if self.line_offset.is_none() {
152 self.line_offset = Some(compute_line_offsets(&self.text, true, None));
153 }
154 self.line_offset.as_mut().unwrap()
155 }
156 pub fn offset_at(&mut self, position: Position) -> usize {
157 let line_offsets = self.get_line_offsets();
158 if position.line >= line_offsets.len() as u32 {
159 return self.text.len();
160 }
161 let line_offset = line_offsets[position.line as usize];
162 let next_line_offset = if position.line + 1 < line_offsets.len() as u32 {
163 line_offsets[position.line as usize + 1]
164 } else {
165 self.text.len()
166 };
167 (line_offset + position.character as usize)
168 .min(next_line_offset)
169 .max(line_offset)
170 }
175}
176
177pub fn compute_line_offsets(
178 text: &String,
179 is_at_line_start: bool,
180 text_offset: Option<usize>,
181) -> Vec<usize> {
182 let text_offset = if let Some(offset) = text_offset {
183 offset
184 } else {
185 0
186 };
187 let mut result = if is_at_line_start {
188 vec![text_offset]
189 } else {
190 vec![]
191 };
192 let char_array: Vec<char> = text.chars().collect();
193 let mut i = 0;
194 while i < char_array.len() {
195 let &ch = unsafe { char_array.get_unchecked(i) };
196 if ch == '\r' || ch == '\n' {
197 if ch == '\r'
198 && i + 1 < char_array.len()
199 && unsafe { char_array.get_unchecked(i + 1) == &'\n' }
200 {
201 i += 1;
202 }
203 result.push(text_offset + i + 1);
204 }
205 i += 1;
206 }
207 result
208}
209
210fn get_wellformed_range(range: Range) -> Range {
211 let start = range.start;
212 let end = range.end;
213 if start.line > end.line || (start.line == end.line && start.character > end.character) {
214 Range::new(end, start)
215 } else {
216 range
217 }
218}