makepad_code_editor/
session.rs

1use {
2    crate::{
3        char::CharExt,
4        document::Document,
5        history::EditKind,
6        layout::{BlockElement, Layout, WrappedElement},
7        selection::{Affinity, Cursor, SelectionSet},
8        str::StrExt,
9        text::{Change, Drift, Edit, Length, Position, Text},
10        wrap,
11        wrap::WrapData,
12        Selection, Settings,
13    },
14    std::{
15        cell::{Ref, RefCell},
16        collections::HashSet,
17        fmt::Write,
18        iter, mem,
19        rc::Rc,
20        sync::{atomic, atomic::AtomicUsize, mpsc, mpsc::Receiver},
21    },
22};
23
24#[derive(Debug)]
25pub struct Session {
26    id: SessionId,
27    settings: Rc<Settings>,
28    document: Document,
29    layout: RefCell<SessionLayout>,
30    selection_state: RefCell<SelectionState>,
31    wrap_column: Option<usize>,
32    folding_lines: HashSet<usize>,
33    folded_lines: HashSet<usize>,
34    unfolding_lines: HashSet<usize>,
35    edit_receiver: Receiver<(Option<SelectionSet>, Vec<Edit>)>,
36}
37
38impl Session {
39    pub fn new(document: Document) -> Self {
40        static ID: AtomicUsize = AtomicUsize::new(0);
41
42        let (edit_sender, edit_receiver) = mpsc::channel();
43        let line_count = document.as_text().as_lines().len();
44        let mut session = Self {
45            id: SessionId(ID.fetch_add(1, atomic::Ordering::AcqRel)),
46            settings: Rc::new(Settings::default()),
47            document,
48            layout: RefCell::new(SessionLayout {
49                y: Vec::new(),
50                column_count: (0..line_count).map(|_| None).collect(),
51                fold_column: (0..line_count).map(|_| 0).collect(),
52                scale: (0..line_count).map(|_| 1.0).collect(),
53                wrap_data: (0..line_count).map(|_| None).collect(),
54            }),
55            selection_state: RefCell::new(SelectionState {
56                selections: SelectionSet::new(),
57                last_added_selection_index: Some(0),
58                injected_char_stack: Vec::new(),
59                highlighted_delimiter_positions: HashSet::new(),
60            }),
61            wrap_column: None,
62            folding_lines: HashSet::new(),
63            folded_lines: HashSet::new(),
64            unfolding_lines: HashSet::new(),
65
66            edit_receiver,
67        };
68        for line in 0..line_count {
69            session.update_wrap_data(line);
70        }
71        session.update_y();
72        session.document.add_session(session.id, edit_sender);
73        session
74    }
75
76    pub fn id(&self) -> SessionId {
77        self.id
78    }
79
80    pub fn settings(&self) -> &Rc<Settings> {
81        &self.settings
82    }
83
84    pub fn document(&self) -> &Document {
85        &self.document
86    }
87
88    pub fn layout(&self) -> Layout<'_> {
89        Layout {
90            text: self.document.as_text(),
91            document_layout: self.document.layout(),
92            session_layout: self.layout.borrow(),
93        }
94    }
95
96    pub fn wrap_column(&self) -> Option<usize> {
97        self.wrap_column
98    }
99
100    pub fn selections(&self) -> Ref<'_, [Selection]> {
101        Ref::map(self.selection_state.borrow(), |selection_state| {
102            selection_state.selections.as_selections()
103        })
104    }
105
106    pub fn last_added_selection_index(&self) -> Option<usize> {
107        self.selection_state.borrow().last_added_selection_index
108    }
109
110    pub fn highlighted_delimiter_positions(&self) -> Ref<'_, HashSet<Position>> {
111        Ref::map(self.selection_state.borrow(), |selection_state| {
112            &selection_state.highlighted_delimiter_positions
113        })
114    }
115
116    pub fn set_wrap_column(&mut self, wrap_column: Option<usize>) {
117        if self.wrap_column == wrap_column {
118            return;
119        }
120        self.wrap_column = wrap_column;
121        let line_count = self.document.as_text().as_lines().len();
122        for line in 0..line_count {
123            self.update_wrap_data(line);
124        }
125        self.update_y();
126    }
127
128    pub fn fold(&mut self) {
129        let line_count = self.document().as_text().as_lines().len();
130        for line_index in 0..line_count {
131            let layout = self.layout();
132            let line = layout.line(line_index);
133            let indent_level = line.indent_column_count() / self.settings.tab_column_count;
134            drop(layout);
135            if indent_level >= self.settings.fold_level && !self.folded_lines.contains(&line_index) {
136                self.layout.borrow_mut().fold_column[line_index] =
137                    self.settings.fold_level * self.settings.tab_column_count;
138                self.unfolding_lines.remove(&line_index);
139                self.folding_lines.insert(line_index);
140            }
141        }
142    }
143
144    pub fn unfold(&mut self) {
145        for line in self.folding_lines.drain() {
146            self.unfolding_lines.insert(line);
147        }
148        for line in self.folded_lines.drain() {
149            self.unfolding_lines.insert(line);
150        }
151    }
152
153    pub fn update_folds(&mut self) -> bool {
154        if self.folding_lines.is_empty() && self.unfolding_lines.is_empty() {
155            return false;
156        }
157        let mut new_folding_lines = HashSet::new();
158        for &line in &self.folding_lines {
159            self.layout.borrow_mut().scale[line] *= 0.9;
160            if self.layout.borrow().scale[line] < 0.1 + 0.001 {
161                self.layout.borrow_mut().scale[line] = 0.1;
162                self.folded_lines.insert(line);
163            } else {
164                new_folding_lines.insert(line);
165            }
166            self.layout.borrow_mut().y.truncate(line + 1);
167        }
168        self.folding_lines = new_folding_lines;
169        let mut new_unfolding_lines = HashSet::new();
170        for &line in &self.unfolding_lines {
171            let scale = self.layout.borrow().scale[line];
172            self.layout.borrow_mut().scale[line] = 1.0 - 0.9 * (1.0 - scale);
173            if self.layout.borrow().scale[line] > 1.0 - 0.001 {
174                self.layout.borrow_mut().scale[line] = 1.0;
175            } else {
176                new_unfolding_lines.insert(line);
177            }
178            self.layout.borrow_mut().y.truncate(line + 1);
179        }
180        self.unfolding_lines = new_unfolding_lines;
181        self.update_y();
182        true
183    }
184
185    pub fn set_selection(&mut self, position: Position, affinity: Affinity, tap_count: u32) {
186        let mut selection= Selection::from(Cursor {
187            position,
188            affinity,
189            preferred_column_index: None,
190        });
191        if tap_count == 2 {
192            let text = self.document().as_text();
193            let lines = text.as_lines();
194            match lines[position.line_index][..position.byte_index].chars().next_back() {
195                Some(char) if char.is_opening_delimiter() => {
196                    let opening_delimiter_position = Position {
197                        line_index: position.line_index,
198                        byte_index: position.byte_index - char.len_utf8()
199                    };
200                    if let Some(closing_delimiter_position) = find_closing_delimiter(lines, position, char) {
201                        selection = Selection {
202                            cursor: Cursor::from(closing_delimiter_position),
203                            anchor: opening_delimiter_position,
204                        }
205                    }
206                }
207                _ => {}
208            }
209            drop(text);
210        };
211        let mut selection_state = self.selection_state.borrow_mut();
212        selection_state
213            .selections
214            .set_selection(selection);
215        selection_state.last_added_selection_index = Some(0);
216        selection_state.injected_char_stack.clear();
217        drop(selection_state);
218        self.update_highlighted_delimiter_positions();
219        self.document.force_new_group();
220    }
221
222    pub fn add_selection(&mut self, position: Position, affinity: Affinity, _tap_count: u32) {
223        let mut selection_state = self.selection_state.borrow_mut();
224        selection_state.last_added_selection_index = Some(
225            selection_state
226                .selections
227                .add_selection(Selection::from(Cursor {
228                    position,
229                    affinity,
230                    preferred_column_index: None,
231                })),
232        );
233        selection_state.injected_char_stack.clear();
234        drop(selection_state);
235        self.update_highlighted_delimiter_positions();
236        self.document.force_new_group();
237    }
238
239    pub fn move_to(&mut self, position: Position, affinity: Affinity) {
240        let mut selection_state = self.selection_state.borrow_mut();
241        let last_added_selection_index = selection_state.last_added_selection_index.unwrap();
242        selection_state.last_added_selection_index = Some(
243            selection_state
244                .selections
245                .update_selection(last_added_selection_index, |selection| {
246                    selection.update_cursor(|_| Cursor {
247                        position,
248                        affinity,
249                        preferred_column_index: None,
250                    })
251                }),
252        );
253        selection_state.injected_char_stack.clear();
254        drop(selection_state);
255        self.update_highlighted_delimiter_positions();
256        self.document.force_new_group();
257    }
258
259    pub fn move_left(&mut self, reset_anchor: bool) {
260        self.modify_selections(reset_anchor, |selection, layout| {
261            selection.update_cursor(|cursor| cursor.move_left(layout.as_text().as_lines()))
262        });
263    }
264
265    pub fn move_right(&mut self, reset_anchor: bool) {
266        self.modify_selections(reset_anchor, |selection, layout| {
267            selection.update_cursor(|cursor| cursor.move_right(layout.as_text().as_lines()))
268        });
269    }
270
271    pub fn move_up(&mut self, reset_anchor: bool) {
272        self.modify_selections(reset_anchor, |selection, layout| {
273            selection.update_cursor(|cursor| cursor.move_up(layout))
274        });
275    }
276
277    pub fn move_down(&mut self, reset_anchor: bool) {
278        self.modify_selections(reset_anchor, |selection, layout| {
279            selection.update_cursor(|cursor| cursor.move_down(layout))
280        });
281    }
282
283    pub fn insert(&mut self, text: Text) {
284        let mut edit_kind = EditKind::Insert;
285        let mut inject_char = None;
286        let mut uninject_char = None;
287        {}
288        if let Some(char) = text.to_single_char() {
289            let mut selection_state = self.selection_state.borrow_mut();
290            if char == ' ' {
291                edit_kind = EditKind::InsertSpace;
292            } else if char == '"' || char.is_opening_delimiter() {
293                if selection_state
294                    .selections
295                    .iter()
296                    .all(|selection| !selection.is_empty())
297                    || selection_state.selections.iter().all(|selection| {
298                        selection.is_empty()
299                            && match self.document.as_text().as_lines()
300                                [selection.cursor.position.line_index]
301                                [selection.cursor.position.byte_index..]
302                                .chars()
303                                .next()
304                            {
305                                Some(char) => {
306                                    char == '"'
307                                        || char.is_closing_delimiter()
308                                        || char.is_whitespace()
309                                }
310                                None => true,
311                            }
312                    })
313                {
314                    // We are inserting either a string or opening delimiter, and either all
315                    // selections are non-empty, or all selections are empty and followed by either
316                    // a string or closing delimiter or whitespace. In this case, we automatically
317                    // inject the corresponding string or closing delimiter.
318                    let opposite_char = if char == '"' {
319                        '"'
320                    } else {
321                        char.opposite_delimiter().unwrap()
322                    };
323                    inject_char = Some(opposite_char);
324                    selection_state.injected_char_stack.push(opposite_char);
325                }
326            } else if selection_state
327                .injected_char_stack
328                .last()
329                .map_or(false, |&last_char| last_char == char)
330            {
331                // We are inserting a single character that we automatically injected earlier, so we need
332                // to uninject it before inserting it again.
333                uninject_char = Some(selection_state.injected_char_stack.pop().unwrap());
334            }
335            drop(selection_state);
336        }
337        self.document.edit_selections(
338            self.id,
339            edit_kind,
340            &self.selection_state.borrow().selections,
341            &self.settings,
342            |mut editor, position, length| {
343                let mut position = position;
344                let mut length = length;
345                if inject_char.is_none() {
346                    // Only delete the selection if we are NOT injecting a character. This is for the
347                    // use case where we have selected `abc` and want to enclose it like: `{abc}`.
348                    editor.apply_edit(Edit {
349                        change: Change::Delete(position, length),
350                        drift: Drift::Before,
351                    });
352                    length = Length::zero();
353                }
354                if let Some(uninject_delimiter) = uninject_char {
355                    // To uninject a character, we simply delete it.
356                    editor.apply_edit(Edit {
357                        change: Change::Delete(
358                            position,
359                            Length {
360                                line_count: 0,
361                                byte_count: uninject_delimiter.len_utf8(),
362                            },
363                        ),
364                        drift: Drift::Before,
365                    })
366                }
367                editor.apply_edit(Edit {
368                    change: Change::Insert(position, text.clone()),
369                    drift: Drift::Before,
370                });
371                position += text.length();
372                if let Some(inject_delimiter) = inject_char {
373                    // To inject a character, we do an extra insert with Drift::After so that the
374                    // cursor stays in place. Note that we have to add the selected length to our
375                    // position, because the selection is only deleted if we are NOT injecting a
376                    // character. This is for the use case where we have selected `abc` and want
377                    // to enclose it like: `{abc}`.
378                    editor.apply_edit(Edit {
379                        change: Change::Insert(position + length, Text::from(inject_delimiter)),
380                        drift: Drift::After,
381                    })
382                }
383            },
384        );
385    }
386
387    pub fn enter(&mut self) {
388        self.selection_state
389            .borrow_mut()
390            .injected_char_stack
391            .clear();
392        self.document.edit_selections(
393            self.id,
394            EditKind::Other,
395            &self.selection_state.borrow().selections,
396            &self.settings,
397            |mut editor, position, length| {
398                let line = &editor.as_text().as_lines()[position.line_index];
399                let delete_whitespace = !line.is_empty()
400                    && line[..position.byte_index]
401                        .chars()
402                        .all(|char| char.is_whitespace());
403                let inject_newline = line[..position.byte_index]
404                    .chars()
405                    .rev()
406                    .find_map(|char| {
407                        if char.is_opening_delimiter() {
408                            return Some(true);
409                        }
410                        if char.is_closing_delimiter() {
411                            return Some(false);
412                        }
413                        None
414                    })
415                    .unwrap_or(false)
416                    && line[position.byte_index..]
417                        .chars()
418                        .find_map(|char| {
419                            if char.is_closing_delimiter() {
420                                return Some(true);
421                            }
422                            if !char.is_whitespace() {
423                                return Some(false);
424                            }
425                            None
426                        })
427                        .unwrap_or(false);
428                let mut position = position;
429                if delete_whitespace {
430                    editor.apply_edit(Edit {
431                        change: Change::Delete(
432                            Position {
433                                line_index: position.line_index,
434                                byte_index: 0,
435                            },
436                            Length {
437                                line_count: 0,
438                                byte_count: position.byte_index,
439                            },
440                        ),
441                        drift: Drift::Before,
442                    });
443                    position.byte_index = 0;
444                }
445                editor.apply_edit(Edit {
446                    change: Change::Delete(position, length),
447                    drift: Drift::Before,
448                });
449                editor.apply_edit(Edit {
450                    change: Change::Insert(position, Text::newline()),
451                    drift: Drift::Before,
452                });
453                position.line_index += 1;
454                position.byte_index = 0;
455                if inject_newline {
456                    editor.apply_edit(Edit {
457                        change: Change::Insert(position, Text::newline()),
458                        drift: Drift::After,
459                    });
460                }
461            },
462        );
463    }
464
465    pub fn delete(&mut self) {
466        self.selection_state
467            .borrow_mut()
468            .injected_char_stack
469            .clear();
470        self.document.edit_selections(
471            self.id,
472            EditKind::Delete,
473            &self.selection_state.borrow().selections,
474            &self.settings,
475            |mut editor, position, length| {
476                if length == Length::zero() {
477                    // The selection is empty, so delete forward.
478                    let lines = editor.as_text().as_lines();
479                    if lines[position.line_index][position.byte_index..]
480                        .chars()
481                        .all(|char| char.is_whitespace())
482                    {
483                        // There are only whitespace characters after the cursor on this line, so
484                        // delete forward until either the first non-whitespace character on the
485                        // next line, if it exists, or otherwise until the end of the text.
486                        if position.line_index < lines.len() - 1 {
487                            // There is a next line, so delete until the first non-whitespace
488                            // character on the next line.
489                            let byte_count = lines[position.line_index + 1]
490                                .chars()
491                                .take_while(|char| char.is_whitespace())
492                                .map(|char| char.len_utf8())
493                                .sum::<usize>();
494                            editor.apply_edit(Edit {
495                                change: Change::Delete(
496                                    position,
497                                    Length {
498                                        line_count: 1,
499                                        byte_count,
500                                    },
501                                ),
502                                drift: Drift::Before,
503                            });
504                        } else {
505                            // There is no next line, so delete forward until the start of the
506                            // text.
507                            let byte_count = lines[position.line_index].len() - position.byte_index;
508                            editor.apply_edit(Edit {
509                                change: Change::Delete(
510                                    position,
511                                    Length {
512                                        line_count: 0,
513                                        byte_count,
514                                    },
515                                ),
516                                drift: Drift::Before,
517                            });
518                        }
519                    } else {
520                        // There is at least one non-whitespace character before the cursor on the
521                        // current line, so delete forward by a single grapheme.
522                        let byte_count =
523                            lines[position.line_index].graphemes().next().unwrap().len();
524                        editor.apply_edit(Edit {
525                            change: Change::Delete(
526                                position,
527                                Length {
528                                    line_count: 0,
529                                    byte_count,
530                                },
531                            ),
532                            drift: Drift::Before,
533                        });
534                    }
535                } else {
536                    // The selection is non-empty, so delete it.
537                    editor.apply_edit(Edit {
538                        change: Change::Delete(position, length),
539                        drift: Drift::Before,
540                    });
541                }
542            },
543        );
544    }
545
546    pub fn backspace(&mut self) {
547        self.selection_state
548            .borrow_mut()
549            .injected_char_stack
550            .clear();
551        self.document.edit_selections(
552            self.id,
553            EditKind::Delete,
554            &self.selection_state.borrow().selections,
555            &self.settings,
556            |mut editor, position, length| {
557                if length == Length::zero() {
558                    // The selection is empty, so delete backwards.
559                    let lines = editor.as_text().as_lines();
560                    if lines[position.line_index][..position.byte_index]
561                        .chars()
562                        .all(|char| char.is_whitespace())
563                    {
564                        // There are only whitespace characters before the cursor on this line, so
565                        // delete backwards until either the first non-whitespace character on the
566                        // previous line, if it exists, or otherwise until the start of the text.
567                        if position.line_index > 0 {
568                            // There is a previous line, so delete until the first non-whitespace
569                            // character on the previous line.
570                            let byte_count = lines[position.line_index - 1]
571                                .chars()
572                                .rev()
573                                .take_while(|char| char.is_whitespace())
574                                .map(|char| char.len_utf8())
575                                .sum::<usize>();
576                            let byte_index = lines[position.line_index - 1].len() - byte_count;
577                            if byte_index == 0 {
578                                // The previous line is empty, so keep the indentation on the
579                                // current line.
580                                editor.apply_edit(Edit {
581                                    change: Change::Delete(
582                                        Position {
583                                            line_index: position.line_index - 1,
584                                            byte_index,
585                                        },
586                                        Length {
587                                            line_count: 1,
588                                            byte_count: 0,
589                                        },
590                                    ),
591                                    drift: Drift::Before,
592                                });
593                            } else {
594                                // The previous line is non-empty, so don't keep the indentation on
595                                // the current line.
596                                editor.apply_edit(Edit {
597                                    change: Change::Delete(
598                                        Position {
599                                            line_index: position.line_index - 1,
600                                            byte_index,
601                                        },
602                                        Length {
603                                            line_count: 1,
604                                            byte_count: position.byte_index,
605                                        },
606                                    ),
607                                    drift: Drift::Before,
608                                });
609                            }
610                        } else {
611                            // There is no previous line, so delete backwards until the start of the
612                            // text.
613                            editor.apply_edit(Edit {
614                                change: Change::Delete(
615                                    Position::zero(),
616                                    Length {
617                                        line_count: 0,
618                                        byte_count: position.byte_index,
619                                    },
620                                ),
621                                drift: Drift::Before,
622                            });
623                        }
624                    } else {
625                        // There is at least one non-whitespace character before the cursor on the
626                        // current line, so delete backwards by a single grapheme.
627                        let byte_count = lines[position.line_index]
628                            .graphemes()
629                            .next_back()
630                            .unwrap()
631                            .len();
632                        editor.apply_edit(Edit {
633                            change: Change::Delete(
634                                Position {
635                                    line_index: position.line_index,
636                                    byte_index: position.byte_index - byte_count,
637                                },
638                                Length {
639                                    line_count: 0,
640                                    byte_count,
641                                },
642                            ),
643                            drift: Drift::Before,
644                        });
645                    }
646                } else {
647                    // The selection is non-empty, so delete it.
648                    editor.apply_edit(Edit {
649                        change: Change::Delete(position, length),
650                        drift: Drift::Before,
651                    });
652                }
653            },
654        );
655    }
656
657    pub fn indent(&mut self) {
658        self.document.edit_linewise(
659            self.id,
660            EditKind::Other,
661            &self.selection_state.borrow().selections,
662            |mut editor, line_index| {
663                let indent_column_count = editor.as_text().as_lines()[line_index]
664                    .indent()
665                    .unwrap_or("")
666                    .len();
667                let column_count = self.settings.tab_column_count
668                    - indent_column_count % self.settings.tab_column_count;
669                editor.apply_edit(Edit {
670                    change: Change::Insert(
671                        Position {
672                            line_index,
673                            byte_index: indent_column_count,
674                        },
675                        iter::repeat(' ').take(column_count).collect(),
676                    ),
677                    drift: Drift::Before,
678                });
679            },
680        );
681    }
682
683    pub fn outdent(&mut self) {
684        self.document.edit_linewise(
685            self.id,
686            EditKind::Other,
687            &self.selection_state.borrow().selections,
688            |mut editor, line_index| {
689                let indent_column_count = editor.as_text().as_lines()[line_index]
690                    .indent()
691                    .unwrap_or("")
692                    .len();
693                let column_count = indent_column_count.min(
694                    (indent_column_count + self.settings.tab_column_count - 1)
695                        % self.settings.tab_column_count
696                        + 1,
697                );
698                editor.apply_edit(Edit {
699                    change: Change::Delete(
700                        Position {
701                            line_index,
702                            byte_index: indent_column_count - column_count,
703                        },
704                        Length {
705                            line_count: 0,
706                            byte_count: column_count,
707                        },
708                    ),
709                    drift: Drift::Before,
710                });
711            },
712        );
713    }
714
715    pub fn copy(&self) -> String {
716        let mut string = String::new();
717        for selection in &self.selection_state.borrow().selections {
718            write!(
719                &mut string,
720                "{}",
721                self.document
722                    .as_text()
723                    .slice(selection.start(), selection.length())
724            )
725            .unwrap();
726        }
727        string
728    }
729
730    pub fn undo(&mut self) -> bool {
731        self.selection_state.borrow_mut().injected_char_stack.clear();
732        self.document
733            .undo(self.id, &self.selection_state.borrow().selections)
734    }
735
736    pub fn redo(&mut self) -> bool {
737        self.selection_state.borrow_mut().injected_char_stack.clear();
738        self.document
739            .redo(self.id, &self.selection_state.borrow().selections)
740    }
741
742    pub fn handle_changes(&mut self) {
743        while let Ok((selections, edits)) = self.edit_receiver.try_recv() {
744            self.update_after_edit(selections, &edits);
745        }
746    }
747
748    fn modify_selections(
749        &mut self,
750        reset_anchor: bool,
751        mut f: impl FnMut(Selection, &Layout) -> Selection,
752    ) {
753        let layout = Layout {
754            text: self.document.as_text(),
755            document_layout: self.document.layout(),
756            session_layout: self.layout.borrow(),
757        };
758        let mut selection_state = self.selection_state.borrow_mut();
759        let last_added_selection_index = selection_state.last_added_selection_index;
760        selection_state.last_added_selection_index = selection_state
761            .selections
762            .update_all_selections(last_added_selection_index, |selection| {
763                let mut selection = f(selection, &layout);
764                if reset_anchor {
765                    selection = selection.reset_anchor();
766                }
767                selection
768            });
769        selection_state.injected_char_stack.clear();
770        drop(selection_state);
771        drop(layout);
772        self.update_highlighted_delimiter_positions();
773        self.document.force_new_group();
774    }
775
776    fn update_after_edit(&self, selections: Option<SelectionSet>, edits: &[Edit]) {
777        for edit in edits {
778            match edit.change {
779                Change::Insert(point, ref text) => {
780                    self.layout.borrow_mut().column_count[point.line_index] = None;
781                    self.layout.borrow_mut().wrap_data[point.line_index] = None;
782                    let line_count = text.length().line_count;
783                    if line_count > 0 {
784                        let line = point.line_index + 1;
785                        self.layout.borrow_mut().y.truncate(line);
786                        self.layout
787                            .borrow_mut()
788                            .column_count
789                            .splice(line..line, (0..line_count).map(|_| None));
790                        self.layout
791                            .borrow_mut()
792                            .fold_column
793                            .splice(line..line, (0..line_count).map(|_| 0));
794                        self.layout
795                            .borrow_mut()
796                            .scale
797                            .splice(line..line, (0..line_count).map(|_| 1.0));
798                        self.layout
799                            .borrow_mut()
800                            .wrap_data
801                            .splice(line..line, (0..line_count).map(|_| None));
802                    }
803                }
804                Change::Delete(start, length) => {
805                    self.layout.borrow_mut().column_count[start.line_index] = None;
806                    self.layout.borrow_mut().wrap_data[start.line_index] = None;
807                    let line_count = length.line_count;
808                    if line_count > 0 {
809                        let start_line = start.line_index + 1;
810                        let end_line = start_line + line_count;
811                        self.layout.borrow_mut().y.truncate(start_line);
812                        self.layout
813                            .borrow_mut()
814                            .column_count
815                            .drain(start_line..end_line);
816                        self.layout
817                            .borrow_mut()
818                            .fold_column
819                            .drain(start_line..end_line);
820                        self.layout.borrow_mut().scale.drain(start_line..end_line);
821                        self.layout
822                            .borrow_mut()
823                            .wrap_data
824                            .drain(start_line..end_line);
825                    }
826                }
827            }
828        }
829        let line_count = self.document.as_text().as_lines().len();
830        for line in 0..line_count {
831            if self.layout.borrow().wrap_data[line].is_none() {
832                self.update_wrap_data(line);
833            }
834        }
835        self.update_y();
836        let mut selection_state = self.selection_state.borrow_mut();
837        if let Some(selections) = selections {
838            selection_state.selections = selections;
839        } else {
840            for edit in edits {
841                selection_state.selections.apply_edit(edit);
842            }
843        }
844        drop(selection_state);
845        self.update_highlighted_delimiter_positions();
846    }
847
848    fn update_y(&self) {
849        let start = self.layout.borrow().y.len();
850        let end = self.document.as_text().as_lines().len();
851        if start == end + 1 {
852            return;
853        }
854        let mut y = if start == 0 {
855            0.0
856        } else {
857            let layout = self.layout();
858            let line = layout.line(start - 1);
859            line.y() + line.height()
860        };
861        let mut ys = mem::take(&mut self.layout.borrow_mut().y);
862        for block in self.layout().block_elements(start, end) {
863            match block {
864                BlockElement::Line { is_inlay, line } => {
865                    if !is_inlay {
866                        ys.push(y);
867                    }
868                    y += line.height();
869                }
870                BlockElement::Widget(widget) => {
871                    y += widget.height;
872                }
873            }
874        }
875        ys.push(y);
876        self.layout.borrow_mut().y = ys;
877    }
878
879    fn update_column_count(&self, index: usize) {
880        let mut column_count = 0;
881        let mut column = 0;
882        let layout = self.layout();
883        let line = layout.line(index);
884        for wrapped in line.wrapped_elements() {
885            match wrapped {
886                WrappedElement::Text { text, .. } => {
887                    column += text.column_count();
888                }
889                WrappedElement::Widget(widget) => {
890                    column += widget.column_count;
891                }
892                WrappedElement::Wrap => {
893                    column_count = column_count.max(column);
894                    column = line.wrap_indent_column_count();
895                }
896            }
897        }
898        drop(layout);
899        self.layout.borrow_mut().column_count[index] = Some(column_count.max(column));
900    }
901
902    fn update_wrap_data(&self, line: usize) {
903        let wrap_data = match self.wrap_column {
904            Some(wrap_column) => {
905                let layout = self.layout();
906                let line = layout.line(line);
907                wrap::compute_wrap_data(line, wrap_column)
908            }
909            None => WrapData::default(),
910        };
911        self.layout.borrow_mut().wrap_data[line] = Some(wrap_data);
912        self.layout.borrow_mut().y.truncate(line + 1);
913        self.update_column_count(line);
914    }
915
916    fn update_highlighted_delimiter_positions(&self) {
917        let mut selection_state = self.selection_state.borrow_mut();
918        let mut highlighted_delimiter_positions =
919            mem::take(&mut selection_state.highlighted_delimiter_positions);
920        highlighted_delimiter_positions.clear();
921        for selection in &selection_state.selections {
922            if !selection.is_empty() {
923                continue;
924            }
925            if let Some((opening_delimiter_position, closing_delimiter_position)) =
926                find_highlighted_delimiter_pair(
927                    self.document.as_text().as_lines(),
928                    selection.cursor.position,
929                )
930            {
931                highlighted_delimiter_positions.insert(opening_delimiter_position);
932                highlighted_delimiter_positions.insert(closing_delimiter_position);
933            }
934        }
935        selection_state.highlighted_delimiter_positions = highlighted_delimiter_positions;
936    }
937}
938
939impl Drop for Session {
940    fn drop(&mut self) {
941        self.document.remove_session(self.id);
942    }
943}
944
945#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
946pub struct SessionId(usize);
947
948#[derive(Debug)]
949pub struct SessionLayout {
950    pub y: Vec<f64>,
951    pub column_count: Vec<Option<usize>>,
952    pub fold_column: Vec<usize>,
953    pub scale: Vec<f64>,
954    pub wrap_data: Vec<Option<WrapData>>,
955}
956
957#[derive(Debug)]
958struct SelectionState {
959    selections: SelectionSet,
960    last_added_selection_index: Option<usize>,
961    injected_char_stack: Vec<char>,
962    highlighted_delimiter_positions: HashSet<Position>,
963}
964
965pub fn reindent(string: &str, f: impl FnOnce(usize) -> usize) -> (usize, usize, String) {
966    let indentation = string.indent().unwrap_or("");
967    let indentation_column_count = indentation.column_count();
968    let new_indentation_column_count = f(indentation_column_count);
969    let new_indentation = new_indentation(new_indentation_column_count);
970    let len = indentation.longest_common_prefix(&new_indentation).len();
971    (
972        len,
973        indentation.len() - len.min(indentation.len()),
974        new_indentation[len..].to_owned(),
975    )
976}
977
978fn new_indentation(column_count: usize) -> String {
979    iter::repeat(' ').take(column_count).collect()
980}
981
982fn find_highlighted_delimiter_pair(
983    lines: &[String],
984    position: Position,
985) -> Option<(Position, Position)> {
986    // Cursor is before an opening delimiter
987    match lines[position.line_index][position.byte_index..]
988        .chars()
989        .next()
990    {
991        Some(ch) if ch.is_opening_delimiter() => {
992            let opening_delimiter_position = position;
993            if let Some(closing_delimiter_position) = find_closing_delimiter(
994                lines,
995                Position {
996                    line_index: position.line_index,
997                    byte_index: position.byte_index + ch.len_utf8(),
998                },
999                ch,
1000            ) {
1001                return Some((opening_delimiter_position, closing_delimiter_position));
1002            }
1003        }
1004        _ => {}
1005    }
1006    // Cursor is before a closing delimiter
1007    match lines[position.line_index][position.byte_index..]
1008        .chars()
1009        .next()
1010    {
1011        Some(ch) if ch.is_closing_delimiter() => {
1012            let closing_delimiter_position = position;
1013            if let Some(opening_delimiter_position) = find_opening_delimiter(lines, position, ch) {
1014                return Some((opening_delimiter_position, closing_delimiter_position));
1015            }
1016        }
1017        _ => {}
1018    }
1019    // Cursor is after a closing delimiter
1020    match lines[position.line_index][..position.byte_index]
1021        .chars()
1022        .next_back()
1023    {
1024        Some(ch) if ch.is_closing_delimiter() => {
1025            let closing_delimiter_position = Position {
1026                line_index: position.line_index,
1027                byte_index: position.byte_index - ch.len_utf8(),
1028            };
1029            if let Some(opening_delimiter_position) =
1030                find_opening_delimiter(lines, closing_delimiter_position, ch)
1031            {
1032                return Some((opening_delimiter_position, closing_delimiter_position));
1033            }
1034        }
1035        _ => {}
1036    }
1037    // Cursor is after an opening delimiter
1038    match lines[position.line_index][..position.byte_index]
1039        .chars()
1040        .next_back()
1041    {
1042        Some(ch) if ch.is_opening_delimiter() => {
1043            let opening_delimiter_position = Position {
1044                line_index: position.line_index,
1045                byte_index: position.byte_index - ch.len_utf8(),
1046            };
1047            if let Some(closing_delimiter_position) = find_closing_delimiter(lines, position, ch) {
1048                return Some((opening_delimiter_position, closing_delimiter_position));
1049            }
1050        }
1051        _ => {}
1052    }
1053    None
1054}
1055
1056fn find_opening_delimiter(
1057    lines: &[String],
1058    position: Position,
1059    closing_delimiter: char,
1060) -> Option<Position> {
1061    let mut delimiter_stack = vec![closing_delimiter];
1062    let mut position = position;
1063    loop {
1064        for char in lines[position.line_index][..position.byte_index]
1065            .chars()
1066            .rev()
1067        {
1068            position.byte_index -= char.len_utf8();
1069            if char.is_closing_delimiter() {
1070                delimiter_stack.push(char);
1071            }
1072            if char.is_opening_delimiter() {
1073                if delimiter_stack.last() != Some(&char.opposite_delimiter().unwrap()) {
1074                    return None;
1075                }
1076                delimiter_stack.pop().unwrap();
1077                if delimiter_stack.is_empty() {
1078                    return Some(position);
1079                }
1080            }
1081        }
1082        if position.line_index == 0 {
1083            return None;
1084        }
1085        position.line_index -= 1;
1086        position.byte_index = lines[position.line_index].len();
1087    }
1088}
1089
1090fn find_closing_delimiter(
1091    lines: &[String],
1092    position: Position,
1093    opening_delimiter: char,
1094) -> Option<Position> {
1095    let mut delimiter_stack = vec![opening_delimiter];
1096    let mut position = position;
1097    loop {
1098        for char in lines[position.line_index][position.byte_index..].chars() {
1099            if char.is_opening_delimiter() {
1100                delimiter_stack.push(char);
1101            }
1102            if char.is_closing_delimiter() {
1103                if delimiter_stack.last() != Some(&char.opposite_delimiter().unwrap()) {
1104                    return None;
1105                }
1106                delimiter_stack.pop().unwrap();
1107                if delimiter_stack.is_empty() {
1108                    return Some(position);
1109                }
1110            }
1111            position.byte_index += char.len_utf8();
1112        }
1113        if position.line_index == lines.len() - 1 {
1114            return None;
1115        }
1116        position.line_index += 1;
1117        position.byte_index = 0;
1118    }
1119}