makepad_code_editor/
session.rs

1use {
2    crate::{
3        char::CharExt,
4        document::CodeDocument,
5        history::{EditKind,NewGroup},
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::{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 CodeSession {
26    id: SessionId,
27    settings: Rc<Settings>,
28    document: CodeDocument,
29    layout: RefCell<SessionLayout>,
30    selection_state: RefCell<SelectionState>,
31    wrap_column: Cell<Option<usize>>,
32    fold_state: RefCell<FoldState>,
33    edit_receiver: Receiver<(Option<SelectionSet>, Vec<Edit>)>,
34}
35
36impl CodeSession {
37    pub fn new(document: CodeDocument) -> Self {
38        static ID: AtomicUsize = AtomicUsize::new(0);
39
40        let (edit_sender, edit_receiver) = mpsc::channel();
41        let line_count = document.as_text().as_lines().len();
42        let mut session = Self {
43            id: SessionId(ID.fetch_add(1, atomic::Ordering::AcqRel)),
44            settings: Rc::new(Settings::default()),
45            document,
46            layout: RefCell::new(SessionLayout {
47                y: Vec::new(),
48                column_count: (0..line_count).map(|_| None).collect(),
49                fold_column: (0..line_count).map(|_| 0).collect(),
50                scale: (0..line_count).map(|_| 1.0).collect(),
51                wrap_data: (0..line_count).map(|_| None).collect(),
52            }),
53            selection_state: RefCell::new(SelectionState {
54                mode: SelectionMode::Simple,
55                selections: SelectionSet::new(),
56                last_added_selection_index: Some(0),
57                injected_char_stack: Vec::new(),
58                highlighted_delimiter_positions: HashSet::new(),
59            }),
60            wrap_column: Cell::new(None),
61            fold_state: RefCell::new(FoldState {
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) -> &CodeDocument {
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.get()
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(&self, wrap_column: Option<usize>) {
117        if self.wrap_column.get() == wrap_column {
118            return;
119        }
120        self.wrap_column.set(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(&self) {
129        let mut fold_state = self.fold_state.borrow_mut();
130        let line_count = self.document().as_text().as_lines().len();
131        for line_index in 0..line_count {
132            let layout = self.layout();
133            let line = layout.line(line_index);
134            let indent_level = line.indent_column_count() / self.settings.tab_column_count;
135            drop(layout);
136            if indent_level >= self.settings.fold_level
137                && !fold_state.folded_lines.contains(&line_index)
138            {
139                self.layout.borrow_mut().fold_column[line_index] =
140                    self.settings.fold_level * self.settings.tab_column_count;
141                fold_state.unfolding_lines.remove(&line_index);
142                fold_state.folding_lines.insert(line_index);
143            }
144        }
145    }
146
147    pub fn unfold(&self) {
148        let fold_state = &mut *self.fold_state.borrow_mut();
149        for line in fold_state.folding_lines.drain() {
150            fold_state.unfolding_lines.insert(line);
151        }
152        for line in fold_state.folded_lines.drain() {
153            fold_state.unfolding_lines.insert(line);
154        }
155    }
156
157    pub fn update_folds(&self) -> bool {
158        let mut fold_state_ref = self.fold_state.borrow_mut();
159        if fold_state_ref.folding_lines.is_empty() && fold_state_ref.unfolding_lines.is_empty() {
160            return false;
161        }
162        let mut layout = self.layout.borrow_mut();
163        let mut new_folding_lines = HashSet::new();
164        let fold_state = &mut *fold_state_ref;
165        for &line in &fold_state.folding_lines {
166            if let Some(scale) = layout.scale.get_mut(line){
167                *scale *= 0.9;
168                if *scale < 0.1 + 0.001 {
169                    *scale = 0.1;
170                    fold_state.folded_lines.insert(line);
171                } else {
172                    new_folding_lines.insert(line);
173                }
174                layout.y.truncate(line + 1);
175            }
176        }
177        fold_state.folding_lines = new_folding_lines;
178        let mut new_unfolding_lines = HashSet::new();
179        for &line in &fold_state_ref.unfolding_lines {
180            if let Some(scale) = layout.scale.get_mut(line){
181                *scale = 1.0 - 0.9 * (1.0 - *scale);
182                if *scale > 1.0 - 0.001 {
183                    *scale = 1.0;
184                } else {
185                    new_unfolding_lines.insert(line);
186                }
187                layout.y.truncate(line + 1);
188            }
189        }
190        fold_state_ref.unfolding_lines = new_unfolding_lines;
191        drop(layout);
192        drop(fold_state_ref);
193        self.update_y();
194        true
195    }
196
197    pub fn set_selection(&self, position: Position, affinity: Affinity, mode: SelectionMode, new_group:NewGroup) {
198        let position = self.clamp_position(position);
199        let selection = grow_selection(
200            Selection::from(Cursor {
201                position,
202                affinity,
203                preferred_column_index: None,
204            }),
205            self.document().as_text().as_lines(),
206            mode,
207            &self.settings.word_separators,
208        );
209        let mut selection_state = self.selection_state.borrow_mut();
210        selection_state.mode = mode;
211        selection_state.selections.set_selection(selection);
212        selection_state.last_added_selection_index = Some(0);
213        selection_state.injected_char_stack.clear();
214        drop(selection_state);
215        self.update_highlighted_delimiter_positions();
216        if let NewGroup::Yes = new_group{
217            self.document().force_new_group();
218        }
219    }
220    
221    
222    pub fn clamp_position(&self, mut position: Position) -> Position {
223        let text = self.document().as_text();
224        let lines = text.as_lines();
225        if position.line_index >= lines.len() {
226            position.line_index = lines.len().saturating_sub(1);
227            position.byte_index = lines[position.line_index].len();
228        } else {
229            let line_len = lines[position.line_index].len();
230            if position.byte_index > line_len {
231                position.byte_index = line_len;
232            }
233        }
234        position
235    }
236
237    pub fn add_selection(&self, position: Position, affinity: Affinity, mode: SelectionMode) {
238        let selection = grow_selection(
239            Selection::from(Cursor {
240                position,
241                affinity,
242                preferred_column_index: None,
243            }),
244            self.document().as_text().as_lines(),
245            mode,
246            &self.settings.word_separators,
247        );
248        let mut selection_state = self.selection_state.borrow_mut();
249        selection_state.mode = mode;
250        selection_state.last_added_selection_index =
251            Some(selection_state.selections.add_selection(selection));
252        selection_state.injected_char_stack.clear();
253        drop(selection_state);
254        self.update_highlighted_delimiter_positions();
255        self.document().force_new_group();
256    }
257
258    pub fn move_to(&self, position: Position, affinity: Affinity, new_group:NewGroup) {
259        let mut selection_state = self.selection_state.borrow_mut();
260        let last_added_selection_index = selection_state.last_added_selection_index.unwrap();
261        let mode = selection_state.mode;
262        selection_state.last_added_selection_index = Some(
263            selection_state
264                .selections
265                .update_selection(last_added_selection_index, |selection| {
266                    grow_selection(
267                        selection.update_cursor(|_| Cursor {
268                            position,
269                            affinity,
270                            preferred_column_index: None,
271                        }),
272                        self.document.as_text().as_lines(),
273                        mode,
274                        &self.settings.word_separators,
275                    )
276                }),
277        );
278        selection_state.injected_char_stack.clear();
279        drop(selection_state);
280        self.update_highlighted_delimiter_positions();
281        if let NewGroup::Yes = new_group{
282            self.document().force_new_group();
283        }
284    }
285
286    pub fn move_left(&self, reset_anchor: bool) {
287        self.modify_selections(reset_anchor, |selection, layout| {
288            selection.update_cursor(|cursor| cursor.move_left(layout.as_text().as_lines()))
289        });
290    }
291
292    pub fn move_right(&self, reset_anchor: bool) {
293        self.modify_selections(reset_anchor, |selection, layout| {
294            selection.update_cursor(|cursor| cursor.move_right(layout.as_text().as_lines()))
295        });
296    }
297
298    pub fn move_up(&self, reset_anchor: bool) {
299        self.modify_selections(reset_anchor, |selection, layout| {
300            selection.update_cursor(|cursor| cursor.move_up(layout))
301        });
302    }
303
304    pub fn move_down(&self, reset_anchor: bool) {
305        self.modify_selections(reset_anchor, |selection, layout| {
306            selection.update_cursor(|cursor| cursor.move_down(layout))
307        });
308    }
309
310    pub fn home(&self, reset_anchor: bool) {
311        self.modify_selections(reset_anchor, |selection, layout| {
312            selection.update_cursor(|cursor| cursor.home(layout.as_text().as_lines()))
313        });
314    }
315
316    pub fn end(&self, reset_anchor: bool) {
317        self.modify_selections(reset_anchor, |selection, layout| {
318            selection.update_cursor(|cursor| cursor.end(layout.as_text().as_lines()))
319        });
320    }
321
322    pub fn insert(&self, text: Text) {
323
324        let mut edit_kind = EditKind::Insert;
325        let mut inject_char = None;
326        let mut uninject_char = None;
327        if let Some(char) = text.to_single_char() {
328            let mut selection_state = self.selection_state.borrow_mut();
329            if char == ' ' {
330                edit_kind = EditKind::InsertSpace;
331            } else if char == '"' || char.is_opening_delimiter() {
332                if selection_state
333                    .selections
334                    .iter()
335                    .all(|selection| !selection.is_empty())
336                    || selection_state.selections.iter().all(|selection| {
337                        selection.is_empty()
338                            && match self.document.as_text().as_lines()
339                                [selection.cursor.position.line_index]
340                                [selection.cursor.position.byte_index..]
341                                .chars()
342                                .next()
343                            {
344                                Some(char) => {
345                                    char == '"'
346                                        || char.is_closing_delimiter()
347                                        || char.is_whitespace()
348                                }
349                                None => true,
350                            }
351                    })
352                {
353                    // We are inserting either a string or opening delimiter, and either all
354                    // selections are non-empty, or all selections are empty and followed by either
355                    // a string or closing delimiter or whitespace. In this case, we automatically
356                    // inject the corresponding string or closing delimiter.
357                    let opposite_char = if char == '"' {
358                        '"'
359                    } else {
360                        char.opposite_delimiter().unwrap()
361                    };
362                    inject_char = Some(opposite_char);
363                    selection_state.injected_char_stack.push(opposite_char);
364                }
365            } else if selection_state
366                .injected_char_stack
367                .last()
368                .map_or(false, |&last_char| last_char == char)
369            {
370                // We are inserting a single character that we automatically injected earlier, so we need
371                // to uninject it before inserting it again.
372                uninject_char = Some(selection_state.injected_char_stack.pop().unwrap());
373            }
374            drop(selection_state);
375        }
376        self.document.edit_selections(
377            self.id,
378            edit_kind,
379            &self.selection_state.borrow().selections,
380            &self.settings,
381            |mut editor, position, length| {
382                let mut position = position;
383                let mut length = length;
384                if inject_char.is_none() {
385                    // Only delete the selection if we are NOT injecting a character. This is for the
386                    // use case where we have selected `abc` and want to enclose it like: `{abc}`.
387                    editor.apply_edit(Edit {
388                        change: Change::Delete(position, length),
389                        drift: Drift::Before,
390                    });
391                    length = Length::zero();
392                }
393                if let Some(uninject_delimiter) = uninject_char {
394                    // To uninject a character, we simply delete it.
395                    editor.apply_edit(Edit {
396                        change: Change::Delete(
397                            position,
398                            Length {
399                                line_count: 0,
400                                byte_count: uninject_delimiter.len_utf8(),
401                            },
402                        ),
403                        drift: Drift::Before,
404                    })
405                }
406                editor.apply_edit(Edit {
407                    change: Change::Insert(position, text.clone()),
408                    drift: Drift::Before,
409                });
410                position += text.length();
411                if let Some(inject_delimiter) = inject_char {
412                    // To inject a character, we do an extra insert with Drift::After so that the
413                    // cursor stays in place. Note that we have to add the selected length to our
414                    // position, because the selection is only deleted if we are NOT injecting a
415                    // character. This is for the use case where we have selected `abc` and want
416                    // to enclose it like: `{abc}`.
417                    editor.apply_edit(Edit {
418                        change: Change::Insert(position + length, Text::from(inject_delimiter)),
419                        drift: Drift::After,
420                    })
421                }
422            },
423        );
424    }
425
426    pub fn paste(&self, text: Text) {
427        self.document.edit_selections(
428            self.id,
429            EditKind::Other,
430            &self.selection_state.borrow().selections,
431            &self.settings,
432            |mut editor, position, length| {
433                editor.apply_edit(Edit {
434                    change: Change::Delete(position, length),
435                    drift: Drift::Before,
436                });
437                editor.apply_edit(Edit {
438                    change: Change::Insert(position, text.clone()),
439                    drift: Drift::Before,
440                });
441            },
442        );
443    }
444    
445    pub fn paste_grouped(&self, text: Text, group:u64) {
446        self.document.edit_selections(
447            self.id,
448            EditKind::Group(group),
449            &self.selection_state.borrow().selections,
450            &self.settings,
451            |mut editor, position, length| {
452                editor.apply_edit(Edit {
453                    change: Change::Delete(position, length),
454                    drift: Drift::Before,
455                });
456                editor.apply_edit(Edit {
457                    change: Change::Insert(position, text.clone()),
458                    drift: Drift::Before,
459                });
460            },
461        );
462    }
463    
464    pub fn enter(&self) {
465        self.selection_state
466            .borrow_mut()
467            .injected_char_stack
468            .clear();
469        self.document.edit_selections(
470            self.id,
471            EditKind::Other,
472            &self.selection_state.borrow().selections,
473            &self.settings,
474            |mut editor, position, length| {
475                let line = &editor.as_text().as_lines()[position.line_index];
476                let delete_whitespace = !line.is_empty()
477                    && line[..position.byte_index]
478                        .chars()
479                        .all(|char| char.is_whitespace());
480                let inject_newline = line[..position.byte_index]
481                    .chars()
482                    .rev()
483                    .find_map(|char| {
484                        if char.is_opening_delimiter() {
485                            return Some(true);
486                        }
487                        if char.is_closing_delimiter() {
488                            return Some(false);
489                        }
490                        None
491                    })
492                    .unwrap_or(false)
493                    && line[position.byte_index..]
494                        .chars()
495                        .find_map(|char| {
496                            if char.is_closing_delimiter() {
497                                return Some(true);
498                            }
499                            if !char.is_whitespace() {
500                                return Some(false);
501                            }
502                            None
503                        })
504                        .unwrap_or(false);
505                let mut position = position;
506                if delete_whitespace {
507                    editor.apply_edit(Edit {
508                        change: Change::Delete(
509                            Position {
510                                line_index: position.line_index,
511                                byte_index: 0,
512                            },
513                            Length {
514                                line_count: 0,
515                                byte_count: position.byte_index,
516                            },
517                        ),
518                        drift: Drift::Before,
519                    });
520                    position.byte_index = 0;
521                }
522                editor.apply_edit(Edit {
523                    change: Change::Delete(position, length),
524                    drift: Drift::Before,
525                });
526                editor.apply_edit(Edit {
527                    change: Change::Insert(position, Text::newline()),
528                    drift: Drift::Before,
529                });
530                position.line_index += 1;
531                position.byte_index = 0;
532                if inject_newline {
533                    editor.apply_edit(Edit {
534                        change: Change::Insert(position, Text::newline()),
535                        drift: Drift::After,
536                    });
537                }
538            },
539        );
540    }
541
542    pub fn delete(&self) {
543        self.selection_state
544            .borrow_mut()
545            .injected_char_stack
546            .clear();
547        self.document.edit_selections(
548            self.id,
549            EditKind::Delete,
550            &self.selection_state.borrow().selections,
551            &self.settings,
552            |mut editor, position, length| {
553                if length == Length::zero() {
554                    // The selection is empty, so delete forward.
555                    let lines = editor.as_text().as_lines();
556                    if lines[position.line_index][position.byte_index..]
557                        .chars()
558                        .all(|char| char.is_whitespace())
559                    {
560                        // There are only whitespace characters after the cursor on this line, so
561                        // delete forward until either the first non-whitespace character on the
562                        // next line, if it exists, or otherwise until the end of the text.
563                        if position.line_index < lines.len() - 1 {
564                            // There is a next line, so delete until the first non-whitespace
565                            // character on the next line.
566                            let byte_count = lines[position.line_index + 1]
567                                .chars()
568                                .take_while(|char| char.is_whitespace())
569                                .map(|char| char.len_utf8())
570                                .sum::<usize>();
571                            editor.apply_edit(Edit {
572                                change: Change::Delete(
573                                    position,
574                                    Length {
575                                        line_count: 1,
576                                        byte_count,
577                                    },
578                                ),
579                                drift: Drift::Before,
580                            });
581                        } else {
582                            // There is no next line, so delete forward until the start of the
583                            // text.
584                            let byte_count = lines[position.line_index].len() - position.byte_index;
585                            editor.apply_edit(Edit {
586                                change: Change::Delete(
587                                    position,
588                                    Length {
589                                        line_count: 0,
590                                        byte_count,
591                                    },
592                                ),
593                                drift: Drift::Before,
594                            });
595                        }
596                    } else {
597                        // There is at least one non-whitespace character before the cursor on the
598                        // current line, so delete forward by a single grapheme.
599                        let byte_count =
600                            lines[position.line_index].graphemes().next().unwrap().len();
601                        editor.apply_edit(Edit {
602                            change: Change::Delete(
603                                position,
604                                Length {
605                                    line_count: 0,
606                                    byte_count,
607                                },
608                            ),
609                            drift: Drift::Before,
610                        });
611                    }
612                } else {
613                    // The selection is non-empty, so delete it.
614                    editor.apply_edit(Edit {
615                        change: Change::Delete(position, length),
616                        drift: Drift::Before,
617                    });
618                }
619            },
620        );
621    }
622
623    pub fn backspace(&self) {
624        self.selection_state
625            .borrow_mut()
626            .injected_char_stack
627            .clear();
628        self.document.edit_selections(
629            self.id,
630            EditKind::Delete,
631            &self.selection_state.borrow().selections,
632            &self.settings,
633            |mut editor, position, length| {
634                if length == Length::zero() {
635                    // The selection is empty, so delete backwards.
636                    let lines = editor.as_text().as_lines();
637                    if lines[position.line_index][..position.byte_index]
638                        .chars()
639                        .all(|char| char.is_whitespace())
640                    {
641                        // There are only whitespace characters before the cursor on this line, so
642                        // delete backwards until either the first non-whitespace character on the
643                        // previous line, if it exists, or otherwise until the start of the text.
644                        if position.line_index > 0 {
645                            // There is a previous line, so delete until the first non-whitespace
646                            // character on the previous line.
647                            let byte_count = lines[position.line_index - 1]
648                                .chars()
649                                .rev()
650                                .take_while(|char| char.is_whitespace())
651                                .map(|char| char.len_utf8())
652                                .sum::<usize>();
653                            let byte_index = lines[position.line_index - 1].len() - byte_count;
654                            if byte_index == 0 {
655                                // The previous line is empty, so keep the indentation on the
656                                // current line.
657                                editor.apply_edit(Edit {
658                                    change: Change::Delete(
659                                        Position {
660                                            line_index: position.line_index - 1,
661                                            byte_index,
662                                        },
663                                        Length {
664                                            line_count: 1,
665                                            byte_count: 0,
666                                        },
667                                    ),
668                                    drift: Drift::Before,
669                                });
670                            } else {
671                                // The previous line is non-empty, so don't keep the indentation on
672                                // the current line.
673                                editor.apply_edit(Edit {
674                                    change: Change::Delete(
675                                        Position {
676                                            line_index: position.line_index - 1,
677                                            byte_index,
678                                        },
679                                        Length {
680                                            line_count: 1,
681                                            byte_count: position.byte_index,
682                                        },
683                                    ),
684                                    drift: Drift::Before,
685                                });
686                            }
687                        } else {
688                            // There is no previous line, so delete backwards until the start of the
689                            // text.
690                            editor.apply_edit(Edit {
691                                change: Change::Delete(
692                                    Position::zero(),
693                                    Length {
694                                        line_count: 0,
695                                        byte_count: position.byte_index,
696                                    },
697                                ),
698                                drift: Drift::Before,
699                            });
700                        }
701                    } else {
702                        // There is at least one non-whitespace character before the cursor on the
703                        // current line, so delete backwards by a single grapheme.
704                        let byte_count = lines[position.line_index][..position.byte_index]
705                            .graphemes()
706                            .next_back()
707                            .unwrap()
708                            .len();
709                        editor.apply_edit(Edit {
710                            change: Change::Delete(
711                                Position {
712                                    line_index: position.line_index,
713                                    byte_index: position.byte_index - byte_count,
714                                },
715                                Length {
716                                    line_count: 0,
717                                    byte_count,
718                                },
719                            ),
720                            drift: Drift::Before,
721                        });
722                    }
723                } else {
724                    // The selection is non-empty, so delete it.
725                    editor.apply_edit(Edit {
726                        change: Change::Delete(position, length),
727                        drift: Drift::Before,
728                    });
729                }
730            },
731        );
732    }
733
734    pub fn indent(&self) {
735        self.document.edit_linewise(
736            self.id,
737            EditKind::Other,
738            &self.selection_state.borrow().selections,
739            |mut editor, line_index| {
740                let indent_column_count = editor.as_text().as_lines()[line_index]
741                    .indent()
742                    .unwrap_or("")
743                    .len();
744                let column_count = self.settings.tab_column_count
745                    - indent_column_count % self.settings.tab_column_count;
746                editor.apply_edit(Edit {
747                    change: Change::Insert(
748                        Position {
749                            line_index,
750                            byte_index: indent_column_count,
751                        },
752                        iter::repeat(' ').take(column_count).collect(),
753                    ),
754                    drift: Drift::Before,
755                });
756            },
757        );
758    }
759
760    pub fn outdent(&self) {
761        self.document.edit_linewise(
762            self.id,
763            EditKind::Other,
764            &self.selection_state.borrow().selections,
765            |mut editor, line_index| {
766                let indent_column_count = editor.as_text().as_lines()[line_index]
767                    .indent()
768                    .unwrap_or("")
769                    .len();
770                let column_count = indent_column_count.min(
771                    (indent_column_count + self.settings.tab_column_count - 1)
772                        % self.settings.tab_column_count
773                        + 1,
774                );
775                editor.apply_edit(Edit {
776                    change: Change::Delete(
777                        Position {
778                            line_index,
779                            byte_index: indent_column_count - column_count,
780                        },
781                        Length {
782                            line_count: 0,
783                            byte_count: column_count,
784                        },
785                    ),
786                    drift: Drift::Before,
787                });
788            },
789        );
790    }
791
792    pub fn copy(&self) -> String {
793        let mut string = String::new();
794        for selection in &self.selection_state.borrow().selections {
795            write!(
796                &mut string,
797                "{}",
798                self.document
799                    .as_text()
800                    .slice(selection.start(), selection.length())
801            )
802            .unwrap();
803        }
804        string
805    }
806
807    pub fn undo(&self) -> bool {
808        self.selection_state
809            .borrow_mut()
810            .injected_char_stack
811            .clear();
812        self.document
813            .undo(self.id, &self.selection_state.borrow().selections)
814    }
815
816    pub fn redo(&self) -> bool {
817        self.selection_state
818            .borrow_mut()
819            .injected_char_stack
820            .clear();
821        self.document
822            .redo(self.id, &self.selection_state.borrow().selections)
823    }
824
825    /// Returns the word at the main cursor position as a String.
826    pub fn word_at_cursor(&self) -> Option<String> {
827        let selection_state = self.selection_state.borrow();
828        if let Some(index) = selection_state.last_added_selection_index {
829            let cursor = selection_state.selections[index].cursor;
830            let position = cursor.position;
831            let text = self.document().as_text();
832            let lines = text.as_lines();
833            
834            // Handle empty document or invalid cursor position
835            if lines.is_empty() || position.line_index >= lines.len() {
836                return None;
837            }
838            
839            let line = &lines[position.line_index];
840            let word_separators = &self.settings.word_separators;
841            
842            // Find word boundaries
843            let start_byte_index = line.find_prev_word_boundary(position.byte_index, word_separators);
844            let end_byte_index = line.find_next_word_boundary(position.byte_index, word_separators);
845            if start_byte_index!=end_byte_index{
846                return Some(line[start_byte_index..end_byte_index].to_string())
847            }
848        }
849        None
850    }
851
852    pub fn handle_changes(&mut self) {
853        while let Ok((selections, edits)) = self.edit_receiver.try_recv() {
854            self.update_after_edit(selections, &edits);
855        }
856    }
857
858    fn modify_selections(
859        &self,
860        reset_anchor: bool,
861        mut f: impl FnMut(Selection, &Layout) -> Selection,
862    ) {
863        let layout = Layout {
864            text: self.document.as_text(),
865            document_layout: self.document.layout(),
866            session_layout: self.layout.borrow(),
867        };
868        let mut selection_state = self.selection_state.borrow_mut();
869        let last_added_selection_index = selection_state.last_added_selection_index;
870        selection_state.last_added_selection_index = selection_state
871            .selections
872            .update_all_selections(last_added_selection_index, |selection| {
873                let mut selection = f(selection, &layout);
874                if reset_anchor {
875                    selection = selection.reset_anchor();
876                }
877                selection
878            });
879        selection_state.injected_char_stack.clear();
880        drop(selection_state);
881        drop(layout);
882        self.update_highlighted_delimiter_positions();
883        self.document().force_new_group();
884    }
885
886    fn update_after_edit(&self, selections: Option<SelectionSet>, edits: &[Edit]) {
887        for edit in edits {
888            match edit.change {
889                Change::Insert(point, ref text) => {
890                    self.layout.borrow_mut().column_count[point.line_index] = None;
891                    self.layout.borrow_mut().wrap_data[point.line_index] = None;
892                    let line_count = text.length().line_count;
893                    if line_count > 0 {
894                        let line = point.line_index + 1;
895                        self.layout.borrow_mut().y.truncate(line);
896                        self.layout
897                            .borrow_mut()
898                            .column_count
899                            .splice(line..line, (0..line_count).map(|_| None));
900                        self.layout
901                            .borrow_mut()
902                            .fold_column
903                            .splice(line..line, (0..line_count).map(|_| 0));
904                        self.layout
905                            .borrow_mut()
906                            .scale
907                            .splice(line..line, (0..line_count).map(|_| 1.0));
908                        self.layout
909                            .borrow_mut()
910                            .wrap_data
911                            .splice(line..line, (0..line_count).map(|_| None));
912                    }
913                }
914                Change::Delete(start, length) => {
915                    self.layout.borrow_mut().column_count[start.line_index] = None;
916                    self.layout.borrow_mut().wrap_data[start.line_index] = None;
917                    let line_count = length.line_count;
918                    if line_count > 0 {
919                        let start_line = start.line_index + 1;
920                        let end_line = start_line + line_count;
921                        self.layout.borrow_mut().y.truncate(start_line);
922                        self.layout
923                            .borrow_mut()
924                            .column_count
925                            .drain(start_line..end_line);
926                        self.layout
927                            .borrow_mut()
928                            .fold_column
929                            .drain(start_line..end_line);
930                        self.layout.borrow_mut().scale.drain(start_line..end_line);
931                        self.layout
932                            .borrow_mut()
933                            .wrap_data
934                            .drain(start_line..end_line);
935                    }
936                }
937            }
938        }
939        let line_count = self.document.as_text().as_lines().len();
940        for line in 0..line_count {
941            if self.layout.borrow().wrap_data[line].is_none() {
942                self.update_wrap_data(line);
943            }
944        }
945        self.update_y();
946        let mut selection_state = self.selection_state.borrow_mut();
947        if let Some(selections) = selections {
948            selection_state.selections = selections;
949        } else {
950            for edit in edits {
951                let last_added_selection_index = selection_state.last_added_selection_index;
952                selection_state.last_added_selection_index = selection_state
953                    .selections
954                    .apply_edit(edit, last_added_selection_index);
955            }
956        }
957        drop(selection_state);
958        self.update_highlighted_delimiter_positions();
959    }
960
961    fn update_y(&self) {
962        let start = self.layout.borrow().y.len();
963        let end = self.document.as_text().as_lines().len();
964        if start == end + 1 {
965            return;
966        }
967        let mut y = if start == 0 {
968            0.0
969        } else {
970            let layout = self.layout();
971            let line = layout.line(start - 1);
972            line.y() + line.height()
973        };
974        let mut ys = mem::take(&mut self.layout.borrow_mut().y);
975        for block in self.layout().block_elements(start, end) {
976            match block {
977                BlockElement::Line { is_inlay, line } => {
978                    if !is_inlay {
979                        ys.push(y);
980                    }
981                    y += line.height();
982                }
983                BlockElement::Widget(widget) => {
984                    y += widget.height;
985                }
986            }
987        }
988        ys.push(y);
989        self.layout.borrow_mut().y = ys;
990    }
991
992    fn update_column_count(&self, index: usize) {
993        let mut column_count = 0;
994        let mut column = 0;
995        let layout = self.layout();
996        let line = layout.line(index);
997        for wrapped in line.wrapped_elements() {
998            match wrapped {
999                WrappedElement::Text { text, .. } => {
1000                    column += text.column_count();
1001                }
1002                WrappedElement::Widget(widget) => {
1003                    column += widget.column_count;
1004                }
1005                WrappedElement::Wrap => {
1006                    column_count = column_count.max(column);
1007                    column = line.wrap_indent_column_count();
1008                }
1009            }
1010        }
1011        drop(layout);
1012        self.layout.borrow_mut().column_count[index] = Some(column_count.max(column));
1013    }
1014
1015    fn update_wrap_data(&self, line: usize) {
1016        let wrap_data = match self.wrap_column.get() {
1017            Some(wrap_column) => {
1018                let layout = self.layout();
1019                let line = layout.line(line);
1020                wrap::compute_wrap_data(line, wrap_column)
1021            }
1022            None => WrapData::default(),
1023        };
1024        self.layout.borrow_mut().wrap_data[line] = Some(wrap_data);
1025        self.layout.borrow_mut().y.truncate(line + 1);
1026        self.update_column_count(line);
1027    }
1028
1029    fn update_highlighted_delimiter_positions(&self) {
1030        let mut selection_state = self.selection_state.borrow_mut();
1031        let mut highlighted_delimiter_positions =
1032            mem::take(&mut selection_state.highlighted_delimiter_positions);
1033        highlighted_delimiter_positions.clear();
1034        for selection in &selection_state.selections {
1035            if !selection.is_empty() {
1036                continue;
1037            }
1038            if let Some((opening_delimiter_position, closing_delimiter_position)) =
1039                find_highlighted_delimiter_pair(
1040                    self.document.as_text().as_lines(),
1041                    selection.cursor.position,
1042                )
1043            {
1044                highlighted_delimiter_positions.insert(opening_delimiter_position);
1045                highlighted_delimiter_positions.insert(closing_delimiter_position);
1046            }
1047        }
1048        selection_state.highlighted_delimiter_positions = highlighted_delimiter_positions;
1049    }
1050    
1051        
1052    pub fn set_cursor_at_file_end(&self) {
1053        let position = {
1054            let text = self.document().as_text();
1055            let lines = text.as_lines();
1056                    
1057            if lines.is_empty() {
1058                return;
1059            }
1060                    
1061            let last_line_index = lines.len() - 1;
1062            let last_line_byte_index = 0;//lines[last_line_index].len();
1063                    
1064            let position = Position {
1065                line_index: last_line_index,
1066                byte_index: last_line_byte_index,
1067            };
1068            position
1069        };
1070                    
1071        self.set_selection(position, Affinity::After, SelectionMode::Simple, NewGroup::No);
1072    }
1073}
1074
1075impl Drop for CodeSession {
1076    fn drop(&mut self) {
1077        self.document.remove_session(self.id);
1078    }
1079}
1080
1081#[derive(Clone, Copy, Debug, Eq, Hash, Default, PartialEq)]
1082pub struct SessionId(usize);
1083
1084#[derive(Debug)]
1085pub struct SessionLayout {
1086    pub y: Vec<f64>,
1087    pub column_count: Vec<Option<usize>>,
1088    pub fold_column: Vec<usize>,
1089    pub scale: Vec<f64>,
1090    pub wrap_data: Vec<Option<WrapData>>,
1091}
1092
1093#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1094pub enum SelectionMode {
1095    Simple,
1096    Word,
1097    Line,
1098    All,
1099}
1100
1101#[derive(Debug)]
1102struct SelectionState {
1103    mode: SelectionMode,
1104    selections: SelectionSet,
1105    last_added_selection_index: Option<usize>,
1106    injected_char_stack: Vec<char>,
1107    highlighted_delimiter_positions: HashSet<Position>,
1108}
1109
1110#[derive(Debug)]
1111struct FoldState {
1112    folding_lines: HashSet<usize>,
1113    folded_lines: HashSet<usize>,
1114    unfolding_lines: HashSet<usize>,
1115}
1116
1117pub fn reindent(string: &str, f: impl FnOnce(usize) -> usize) -> (usize, usize, String) {
1118    let indentation = string.indent().unwrap_or("");
1119    let indentation_column_count = indentation.column_count();
1120    let new_indentation_column_count = f(indentation_column_count);
1121    let new_indentation = new_indentation(new_indentation_column_count);
1122    let len = indentation.longest_common_prefix(&new_indentation).len();
1123    (
1124        len,
1125        indentation.len() - len.min(indentation.len()),
1126        new_indentation[len..].to_owned(),
1127    )
1128}
1129
1130fn grow_selection(
1131    selection: Selection,
1132    lines: &[String],
1133    mode: SelectionMode,
1134    word_separators: &[char],
1135) -> Selection {
1136    match mode {
1137        SelectionMode::Simple => selection,
1138        SelectionMode::Word => {
1139            let position = selection.cursor.position;
1140            let start_byte_index = lines[position.line_index]
1141                .find_prev_word_boundary(position.byte_index, word_separators);
1142            let end_byte_index = lines[position.line_index]
1143                .find_next_word_boundary(position.byte_index, word_separators);
1144            if selection.anchor < selection.cursor.position {
1145                Selection {
1146                    cursor: Cursor {
1147                        position: Position {
1148                            line_index: position.line_index,
1149                            byte_index: end_byte_index,
1150                        },
1151                        affinity: Affinity::Before,
1152                        preferred_column_index: None,
1153                    },
1154                    anchor: selection.anchor,
1155                }
1156            } else if selection.anchor > selection.cursor.position {
1157                Selection {
1158                    cursor: Cursor {
1159                        position: Position {
1160                            line_index: position.line_index,
1161                            byte_index: start_byte_index,
1162                        },
1163                        affinity: Affinity::After,
1164                        preferred_column_index: None,
1165                    },
1166                    anchor: selection.anchor,
1167                }
1168            } else {
1169                Selection {
1170                    cursor: Cursor {
1171                        position: Position {
1172                            line_index: position.line_index,
1173                            byte_index: end_byte_index,
1174                        },
1175                        affinity: Affinity::After,
1176                        preferred_column_index: None,
1177                    },
1178                    anchor: Position {
1179                        line_index: position.line_index,
1180                        byte_index: start_byte_index,
1181                    },
1182                }
1183            }
1184        }
1185        SelectionMode::Line => {
1186            let position = selection.cursor.position;
1187            if selection.anchor < selection.cursor.position {
1188                Selection {
1189                    cursor: Cursor {
1190                        position: Position {
1191                            line_index: position.line_index,
1192                            byte_index: lines[position.line_index].len(),
1193                        },
1194                        affinity: Affinity::Before,
1195                        preferred_column_index: None,
1196                    },
1197                    anchor: Position {
1198                        line_index: selection.anchor.line_index,
1199                        byte_index: 0,
1200                    },
1201                }
1202            } else if selection.anchor > selection.cursor.position {
1203                Selection {
1204                    cursor: Cursor {
1205                        position: Position {
1206                            line_index: position.line_index,
1207                            byte_index: 0,
1208                        },
1209                        affinity: Affinity::After,
1210                        preferred_column_index: None,
1211                    },
1212                    anchor: Position {
1213                        line_index: selection.anchor.line_index,
1214                        byte_index: lines[selection.anchor.line_index].len(),
1215                    },
1216                }
1217            } else {
1218                Selection {
1219                    cursor: Cursor {
1220                        position: Position {
1221                            line_index: position.line_index,
1222                            byte_index: lines[position.line_index].len(),
1223                        },
1224                        affinity: Affinity::After,
1225                        preferred_column_index: None,
1226                    },
1227                    anchor: Position {
1228                        line_index: position.line_index,
1229                        byte_index: 0,
1230                    },
1231                }
1232            }
1233        }
1234        SelectionMode::All => Selection {
1235            cursor: Cursor {
1236                position: Position {
1237                    line_index: lines.len() - 1,
1238                    byte_index: lines[lines.len() - 1].len(),
1239                },
1240                affinity: Affinity::After,
1241                preferred_column_index: None,
1242            },
1243            anchor: Position {
1244                line_index: 0,
1245                byte_index: 0,
1246            },
1247        },
1248    }
1249}
1250
1251fn new_indentation(column_count: usize) -> String {
1252    iter::repeat(' ').take(column_count).collect()
1253}
1254
1255fn find_highlighted_delimiter_pair(
1256    lines: &[String],
1257    position: Position,
1258) -> Option<(Position, Position)> {
1259    // Cursor is before an opening delimiter
1260    match lines[position.line_index][position.byte_index..]
1261        .chars()
1262        .next()
1263    {
1264        Some(ch) if ch.is_opening_delimiter() => {
1265            let opening_delimiter_position = position;
1266            if let Some(closing_delimiter_position) = find_closing_delimiter(
1267                lines,
1268                Position {
1269                    line_index: position.line_index,
1270                    byte_index: position.byte_index + ch.len_utf8(),
1271                },
1272                ch,
1273            ) {
1274                return Some((opening_delimiter_position, closing_delimiter_position));
1275            }
1276        }
1277        _ => {}
1278    }
1279    // Cursor is before a closing delimiter
1280    match lines[position.line_index][position.byte_index..]
1281        .chars()
1282        .next()
1283    {
1284        Some(ch) if ch.is_closing_delimiter() => {
1285            let closing_delimiter_position = position;
1286            if let Some(opening_delimiter_position) = find_opening_delimiter(lines, position, ch) {
1287                return Some((opening_delimiter_position, closing_delimiter_position));
1288            }
1289        }
1290        _ => {}
1291    }
1292    // Cursor is after a closing delimiter
1293    match lines[position.line_index][..position.byte_index]
1294        .chars()
1295        .next_back()
1296    {
1297        Some(ch) if ch.is_closing_delimiter() => {
1298            let closing_delimiter_position = Position {
1299                line_index: position.line_index,
1300                byte_index: position.byte_index - ch.len_utf8(),
1301            };
1302            if let Some(opening_delimiter_position) =
1303                find_opening_delimiter(lines, closing_delimiter_position, ch)
1304            {
1305                return Some((opening_delimiter_position, closing_delimiter_position));
1306            }
1307        }
1308        _ => {}
1309    }
1310    // Cursor is after an opening delimiter
1311    match lines[position.line_index][..position.byte_index]
1312        .chars()
1313        .next_back()
1314    {
1315        Some(ch) if ch.is_opening_delimiter() => {
1316            let opening_delimiter_position = Position {
1317                line_index: position.line_index,
1318                byte_index: position.byte_index - ch.len_utf8(),
1319            };
1320            if let Some(closing_delimiter_position) = find_closing_delimiter(lines, position, ch) {
1321                return Some((opening_delimiter_position, closing_delimiter_position));
1322            }
1323        }
1324        _ => {}
1325    }
1326    None
1327}
1328
1329fn find_opening_delimiter(
1330    lines: &[String],
1331    position: Position,
1332    closing_delimiter: char,
1333) -> Option<Position> {
1334    let mut delimiter_stack = vec![closing_delimiter];
1335    let mut position = position;
1336    loop {
1337        for char in lines[position.line_index][..position.byte_index]
1338            .chars()
1339            .rev()
1340        {
1341            position.byte_index -= char.len_utf8();
1342            if char.is_closing_delimiter() {
1343                delimiter_stack.push(char);
1344            }
1345            if char.is_opening_delimiter() {
1346                if delimiter_stack.last() != Some(&char.opposite_delimiter().unwrap()) {
1347                    return None;
1348                }
1349                delimiter_stack.pop().unwrap();
1350                if delimiter_stack.is_empty() {
1351                    return Some(position);
1352                }
1353            }
1354        }
1355        if position.line_index == 0 {
1356            return None;
1357        }
1358        position.line_index -= 1;
1359        position.byte_index = lines[position.line_index].len();
1360    }
1361}
1362
1363fn find_closing_delimiter(
1364    lines: &[String],
1365    position: Position,
1366    opening_delimiter: char,
1367) -> Option<Position> {
1368    let mut delimiter_stack = vec![opening_delimiter];
1369    let mut position = position;
1370    loop {
1371        for char in lines[position.line_index][position.byte_index..].chars() {
1372            if char.is_opening_delimiter() {
1373                delimiter_stack.push(char);
1374            }
1375            if char.is_closing_delimiter() {
1376                if delimiter_stack.last() != Some(&char.opposite_delimiter().unwrap()) {
1377                    return None;
1378                }
1379                delimiter_stack.pop().unwrap();
1380                if delimiter_stack.is_empty() {
1381                    return Some(position);
1382                }
1383            }
1384            position.byte_index += char.len_utf8();
1385        }
1386        if position.line_index == lines.len() - 1 {
1387            return None;
1388        }
1389        position.line_index += 1;
1390        position.byte_index = 0;
1391    }
1392}