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