makepad_code_editor/
document.rs

1use {
2    crate::{
3        char::CharExt,
4        decoration::{Decoration, DecorationSet},
5        history::{EditKind, History},
6        inlays::{BlockInlay, InlineInlay},
7        iter::IteratorExt,
8        selection::SelectionSet,
9        session::SessionId,
10        settings::Settings,
11        str::StrExt,
12        text::{Change, Drift, Edit, Length, Position, Text},
13        token::{Token, TokenKind},
14        tokenizer::Tokenizer,
15    },
16    std::{
17        cell::{Ref, RefCell},
18        cmp::Ordering,
19        collections::HashMap,
20        iter,
21        ops::Range,
22        rc::Rc,
23        sync::mpsc::Sender,
24    },
25};
26
27#[derive(Clone, Debug)]
28pub struct Document(Rc<DocumentInner>);
29
30impl Document {
31    pub fn new(text: Text, decorations:DecorationSet) -> Self {
32        let line_count = text.as_lines().len();
33        let tokens: Vec<_> = (0..line_count)
34            .map(|line| tokenize(&text.as_lines()[line]).collect::<Vec<_>>())
35            .collect();
36        let inner = Self(Rc::new(DocumentInner {
37            history: RefCell::new(History::from(text)),
38            layout: RefCell::new(DocumentLayout {
39                indent_state: (0..line_count).map(|_| None).collect(),
40                tokens,
41                inline_inlays: (0..line_count).map(|_| Vec::new()).collect(),
42                block_inlays: Vec::new(),
43            }),
44            tokenizer: RefCell::new(Tokenizer::new(line_count)),
45            decorations: RefCell::new(decorations),
46            edit_senders: RefCell::new(HashMap::new()),
47        }));
48        inner.update_indent_state();
49        inner.0.tokenizer.borrow_mut().update(
50            &inner.0.history.borrow().as_text(),
51            &mut inner.0.layout.borrow_mut().tokens,
52        );
53        inner
54    }
55
56    pub fn as_text(&self) -> Ref<'_, Text> {
57        Ref::map(self.0.history.borrow(), |history| history.as_text())
58    }
59
60    pub fn layout(&self) -> Ref<'_, DocumentLayout> {
61        self.0.layout.borrow()
62    }
63
64    pub fn decorations(&self) -> Ref<'_, [Decoration]> {
65        Ref::map(self.0.decorations.borrow(), |decorations| decorations.as_decorations())
66    }
67
68    pub fn edit_selections(
69        &self,
70        session_id: SessionId,
71        kind: EditKind,
72        selections: &SelectionSet,
73        settings: &Settings,
74        mut f: impl FnMut(Editor<'_>, Position, Length),
75    ) {
76        let mut history = self.0.history.borrow_mut();
77        history.push_or_extend_group(session_id, kind, selections);
78        let mut edits = Vec::new();
79        let mut line_ranges = Vec::new();
80        let mut prev_start = Position::zero();
81        let mut prev_adjusted_start = Position::zero();
82        let mut prev_edit_start = 0;
83        for &selection in selections {
84            let mut adjusted_start = prev_adjusted_start + (selection.start() - prev_start);
85            for edit in &edits[prev_edit_start..] {
86                adjusted_start = adjusted_start.apply_edit(edit);
87            }
88            let edit_start = edits.len();
89            f(
90                Editor {
91                    history: &mut *history,
92                    edits: &mut edits,
93                },
94                adjusted_start,
95                selection.length(),
96            );
97            for edit in &edits[edit_start..] {
98                match edit.change {
99                    Change::Insert(position, ref text) if text.as_lines().len() > 1 => {
100                        line_ranges.push(Range {
101                            start: if history.as_text().as_lines()[position.line_index]
102                                [..position.byte_index]
103                                .chars()
104                                .all(|char| char.is_whitespace())
105                            {
106                                position.line_index
107                            } else {
108                                position.line_index + 1
109                            },
110                            end: position.line_index + text.as_lines().len(),
111                        });
112                    }
113                    _ => {}
114                }
115            }
116            prev_start = selection.start();
117            prev_adjusted_start = adjusted_start;
118            prev_edit_start = edit_start;
119        }
120        drop(history);
121        self.autoindent(&line_ranges, settings.tab_column_count, &mut edits);
122        self.update_after_edit(session_id, None, &edits);
123    }
124
125    pub fn edit_linewise(
126        &self,
127        origin_id: SessionId,
128        kind: EditKind,
129        selections: &SelectionSet,
130        mut f: impl FnMut(Editor, usize),
131    ) {
132        let mut history = self.0.history.borrow_mut();
133        history.push_or_extend_group(origin_id, kind, selections);
134        let mut edits = Vec::new();
135        for line_range in selections
136            .iter()
137            .copied()
138            .map(|selection| selection.line_range())
139            .merge(|line_range_0, line_range_1| {
140                if line_range_0.end >= line_range_1.start {
141                    Ok(line_range_0.start..line_range_1.end)
142                } else {
143                    Err((line_range_0, line_range_1))
144                }
145            })
146        {
147            for line_index in line_range {
148                f(
149                    Editor {
150                        history: &mut *history,
151                        edits: &mut edits,
152                    },
153                    line_index,
154                );
155            }
156        }
157        drop(history);
158        self.update_after_edit(origin_id, None, &edits);
159    }
160
161    pub fn add_decoration(&mut self, decoration: Decoration) {
162        self.0.decorations.borrow_mut().add_decoration(decoration);
163    }
164
165    pub fn clear_decorations(&mut self) {
166        self.0.decorations.borrow_mut().clear()
167    }
168
169    pub fn add_session(
170        &mut self,
171        session_id: SessionId,
172        edit_sender: Sender<(Option<SelectionSet>, Vec<Edit>)>,
173    ) {
174        self.0
175            .edit_senders
176            .borrow_mut()
177            .insert(session_id, edit_sender);
178    }
179
180    pub fn remove_session(&mut self, session_id: SessionId) {
181        self.0.edit_senders.borrow_mut().remove(&session_id);
182    }
183
184    fn autoindent(
185        &self,
186        line_ranges: &[Range<usize>],
187        indent_column_count: usize,
188        edits: &mut Vec<Edit>,
189    ) {
190        fn next_line_indent_column_count(line: &str, tab_column_count: usize) -> Option<usize> {
191            if let Some(indent) = line.indent() {
192                let mut indent_column_count = indent.column_count();
193                if line
194                    .chars()
195                    .rev()
196                    .find_map(|char| {
197                        if char.is_opening_delimiter() {
198                            return Some(true);
199                        }
200                        if char.is_closing_delimiter() {
201                            return Some(false);
202                        }
203                        None
204                    })
205                    .unwrap_or(false)
206                {
207                    indent_column_count += tab_column_count;
208                };
209                Some(indent_column_count)
210            } else {
211                None
212            }
213        }
214
215        for line_range in line_ranges
216            .iter()
217            .cloned()
218            .merge(|line_range_0, line_range_1| {
219                if line_range_0.end >= line_range_1.start {
220                    Ok(line_range_0.start..line_range_1.end)
221                } else {
222                    Err((line_range_0, line_range_1))
223                }
224            })
225        {
226            let mut desired_indentation_column_count = self.as_text().as_lines()
227                [..line_range.start]
228                .iter()
229                .rev()
230                .find_map(|line| next_line_indent_column_count(line, indent_column_count))
231                .unwrap_or(0);
232            for line in line_range {
233                if self.as_text().as_lines()[line]
234                    .chars()
235                    .find_map(|char| {
236                        if char.is_closing_delimiter() {
237                            return Some(true);
238                        }
239                        if !char.is_whitespace() {
240                            return Some(false);
241                        }
242                        None
243                    })
244                    .unwrap_or(false)
245                {
246                    desired_indentation_column_count -= 4;
247                }
248                self.edit_lines_internal(line, edits, |line| {
249                    crate::session::reindent(line, |_| desired_indentation_column_count)
250                });
251                if let Some(next_line_indentation_column_count) = next_line_indent_column_count(
252                    &self.as_text().as_lines()[line],
253                    indent_column_count,
254                ) {
255                    desired_indentation_column_count = next_line_indentation_column_count;
256                }
257            }
258        }
259    }
260
261    fn edit_lines_internal(
262        &self,
263        line: usize,
264        edits: &mut Vec<Edit>,
265        mut f: impl FnMut(&str) -> (usize, usize, String),
266    ) {
267        let mut history = self.0.history.borrow_mut();
268        let (byte, delete_byte_count, insert_text) = f(&history.as_text().as_lines()[line]);
269        if delete_byte_count > 0 {
270            let edit = Edit {
271                change: Change::Delete(
272                    Position {
273                        line_index: line,
274                        byte_index: byte,
275                    },
276                    Length {
277                        line_count: 0,
278                        byte_count: delete_byte_count,
279                    },
280                ),
281                drift: Drift::Before,
282            };
283            edits.push(edit.clone());
284            history.apply_edit(edit);
285        }
286        if !insert_text.is_empty() {
287            let edit = Edit {
288                change: Change::Insert(
289                    Position {
290                        line_index: line,
291                        byte_index: byte,
292                    },
293                    insert_text.into(),
294                ),
295                drift: Drift::Before,
296            };
297            edits.push(edit.clone());
298            history.apply_edit(edit);
299        }
300    }
301
302    pub fn force_new_group(&mut self) {
303        self.0.history.borrow_mut().force_new_group()
304    }
305
306    pub fn undo(&mut self, origin_id: SessionId, selections: &SelectionSet) -> bool {
307        let mut changes = Vec::new();
308        let selections = self.0.history.borrow_mut().undo(selections, &mut changes);
309        if let Some(selections) = selections {
310            self.update_after_edit(origin_id, Some(selections), &changes);
311            true
312        } else {
313            false
314        }
315    }
316
317    pub fn redo(&mut self, origin_id: SessionId, selections: &SelectionSet) -> bool {
318        let mut changes = Vec::new();
319        let selections = self.0.history.borrow_mut().redo(selections, &mut changes);
320        if let Some(selections) = selections {
321            self.update_after_edit(origin_id, Some(selections), &changes);
322            true
323        } else {
324            false
325        }
326    }
327
328    fn update_after_edit(
329        &self,
330        origin_id: SessionId,
331        selections: Option<SelectionSet>,
332        edits: &[Edit],
333    ) {
334        let mut layout = self.0.layout.borrow_mut();
335        for edit in edits {
336            match edit.change {
337                Change::Insert(position, ref text) => {
338                    layout.indent_state[position.line_index] = None;
339                    let line_count = text.length().line_count;
340                    if line_count > 0 {
341                        let line_index = position.line_index + 1;
342                        layout
343                            .indent_state
344                            .splice(line_index..line_index, (0..line_count).map(|_| None));
345                    }
346                }
347                Change::Delete(start, length) => {
348                    layout.indent_state[start.line_index] = None;
349                    if length.line_count > 0 {
350                        let line_start = start.line_index + 1;
351                        let line_end = line_start + length.line_count;
352                        layout.indent_state.drain(line_start..line_end);
353                    }
354                }
355            }
356        }
357        drop(layout);
358        for edit in edits {
359            self.apply_change_to_tokens(&edit.change);
360            self.apply_change_to_inline_inlays(&edit.change, edit.drift);
361            self.0.tokenizer.borrow_mut().apply_change(&edit.change);
362        }
363        self.update_indent_state();
364        self.0.tokenizer.borrow_mut().update(
365            self.0.history.borrow().as_text(),
366            &mut self.0.layout.borrow_mut().tokens,
367        );
368        let mut decorations = self.0.decorations.borrow_mut();
369        for edit in edits {
370            decorations.apply_edit(edit);
371        }
372        drop(decorations);
373        for (&session_id, edit_sender) in &*self.0.edit_senders.borrow() {
374            if session_id == origin_id {
375                edit_sender
376                    .send((selections.clone(), edits.to_vec()))
377                    .unwrap();
378            } else {
379                edit_sender
380                    .send((
381                        None,
382                        edits
383                            .iter()
384                            .cloned()
385                            .map(|edit| Edit {
386                                change: edit.change,
387                                drift: Drift::Before,
388                            })
389                            .collect(),
390                    ))
391                    .unwrap();
392            }
393        }
394    }
395
396    fn apply_change_to_tokens(&self, change: &Change) {
397        let mut layout = self.0.layout.borrow_mut();
398        let tokens = &mut layout.tokens;
399        match *change {
400            Change::Insert(point, ref text) => {
401                let mut byte = 0;
402                let mut index = tokens[point.line_index]
403                    .iter()
404                    .position(|token| {
405                        if byte + token.len > point.byte_index {
406                            return true;
407                        }
408                        byte += token.len;
409                        false
410                    })
411                    .unwrap_or(tokens[point.line_index].len());
412                if byte != point.byte_index {
413                    let token = tokens[point.line_index][index];
414                    let mid = point.byte_index - byte;
415                    tokens[point.line_index][index] = Token {
416                        len: mid,
417                        kind: token.kind,
418                    };
419                    index += 1;
420                    tokens[point.line_index].insert(
421                        index,
422                        Token {
423                            len: token.len - mid,
424                            kind: token.kind,
425                        },
426                    );
427                }
428                if text.length().line_count == 0 {
429                    tokens[point.line_index]
430                        .splice(index..index, tokenize(text.as_lines().first().unwrap()));
431                } else {
432                    let mut new_tokens = (0..text.as_lines().len())
433                        .map(|line| tokenize(&text.as_lines()[line]).collect::<Vec<_>>())
434                        .collect::<Vec<_>>();
435                    new_tokens
436                        .first_mut()
437                        .unwrap()
438                        .splice(..0, tokens[point.line_index][..index].iter().copied());
439                    new_tokens
440                        .last_mut()
441                        .unwrap()
442                        .splice(..0, tokens[point.line_index][index..].iter().copied());
443                    tokens.splice(point.line_index..point.line_index + 1, new_tokens);
444                }
445            }
446            Change::Delete(start, length) => {
447                let end = start + length;
448                let mut byte = 0;
449                let mut start_token = tokens[start.line_index]
450                    .iter()
451                    .position(|token| {
452                        if byte + token.len > start.byte_index {
453                            return true;
454                        }
455                        byte += token.len;
456                        false
457                    })
458                    .unwrap_or(tokens[start.line_index].len());
459                if byte != start.byte_index {
460                    let token = tokens[start.line_index][start_token];
461                    let mid = start.byte_index - byte;
462                    tokens[start.line_index][start_token] = Token {
463                        len: mid,
464                        kind: token.kind,
465                    };
466                    start_token += 1;
467                    tokens[start.line_index].insert(
468                        start_token,
469                        Token {
470                            len: token.len - mid,
471                            kind: token.kind,
472                        },
473                    );
474                }
475                let mut byte = 0;
476                let mut end_token = tokens[end.line_index]
477                    .iter()
478                    .position(|token| {
479                        if byte + token.len > end.byte_index {
480                            return true;
481                        }
482                        byte += token.len;
483                        false
484                    })
485                    .unwrap_or(tokens[end.line_index].len());
486                if byte != end.byte_index {
487                    let token = tokens[end.line_index][end_token];
488                    let mid = end.byte_index - byte;
489                    tokens[end.line_index][end_token] = Token {
490                        len: mid,
491                        kind: token.kind,
492                    };
493                    end_token += 1;
494                    tokens[end.line_index].insert(
495                        end_token,
496                        Token {
497                            len: token.len - mid,
498                            kind: token.kind,
499                        },
500                    );
501                }
502                if length.line_count == 0 {
503                    tokens[start.line_index].drain(start_token..end_token);
504                } else {
505                    let mut new_tokens = tokens[start.line_index][..start_token]
506                        .iter()
507                        .copied()
508                        .collect::<Vec<_>>();
509                    new_tokens.extend(tokens[end.line_index][end_token..].iter().copied());
510                    tokens.splice(start.line_index..end.line_index + 1, iter::once(new_tokens));
511                }
512            }
513        }
514    }
515
516    fn apply_change_to_inline_inlays(&self, change: &Change, drift: Drift) {
517        let mut layout = self.0.layout.borrow_mut();
518        let inline_inlays = &mut layout.inline_inlays;
519        match *change {
520            Change::Insert(point, ref text) => {
521                let index = inline_inlays[point.line_index]
522                    .iter()
523                    .position(|(byte, _)| match byte.cmp(&point.byte_index) {
524                        Ordering::Less => false,
525                        Ordering::Equal => match drift {
526                            Drift::Before => true,
527                            Drift::After => false,
528                        },
529                        Ordering::Greater => true,
530                    })
531                    .unwrap_or(inline_inlays[point.line_index].len());
532                if text.length().line_count == 0 {
533                    for (byte, _) in &mut inline_inlays[point.line_index][index..] {
534                        *byte += text.length().byte_count;
535                    }
536                } else {
537                    let mut new_inline_inlays = (0..text.as_lines().len())
538                        .map(|_| Vec::new())
539                        .collect::<Vec<_>>();
540                    new_inline_inlays
541                        .first_mut()
542                        .unwrap()
543                        .splice(..0, inline_inlays[point.line_index].drain(..index));
544                    new_inline_inlays.last_mut().unwrap().splice(
545                        ..0,
546                        inline_inlays[point.line_index]
547                            .drain(..)
548                            .map(|(byte, inline_inlay)| {
549                                (byte + text.length().byte_count, inline_inlay)
550                            }),
551                    );
552                    inline_inlays.splice(point.line_index..point.line_index + 1, new_inline_inlays);
553                }
554            }
555            Change::Delete(start, length) => {
556                let end = start + length;
557                let start_inlay = inline_inlays[start.line_index]
558                    .iter()
559                    .position(|&(byte, _)| byte >= start.byte_index)
560                    .unwrap_or(inline_inlays[start.line_index].len());
561                let end_inlay = inline_inlays[end.line_index]
562                    .iter()
563                    .position(|&(byte, _)| byte >= end.byte_index)
564                    .unwrap_or(inline_inlays[end.line_index].len());
565                if length.line_count == 0 {
566                    inline_inlays[start.line_index].drain(start_inlay..end_inlay);
567                    for (byte, _) in &mut inline_inlays[start.line_index][start_inlay..] {
568                        *byte = start.byte_index + (*byte - end.byte_index.min(*byte));
569                    }
570                } else {
571                    let mut new_inline_inlays = inline_inlays[start.line_index]
572                        .drain(..start_inlay)
573                        .collect::<Vec<_>>();
574                    new_inline_inlays.extend(inline_inlays[end.line_index].drain(end_inlay..).map(
575                        |(byte, inline_inlay)| {
576                            (
577                                start.byte_index + byte - end.byte_index.min(byte),
578                                inline_inlay,
579                            )
580                        },
581                    ));
582                    inline_inlays.splice(
583                        start.line_index..end.line_index + 1,
584                        iter::once(new_inline_inlays),
585                    );
586                }
587            }
588        }
589    }
590
591    fn update_indent_state(&self) {
592        let mut layout = self.0.layout.borrow_mut();
593        let indent_state = &mut layout.indent_state;
594        let history = self.0.history.borrow();
595        let lines = history.as_text().as_lines();
596        let mut current_indent_column_count = 0;
597        for line_index in 0..lines.len() {
598            match indent_state[line_index] {
599                Some(IndentState::NonEmpty(_, next_indent_column_count)) => {
600                    current_indent_column_count = next_indent_column_count;
601                }
602                _ => {
603                    indent_state[line_index] = Some(match lines[line_index].indent() {
604                        Some(indent) => {
605                            let indent_column_count = indent.column_count();
606                            let mut next_indent_column_count = indent_column_count;
607                            if lines[line_index]
608                                .chars()
609                                .rev()
610                                .find_map(|char| {
611                                    if char.is_opening_delimiter() {
612                                        return Some(true);
613                                    }
614                                    if char.is_closing_delimiter() {
615                                        return Some(false);
616                                    }
617                                    None
618                                })
619                                .unwrap_or(false)
620                            {
621                                next_indent_column_count += 4;
622                            }
623                            current_indent_column_count = next_indent_column_count;
624                            IndentState::NonEmpty(indent_column_count, next_indent_column_count)
625                        }
626                        None => IndentState::Empty(current_indent_column_count),
627                    })
628                }
629            }
630        }
631    }
632}
633
634#[derive(Debug)]
635pub struct DocumentLayout {
636    pub indent_state: Vec<Option<IndentState>>,
637    pub tokens: Vec<Vec<Token>>,
638    pub inline_inlays: Vec<Vec<(usize, InlineInlay)>>,
639    pub block_inlays: Vec<(usize, BlockInlay)>,
640}
641
642#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
643pub enum IndentState {
644    Empty(usize),
645    NonEmpty(usize, usize),
646}
647
648#[derive(Debug)]
649pub struct Editor<'a> {
650    history: &'a mut History,
651    edits: &'a mut Vec<Edit>,
652}
653
654impl<'a> Editor<'a> {
655    pub fn as_text(&mut self) -> &Text {
656        self.history.as_text()
657    }
658
659    pub fn apply_edit(&mut self, edit: Edit) {
660        self.history.apply_edit(edit.clone());
661        self.edits.push(edit);
662    }
663}
664
665#[derive(Debug)]
666struct DocumentInner {
667    history: RefCell<History>,
668    layout: RefCell<DocumentLayout>,
669    tokenizer: RefCell<Tokenizer>,
670    decorations: RefCell<DecorationSet>,
671    edit_senders: RefCell<HashMap<SessionId, Sender<(Option<SelectionSet>, Vec<Edit>)>>>,
672}
673
674fn tokenize(text: &str) -> impl Iterator<Item = Token> + '_ {
675    text.split_whitespace_boundaries().map(|string| Token {
676        len: string.len(),
677        kind: if string.chars().next().unwrap().is_whitespace() {
678            TokenKind::Whitespace
679        } else {
680            TokenKind::Unknown
681        },
682    })
683}