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