makepad_code_editor/
text.rs

1use std::{
2    cmp::Ordering,
3    fmt, io,
4    io::BufRead,
5    iter,
6    ops::{Add, AddAssign, Sub, SubAssign},
7};
8
9#[derive(Clone, Debug, Eq, Hash, PartialEq)]
10pub struct Text {
11    lines: Vec<String>,
12}
13
14impl Text {
15    pub fn new() -> Self {
16        Self::default()
17    }
18
19    pub fn newline() -> Self {
20        Self {
21            lines: vec![String::new(), String::new()],
22        }
23    }
24
25    pub fn from_buf_reader<R>(reader: R) -> io::Result<Self>
26    where
27        R: BufRead,
28    {
29        Ok(Self {
30            lines: reader.lines().collect::<Result<_, _>>()?,
31        })
32    }
33
34    pub fn is_empty(&self) -> bool {
35        self.length() == Length::zero()
36    }
37
38    pub fn length(&self) -> Length {
39        Length {
40            line_count: self.lines.len() - 1,
41            byte_count: self.lines.last().unwrap().len(),
42        }
43    }
44
45    pub fn to_single_char(&self) -> Option<char> {
46        if self.lines.len() > 1 {
47            return None;
48        }
49        let mut chars = self.lines[0].chars();
50        match (chars.next(), chars.next()) {
51            (Some(char), None) => Some(char),
52            _ => None,
53        }
54    }
55
56    pub fn as_lines(&self) -> &[String] {
57        &self.lines
58    }
59
60    pub fn slice(&self, start: Position, length: Length) -> Self {
61        let end = start + length;
62        let mut lines = Vec::new();
63        if start.line_index == end.line_index {
64            lines.push(self.lines[start.line_index][start.byte_index..end.byte_index].to_string());
65        } else {
66            lines.reserve(end.line_index - start.line_index + 1);
67            lines.push(self.lines[start.line_index][start.byte_index..].to_string());
68            lines.extend(
69                self.lines[start.line_index + 1..end.line_index]
70                    .iter()
71                    .cloned(),
72            );
73            lines.push(self.lines[end.line_index][..end.byte_index].to_string());
74        }
75        Text { lines }
76    }
77
78    pub fn apply_change(&mut self, change: Change) {
79        match change {
80            Change::Insert(position, text) => self.insert(position, text),
81            Change::Delete(start, length) => self.delete(start, length),
82        }
83    }
84
85    pub fn into_lines(self) -> Vec<String> {
86        self.lines
87    }
88
89    fn insert(&mut self, point: Position, mut text: Self) {
90        if text.length().line_count == 0 {
91            self.lines[point.line_index].replace_range(
92                point.byte_index..point.byte_index,
93                text.lines.first().unwrap(),
94            );
95        } else {
96            text.lines
97                .first_mut()
98                .unwrap()
99                .replace_range(..0, &self.lines[point.line_index][..point.byte_index]);
100            text.lines
101                .last_mut()
102                .unwrap()
103                .push_str(&self.lines[point.line_index][point.byte_index..]);
104            self.lines
105                .splice(point.line_index..point.line_index + 1, text.lines);
106        }
107    }
108
109    fn delete(&mut self, start: Position, length: Length) {
110        let end = start + length;
111        if start.line_index == end.line_index {
112            self.lines[start.line_index].replace_range(start.byte_index..end.byte_index, "");
113        } else {
114            let mut line = self.lines[start.line_index][..start.byte_index].to_string();
115            line.push_str(&self.lines[end.line_index][end.byte_index..]);
116            self.lines
117                .splice(start.line_index..end.line_index + 1, iter::once(line));
118        }
119    }
120}
121
122impl Default for Text {
123    fn default() -> Self {
124        Self {
125            lines: vec![String::new()],
126        }
127    }
128}
129
130impl fmt::Display for Text {
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        let (last_line, remaining_lines) = self.lines.split_last().unwrap();
133        for line in remaining_lines {
134            writeln!(f, "{}", line)?;
135        }
136        write!(f, "{}", last_line)
137    }
138}
139
140impl From<char> for Text {
141    fn from(char: char) -> Self {
142        Self {
143            lines: vec![String::from(char)],
144        }
145    }
146}
147
148impl From<&str> for Text {
149    fn from(string: &str) -> Self {
150        Self {
151            lines: string.split('\n').map(|string| string.to_owned()).collect(),
152        }
153    }
154}
155
156impl From<&String> for Text {
157    fn from(string: &String) -> Self {
158        string.as_str().into()
159    }
160}
161
162impl From<String> for Text {
163    fn from(string: String) -> Self {
164        string.as_str().into()
165    }
166}
167
168impl FromIterator<char> for Text {
169    fn from_iter<I>(iter: I) -> Self
170    where
171        I: IntoIterator<Item = char>,
172    {
173        Text::from(iter.into_iter().collect::<String>())
174    }
175}
176
177#[derive(Clone, Debug, Eq, Hash, PartialEq)]
178pub struct Edit {
179    pub change: Change,
180    pub drift: Drift,
181}
182
183impl Edit {
184    pub fn invert(self, text: &Text) -> Self {
185        Self {
186            change: self.change.invert(text),
187            drift: self.drift,
188        }
189    }
190}
191
192#[derive(Clone, Debug, Eq, Hash, PartialEq)]
193pub enum Change {
194    Insert(Position, Text),
195    Delete(Position, Length),
196}
197
198impl Change {
199    pub fn invert(self, text: &Text) -> Self {
200        match self {
201            Self::Insert(position, text) => Change::Delete(position, text.length()),
202            Self::Delete(start, length) => Change::Insert(start, text.slice(start, length)),
203        }
204    }
205}
206
207#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
208pub struct Position {
209    pub line_index: usize,
210    pub byte_index: usize,
211}
212
213impl Position {
214    pub fn zero() -> Self {
215        Self::default()
216    }
217
218    pub fn apply_edit(self, edit: &Edit) -> Self {
219        match edit.change {
220            Change::Insert(point, ref text) => match self.cmp(&point) {
221                Ordering::Less => self,
222                Ordering::Equal => match edit.drift {
223                    Drift::Before => point + text.length() + (self - point),
224                    Drift::After => self,
225                },
226                Ordering::Greater => point + text.length() + (self - point),
227            },
228            Change::Delete(start, length) => {
229                let end = start + length;
230                if self < start {
231                    self
232                } else {
233                    start + (self - end.min(self))
234                }
235            }
236        }
237    }
238}
239
240impl Add<Length> for Position {
241    type Output = Self;
242
243    fn add(self, length: Length) -> Self::Output {
244        if length.line_count == 0 {
245            Self {
246                line_index: self.line_index,
247                byte_index: self.byte_index + length.byte_count,
248            }
249        } else {
250            Self {
251                line_index: self.line_index + length.line_count,
252                byte_index: length.byte_count,
253            }
254        }
255    }
256}
257
258impl AddAssign<Length> for Position {
259    fn add_assign(&mut self, length: Length) {
260        *self = *self + length;
261    }
262}
263
264impl Sub for Position {
265    type Output = Length;
266
267    fn sub(self, other: Self) -> Self::Output {
268        if self.line_index == other.line_index {
269            Length {
270                line_count: 0,
271                byte_count: self.byte_index - other.byte_index,
272            }
273        } else {
274            Length {
275                line_count: self.line_index - other.line_index,
276                byte_count: self.byte_index,
277            }
278        }
279    }
280}
281
282#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
283pub struct Length {
284    pub line_count: usize,
285    pub byte_count: usize,
286}
287
288impl Length {
289    pub fn zero() -> Length {
290        Self::default()
291    }
292}
293
294impl Add for Length {
295    type Output = Length;
296
297    fn add(self, other: Self) -> Self::Output {
298        if other.line_count == 0 {
299            Self {
300                line_count: self.line_count,
301                byte_count: self.byte_count + other.byte_count,
302            }
303        } else {
304            Self {
305                line_count: self.line_count + other.line_count,
306                byte_count: other.byte_count,
307            }
308        }
309    }
310}
311
312impl AddAssign for Length {
313    fn add_assign(&mut self, other: Self) {
314        *self = *self + other;
315    }
316}
317
318impl Sub for Length {
319    type Output = Length;
320
321    fn sub(self, other: Self) -> Self::Output {
322        if self.line_count == other.line_count {
323            Self {
324                line_count: 0,
325                byte_count: self.byte_count - other.byte_count,
326            }
327        } else {
328            Self {
329                line_count: self.line_count - other.line_count,
330                byte_count: self.byte_count,
331            }
332        }
333    }
334}
335
336impl SubAssign for Length {
337    fn sub_assign(&mut self, other: Self) {
338        *self = *self - other;
339    }
340}
341
342#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
343pub enum Drift {
344    Before,
345    After,
346}