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 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 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 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 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 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 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 if position.line_index < lines.len() - 1 {
564 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 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 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 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 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 if position.line_index > 0 {
645 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 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 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 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 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 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 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 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 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;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 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 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 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 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}