1pub mod display_map;
2mod element;
3pub mod movement;
4
5#[cfg(test)]
6mod test;
7
8use buffer::rope::TextDimension;
9use clock::ReplicaId;
10pub use display_map::DisplayPoint;
11use display_map::*;
12pub use element::*;
13use gpui::{
14 action, geometry::vector::Vector2F, keymap::Binding, text_layout, AppContext, ClipboardItem,
15 Element, ElementBox, Entity, ModelHandle, MutableAppContext, RenderContext, View, ViewContext,
16 WeakViewHandle,
17};
18use language::*;
19use serde::{Deserialize, Serialize};
20use smallvec::SmallVec;
21use smol::Timer;
22use std::{
23 cell::RefCell,
24 cmp::{self, Ordering},
25 iter, mem,
26 ops::{Range, RangeInclusive},
27 rc::Rc,
28 sync::Arc,
29 time::Duration,
30};
31use sum_tree::Bias;
32use theme::EditorStyle;
33use util::post_inc;
34
35const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
36const MAX_LINE_LEN: usize = 1024;
37
38action!(Cancel);
39action!(Backspace);
40action!(Delete);
41action!(Input, String);
42action!(Newline);
43action!(Tab);
44action!(DeleteLine);
45action!(DeleteToPreviousWordBoundary);
46action!(DeleteToNextWordBoundary);
47action!(DeleteToBeginningOfLine);
48action!(DeleteToEndOfLine);
49action!(CutToEndOfLine);
50action!(DuplicateLine);
51action!(MoveLineUp);
52action!(MoveLineDown);
53action!(Cut);
54action!(Copy);
55action!(Paste);
56action!(Undo);
57action!(Redo);
58action!(MoveUp);
59action!(MoveDown);
60action!(MoveLeft);
61action!(MoveRight);
62action!(MoveToPreviousWordBoundary);
63action!(MoveToNextWordBoundary);
64action!(MoveToBeginningOfLine);
65action!(MoveToEndOfLine);
66action!(MoveToBeginning);
67action!(MoveToEnd);
68action!(SelectUp);
69action!(SelectDown);
70action!(SelectLeft);
71action!(SelectRight);
72action!(SelectToPreviousWordBoundary);
73action!(SelectToNextWordBoundary);
74action!(SelectToBeginningOfLine, bool);
75action!(SelectToEndOfLine);
76action!(SelectToBeginning);
77action!(SelectToEnd);
78action!(SelectAll);
79action!(SelectLine);
80action!(SplitSelectionIntoLines);
81action!(AddSelectionAbove);
82action!(AddSelectionBelow);
83action!(SelectLargerSyntaxNode);
84action!(SelectSmallerSyntaxNode);
85action!(MoveToEnclosingBracket);
86action!(PageUp);
87action!(PageDown);
88action!(Fold);
89action!(Unfold);
90action!(FoldSelectedRanges);
91action!(Scroll, Vector2F);
92action!(Select, SelectPhase);
93
94pub fn init(cx: &mut MutableAppContext) {
95 cx.add_bindings(vec![
96 Binding::new("escape", Cancel, Some("Editor")),
97 Binding::new("backspace", Backspace, Some("Editor")),
98 Binding::new("ctrl-h", Backspace, Some("Editor")),
99 Binding::new("delete", Delete, Some("Editor")),
100 Binding::new("ctrl-d", Delete, Some("Editor")),
101 Binding::new("enter", Newline, Some("Editor && mode == full")),
102 Binding::new(
103 "alt-enter",
104 Input("\n".into()),
105 Some("Editor && mode == auto_height"),
106 ),
107 Binding::new("tab", Tab, Some("Editor")),
108 Binding::new("ctrl-shift-K", DeleteLine, Some("Editor")),
109 Binding::new(
110 "alt-backspace",
111 DeleteToPreviousWordBoundary,
112 Some("Editor"),
113 ),
114 Binding::new("alt-h", DeleteToPreviousWordBoundary, Some("Editor")),
115 Binding::new("alt-delete", DeleteToNextWordBoundary, Some("Editor")),
116 Binding::new("alt-d", DeleteToNextWordBoundary, Some("Editor")),
117 Binding::new("cmd-backspace", DeleteToBeginningOfLine, Some("Editor")),
118 Binding::new("cmd-delete", DeleteToEndOfLine, Some("Editor")),
119 Binding::new("ctrl-k", CutToEndOfLine, Some("Editor")),
120 Binding::new("cmd-shift-D", DuplicateLine, Some("Editor")),
121 Binding::new("ctrl-cmd-up", MoveLineUp, Some("Editor")),
122 Binding::new("ctrl-cmd-down", MoveLineDown, Some("Editor")),
123 Binding::new("cmd-x", Cut, Some("Editor")),
124 Binding::new("cmd-c", Copy, Some("Editor")),
125 Binding::new("cmd-v", Paste, Some("Editor")),
126 Binding::new("cmd-z", Undo, Some("Editor")),
127 Binding::new("cmd-shift-Z", Redo, Some("Editor")),
128 Binding::new("up", MoveUp, Some("Editor")),
129 Binding::new("down", MoveDown, Some("Editor")),
130 Binding::new("left", MoveLeft, Some("Editor")),
131 Binding::new("right", MoveRight, Some("Editor")),
132 Binding::new("ctrl-p", MoveUp, Some("Editor")),
133 Binding::new("ctrl-n", MoveDown, Some("Editor")),
134 Binding::new("ctrl-b", MoveLeft, Some("Editor")),
135 Binding::new("ctrl-f", MoveRight, Some("Editor")),
136 Binding::new("alt-left", MoveToPreviousWordBoundary, Some("Editor")),
137 Binding::new("alt-b", MoveToPreviousWordBoundary, Some("Editor")),
138 Binding::new("alt-right", MoveToNextWordBoundary, Some("Editor")),
139 Binding::new("alt-f", MoveToNextWordBoundary, Some("Editor")),
140 Binding::new("cmd-left", MoveToBeginningOfLine, Some("Editor")),
141 Binding::new("ctrl-a", MoveToBeginningOfLine, Some("Editor")),
142 Binding::new("cmd-right", MoveToEndOfLine, Some("Editor")),
143 Binding::new("ctrl-e", MoveToEndOfLine, Some("Editor")),
144 Binding::new("cmd-up", MoveToBeginning, Some("Editor")),
145 Binding::new("cmd-down", MoveToEnd, Some("Editor")),
146 Binding::new("shift-up", SelectUp, Some("Editor")),
147 Binding::new("ctrl-shift-P", SelectUp, Some("Editor")),
148 Binding::new("shift-down", SelectDown, Some("Editor")),
149 Binding::new("ctrl-shift-N", SelectDown, Some("Editor")),
150 Binding::new("shift-left", SelectLeft, Some("Editor")),
151 Binding::new("ctrl-shift-B", SelectLeft, Some("Editor")),
152 Binding::new("shift-right", SelectRight, Some("Editor")),
153 Binding::new("ctrl-shift-F", SelectRight, Some("Editor")),
154 Binding::new(
155 "alt-shift-left",
156 SelectToPreviousWordBoundary,
157 Some("Editor"),
158 ),
159 Binding::new("alt-shift-B", SelectToPreviousWordBoundary, Some("Editor")),
160 Binding::new("alt-shift-right", SelectToNextWordBoundary, Some("Editor")),
161 Binding::new("alt-shift-F", SelectToNextWordBoundary, Some("Editor")),
162 Binding::new(
163 "cmd-shift-left",
164 SelectToBeginningOfLine(true),
165 Some("Editor"),
166 ),
167 Binding::new(
168 "ctrl-shift-A",
169 SelectToBeginningOfLine(true),
170 Some("Editor"),
171 ),
172 Binding::new("cmd-shift-right", SelectToEndOfLine, Some("Editor")),
173 Binding::new("ctrl-shift-E", SelectToEndOfLine, Some("Editor")),
174 Binding::new("cmd-shift-up", SelectToBeginning, Some("Editor")),
175 Binding::new("cmd-shift-down", SelectToEnd, Some("Editor")),
176 Binding::new("cmd-a", SelectAll, Some("Editor")),
177 Binding::new("cmd-l", SelectLine, Some("Editor")),
178 Binding::new("cmd-shift-L", SplitSelectionIntoLines, Some("Editor")),
179 Binding::new("cmd-alt-up", AddSelectionAbove, Some("Editor")),
180 Binding::new("cmd-ctrl-p", AddSelectionAbove, Some("Editor")),
181 Binding::new("cmd-alt-down", AddSelectionBelow, Some("Editor")),
182 Binding::new("cmd-ctrl-n", AddSelectionBelow, Some("Editor")),
183 Binding::new("alt-up", SelectLargerSyntaxNode, Some("Editor")),
184 Binding::new("ctrl-w", SelectLargerSyntaxNode, Some("Editor")),
185 Binding::new("alt-down", SelectSmallerSyntaxNode, Some("Editor")),
186 Binding::new("ctrl-shift-W", SelectSmallerSyntaxNode, Some("Editor")),
187 Binding::new("ctrl-m", MoveToEnclosingBracket, Some("Editor")),
188 Binding::new("pageup", PageUp, Some("Editor")),
189 Binding::new("pagedown", PageDown, Some("Editor")),
190 Binding::new("alt-cmd-[", Fold, Some("Editor")),
191 Binding::new("alt-cmd-]", Unfold, Some("Editor")),
192 Binding::new("alt-cmd-f", FoldSelectedRanges, Some("Editor")),
193 ]);
194
195 cx.add_action(|this: &mut Editor, action: &Scroll, cx| this.set_scroll_position(action.0, cx));
196 cx.add_action(Editor::select);
197 cx.add_action(Editor::cancel);
198 cx.add_action(Editor::handle_input);
199 cx.add_action(Editor::newline);
200 cx.add_action(Editor::backspace);
201 cx.add_action(Editor::delete);
202 cx.add_action(Editor::tab);
203 cx.add_action(Editor::delete_line);
204 cx.add_action(Editor::delete_to_previous_word_boundary);
205 cx.add_action(Editor::delete_to_next_word_boundary);
206 cx.add_action(Editor::delete_to_beginning_of_line);
207 cx.add_action(Editor::delete_to_end_of_line);
208 cx.add_action(Editor::cut_to_end_of_line);
209 cx.add_action(Editor::duplicate_line);
210 cx.add_action(Editor::move_line_up);
211 cx.add_action(Editor::move_line_down);
212 cx.add_action(Editor::cut);
213 cx.add_action(Editor::copy);
214 cx.add_action(Editor::paste);
215 cx.add_action(Editor::undo);
216 cx.add_action(Editor::redo);
217 cx.add_action(Editor::move_up);
218 cx.add_action(Editor::move_down);
219 cx.add_action(Editor::move_left);
220 cx.add_action(Editor::move_right);
221 cx.add_action(Editor::move_to_previous_word_boundary);
222 cx.add_action(Editor::move_to_next_word_boundary);
223 cx.add_action(Editor::move_to_beginning_of_line);
224 cx.add_action(Editor::move_to_end_of_line);
225 cx.add_action(Editor::move_to_beginning);
226 cx.add_action(Editor::move_to_end);
227 cx.add_action(Editor::select_up);
228 cx.add_action(Editor::select_down);
229 cx.add_action(Editor::select_left);
230 cx.add_action(Editor::select_right);
231 cx.add_action(Editor::select_to_previous_word_boundary);
232 cx.add_action(Editor::select_to_next_word_boundary);
233 cx.add_action(Editor::select_to_beginning_of_line);
234 cx.add_action(Editor::select_to_end_of_line);
235 cx.add_action(Editor::select_to_beginning);
236 cx.add_action(Editor::select_to_end);
237 cx.add_action(Editor::select_all);
238 cx.add_action(Editor::select_line);
239 cx.add_action(Editor::split_selection_into_lines);
240 cx.add_action(Editor::add_selection_above);
241 cx.add_action(Editor::add_selection_below);
242 cx.add_action(Editor::select_larger_syntax_node);
243 cx.add_action(Editor::select_smaller_syntax_node);
244 cx.add_action(Editor::move_to_enclosing_bracket);
245 cx.add_action(Editor::page_up);
246 cx.add_action(Editor::page_down);
247 cx.add_action(Editor::fold);
248 cx.add_action(Editor::unfold);
249 cx.add_action(Editor::fold_selected_ranges);
250}
251
252trait SelectionExt {
253 fn display_range(&self, map: &DisplayMapSnapshot) -> Range<DisplayPoint>;
254 fn spanned_rows(
255 &self,
256 include_end_if_at_line_start: bool,
257 map: &DisplayMapSnapshot,
258 ) -> SpannedRows;
259}
260
261struct SpannedRows {
262 buffer_rows: Range<u32>,
263 display_rows: Range<u32>,
264}
265
266#[derive(Clone, Debug)]
267pub enum SelectPhase {
268 Begin {
269 position: DisplayPoint,
270 add: bool,
271 },
272 Update {
273 position: DisplayPoint,
274 scroll_position: Vector2F,
275 },
276 End,
277}
278
279#[derive(Copy, Clone, PartialEq, Eq)]
280pub enum EditorMode {
281 SingleLine,
282 AutoHeight { max_lines: usize },
283 Full,
284}
285
286#[derive(Clone)]
287pub struct EditorSettings {
288 pub tab_size: usize,
289 pub style: EditorStyle,
290}
291
292pub struct Editor {
293 handle: WeakViewHandle<Self>,
294 buffer: ModelHandle<Buffer>,
295 display_map: ModelHandle<DisplayMap>,
296 selection_set_id: SelectionSetId,
297 pending_selection: Option<Selection<Anchor>>,
298 next_selection_id: usize,
299 add_selections_state: Option<AddSelectionsState>,
300 autoclose_stack: Vec<BracketPairState>,
301 select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
302 scroll_position: Vector2F,
303 scroll_top_anchor: Anchor,
304 autoscroll_requested: bool,
305 build_settings: Rc<RefCell<dyn Fn(&AppContext) -> EditorSettings>>,
306 focused: bool,
307 show_local_cursors: bool,
308 blink_epoch: usize,
309 blinking_paused: bool,
310 mode: EditorMode,
311 placeholder_text: Option<Arc<str>>,
312}
313
314pub struct Snapshot {
315 pub mode: EditorMode,
316 pub display_snapshot: DisplayMapSnapshot,
317 pub placeholder_text: Option<Arc<str>>,
318 is_focused: bool,
319 scroll_position: Vector2F,
320 scroll_top_anchor: Anchor,
321}
322
323struct AddSelectionsState {
324 above: bool,
325 stack: Vec<usize>,
326}
327
328#[derive(Debug)]
329struct BracketPairState {
330 ranges: AnchorRangeSet,
331 pair: BracketPair,
332}
333
334#[derive(Serialize, Deserialize)]
335struct ClipboardSelection {
336 len: usize,
337 is_entire_line: bool,
338}
339
340impl Editor {
341 pub fn single_line(
342 build_settings: impl 'static + Fn(&AppContext) -> EditorSettings,
343 cx: &mut ViewContext<Self>,
344 ) -> Self {
345 let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
346 let mut view = Self::for_buffer(buffer, build_settings, cx);
347 view.mode = EditorMode::SingleLine;
348 view
349 }
350
351 pub fn auto_height(
352 max_lines: usize,
353 build_settings: impl 'static + Fn(&AppContext) -> EditorSettings,
354 cx: &mut ViewContext<Self>,
355 ) -> Self {
356 let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
357 let mut view = Self::for_buffer(buffer, build_settings, cx);
358 view.mode = EditorMode::AutoHeight { max_lines };
359 view
360 }
361
362 pub fn for_buffer(
363 buffer: ModelHandle<Buffer>,
364 build_settings: impl 'static + Fn(&AppContext) -> EditorSettings,
365 cx: &mut ViewContext<Self>,
366 ) -> Self {
367 Self::new(buffer, Rc::new(RefCell::new(build_settings)), cx)
368 }
369
370 pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
371 let mut clone = Self::new(self.buffer.clone(), self.build_settings.clone(), cx);
372 clone.scroll_position = self.scroll_position;
373 clone.scroll_top_anchor = self.scroll_top_anchor.clone();
374 clone
375 }
376
377 pub fn new(
378 buffer: ModelHandle<Buffer>,
379 build_settings: Rc<RefCell<dyn Fn(&AppContext) -> EditorSettings>>,
380 cx: &mut ViewContext<Self>,
381 ) -> Self {
382 let settings = build_settings.borrow_mut()(cx);
383 let display_map = cx.add_model(|cx| {
384 DisplayMap::new(
385 buffer.clone(),
386 settings.tab_size,
387 settings.style.text.font_id,
388 settings.style.text.font_size,
389 None,
390 cx,
391 )
392 });
393 cx.observe(&buffer, Self::on_buffer_changed).detach();
394 cx.subscribe(&buffer, Self::on_buffer_event).detach();
395 cx.observe(&display_map, Self::on_display_map_changed)
396 .detach();
397
398 let mut next_selection_id = 0;
399 let selection_set_id = buffer.update(cx, |buffer, cx| {
400 buffer.add_selection_set(
401 &[Selection {
402 id: post_inc(&mut next_selection_id),
403 start: 0,
404 end: 0,
405 reversed: false,
406 goal: SelectionGoal::None,
407 }],
408 cx,
409 )
410 });
411 Self {
412 handle: cx.handle().downgrade(),
413 buffer,
414 display_map,
415 selection_set_id,
416 pending_selection: None,
417 next_selection_id,
418 add_selections_state: None,
419 autoclose_stack: Default::default(),
420 select_larger_syntax_node_stack: Vec::new(),
421 build_settings,
422 scroll_position: Vector2F::zero(),
423 scroll_top_anchor: Anchor::min(),
424 autoscroll_requested: false,
425 focused: false,
426 show_local_cursors: false,
427 blink_epoch: 0,
428 blinking_paused: false,
429 mode: EditorMode::Full,
430 placeholder_text: None,
431 }
432 }
433
434 pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
435 self.buffer.read(cx).replica_id()
436 }
437
438 pub fn buffer(&self) -> &ModelHandle<Buffer> {
439 &self.buffer
440 }
441
442 pub fn snapshot(&mut self, cx: &mut MutableAppContext) -> Snapshot {
443 Snapshot {
444 mode: self.mode,
445 display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
446 scroll_position: self.scroll_position,
447 scroll_top_anchor: self.scroll_top_anchor.clone(),
448 placeholder_text: self.placeholder_text.clone(),
449 is_focused: self
450 .handle
451 .upgrade(cx)
452 .map_or(false, |handle| handle.is_focused(cx)),
453 }
454 }
455
456 pub fn language<'a>(&self, cx: &'a AppContext) -> Option<&'a Arc<Language>> {
457 self.buffer.read(cx).language()
458 }
459
460 pub fn set_placeholder_text(
461 &mut self,
462 placeholder_text: impl Into<Arc<str>>,
463 cx: &mut ViewContext<Self>,
464 ) {
465 self.placeholder_text = Some(placeholder_text.into());
466 cx.notify();
467 }
468
469 fn set_scroll_position(&mut self, mut scroll_position: Vector2F, cx: &mut ViewContext<Self>) {
470 let map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
471 let scroll_top_buffer_offset =
472 DisplayPoint::new(scroll_position.y() as u32, 0).to_offset(&map, Bias::Right);
473 self.scroll_top_anchor = self
474 .buffer
475 .read(cx)
476 .anchor_at(scroll_top_buffer_offset, Bias::Right);
477 scroll_position.set_y(scroll_position.y().fract());
478 self.scroll_position = scroll_position;
479 cx.notify();
480 }
481
482 pub fn clamp_scroll_left(&mut self, max: f32) -> bool {
483 if max < self.scroll_position.x() {
484 self.scroll_position.set_x(max);
485 true
486 } else {
487 false
488 }
489 }
490
491 pub fn autoscroll_vertically(
492 &mut self,
493 viewport_height: f32,
494 line_height: f32,
495 cx: &mut ViewContext<Self>,
496 ) -> bool {
497 let visible_lines = viewport_height / line_height;
498 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
499 let mut scroll_position =
500 compute_scroll_position(&display_map, self.scroll_position, &self.scroll_top_anchor);
501 let max_scroll_top = if matches!(self.mode, EditorMode::AutoHeight { .. }) {
502 (display_map.max_point().row() as f32 - visible_lines + 1.).max(0.)
503 } else {
504 display_map.max_point().row().saturating_sub(1) as f32
505 };
506 if scroll_position.y() > max_scroll_top {
507 scroll_position.set_y(max_scroll_top);
508 self.set_scroll_position(scroll_position, cx);
509 }
510
511 if self.autoscroll_requested {
512 self.autoscroll_requested = false;
513 } else {
514 return false;
515 }
516
517 let mut selections = self.selections::<Point>(cx).peekable();
518 let first_cursor_top = selections
519 .peek()
520 .unwrap()
521 .head()
522 .to_display_point(&display_map)
523 .row() as f32;
524 let last_cursor_bottom = selections
525 .last()
526 .unwrap()
527 .head()
528 .to_display_point(&display_map)
529 .row() as f32
530 + 1.0;
531
532 let margin = if matches!(self.mode, EditorMode::AutoHeight { .. }) {
533 0.
534 } else {
535 ((visible_lines - (last_cursor_bottom - first_cursor_top)) / 2.0)
536 .floor()
537 .min(3.0)
538 };
539 if margin < 0.0 {
540 return false;
541 }
542
543 let target_top = (first_cursor_top - margin).max(0.0);
544 let target_bottom = last_cursor_bottom + margin;
545 let start_row = scroll_position.y();
546 let end_row = start_row + visible_lines;
547
548 if target_top < start_row {
549 scroll_position.set_y(target_top);
550 self.set_scroll_position(scroll_position, cx);
551 } else if target_bottom >= end_row {
552 scroll_position.set_y(target_bottom - visible_lines);
553 self.set_scroll_position(scroll_position, cx);
554 }
555
556 true
557 }
558
559 pub fn autoscroll_horizontally(
560 &mut self,
561 start_row: u32,
562 viewport_width: f32,
563 scroll_width: f32,
564 max_glyph_width: f32,
565 layouts: &[text_layout::Line],
566 cx: &mut ViewContext<Self>,
567 ) -> bool {
568 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
569 let selections = self.selections::<Point>(cx);
570 let mut target_left = std::f32::INFINITY;
571 let mut target_right = 0.0_f32;
572 for selection in selections {
573 let head = selection.head().to_display_point(&display_map);
574 let start_column = head.column().saturating_sub(3);
575 let end_column = cmp::min(display_map.line_len(head.row()), head.column() + 3);
576 target_left = target_left
577 .min(layouts[(head.row() - start_row) as usize].x_for_index(start_column as usize));
578 target_right = target_right.max(
579 layouts[(head.row() - start_row) as usize].x_for_index(end_column as usize)
580 + max_glyph_width,
581 );
582 }
583 target_right = target_right.min(scroll_width);
584
585 if target_right - target_left > viewport_width {
586 return false;
587 }
588
589 let scroll_left = self.scroll_position.x() * max_glyph_width;
590 let scroll_right = scroll_left + viewport_width;
591
592 if target_left < scroll_left {
593 self.scroll_position.set_x(target_left / max_glyph_width);
594 true
595 } else if target_right > scroll_right {
596 self.scroll_position
597 .set_x((target_right - viewport_width) / max_glyph_width);
598 true
599 } else {
600 false
601 }
602 }
603
604 fn select(&mut self, Select(phase): &Select, cx: &mut ViewContext<Self>) {
605 match phase {
606 SelectPhase::Begin { position, add } => self.begin_selection(*position, *add, cx),
607 SelectPhase::Update {
608 position,
609 scroll_position,
610 } => self.update_selection(*position, *scroll_position, cx),
611 SelectPhase::End => self.end_selection(cx),
612 }
613 }
614
615 fn begin_selection(&mut self, position: DisplayPoint, add: bool, cx: &mut ViewContext<Self>) {
616 if !self.focused {
617 cx.focus_self();
618 cx.emit(Event::Activate);
619 }
620
621 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
622 let buffer = self.buffer.read(cx);
623 let cursor = buffer.anchor_before(position.to_point(&display_map));
624 let selection = Selection {
625 id: post_inc(&mut self.next_selection_id),
626 start: cursor.clone(),
627 end: cursor,
628 reversed: false,
629 goal: SelectionGoal::None,
630 };
631
632 if !add {
633 self.update_selections::<usize>(Vec::new(), false, cx);
634 }
635 self.pending_selection = Some(selection);
636
637 cx.notify();
638 }
639
640 fn update_selection(
641 &mut self,
642 position: DisplayPoint,
643 scroll_position: Vector2F,
644 cx: &mut ViewContext<Self>,
645 ) {
646 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
647 if let Some(pending_selection) = self.pending_selection.as_mut() {
648 let buffer = self.buffer.read(cx);
649 let cursor = buffer.anchor_before(position.to_point(&display_map));
650 if cursor.cmp(&pending_selection.tail(), buffer).unwrap() < Ordering::Equal {
651 if !pending_selection.reversed {
652 pending_selection.end = pending_selection.start.clone();
653 pending_selection.reversed = true;
654 }
655 pending_selection.start = cursor;
656 } else {
657 if pending_selection.reversed {
658 pending_selection.start = pending_selection.end.clone();
659 pending_selection.reversed = false;
660 }
661 pending_selection.end = cursor;
662 }
663 } else {
664 log::error!("update_selection dispatched with no pending selection");
665 return;
666 }
667
668 self.set_scroll_position(scroll_position, cx);
669 cx.notify();
670 }
671
672 fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
673 if self.pending_selection.is_some() {
674 let selections = self.selections::<usize>(cx).collect::<Vec<_>>();
675 self.update_selections(selections, false, cx);
676 }
677 }
678
679 pub fn is_selecting(&self) -> bool {
680 self.pending_selection.is_some()
681 }
682
683 pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
684 if let Some(pending_selection) = self.pending_selection.take() {
685 let buffer = self.buffer.read(cx);
686 let pending_selection = Selection {
687 id: pending_selection.id,
688 start: pending_selection.start.to_point(buffer),
689 end: pending_selection.end.to_point(buffer),
690 reversed: pending_selection.reversed,
691 goal: pending_selection.goal,
692 };
693 if self.selections::<Point>(cx).next().is_none() {
694 self.update_selections(vec![pending_selection], true, cx);
695 }
696 } else {
697 let selections = self.selections::<Point>(cx);
698 let mut selection_count = 0;
699 let mut oldest_selection = selections
700 .min_by_key(|s| {
701 selection_count += 1;
702 s.id
703 })
704 .unwrap()
705 .clone();
706 if selection_count == 1 {
707 oldest_selection.start = oldest_selection.head().clone();
708 oldest_selection.end = oldest_selection.head().clone();
709 }
710 self.update_selections(vec![oldest_selection], true, cx);
711 }
712 }
713
714 fn select_ranges<I, T>(&mut self, ranges: I, autoscroll: bool, cx: &mut ViewContext<Self>)
715 where
716 I: IntoIterator<Item = Range<T>>,
717 T: ToOffset,
718 {
719 let buffer = self.buffer.read(cx);
720 let selections = ranges
721 .into_iter()
722 .map(|range| {
723 let mut start = range.start.to_offset(buffer);
724 let mut end = range.end.to_offset(buffer);
725 let reversed = if start > end {
726 mem::swap(&mut start, &mut end);
727 true
728 } else {
729 false
730 };
731 Selection {
732 id: post_inc(&mut self.next_selection_id),
733 start: start,
734 end: end,
735 reversed,
736 goal: SelectionGoal::None,
737 }
738 })
739 .collect();
740 self.update_selections(selections, autoscroll, cx);
741 }
742
743 #[cfg(test)]
744 fn select_display_ranges<'a, T>(
745 &mut self,
746 ranges: T,
747 cx: &mut ViewContext<Self>,
748 ) -> anyhow::Result<()>
749 where
750 T: IntoIterator<Item = &'a Range<DisplayPoint>>,
751 {
752 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
753 let selections = ranges
754 .into_iter()
755 .map(|range| {
756 let mut start = range.start;
757 let mut end = range.end;
758 let reversed = if start > end {
759 mem::swap(&mut start, &mut end);
760 true
761 } else {
762 false
763 };
764 Selection {
765 id: post_inc(&mut self.next_selection_id),
766 start: start.to_point(&display_map),
767 end: end.to_point(&display_map),
768 reversed,
769 goal: SelectionGoal::None,
770 }
771 })
772 .collect();
773 self.update_selections(selections, false, cx);
774 Ok(())
775 }
776
777 pub fn handle_input(&mut self, action: &Input, cx: &mut ViewContext<Self>) {
778 let text = action.0.as_ref();
779 if !self.skip_autoclose_end(text, cx) {
780 self.start_transaction(cx);
781 self.insert(text, cx);
782 self.autoclose_pairs(cx);
783 self.end_transaction(cx);
784 }
785 }
786
787 pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
788 self.start_transaction(cx);
789 let mut old_selections = SmallVec::<[_; 32]>::new();
790 {
791 let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
792 let buffer = self.buffer.read(cx);
793 for selection in selections.iter() {
794 let start_point = selection.start;
795 let indent = buffer
796 .indent_column_for_line(start_point.row)
797 .min(start_point.column);
798 let start = selection.start.to_offset(buffer);
799 let end = selection.end.to_offset(buffer);
800
801 let mut insert_extra_newline = false;
802 if let Some(language) = buffer.language() {
803 let leading_whitespace_len = buffer
804 .reversed_chars_at(start)
805 .take_while(|c| c.is_whitespace() && *c != '\n')
806 .map(|c| c.len_utf8())
807 .sum::<usize>();
808
809 let trailing_whitespace_len = buffer
810 .chars_at(end)
811 .take_while(|c| c.is_whitespace() && *c != '\n')
812 .map(|c| c.len_utf8())
813 .sum::<usize>();
814
815 insert_extra_newline = language.brackets().iter().any(|pair| {
816 let pair_start = pair.start.trim_end();
817 let pair_end = pair.end.trim_start();
818
819 pair.newline
820 && buffer.contains_str_at(end + trailing_whitespace_len, pair_end)
821 && buffer.contains_str_at(
822 (start - leading_whitespace_len).saturating_sub(pair_start.len()),
823 pair_start,
824 )
825 });
826 }
827
828 old_selections.push((selection.id, start..end, indent, insert_extra_newline));
829 }
830 }
831
832 let mut new_selections = Vec::with_capacity(old_selections.len());
833 self.buffer.update(cx, |buffer, cx| {
834 let mut delta = 0_isize;
835 let mut pending_edit: Option<PendingEdit> = None;
836 for (_, range, indent, insert_extra_newline) in &old_selections {
837 if pending_edit.as_ref().map_or(false, |pending| {
838 pending.indent != *indent
839 || pending.insert_extra_newline != *insert_extra_newline
840 }) {
841 let pending = pending_edit.take().unwrap();
842 let mut new_text = String::with_capacity(1 + pending.indent as usize);
843 new_text.push('\n');
844 new_text.extend(iter::repeat(' ').take(pending.indent as usize));
845 if pending.insert_extra_newline {
846 new_text = new_text.repeat(2);
847 }
848 buffer.edit_with_autoindent(pending.ranges, new_text, cx);
849 delta += pending.delta;
850 }
851
852 let start = (range.start as isize + delta) as usize;
853 let end = (range.end as isize + delta) as usize;
854 let mut text_len = *indent as usize + 1;
855 if *insert_extra_newline {
856 text_len *= 2;
857 }
858
859 let pending = pending_edit.get_or_insert_with(Default::default);
860 pending.delta += text_len as isize - (end - start) as isize;
861 pending.indent = *indent;
862 pending.insert_extra_newline = *insert_extra_newline;
863 pending.ranges.push(start..end);
864 }
865
866 let pending = pending_edit.unwrap();
867 let mut new_text = String::with_capacity(1 + pending.indent as usize);
868 new_text.push('\n');
869 new_text.extend(iter::repeat(' ').take(pending.indent as usize));
870 if pending.insert_extra_newline {
871 new_text = new_text.repeat(2);
872 }
873 buffer.edit_with_autoindent(pending.ranges, new_text, cx);
874
875 let mut delta = 0_isize;
876 new_selections.extend(old_selections.into_iter().map(
877 |(id, range, indent, insert_extra_newline)| {
878 let start = (range.start as isize + delta) as usize;
879 let end = (range.end as isize + delta) as usize;
880 let text_before_cursor_len = indent as usize + 1;
881 let cursor = start + text_before_cursor_len;
882 let text_len = if insert_extra_newline {
883 text_before_cursor_len * 2
884 } else {
885 text_before_cursor_len
886 };
887 delta += text_len as isize - (end - start) as isize;
888 Selection {
889 id,
890 start: cursor,
891 end: cursor,
892 reversed: false,
893 goal: SelectionGoal::None,
894 }
895 },
896 ))
897 });
898
899 self.update_selections(new_selections, true, cx);
900 self.end_transaction(cx);
901
902 #[derive(Default)]
903 struct PendingEdit {
904 indent: u32,
905 insert_extra_newline: bool,
906 delta: isize,
907 ranges: SmallVec<[Range<usize>; 32]>,
908 }
909 }
910
911 fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
912 self.start_transaction(cx);
913 let old_selections = self.selections::<usize>(cx).collect::<SmallVec<[_; 32]>>();
914 let mut new_selections = Vec::new();
915 self.buffer.update(cx, |buffer, cx| {
916 let edit_ranges = old_selections.iter().map(|s| s.start..s.end);
917 buffer.edit_with_autoindent(edit_ranges, text, cx);
918 let text_len = text.len() as isize;
919 let mut delta = 0_isize;
920 new_selections = old_selections
921 .into_iter()
922 .map(|selection| {
923 let start = selection.start as isize;
924 let end = selection.end as isize;
925 let cursor = (start + delta + text_len) as usize;
926 let deleted_count = end - start;
927 delta += text_len - deleted_count;
928 Selection {
929 id: selection.id,
930 start: cursor,
931 end: cursor,
932 reversed: false,
933 goal: SelectionGoal::None,
934 }
935 })
936 .collect();
937 });
938
939 self.update_selections(new_selections, true, cx);
940 self.end_transaction(cx);
941 }
942
943 fn autoclose_pairs(&mut self, cx: &mut ViewContext<Self>) {
944 let selections = self.selections::<usize>(cx).collect::<Vec<_>>();
945 let new_autoclose_pair_state = self.buffer.update(cx, |buffer, cx| {
946 let autoclose_pair = buffer.language().and_then(|language| {
947 let first_selection_start = selections.first().unwrap().start;
948 let pair = language.brackets().iter().find(|pair| {
949 buffer.contains_str_at(
950 first_selection_start.saturating_sub(pair.start.len()),
951 &pair.start,
952 )
953 });
954 pair.and_then(|pair| {
955 let should_autoclose = selections[1..].iter().all(|selection| {
956 buffer.contains_str_at(
957 selection.start.saturating_sub(pair.start.len()),
958 &pair.start,
959 )
960 });
961
962 if should_autoclose {
963 Some(pair.clone())
964 } else {
965 None
966 }
967 })
968 });
969
970 autoclose_pair.and_then(|pair| {
971 let selection_ranges = selections
972 .iter()
973 .map(|selection| {
974 let start = selection.start.to_offset(&*buffer);
975 start..start
976 })
977 .collect::<SmallVec<[_; 32]>>();
978
979 buffer.edit(selection_ranges, &pair.end, cx);
980
981 if pair.end.len() == 1 {
982 let mut delta = 0;
983 Some(BracketPairState {
984 ranges: buffer.anchor_range_set(selections.iter().map(move |selection| {
985 let offset = selection.start + delta;
986 delta += 1;
987 (offset, Bias::Left)..(offset, Bias::Right)
988 })),
989 pair,
990 })
991 } else {
992 None
993 }
994 })
995 });
996 self.autoclose_stack.extend(new_autoclose_pair_state);
997 }
998
999 fn skip_autoclose_end(&mut self, text: &str, cx: &mut ViewContext<Self>) -> bool {
1000 let old_selections = self.selections::<usize>(cx).collect::<Vec<_>>();
1001 let autoclose_pair_state = if let Some(autoclose_pair_state) = self.autoclose_stack.last() {
1002 autoclose_pair_state
1003 } else {
1004 return false;
1005 };
1006 if text != autoclose_pair_state.pair.end {
1007 return false;
1008 }
1009
1010 debug_assert_eq!(old_selections.len(), autoclose_pair_state.ranges.len());
1011
1012 let buffer = self.buffer.read(cx);
1013 if old_selections
1014 .iter()
1015 .zip(autoclose_pair_state.ranges.ranges::<usize, _>(buffer))
1016 .all(|(selection, autoclose_range)| {
1017 let autoclose_range_end = autoclose_range.end.to_offset(buffer);
1018 selection.is_empty() && selection.start == autoclose_range_end
1019 })
1020 {
1021 let new_selections = old_selections
1022 .into_iter()
1023 .map(|selection| {
1024 let cursor = selection.start + 1;
1025 Selection {
1026 id: selection.id,
1027 start: cursor,
1028 end: cursor,
1029 reversed: false,
1030 goal: SelectionGoal::None,
1031 }
1032 })
1033 .collect();
1034 self.autoclose_stack.pop();
1035 self.update_selections(new_selections, true, cx);
1036 true
1037 } else {
1038 false
1039 }
1040 }
1041
1042 pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
1043 self.start_transaction(cx);
1044 self.select_all(&SelectAll, cx);
1045 self.insert("", cx);
1046 self.end_transaction(cx);
1047 }
1048
1049 pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
1050 self.start_transaction(cx);
1051 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1052 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1053 for selection in &mut selections {
1054 if selection.is_empty() {
1055 let head = selection.head().to_display_point(&display_map);
1056 let cursor = movement::left(&display_map, head)
1057 .unwrap()
1058 .to_point(&display_map);
1059 selection.set_head(cursor);
1060 selection.goal = SelectionGoal::None;
1061 }
1062 }
1063 self.update_selections(selections, true, cx);
1064 self.insert("", cx);
1065 self.end_transaction(cx);
1066 }
1067
1068 pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
1069 self.start_transaction(cx);
1070 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1071 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1072 for selection in &mut selections {
1073 if selection.is_empty() {
1074 let head = selection.head().to_display_point(&display_map);
1075 let cursor = movement::right(&display_map, head)
1076 .unwrap()
1077 .to_point(&display_map);
1078 selection.set_head(cursor);
1079 selection.goal = SelectionGoal::None;
1080 }
1081 }
1082 self.update_selections(selections, true, cx);
1083 self.insert(&"", cx);
1084 self.end_transaction(cx);
1085 }
1086
1087 pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
1088 self.start_transaction(cx);
1089 let tab_size = self.build_settings.borrow()(cx).tab_size;
1090 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1091 self.buffer.update(cx, |buffer, cx| {
1092 let mut last_indented_row = None;
1093 for selection in &mut selections {
1094 if selection.is_empty() {
1095 let char_column = buffer
1096 .chars_for_range(Point::new(selection.start.row, 0)..selection.start)
1097 .count();
1098 let chars_to_next_tab_stop = tab_size - (char_column % tab_size);
1099 buffer.edit(
1100 [selection.start..selection.start],
1101 " ".repeat(chars_to_next_tab_stop),
1102 cx,
1103 );
1104 selection.start.column += chars_to_next_tab_stop as u32;
1105 selection.end = selection.start;
1106 } else {
1107 for row in selection.start.row..=selection.end.row {
1108 if last_indented_row != Some(row) {
1109 let char_column = buffer.indent_column_for_line(row) as usize;
1110 let chars_to_next_tab_stop = tab_size - (char_column % tab_size);
1111 let row_start = Point::new(row, 0);
1112 buffer.edit(
1113 [row_start..row_start],
1114 " ".repeat(chars_to_next_tab_stop),
1115 cx,
1116 );
1117 last_indented_row = Some(row);
1118 }
1119 }
1120 }
1121 }
1122 });
1123
1124 self.update_selections(selections, true, cx);
1125 self.end_transaction(cx);
1126 }
1127
1128 pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
1129 self.start_transaction(cx);
1130
1131 let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1132 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1133 let buffer = self.buffer.read(cx);
1134
1135 let mut row_delta = 0;
1136 let mut new_cursors = Vec::new();
1137 let mut edit_ranges = Vec::new();
1138 let mut selections = selections.iter().peekable();
1139 while let Some(selection) = selections.next() {
1140 let mut rows = selection.spanned_rows(false, &display_map).buffer_rows;
1141 let goal_display_column = selection.head().to_display_point(&display_map).column();
1142
1143 // Accumulate contiguous regions of rows that we want to delete.
1144 while let Some(next_selection) = selections.peek() {
1145 let next_rows = next_selection.spanned_rows(false, &display_map).buffer_rows;
1146 if next_rows.start <= rows.end {
1147 rows.end = next_rows.end;
1148 selections.next().unwrap();
1149 } else {
1150 break;
1151 }
1152 }
1153
1154 let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
1155 let edit_end;
1156 let cursor_buffer_row;
1157 if buffer.max_point().row >= rows.end {
1158 // If there's a line after the range, delete the \n from the end of the row range
1159 // and position the cursor on the next line.
1160 edit_end = Point::new(rows.end, 0).to_offset(buffer);
1161 cursor_buffer_row = rows.start;
1162 } else {
1163 // If there isn't a line after the range, delete the \n from the line before the
1164 // start of the row range and position the cursor there.
1165 edit_start = edit_start.saturating_sub(1);
1166 edit_end = buffer.len();
1167 cursor_buffer_row = rows.start.saturating_sub(1);
1168 }
1169
1170 let mut cursor =
1171 Point::new(cursor_buffer_row - row_delta, 0).to_display_point(&display_map);
1172 *cursor.column_mut() =
1173 cmp::min(goal_display_column, display_map.line_len(cursor.row()));
1174 row_delta += rows.len() as u32;
1175
1176 new_cursors.push((selection.id, cursor.to_point(&display_map)));
1177 edit_ranges.push(edit_start..edit_end);
1178 }
1179
1180 new_cursors.sort_unstable_by_key(|(_, point)| point.clone());
1181 let new_selections = new_cursors
1182 .into_iter()
1183 .map(|(id, cursor)| Selection {
1184 id,
1185 start: cursor,
1186 end: cursor,
1187 reversed: false,
1188 goal: SelectionGoal::None,
1189 })
1190 .collect();
1191 self.buffer
1192 .update(cx, |buffer, cx| buffer.edit(edit_ranges, "", cx));
1193 self.update_selections(new_selections, true, cx);
1194 self.end_transaction(cx);
1195 }
1196
1197 pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
1198 self.start_transaction(cx);
1199
1200 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1201 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1202 let buffer = self.buffer.read(cx);
1203
1204 let mut edits = Vec::new();
1205 let mut selections_iter = selections.iter().peekable();
1206 while let Some(selection) = selections_iter.next() {
1207 // Avoid duplicating the same lines twice.
1208 let mut rows = selection.spanned_rows(false, &display_map).buffer_rows;
1209
1210 while let Some(next_selection) = selections_iter.peek() {
1211 let next_rows = next_selection.spanned_rows(false, &display_map).buffer_rows;
1212 if next_rows.start <= rows.end - 1 {
1213 rows.end = next_rows.end;
1214 selections_iter.next().unwrap();
1215 } else {
1216 break;
1217 }
1218 }
1219
1220 // Copy the text from the selected row region and splice it at the start of the region.
1221 let start = Point::new(rows.start, 0);
1222 let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
1223 let text = buffer
1224 .text_for_range(start..end)
1225 .chain(Some("\n"))
1226 .collect::<String>();
1227 edits.push((start, text, rows.len() as u32));
1228 }
1229
1230 let mut edits_iter = edits.iter().peekable();
1231 let mut row_delta = 0;
1232 for selection in selections.iter_mut() {
1233 while let Some((point, _, line_count)) = edits_iter.peek() {
1234 if *point <= selection.start {
1235 row_delta += line_count;
1236 edits_iter.next();
1237 } else {
1238 break;
1239 }
1240 }
1241 selection.start.row += row_delta;
1242 selection.end.row += row_delta;
1243 }
1244
1245 self.buffer.update(cx, |buffer, cx| {
1246 for (point, text, _) in edits.into_iter().rev() {
1247 buffer.edit(Some(point..point), text, cx);
1248 }
1249 });
1250
1251 self.update_selections(selections, true, cx);
1252 self.end_transaction(cx);
1253 }
1254
1255 pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
1256 self.start_transaction(cx);
1257
1258 let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1259 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1260 let buffer = self.buffer.read(cx);
1261
1262 let mut edits = Vec::new();
1263 let mut new_selection_ranges = Vec::new();
1264 let mut old_folds = Vec::new();
1265 let mut new_folds = Vec::new();
1266
1267 let mut selections = selections.iter().peekable();
1268 let mut contiguous_selections = Vec::new();
1269 while let Some(selection) = selections.next() {
1270 // Accumulate contiguous regions of rows that we want to move.
1271 contiguous_selections.push(selection.point_range(buffer));
1272 let SpannedRows {
1273 mut buffer_rows,
1274 mut display_rows,
1275 } = selection.spanned_rows(false, &display_map);
1276
1277 while let Some(next_selection) = selections.peek() {
1278 let SpannedRows {
1279 buffer_rows: next_buffer_rows,
1280 display_rows: next_display_rows,
1281 } = next_selection.spanned_rows(false, &display_map);
1282 if next_buffer_rows.start <= buffer_rows.end {
1283 buffer_rows.end = next_buffer_rows.end;
1284 display_rows.end = next_display_rows.end;
1285 contiguous_selections.push(next_selection.point_range(buffer));
1286 selections.next().unwrap();
1287 } else {
1288 break;
1289 }
1290 }
1291
1292 // Cut the text from the selected rows and paste it at the start of the previous line.
1293 if display_rows.start != 0 {
1294 let start = Point::new(buffer_rows.start, 0).to_offset(buffer);
1295 let end = Point::new(buffer_rows.end - 1, buffer.line_len(buffer_rows.end - 1))
1296 .to_offset(buffer);
1297
1298 let prev_row_display_start = DisplayPoint::new(display_rows.start - 1, 0);
1299 let prev_row_buffer_start = display_map.prev_row_boundary(prev_row_display_start).1;
1300 let prev_row_buffer_start_offset = prev_row_buffer_start.to_offset(buffer);
1301
1302 let mut text = String::new();
1303 text.extend(buffer.text_for_range(start..end));
1304 text.push('\n');
1305 edits.push((
1306 prev_row_buffer_start_offset..prev_row_buffer_start_offset,
1307 text,
1308 ));
1309 edits.push((start - 1..end, String::new()));
1310
1311 let row_delta = buffer_rows.start - prev_row_buffer_start.row;
1312
1313 // Move selections up.
1314 for range in &mut contiguous_selections {
1315 range.start.row -= row_delta;
1316 range.end.row -= row_delta;
1317 }
1318
1319 // Move folds up.
1320 old_folds.push(start..end);
1321 for fold in display_map.folds_in_range(start..end) {
1322 let mut start = fold.start.to_point(buffer);
1323 let mut end = fold.end.to_point(buffer);
1324 start.row -= row_delta;
1325 end.row -= row_delta;
1326 new_folds.push(start..end);
1327 }
1328 }
1329
1330 new_selection_ranges.extend(contiguous_selections.drain(..));
1331 }
1332
1333 self.unfold_ranges(old_folds, cx);
1334 self.buffer.update(cx, |buffer, cx| {
1335 for (range, text) in edits.into_iter().rev() {
1336 buffer.edit(Some(range), text, cx);
1337 }
1338 });
1339 self.fold_ranges(new_folds, cx);
1340 self.select_ranges(new_selection_ranges, true, cx);
1341
1342 self.end_transaction(cx);
1343 }
1344
1345 pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
1346 self.start_transaction(cx);
1347
1348 let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1349 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1350 let buffer = self.buffer.read(cx);
1351
1352 let mut edits = Vec::new();
1353 let mut new_selection_ranges = Vec::new();
1354 let mut old_folds = Vec::new();
1355 let mut new_folds = Vec::new();
1356
1357 let mut selections = selections.iter().peekable();
1358 let mut contiguous_selections = Vec::new();
1359 while let Some(selection) = selections.next() {
1360 // Accumulate contiguous regions of rows that we want to move.
1361 contiguous_selections.push(selection.point_range(buffer));
1362 let SpannedRows {
1363 mut buffer_rows,
1364 mut display_rows,
1365 } = selection.spanned_rows(false, &display_map);
1366 while let Some(next_selection) = selections.peek() {
1367 let SpannedRows {
1368 buffer_rows: next_buffer_rows,
1369 display_rows: next_display_rows,
1370 } = next_selection.spanned_rows(false, &display_map);
1371 if next_buffer_rows.start <= buffer_rows.end {
1372 buffer_rows.end = next_buffer_rows.end;
1373 display_rows.end = next_display_rows.end;
1374 contiguous_selections.push(next_selection.point_range(buffer));
1375 selections.next().unwrap();
1376 } else {
1377 break;
1378 }
1379 }
1380
1381 // Cut the text from the selected rows and paste it at the end of the next line.
1382 if display_rows.end <= display_map.max_point().row() {
1383 let start = Point::new(buffer_rows.start, 0).to_offset(buffer);
1384 let end = Point::new(buffer_rows.end - 1, buffer.line_len(buffer_rows.end - 1))
1385 .to_offset(buffer);
1386
1387 let next_row_display_end =
1388 DisplayPoint::new(display_rows.end, display_map.line_len(display_rows.end));
1389 let next_row_buffer_end = display_map.next_row_boundary(next_row_display_end).1;
1390 let next_row_buffer_end_offset = next_row_buffer_end.to_offset(buffer);
1391
1392 let mut text = String::new();
1393 text.push('\n');
1394 text.extend(buffer.text_for_range(start..end));
1395 edits.push((start..end + 1, String::new()));
1396 edits.push((next_row_buffer_end_offset..next_row_buffer_end_offset, text));
1397
1398 let row_delta = next_row_buffer_end.row - buffer_rows.end + 1;
1399
1400 // Move selections down.
1401 for range in &mut contiguous_selections {
1402 range.start.row += row_delta;
1403 range.end.row += row_delta;
1404 }
1405
1406 // Move folds down.
1407 old_folds.push(start..end);
1408 for fold in display_map.folds_in_range(start..end) {
1409 let mut start = fold.start.to_point(buffer);
1410 let mut end = fold.end.to_point(buffer);
1411 start.row += row_delta;
1412 end.row += row_delta;
1413 new_folds.push(start..end);
1414 }
1415 }
1416
1417 new_selection_ranges.extend(contiguous_selections.drain(..));
1418 }
1419
1420 self.unfold_ranges(old_folds, cx);
1421 self.buffer.update(cx, |buffer, cx| {
1422 for (range, text) in edits.into_iter().rev() {
1423 buffer.edit(Some(range), text, cx);
1424 }
1425 });
1426 self.fold_ranges(new_folds, cx);
1427 self.select_ranges(new_selection_ranges, true, cx);
1428
1429 self.end_transaction(cx);
1430 }
1431
1432 pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
1433 self.start_transaction(cx);
1434 let mut text = String::new();
1435 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1436 let mut clipboard_selections = Vec::with_capacity(selections.len());
1437 {
1438 let buffer = self.buffer.read(cx);
1439 let max_point = buffer.max_point();
1440 for selection in &mut selections {
1441 let is_entire_line = selection.is_empty();
1442 if is_entire_line {
1443 selection.start = Point::new(selection.start.row, 0);
1444 selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
1445 }
1446 let mut len = 0;
1447 for chunk in buffer.text_for_range(selection.start..selection.end) {
1448 text.push_str(chunk);
1449 len += chunk.len();
1450 }
1451 clipboard_selections.push(ClipboardSelection {
1452 len,
1453 is_entire_line,
1454 });
1455 }
1456 }
1457 self.update_selections(selections, true, cx);
1458 self.insert("", cx);
1459 self.end_transaction(cx);
1460
1461 cx.as_mut()
1462 .write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
1463 }
1464
1465 pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
1466 let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1467 let buffer = self.buffer.read(cx);
1468 let max_point = buffer.max_point();
1469 let mut text = String::new();
1470 let mut clipboard_selections = Vec::with_capacity(selections.len());
1471 for selection in selections.iter() {
1472 let mut start = selection.start;
1473 let mut end = selection.end;
1474 let is_entire_line = selection.is_empty();
1475 if is_entire_line {
1476 start = Point::new(start.row, 0);
1477 end = cmp::min(max_point, Point::new(start.row + 1, 0));
1478 }
1479 let mut len = 0;
1480 for chunk in buffer.text_for_range(start..end) {
1481 text.push_str(chunk);
1482 len += chunk.len();
1483 }
1484 clipboard_selections.push(ClipboardSelection {
1485 len,
1486 is_entire_line,
1487 });
1488 }
1489
1490 cx.as_mut()
1491 .write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
1492 }
1493
1494 pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
1495 if let Some(item) = cx.as_mut().read_from_clipboard() {
1496 let clipboard_text = item.text();
1497 if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
1498 let mut selections = self.selections::<usize>(cx).collect::<Vec<_>>();
1499 let all_selections_were_entire_line =
1500 clipboard_selections.iter().all(|s| s.is_entire_line);
1501 if clipboard_selections.len() != selections.len() {
1502 clipboard_selections.clear();
1503 }
1504
1505 let mut delta = 0_isize;
1506 let mut start_offset = 0;
1507 for (i, selection) in selections.iter_mut().enumerate() {
1508 let to_insert;
1509 let entire_line;
1510 if let Some(clipboard_selection) = clipboard_selections.get(i) {
1511 let end_offset = start_offset + clipboard_selection.len;
1512 to_insert = &clipboard_text[start_offset..end_offset];
1513 entire_line = clipboard_selection.is_entire_line;
1514 start_offset = end_offset
1515 } else {
1516 to_insert = clipboard_text.as_str();
1517 entire_line = all_selections_were_entire_line;
1518 }
1519
1520 selection.start = (selection.start as isize + delta) as usize;
1521 selection.end = (selection.end as isize + delta) as usize;
1522
1523 self.buffer.update(cx, |buffer, cx| {
1524 // If the corresponding selection was empty when this slice of the
1525 // clipboard text was written, then the entire line containing the
1526 // selection was copied. If this selection is also currently empty,
1527 // then paste the line before the current line of the buffer.
1528 let range = if selection.is_empty() && entire_line {
1529 let column = selection.start.to_point(&*buffer).column as usize;
1530 let line_start = selection.start - column;
1531 line_start..line_start
1532 } else {
1533 selection.start..selection.end
1534 };
1535
1536 delta += to_insert.len() as isize - range.len() as isize;
1537 buffer.edit([range], to_insert, cx);
1538 selection.start += to_insert.len();
1539 selection.end = selection.start;
1540 });
1541 }
1542 self.update_selections(selections, true, cx);
1543 } else {
1544 self.insert(clipboard_text, cx);
1545 }
1546 }
1547 }
1548
1549 pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
1550 self.buffer.update(cx, |buffer, cx| buffer.undo(cx));
1551 self.request_autoscroll(cx);
1552 }
1553
1554 pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
1555 self.buffer.update(cx, |buffer, cx| buffer.redo(cx));
1556 self.request_autoscroll(cx);
1557 }
1558
1559 pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
1560 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1561 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1562 for selection in &mut selections {
1563 let start = selection.start.to_display_point(&display_map);
1564 let end = selection.end.to_display_point(&display_map);
1565
1566 if start != end {
1567 selection.end = selection.start.clone();
1568 } else {
1569 let cursor = movement::left(&display_map, start)
1570 .unwrap()
1571 .to_point(&display_map);
1572 selection.start = cursor.clone();
1573 selection.end = cursor;
1574 }
1575 selection.reversed = false;
1576 selection.goal = SelectionGoal::None;
1577 }
1578 self.update_selections(selections, true, cx);
1579 }
1580
1581 pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
1582 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1583 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1584 for selection in &mut selections {
1585 let head = selection.head().to_display_point(&display_map);
1586 let cursor = movement::left(&display_map, head)
1587 .unwrap()
1588 .to_point(&display_map);
1589 selection.set_head(cursor);
1590 selection.goal = SelectionGoal::None;
1591 }
1592 self.update_selections(selections, true, cx);
1593 }
1594
1595 pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
1596 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1597 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1598 for selection in &mut selections {
1599 let start = selection.start.to_display_point(&display_map);
1600 let end = selection.end.to_display_point(&display_map);
1601
1602 if start != end {
1603 selection.start = selection.end.clone();
1604 } else {
1605 let cursor = movement::right(&display_map, end)
1606 .unwrap()
1607 .to_point(&display_map);
1608 selection.start = cursor;
1609 selection.end = cursor;
1610 }
1611 selection.reversed = false;
1612 selection.goal = SelectionGoal::None;
1613 }
1614 self.update_selections(selections, true, cx);
1615 }
1616
1617 pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
1618 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1619 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1620 for selection in &mut selections {
1621 let head = selection.head().to_display_point(&display_map);
1622 let cursor = movement::right(&display_map, head)
1623 .unwrap()
1624 .to_point(&display_map);
1625 selection.set_head(cursor);
1626 selection.goal = SelectionGoal::None;
1627 }
1628 self.update_selections(selections, true, cx);
1629 }
1630
1631 pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
1632 if matches!(self.mode, EditorMode::SingleLine) {
1633 cx.propagate_action();
1634 return;
1635 }
1636
1637 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1638 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1639 for selection in &mut selections {
1640 let start = selection.start.to_display_point(&display_map);
1641 let end = selection.end.to_display_point(&display_map);
1642 if start != end {
1643 selection.goal = SelectionGoal::None;
1644 }
1645
1646 let (start, goal) = movement::up(&display_map, start, selection.goal).unwrap();
1647 let cursor = start.to_point(&display_map);
1648 selection.start = cursor;
1649 selection.end = cursor;
1650 selection.goal = goal;
1651 selection.reversed = false;
1652 }
1653 self.update_selections(selections, true, cx);
1654 }
1655
1656 pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
1657 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1658 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1659 for selection in &mut selections {
1660 let head = selection.head().to_display_point(&display_map);
1661 let (head, goal) = movement::up(&display_map, head, selection.goal).unwrap();
1662 let cursor = head.to_point(&display_map);
1663 selection.set_head(cursor);
1664 selection.goal = goal;
1665 }
1666 self.update_selections(selections, true, cx);
1667 }
1668
1669 pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
1670 if matches!(self.mode, EditorMode::SingleLine) {
1671 cx.propagate_action();
1672 return;
1673 }
1674
1675 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1676 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1677 for selection in &mut selections {
1678 let start = selection.start.to_display_point(&display_map);
1679 let end = selection.end.to_display_point(&display_map);
1680 if start != end {
1681 selection.goal = SelectionGoal::None;
1682 }
1683
1684 let (start, goal) = movement::down(&display_map, end, selection.goal).unwrap();
1685 let cursor = start.to_point(&display_map);
1686 selection.start = cursor;
1687 selection.end = cursor;
1688 selection.goal = goal;
1689 selection.reversed = false;
1690 }
1691 self.update_selections(selections, true, cx);
1692 }
1693
1694 pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
1695 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1696 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1697 for selection in &mut selections {
1698 let head = selection.head().to_display_point(&display_map);
1699 let (head, goal) = movement::down(&display_map, head, selection.goal).unwrap();
1700 let cursor = head.to_point(&display_map);
1701 selection.set_head(cursor);
1702 selection.goal = goal;
1703 }
1704 self.update_selections(selections, true, cx);
1705 }
1706
1707 pub fn move_to_previous_word_boundary(
1708 &mut self,
1709 _: &MoveToPreviousWordBoundary,
1710 cx: &mut ViewContext<Self>,
1711 ) {
1712 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1713 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1714 for selection in &mut selections {
1715 let head = selection.head().to_display_point(&display_map);
1716 let new_head = movement::prev_word_boundary(&display_map, head).unwrap();
1717 let cursor = new_head.to_point(&display_map);
1718 selection.start = cursor.clone();
1719 selection.end = cursor;
1720 selection.reversed = false;
1721 selection.goal = SelectionGoal::None;
1722 }
1723 self.update_selections(selections, true, cx);
1724 }
1725
1726 pub fn select_to_previous_word_boundary(
1727 &mut self,
1728 _: &SelectToPreviousWordBoundary,
1729 cx: &mut ViewContext<Self>,
1730 ) {
1731 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1732 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1733 for selection in &mut selections {
1734 let head = selection.head().to_display_point(&display_map);
1735 let new_head = movement::prev_word_boundary(&display_map, head).unwrap();
1736 let cursor = new_head.to_point(&display_map);
1737 selection.set_head(cursor);
1738 selection.goal = SelectionGoal::None;
1739 }
1740 self.update_selections(selections, true, cx);
1741 }
1742
1743 pub fn delete_to_previous_word_boundary(
1744 &mut self,
1745 _: &DeleteToPreviousWordBoundary,
1746 cx: &mut ViewContext<Self>,
1747 ) {
1748 self.start_transaction(cx);
1749 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1750 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1751 for selection in &mut selections {
1752 if selection.is_empty() {
1753 let head = selection.head().to_display_point(&display_map);
1754 let new_head = movement::prev_word_boundary(&display_map, head).unwrap();
1755 let cursor = new_head.to_point(&display_map);
1756 selection.set_head(cursor);
1757 selection.goal = SelectionGoal::None;
1758 }
1759 }
1760 self.update_selections(selections, true, cx);
1761 self.insert("", cx);
1762 self.end_transaction(cx);
1763 }
1764
1765 pub fn move_to_next_word_boundary(
1766 &mut self,
1767 _: &MoveToNextWordBoundary,
1768 cx: &mut ViewContext<Self>,
1769 ) {
1770 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1771 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1772 for selection in &mut selections {
1773 let head = selection.head().to_display_point(&display_map);
1774 let new_head = movement::next_word_boundary(&display_map, head).unwrap();
1775 let cursor = new_head.to_point(&display_map);
1776 selection.start = cursor;
1777 selection.end = cursor;
1778 selection.reversed = false;
1779 selection.goal = SelectionGoal::None;
1780 }
1781 self.update_selections(selections, true, cx);
1782 }
1783
1784 pub fn select_to_next_word_boundary(
1785 &mut self,
1786 _: &SelectToNextWordBoundary,
1787 cx: &mut ViewContext<Self>,
1788 ) {
1789 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1790 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1791 for selection in &mut selections {
1792 let head = selection.head().to_display_point(&display_map);
1793 let new_head = movement::next_word_boundary(&display_map, head).unwrap();
1794 let cursor = new_head.to_point(&display_map);
1795 selection.set_head(cursor);
1796 selection.goal = SelectionGoal::None;
1797 }
1798 self.update_selections(selections, true, cx);
1799 }
1800
1801 pub fn delete_to_next_word_boundary(
1802 &mut self,
1803 _: &DeleteToNextWordBoundary,
1804 cx: &mut ViewContext<Self>,
1805 ) {
1806 self.start_transaction(cx);
1807 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1808 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1809 for selection in &mut selections {
1810 if selection.is_empty() {
1811 let head = selection.head().to_display_point(&display_map);
1812 let new_head = movement::next_word_boundary(&display_map, head).unwrap();
1813 let cursor = new_head.to_point(&display_map);
1814 selection.set_head(cursor);
1815 selection.goal = SelectionGoal::None;
1816 }
1817 }
1818 self.update_selections(selections, true, cx);
1819 self.insert("", cx);
1820 self.end_transaction(cx);
1821 }
1822
1823 pub fn move_to_beginning_of_line(
1824 &mut self,
1825 _: &MoveToBeginningOfLine,
1826 cx: &mut ViewContext<Self>,
1827 ) {
1828 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1829 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1830 for selection in &mut selections {
1831 let head = selection.head().to_display_point(&display_map);
1832 let new_head = movement::line_beginning(&display_map, head, true).unwrap();
1833 let cursor = new_head.to_point(&display_map);
1834 selection.start = cursor;
1835 selection.end = cursor;
1836 selection.reversed = false;
1837 selection.goal = SelectionGoal::None;
1838 }
1839 self.update_selections(selections, true, cx);
1840 }
1841
1842 pub fn select_to_beginning_of_line(
1843 &mut self,
1844 SelectToBeginningOfLine(toggle_indent): &SelectToBeginningOfLine,
1845 cx: &mut ViewContext<Self>,
1846 ) {
1847 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1848 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1849 for selection in &mut selections {
1850 let head = selection.head().to_display_point(&display_map);
1851 let new_head = movement::line_beginning(&display_map, head, *toggle_indent).unwrap();
1852 selection.set_head(new_head.to_point(&display_map));
1853 selection.goal = SelectionGoal::None;
1854 }
1855 self.update_selections(selections, true, cx);
1856 }
1857
1858 pub fn delete_to_beginning_of_line(
1859 &mut self,
1860 _: &DeleteToBeginningOfLine,
1861 cx: &mut ViewContext<Self>,
1862 ) {
1863 self.start_transaction(cx);
1864 self.select_to_beginning_of_line(&SelectToBeginningOfLine(false), cx);
1865 self.backspace(&Backspace, cx);
1866 self.end_transaction(cx);
1867 }
1868
1869 pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
1870 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1871 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1872 {
1873 for selection in &mut selections {
1874 let head = selection.head().to_display_point(&display_map);
1875 let new_head = movement::line_end(&display_map, head).unwrap();
1876 let anchor = new_head.to_point(&display_map);
1877 selection.start = anchor.clone();
1878 selection.end = anchor;
1879 selection.reversed = false;
1880 selection.goal = SelectionGoal::None;
1881 }
1882 }
1883 self.update_selections(selections, true, cx);
1884 }
1885
1886 pub fn select_to_end_of_line(&mut self, _: &SelectToEndOfLine, cx: &mut ViewContext<Self>) {
1887 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1888 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1889 for selection in &mut selections {
1890 let head = selection.head().to_display_point(&display_map);
1891 let new_head = movement::line_end(&display_map, head).unwrap();
1892 selection.set_head(new_head.to_point(&display_map));
1893 selection.goal = SelectionGoal::None;
1894 }
1895 self.update_selections(selections, true, cx);
1896 }
1897
1898 pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
1899 self.start_transaction(cx);
1900 self.select_to_end_of_line(&SelectToEndOfLine, cx);
1901 self.delete(&Delete, cx);
1902 self.end_transaction(cx);
1903 }
1904
1905 pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
1906 self.start_transaction(cx);
1907 self.select_to_end_of_line(&SelectToEndOfLine, cx);
1908 self.cut(&Cut, cx);
1909 self.end_transaction(cx);
1910 }
1911
1912 pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
1913 let selection = Selection {
1914 id: post_inc(&mut self.next_selection_id),
1915 start: 0,
1916 end: 0,
1917 reversed: false,
1918 goal: SelectionGoal::None,
1919 };
1920 self.update_selections(vec![selection], true, cx);
1921 }
1922
1923 pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
1924 let mut selection = self.selections::<Point>(cx).last().unwrap().clone();
1925 selection.set_head(Point::zero());
1926 self.update_selections(vec![selection], true, cx);
1927 }
1928
1929 pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
1930 let buffer = self.buffer.read(cx);
1931 let cursor = buffer.len();
1932 let selection = Selection {
1933 id: post_inc(&mut self.next_selection_id),
1934 start: cursor,
1935 end: cursor,
1936 reversed: false,
1937 goal: SelectionGoal::None,
1938 };
1939 self.update_selections(vec![selection], true, cx);
1940 }
1941
1942 pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
1943 let mut selection = self.selections::<usize>(cx).last().unwrap().clone();
1944 selection.set_head(self.buffer.read(cx).len());
1945 self.update_selections(vec![selection], true, cx);
1946 }
1947
1948 pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
1949 let selection = Selection {
1950 id: post_inc(&mut self.next_selection_id),
1951 start: 0,
1952 end: self.buffer.read(cx).len(),
1953 reversed: false,
1954 goal: SelectionGoal::None,
1955 };
1956 self.update_selections(vec![selection], false, cx);
1957 }
1958
1959 pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
1960 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1961 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1962 let buffer = self.buffer.read(cx);
1963 let max_point = buffer.max_point();
1964 for selection in &mut selections {
1965 let rows = selection.spanned_rows(true, &display_map).buffer_rows;
1966 selection.start = Point::new(rows.start, 0);
1967 selection.end = cmp::min(max_point, Point::new(rows.end, 0));
1968 selection.reversed = false;
1969 }
1970 self.update_selections(selections, true, cx);
1971 }
1972
1973 pub fn split_selection_into_lines(
1974 &mut self,
1975 _: &SplitSelectionIntoLines,
1976 cx: &mut ViewContext<Self>,
1977 ) {
1978 let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
1979 let buffer = self.buffer.read(cx);
1980
1981 let mut to_unfold = Vec::new();
1982 let mut new_selections = Vec::new();
1983 for selection in selections.iter() {
1984 if selection.start.row != selection.end.row {
1985 new_selections.push(Selection {
1986 id: post_inc(&mut self.next_selection_id),
1987 start: selection.start,
1988 end: selection.start,
1989 reversed: false,
1990 goal: SelectionGoal::None,
1991 });
1992 }
1993 for row in selection.start.row + 1..selection.end.row {
1994 let cursor = Point::new(row, buffer.line_len(row));
1995 new_selections.push(Selection {
1996 id: post_inc(&mut self.next_selection_id),
1997 start: cursor,
1998 end: cursor,
1999 reversed: false,
2000 goal: SelectionGoal::None,
2001 });
2002 }
2003 new_selections.push(Selection {
2004 id: selection.id,
2005 start: selection.end,
2006 end: selection.end,
2007 reversed: false,
2008 goal: SelectionGoal::None,
2009 });
2010 to_unfold.push(selection.start..selection.end);
2011 }
2012 self.unfold_ranges(to_unfold, cx);
2013 self.update_selections(new_selections, true, cx);
2014 }
2015
2016 pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
2017 self.add_selection(true, cx);
2018 }
2019
2020 pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
2021 self.add_selection(false, cx);
2022 }
2023
2024 fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
2025 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2026 let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
2027 let mut state = self.add_selections_state.take().unwrap_or_else(|| {
2028 let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
2029 let range = oldest_selection.display_range(&display_map).sorted();
2030 let columns = cmp::min(range.start.column(), range.end.column())
2031 ..cmp::max(range.start.column(), range.end.column());
2032
2033 selections.clear();
2034 let mut stack = Vec::new();
2035 for row in range.start.row()..=range.end.row() {
2036 if let Some(selection) = self.build_columnar_selection(
2037 &display_map,
2038 row,
2039 &columns,
2040 oldest_selection.reversed,
2041 ) {
2042 stack.push(selection.id);
2043 selections.push(selection);
2044 }
2045 }
2046
2047 if above {
2048 stack.reverse();
2049 }
2050
2051 AddSelectionsState { above, stack }
2052 });
2053
2054 let last_added_selection = *state.stack.last().unwrap();
2055 let mut new_selections = Vec::new();
2056 if above == state.above {
2057 let end_row = if above {
2058 0
2059 } else {
2060 display_map.max_point().row()
2061 };
2062
2063 'outer: for selection in selections {
2064 if selection.id == last_added_selection {
2065 let range = selection.display_range(&display_map).sorted();
2066 debug_assert_eq!(range.start.row(), range.end.row());
2067 let mut row = range.start.row();
2068 let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
2069 {
2070 start..end
2071 } else {
2072 cmp::min(range.start.column(), range.end.column())
2073 ..cmp::max(range.start.column(), range.end.column())
2074 };
2075
2076 while row != end_row {
2077 if above {
2078 row -= 1;
2079 } else {
2080 row += 1;
2081 }
2082
2083 if let Some(new_selection) = self.build_columnar_selection(
2084 &display_map,
2085 row,
2086 &columns,
2087 selection.reversed,
2088 ) {
2089 state.stack.push(new_selection.id);
2090 if above {
2091 new_selections.push(new_selection);
2092 new_selections.push(selection);
2093 } else {
2094 new_selections.push(selection);
2095 new_selections.push(new_selection);
2096 }
2097
2098 continue 'outer;
2099 }
2100 }
2101 }
2102
2103 new_selections.push(selection);
2104 }
2105 } else {
2106 new_selections = selections;
2107 new_selections.retain(|s| s.id != last_added_selection);
2108 state.stack.pop();
2109 }
2110
2111 self.update_selections(new_selections, true, cx);
2112 if state.stack.len() > 1 {
2113 self.add_selections_state = Some(state);
2114 }
2115 }
2116
2117 pub fn select_larger_syntax_node(
2118 &mut self,
2119 _: &SelectLargerSyntaxNode,
2120 cx: &mut ViewContext<Self>,
2121 ) {
2122 let old_selections = self.selections::<usize>(cx).collect::<Box<_>>();
2123 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2124 let buffer = self.buffer.read(cx);
2125
2126 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
2127 let mut selected_larger_node = false;
2128 let mut new_selections = old_selections
2129 .iter()
2130 .map(|selection| {
2131 let old_range = selection.start..selection.end;
2132 let mut new_range = old_range.clone();
2133 while let Some(containing_range) =
2134 buffer.range_for_syntax_ancestor(new_range.clone())
2135 {
2136 new_range = containing_range;
2137 if !display_map.intersects_fold(new_range.start)
2138 && !display_map.intersects_fold(new_range.end)
2139 {
2140 break;
2141 }
2142 }
2143
2144 selected_larger_node |= new_range != old_range;
2145 Selection {
2146 id: selection.id,
2147 start: new_range.start,
2148 end: new_range.end,
2149 goal: SelectionGoal::None,
2150 reversed: selection.reversed,
2151 }
2152 })
2153 .collect::<Vec<_>>();
2154
2155 if selected_larger_node {
2156 stack.push(old_selections);
2157 new_selections.sort_unstable_by_key(|selection| selection.start);
2158 self.update_selections(new_selections, true, cx);
2159 }
2160 self.select_larger_syntax_node_stack = stack;
2161 }
2162
2163 pub fn select_smaller_syntax_node(
2164 &mut self,
2165 _: &SelectSmallerSyntaxNode,
2166 cx: &mut ViewContext<Self>,
2167 ) {
2168 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
2169 if let Some(selections) = stack.pop() {
2170 self.update_selections(selections.to_vec(), true, cx);
2171 }
2172 self.select_larger_syntax_node_stack = stack;
2173 }
2174
2175 pub fn move_to_enclosing_bracket(
2176 &mut self,
2177 _: &MoveToEnclosingBracket,
2178 cx: &mut ViewContext<Self>,
2179 ) {
2180 let mut selections = self.selections::<usize>(cx).collect::<Vec<_>>();
2181 let buffer = self.buffer.read(cx.as_ref());
2182 for selection in &mut selections {
2183 if let Some((open_range, close_range)) =
2184 buffer.enclosing_bracket_ranges(selection.start..selection.end)
2185 {
2186 let close_range = close_range.to_inclusive();
2187 let destination = if close_range.contains(&selection.start)
2188 && close_range.contains(&selection.end)
2189 {
2190 open_range.end
2191 } else {
2192 *close_range.start()
2193 };
2194 selection.start = destination;
2195 selection.end = destination;
2196 }
2197 }
2198
2199 self.update_selections(selections, true, cx);
2200 }
2201
2202 fn build_columnar_selection(
2203 &mut self,
2204 display_map: &DisplayMapSnapshot,
2205 row: u32,
2206 columns: &Range<u32>,
2207 reversed: bool,
2208 ) -> Option<Selection<Point>> {
2209 let is_empty = columns.start == columns.end;
2210 let line_len = display_map.line_len(row);
2211 if columns.start < line_len || (is_empty && columns.start == line_len) {
2212 let start = DisplayPoint::new(row, columns.start);
2213 let end = DisplayPoint::new(row, cmp::min(columns.end, line_len));
2214 Some(Selection {
2215 id: post_inc(&mut self.next_selection_id),
2216 start: start.to_point(display_map),
2217 end: end.to_point(display_map),
2218 reversed,
2219 goal: SelectionGoal::ColumnRange {
2220 start: columns.start,
2221 end: columns.end,
2222 },
2223 })
2224 } else {
2225 None
2226 }
2227 }
2228
2229 pub fn active_selection_sets<'a>(
2230 &'a self,
2231 cx: &'a AppContext,
2232 ) -> impl 'a + Iterator<Item = SelectionSetId> {
2233 let buffer = self.buffer.read(cx);
2234 let replica_id = buffer.replica_id();
2235 buffer
2236 .selection_sets()
2237 .filter(move |(set_id, set)| {
2238 set.active && (set_id.replica_id != replica_id || **set_id == self.selection_set_id)
2239 })
2240 .map(|(set_id, _)| *set_id)
2241 }
2242
2243 pub fn selections_in_range<'a>(
2244 &'a self,
2245 set_id: SelectionSetId,
2246 range: Range<DisplayPoint>,
2247 cx: &'a mut MutableAppContext,
2248 ) -> impl 'a + Iterator<Item = Range<DisplayPoint>> {
2249 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2250 let buffer = self.buffer.read(cx);
2251 let selections = buffer
2252 .selection_set(set_id)
2253 .unwrap()
2254 .selections::<Point, _>(buffer)
2255 .collect::<Vec<_>>();
2256 let start = range.start.to_point(&display_map);
2257 let start_index = self.selection_insertion_index(&selections, start);
2258 let pending_selection = if set_id.replica_id == self.buffer.read(cx).replica_id() {
2259 self.pending_selection.as_ref().and_then(|pending| {
2260 let mut selection_start = pending.start.to_display_point(&display_map);
2261 let mut selection_end = pending.end.to_display_point(&display_map);
2262 if pending.reversed {
2263 mem::swap(&mut selection_start, &mut selection_end);
2264 }
2265 if selection_start <= range.end || selection_end <= range.end {
2266 Some(selection_start..selection_end)
2267 } else {
2268 None
2269 }
2270 })
2271 } else {
2272 None
2273 };
2274 selections
2275 .into_iter()
2276 .skip(start_index)
2277 .map(move |s| s.display_range(&display_map))
2278 .take_while(move |r| r.start <= range.end || r.end <= range.end)
2279 .chain(pending_selection)
2280 }
2281
2282 fn selection_insertion_index(&self, selections: &[Selection<Point>], start: Point) -> usize {
2283 match selections.binary_search_by_key(&start, |probe| probe.start) {
2284 Ok(index) => index,
2285 Err(index) => {
2286 if index > 0 && selections[index - 1].end > start {
2287 index - 1
2288 } else {
2289 index
2290 }
2291 }
2292 }
2293 }
2294
2295 pub fn selections<'a, D>(&self, cx: &'a AppContext) -> impl 'a + Iterator<Item = Selection<D>>
2296 where
2297 D: 'a + TextDimension<'a> + Ord,
2298 {
2299 let buffer = self.buffer.read(cx);
2300 let mut selections = buffer
2301 .selection_set(self.selection_set_id)
2302 .unwrap()
2303 .selections::<D, _>(buffer)
2304 .peekable();
2305 let mut pending_selection = self.pending_selection.clone().map(|selection| Selection {
2306 id: selection.id,
2307 start: selection.start.summary::<D, _>(buffer),
2308 end: selection.end.summary::<D, _>(buffer),
2309 reversed: selection.reversed,
2310 goal: selection.goal,
2311 });
2312 iter::from_fn(move || {
2313 if let Some(pending) = pending_selection.as_mut() {
2314 while let Some(next_selection) = selections.peek() {
2315 if pending.start <= next_selection.end && pending.end >= next_selection.start {
2316 let next_selection = selections.next().unwrap();
2317 if next_selection.start < pending.start {
2318 pending.start = next_selection.start;
2319 }
2320 if next_selection.end > pending.end {
2321 pending.end = next_selection.end;
2322 }
2323 } else if next_selection.end < pending.start {
2324 return selections.next();
2325 } else {
2326 break;
2327 }
2328 }
2329
2330 pending_selection.take()
2331 } else {
2332 selections.next()
2333 }
2334 })
2335 }
2336
2337 fn update_selections<T>(
2338 &mut self,
2339 mut selections: Vec<Selection<T>>,
2340 autoscroll: bool,
2341 cx: &mut ViewContext<Self>,
2342 ) where
2343 T: ToOffset + ToPoint + Ord + std::marker::Copy + std::fmt::Debug,
2344 {
2345 // Merge overlapping selections.
2346 let buffer = self.buffer.read(cx);
2347 let mut i = 1;
2348 while i < selections.len() {
2349 if selections[i - 1].end >= selections[i].start {
2350 let removed = selections.remove(i);
2351 if removed.start < selections[i - 1].start {
2352 selections[i - 1].start = removed.start;
2353 }
2354 if removed.end > selections[i - 1].end {
2355 selections[i - 1].end = removed.end;
2356 }
2357 } else {
2358 i += 1;
2359 }
2360 }
2361
2362 self.pending_selection = None;
2363 self.add_selections_state = None;
2364 self.select_larger_syntax_node_stack.clear();
2365 while let Some(autoclose_pair_state) = self.autoclose_stack.last() {
2366 let all_selections_inside_autoclose_ranges =
2367 if selections.len() == autoclose_pair_state.ranges.len() {
2368 selections
2369 .iter()
2370 .zip(autoclose_pair_state.ranges.ranges::<Point, _>(buffer))
2371 .all(|(selection, autoclose_range)| {
2372 let head = selection.head().to_point(&*buffer);
2373 autoclose_range.start <= head && autoclose_range.end >= head
2374 })
2375 } else {
2376 false
2377 };
2378
2379 if all_selections_inside_autoclose_ranges {
2380 break;
2381 } else {
2382 self.autoclose_stack.pop();
2383 }
2384 }
2385
2386 if autoscroll {
2387 self.request_autoscroll(cx);
2388 }
2389 self.pause_cursor_blinking(cx);
2390
2391 self.buffer.update(cx, |buffer, cx| {
2392 buffer
2393 .update_selection_set(self.selection_set_id, &selections, cx)
2394 .unwrap();
2395 });
2396 }
2397
2398 fn request_autoscroll(&mut self, cx: &mut ViewContext<Self>) {
2399 self.autoscroll_requested = true;
2400 cx.notify();
2401 }
2402
2403 fn start_transaction(&mut self, cx: &mut ViewContext<Self>) {
2404 self.end_selection(cx);
2405 self.buffer.update(cx, |buffer, _| {
2406 buffer
2407 .start_transaction(Some(self.selection_set_id))
2408 .unwrap()
2409 });
2410 }
2411
2412 fn end_transaction(&self, cx: &mut ViewContext<Self>) {
2413 self.buffer.update(cx, |buffer, cx| {
2414 buffer
2415 .end_transaction(Some(self.selection_set_id), cx)
2416 .unwrap()
2417 });
2418 }
2419
2420 pub fn page_up(&mut self, _: &PageUp, _: &mut ViewContext<Self>) {
2421 log::info!("Editor::page_up");
2422 }
2423
2424 pub fn page_down(&mut self, _: &PageDown, _: &mut ViewContext<Self>) {
2425 log::info!("Editor::page_down");
2426 }
2427
2428 pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
2429 let mut fold_ranges = Vec::new();
2430
2431 let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
2432 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2433 for selection in selections {
2434 let range = selection.display_range(&display_map).sorted();
2435 let buffer_start_row = range.start.to_point(&display_map).row;
2436
2437 for row in (0..=range.end.row()).rev() {
2438 if self.is_line_foldable(&display_map, row) && !display_map.is_line_folded(row) {
2439 let fold_range = self.foldable_range_for_line(&display_map, row);
2440 if fold_range.end.row >= buffer_start_row {
2441 fold_ranges.push(fold_range);
2442 if row <= range.start.row() {
2443 break;
2444 }
2445 }
2446 }
2447 }
2448 }
2449
2450 self.fold_ranges(fold_ranges, cx);
2451 }
2452
2453 pub fn unfold(&mut self, _: &Unfold, cx: &mut ViewContext<Self>) {
2454 let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
2455 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2456 let buffer = self.buffer.read(cx);
2457 let ranges = selections
2458 .iter()
2459 .map(|s| {
2460 let range = s.display_range(&display_map).sorted();
2461 let mut start = range.start.to_point(&display_map);
2462 let mut end = range.end.to_point(&display_map);
2463 start.column = 0;
2464 end.column = buffer.line_len(end.row);
2465 start..end
2466 })
2467 .collect::<Vec<_>>();
2468 self.unfold_ranges(ranges, cx);
2469 }
2470
2471 fn is_line_foldable(&self, display_map: &DisplayMapSnapshot, display_row: u32) -> bool {
2472 let max_point = display_map.max_point();
2473 if display_row >= max_point.row() {
2474 false
2475 } else {
2476 let (start_indent, is_blank) = display_map.line_indent(display_row);
2477 if is_blank {
2478 false
2479 } else {
2480 for display_row in display_row + 1..=max_point.row() {
2481 let (indent, is_blank) = display_map.line_indent(display_row);
2482 if !is_blank {
2483 return indent > start_indent;
2484 }
2485 }
2486 false
2487 }
2488 }
2489 }
2490
2491 fn foldable_range_for_line(
2492 &self,
2493 display_map: &DisplayMapSnapshot,
2494 start_row: u32,
2495 ) -> Range<Point> {
2496 let max_point = display_map.max_point();
2497
2498 let (start_indent, _) = display_map.line_indent(start_row);
2499 let start = DisplayPoint::new(start_row, display_map.line_len(start_row));
2500 let mut end = None;
2501 for row in start_row + 1..=max_point.row() {
2502 let (indent, is_blank) = display_map.line_indent(row);
2503 if !is_blank && indent <= start_indent {
2504 end = Some(DisplayPoint::new(row - 1, display_map.line_len(row - 1)));
2505 break;
2506 }
2507 }
2508
2509 let end = end.unwrap_or(max_point);
2510 return start.to_point(display_map)..end.to_point(display_map);
2511 }
2512
2513 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
2514 let selections = self.selections::<Point>(cx);
2515 let ranges = selections.map(|s| s.start..s.end).collect();
2516 self.fold_ranges(ranges, cx);
2517 }
2518
2519 fn fold_ranges<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, cx: &mut ViewContext<Self>) {
2520 if !ranges.is_empty() {
2521 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
2522 self.autoscroll_requested = true;
2523 cx.notify();
2524 }
2525 }
2526
2527 fn unfold_ranges<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, cx: &mut ViewContext<Self>) {
2528 if !ranges.is_empty() {
2529 self.display_map
2530 .update(cx, |map, cx| map.unfold(ranges, cx));
2531 self.autoscroll_requested = true;
2532 cx.notify();
2533 }
2534 }
2535
2536 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
2537 self.display_map
2538 .update(cx, |map, cx| map.snapshot(cx))
2539 .longest_row()
2540 }
2541
2542 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
2543 self.display_map
2544 .update(cx, |map, cx| map.snapshot(cx))
2545 .max_point()
2546 }
2547
2548 pub fn text(&self, cx: &AppContext) -> String {
2549 self.buffer.read(cx).text()
2550 }
2551
2552 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
2553 self.display_map
2554 .update(cx, |map, cx| map.snapshot(cx))
2555 .text()
2556 }
2557
2558 // pub fn font_size(&self) -> f32 {
2559 // self.settings.font_size
2560 // }
2561
2562 pub fn set_wrap_width(&self, width: f32, cx: &mut MutableAppContext) -> bool {
2563 self.display_map
2564 .update(cx, |map, cx| map.set_wrap_width(Some(width), cx))
2565 }
2566
2567 fn next_blink_epoch(&mut self) -> usize {
2568 self.blink_epoch += 1;
2569 self.blink_epoch
2570 }
2571
2572 fn pause_cursor_blinking(&mut self, cx: &mut ViewContext<Self>) {
2573 self.show_local_cursors = true;
2574 cx.notify();
2575
2576 let epoch = self.next_blink_epoch();
2577 cx.spawn(|this, mut cx| {
2578 let this = this.downgrade();
2579 async move {
2580 Timer::after(CURSOR_BLINK_INTERVAL).await;
2581 if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
2582 this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
2583 }
2584 }
2585 })
2586 .detach();
2587 }
2588
2589 fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
2590 if epoch == self.blink_epoch {
2591 self.blinking_paused = false;
2592 self.blink_cursors(epoch, cx);
2593 }
2594 }
2595
2596 fn blink_cursors(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
2597 if epoch == self.blink_epoch && self.focused && !self.blinking_paused {
2598 self.show_local_cursors = !self.show_local_cursors;
2599 cx.notify();
2600
2601 let epoch = self.next_blink_epoch();
2602 cx.spawn(|this, mut cx| {
2603 let this = this.downgrade();
2604 async move {
2605 Timer::after(CURSOR_BLINK_INTERVAL).await;
2606 if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
2607 this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx));
2608 }
2609 }
2610 })
2611 .detach();
2612 }
2613 }
2614
2615 pub fn show_local_cursors(&self) -> bool {
2616 self.show_local_cursors
2617 }
2618
2619 fn on_buffer_changed(&mut self, _: ModelHandle<Buffer>, cx: &mut ViewContext<Self>) {
2620 cx.notify();
2621 }
2622
2623 fn on_buffer_event(
2624 &mut self,
2625 _: ModelHandle<Buffer>,
2626 event: &language::Event,
2627 cx: &mut ViewContext<Self>,
2628 ) {
2629 match event {
2630 language::Event::Edited => cx.emit(Event::Edited),
2631 language::Event::Dirtied => cx.emit(Event::Dirtied),
2632 language::Event::Saved => cx.emit(Event::Saved),
2633 language::Event::FileHandleChanged => cx.emit(Event::FileHandleChanged),
2634 language::Event::Reloaded => cx.emit(Event::FileHandleChanged),
2635 language::Event::Closed => cx.emit(Event::Closed),
2636 language::Event::Reparsed => {}
2637 }
2638 }
2639
2640 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
2641 cx.notify();
2642 }
2643}
2644
2645impl Snapshot {
2646 pub fn is_empty(&self) -> bool {
2647 self.display_snapshot.is_empty()
2648 }
2649
2650 pub fn is_focused(&self) -> bool {
2651 self.is_focused
2652 }
2653
2654 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
2655 self.placeholder_text.as_ref()
2656 }
2657
2658 pub fn buffer_row_count(&self) -> u32 {
2659 self.display_snapshot.buffer_row_count()
2660 }
2661
2662 pub fn buffer_rows(&self, start_row: u32) -> BufferRows {
2663 self.display_snapshot.buffer_rows(start_row)
2664 }
2665
2666 pub fn highlighted_chunks_for_rows(
2667 &mut self,
2668 display_rows: Range<u32>,
2669 ) -> display_map::HighlightedChunks {
2670 self.display_snapshot
2671 .highlighted_chunks_for_rows(display_rows)
2672 }
2673
2674 pub fn scroll_position(&self) -> Vector2F {
2675 compute_scroll_position(
2676 &self.display_snapshot,
2677 self.scroll_position,
2678 &self.scroll_top_anchor,
2679 )
2680 }
2681
2682 pub fn max_point(&self) -> DisplayPoint {
2683 self.display_snapshot.max_point()
2684 }
2685
2686 pub fn longest_row(&self) -> u32 {
2687 self.display_snapshot.longest_row()
2688 }
2689
2690 pub fn line_len(&self, display_row: u32) -> u32 {
2691 self.display_snapshot.line_len(display_row)
2692 }
2693
2694 pub fn line(&self, display_row: u32) -> String {
2695 self.display_snapshot.line(display_row)
2696 }
2697
2698 pub fn prev_row_boundary(&self, point: DisplayPoint) -> (DisplayPoint, Point) {
2699 self.display_snapshot.prev_row_boundary(point)
2700 }
2701
2702 pub fn next_row_boundary(&self, point: DisplayPoint) -> (DisplayPoint, Point) {
2703 self.display_snapshot.next_row_boundary(point)
2704 }
2705}
2706
2707impl EditorSettings {
2708 #[cfg(any(test, feature = "test-support"))]
2709 pub fn test(cx: &AppContext) -> Self {
2710 Self {
2711 tab_size: 4,
2712 style: {
2713 let font_cache: &gpui::FontCache = cx.font_cache();
2714 let font_family_name = Arc::from("Monaco");
2715 let font_properties = Default::default();
2716 let font_family_id = font_cache.load_family(&[&font_family_name]).unwrap();
2717 let font_id = font_cache
2718 .select_font(font_family_id, &font_properties)
2719 .unwrap();
2720 EditorStyle {
2721 text: gpui::fonts::TextStyle {
2722 font_family_name,
2723 font_family_id,
2724 font_id,
2725 font_size: 14.,
2726 color: gpui::color::Color::from_u32(0xff0000ff),
2727 font_properties,
2728 underline: None,
2729 },
2730 placeholder_text: None,
2731 background: Default::default(),
2732 gutter_background: Default::default(),
2733 active_line_background: Default::default(),
2734 line_number: Default::default(),
2735 line_number_active: Default::default(),
2736 selection: Default::default(),
2737 guest_selections: Default::default(),
2738 syntax: Default::default(),
2739 error_underline: Default::default(),
2740 warning_underline: Default::default(),
2741 information_underline: Default::default(),
2742 hint_underline: Default::default(),
2743 }
2744 },
2745 }
2746 }
2747}
2748
2749fn compute_scroll_position(
2750 snapshot: &DisplayMapSnapshot,
2751 mut scroll_position: Vector2F,
2752 scroll_top_anchor: &Anchor,
2753) -> Vector2F {
2754 let scroll_top = scroll_top_anchor.to_display_point(snapshot).row() as f32;
2755 scroll_position.set_y(scroll_top + scroll_position.y());
2756 scroll_position
2757}
2758
2759pub enum Event {
2760 Activate,
2761 Edited,
2762 Blurred,
2763 Dirtied,
2764 Saved,
2765 FileHandleChanged,
2766 Closed,
2767}
2768
2769impl Entity for Editor {
2770 type Event = Event;
2771
2772 fn release(&mut self, cx: &mut MutableAppContext) {
2773 self.buffer.update(cx, |buffer, cx| {
2774 buffer
2775 .remove_selection_set(self.selection_set_id, cx)
2776 .unwrap();
2777 });
2778 }
2779}
2780
2781impl View for Editor {
2782 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
2783 let settings = self.build_settings.borrow_mut()(cx);
2784 self.display_map.update(cx, |map, cx| {
2785 map.set_font(
2786 settings.style.text.font_id,
2787 settings.style.text.font_size,
2788 cx,
2789 )
2790 });
2791 EditorElement::new(self.handle.clone(), settings).boxed()
2792 }
2793
2794 fn ui_name() -> &'static str {
2795 "Editor"
2796 }
2797
2798 fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
2799 self.focused = true;
2800 self.blink_cursors(self.blink_epoch, cx);
2801 self.buffer.update(cx, |buffer, cx| {
2802 buffer
2803 .set_active_selection_set(Some(self.selection_set_id), cx)
2804 .unwrap();
2805 });
2806 }
2807
2808 fn on_blur(&mut self, cx: &mut ViewContext<Self>) {
2809 self.focused = false;
2810 self.show_local_cursors = false;
2811 self.buffer.update(cx, |buffer, cx| {
2812 buffer.set_active_selection_set(None, cx).unwrap();
2813 });
2814 cx.emit(Event::Blurred);
2815 cx.notify();
2816 }
2817
2818 fn keymap_context(&self, _: &AppContext) -> gpui::keymap::Context {
2819 let mut cx = Self::default_keymap_context();
2820 let mode = match self.mode {
2821 EditorMode::SingleLine => "single_line",
2822 EditorMode::AutoHeight { .. } => "auto_height",
2823 EditorMode::Full => "full",
2824 };
2825 cx.map.insert("mode".into(), mode.into());
2826 cx
2827 }
2828}
2829
2830impl SelectionExt for Selection<Point> {
2831 fn display_range(&self, map: &DisplayMapSnapshot) -> Range<DisplayPoint> {
2832 let start = self.start.to_display_point(map);
2833 let end = self.end.to_display_point(map);
2834 if self.reversed {
2835 end..start
2836 } else {
2837 start..end
2838 }
2839 }
2840
2841 fn spanned_rows(
2842 &self,
2843 include_end_if_at_line_start: bool,
2844 map: &DisplayMapSnapshot,
2845 ) -> SpannedRows {
2846 let display_start = self.start.to_display_point(map);
2847 let mut display_end = self.end.to_display_point(map);
2848 if !include_end_if_at_line_start
2849 && display_end.row() != map.max_point().row()
2850 && display_start.row() != display_end.row()
2851 && display_end.column() == 0
2852 {
2853 *display_end.row_mut() -= 1;
2854 }
2855
2856 let (display_start, buffer_start) = map.prev_row_boundary(display_start);
2857 let (display_end, buffer_end) = map.next_row_boundary(display_end);
2858
2859 SpannedRows {
2860 buffer_rows: buffer_start.row..buffer_end.row + 1,
2861 display_rows: display_start.row()..display_end.row() + 1,
2862 }
2863 }
2864}
2865
2866#[cfg(test)]
2867mod tests {
2868 use super::*;
2869 use crate::test::sample_text;
2870 use buffer::Point;
2871 use unindent::Unindent;
2872
2873 #[gpui::test]
2874 fn test_selection_with_mouse(cx: &mut gpui::MutableAppContext) {
2875 let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx));
2876 let settings = EditorSettings::test(cx);
2877 let (_, editor) =
2878 cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
2879
2880 editor.update(cx, |view, cx| {
2881 view.begin_selection(DisplayPoint::new(2, 2), false, cx);
2882 });
2883
2884 assert_eq!(
2885 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2886 [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
2887 );
2888
2889 editor.update(cx, |view, cx| {
2890 view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx);
2891 });
2892
2893 assert_eq!(
2894 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2895 [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
2896 );
2897
2898 editor.update(cx, |view, cx| {
2899 view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx);
2900 });
2901
2902 assert_eq!(
2903 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2904 [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
2905 );
2906
2907 editor.update(cx, |view, cx| {
2908 view.end_selection(cx);
2909 view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx);
2910 });
2911
2912 assert_eq!(
2913 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2914 [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
2915 );
2916
2917 editor.update(cx, |view, cx| {
2918 view.begin_selection(DisplayPoint::new(3, 3), true, cx);
2919 view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), cx);
2920 });
2921
2922 assert_eq!(
2923 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2924 [
2925 DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1),
2926 DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)
2927 ]
2928 );
2929
2930 editor.update(cx, |view, cx| {
2931 view.end_selection(cx);
2932 });
2933
2934 assert_eq!(
2935 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2936 [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)]
2937 );
2938 }
2939
2940 #[gpui::test]
2941 fn test_canceling_pending_selection(cx: &mut gpui::MutableAppContext) {
2942 let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx));
2943 let settings = EditorSettings::test(cx);
2944 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
2945
2946 view.update(cx, |view, cx| {
2947 view.begin_selection(DisplayPoint::new(2, 2), false, cx);
2948 assert_eq!(
2949 view.selection_ranges(cx),
2950 [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
2951 );
2952 });
2953
2954 view.update(cx, |view, cx| {
2955 view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx);
2956 assert_eq!(
2957 view.selection_ranges(cx),
2958 [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
2959 );
2960 });
2961
2962 view.update(cx, |view, cx| {
2963 view.cancel(&Cancel, cx);
2964 view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx);
2965 assert_eq!(
2966 view.selection_ranges(cx),
2967 [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
2968 );
2969 });
2970 }
2971
2972 #[gpui::test]
2973 fn test_cancel(cx: &mut gpui::MutableAppContext) {
2974 let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx));
2975 let settings = EditorSettings::test(cx);
2976 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
2977
2978 view.update(cx, |view, cx| {
2979 view.begin_selection(DisplayPoint::new(3, 4), false, cx);
2980 view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx);
2981 view.end_selection(cx);
2982
2983 view.begin_selection(DisplayPoint::new(0, 1), true, cx);
2984 view.update_selection(DisplayPoint::new(0, 3), Vector2F::zero(), cx);
2985 view.end_selection(cx);
2986 assert_eq!(
2987 view.selection_ranges(cx),
2988 [
2989 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
2990 DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1),
2991 ]
2992 );
2993 });
2994
2995 view.update(cx, |view, cx| {
2996 view.cancel(&Cancel, cx);
2997 assert_eq!(
2998 view.selection_ranges(cx),
2999 [DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)]
3000 );
3001 });
3002
3003 view.update(cx, |view, cx| {
3004 view.cancel(&Cancel, cx);
3005 assert_eq!(
3006 view.selection_ranges(cx),
3007 [DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)]
3008 );
3009 });
3010 }
3011
3012 #[gpui::test]
3013 fn test_fold(cx: &mut gpui::MutableAppContext) {
3014 let buffer = cx.add_model(|cx| {
3015 Buffer::new(
3016 0,
3017 "
3018 impl Foo {
3019 // Hello!
3020
3021 fn a() {
3022 1
3023 }
3024
3025 fn b() {
3026 2
3027 }
3028
3029 fn c() {
3030 3
3031 }
3032 }
3033 "
3034 .unindent(),
3035 cx,
3036 )
3037 });
3038 let settings = EditorSettings::test(&cx);
3039 let (_, view) = cx.add_window(Default::default(), |cx| {
3040 build_editor(buffer.clone(), settings, cx)
3041 });
3042
3043 view.update(cx, |view, cx| {
3044 view.select_display_ranges(&[DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)], cx)
3045 .unwrap();
3046 view.fold(&Fold, cx);
3047 assert_eq!(
3048 view.display_text(cx),
3049 "
3050 impl Foo {
3051 // Hello!
3052
3053 fn a() {
3054 1
3055 }
3056
3057 fn b() {…
3058 }
3059
3060 fn c() {…
3061 }
3062 }
3063 "
3064 .unindent(),
3065 );
3066
3067 view.fold(&Fold, cx);
3068 assert_eq!(
3069 view.display_text(cx),
3070 "
3071 impl Foo {…
3072 }
3073 "
3074 .unindent(),
3075 );
3076
3077 view.unfold(&Unfold, cx);
3078 assert_eq!(
3079 view.display_text(cx),
3080 "
3081 impl Foo {
3082 // Hello!
3083
3084 fn a() {
3085 1
3086 }
3087
3088 fn b() {…
3089 }
3090
3091 fn c() {…
3092 }
3093 }
3094 "
3095 .unindent(),
3096 );
3097
3098 view.unfold(&Unfold, cx);
3099 assert_eq!(view.display_text(cx), buffer.read(cx).text());
3100 });
3101 }
3102
3103 #[gpui::test]
3104 fn test_move_cursor(cx: &mut gpui::MutableAppContext) {
3105 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6), cx));
3106 let settings = EditorSettings::test(&cx);
3107 let (_, view) = cx.add_window(Default::default(), |cx| {
3108 build_editor(buffer.clone(), settings, cx)
3109 });
3110
3111 buffer.update(cx, |buffer, cx| {
3112 buffer.edit(
3113 vec![
3114 Point::new(1, 0)..Point::new(1, 0),
3115 Point::new(1, 1)..Point::new(1, 1),
3116 ],
3117 "\t",
3118 cx,
3119 );
3120 });
3121
3122 view.update(cx, |view, cx| {
3123 assert_eq!(
3124 view.selection_ranges(cx),
3125 &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
3126 );
3127
3128 view.move_down(&MoveDown, cx);
3129 assert_eq!(
3130 view.selection_ranges(cx),
3131 &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
3132 );
3133
3134 view.move_right(&MoveRight, cx);
3135 assert_eq!(
3136 view.selection_ranges(cx),
3137 &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)]
3138 );
3139
3140 view.move_left(&MoveLeft, cx);
3141 assert_eq!(
3142 view.selection_ranges(cx),
3143 &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
3144 );
3145
3146 view.move_up(&MoveUp, cx);
3147 assert_eq!(
3148 view.selection_ranges(cx),
3149 &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
3150 );
3151
3152 view.move_to_end(&MoveToEnd, cx);
3153 assert_eq!(
3154 view.selection_ranges(cx),
3155 &[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 6)]
3156 );
3157
3158 view.move_to_beginning(&MoveToBeginning, cx);
3159 assert_eq!(
3160 view.selection_ranges(cx),
3161 &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
3162 );
3163
3164 view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)], cx)
3165 .unwrap();
3166 view.select_to_beginning(&SelectToBeginning, cx);
3167 assert_eq!(
3168 view.selection_ranges(cx),
3169 &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 0)]
3170 );
3171
3172 view.select_to_end(&SelectToEnd, cx);
3173 assert_eq!(
3174 view.selection_ranges(cx),
3175 &[DisplayPoint::new(0, 1)..DisplayPoint::new(5, 6)]
3176 );
3177 });
3178 }
3179
3180 #[gpui::test]
3181 fn test_move_cursor_multibyte(cx: &mut gpui::MutableAppContext) {
3182 let buffer = cx.add_model(|cx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", cx));
3183 let settings = EditorSettings::test(&cx);
3184 let (_, view) = cx.add_window(Default::default(), |cx| {
3185 build_editor(buffer.clone(), settings, cx)
3186 });
3187
3188 assert_eq!('ⓐ'.len_utf8(), 3);
3189 assert_eq!('α'.len_utf8(), 2);
3190
3191 view.update(cx, |view, cx| {
3192 view.fold_ranges(
3193 vec![
3194 Point::new(0, 6)..Point::new(0, 12),
3195 Point::new(1, 2)..Point::new(1, 4),
3196 Point::new(2, 4)..Point::new(2, 8),
3197 ],
3198 cx,
3199 );
3200 assert_eq!(view.display_text(cx), "ⓐⓑ…ⓔ\nab…e\nαβ…ε\n");
3201
3202 view.move_right(&MoveRight, cx);
3203 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐ".len())]);
3204 view.move_right(&MoveRight, cx);
3205 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ".len())]);
3206 view.move_right(&MoveRight, cx);
3207 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ…".len())]);
3208
3209 view.move_down(&MoveDown, cx);
3210 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "ab…".len())]);
3211 view.move_left(&MoveLeft, cx);
3212 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "ab".len())]);
3213 view.move_left(&MoveLeft, cx);
3214 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "a".len())]);
3215
3216 view.move_down(&MoveDown, cx);
3217 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "α".len())]);
3218 view.move_right(&MoveRight, cx);
3219 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβ".len())]);
3220 view.move_right(&MoveRight, cx);
3221 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβ…".len())]);
3222 view.move_right(&MoveRight, cx);
3223 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβ…ε".len())]);
3224
3225 view.move_up(&MoveUp, cx);
3226 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "ab…e".len())]);
3227 view.move_up(&MoveUp, cx);
3228 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ…ⓔ".len())]);
3229 view.move_left(&MoveLeft, cx);
3230 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ…".len())]);
3231 view.move_left(&MoveLeft, cx);
3232 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ".len())]);
3233 view.move_left(&MoveLeft, cx);
3234 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐ".len())]);
3235 });
3236 }
3237
3238 #[gpui::test]
3239 fn test_move_cursor_different_line_lengths(cx: &mut gpui::MutableAppContext) {
3240 let buffer = cx.add_model(|cx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", cx));
3241 let settings = EditorSettings::test(&cx);
3242 let (_, view) = cx.add_window(Default::default(), |cx| {
3243 build_editor(buffer.clone(), settings, cx)
3244 });
3245 view.update(cx, |view, cx| {
3246 view.select_display_ranges(&[empty_range(0, "ⓐⓑⓒⓓⓔ".len())], cx)
3247 .unwrap();
3248
3249 view.move_down(&MoveDown, cx);
3250 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "abcd".len())]);
3251
3252 view.move_down(&MoveDown, cx);
3253 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβγ".len())]);
3254
3255 view.move_down(&MoveDown, cx);
3256 assert_eq!(view.selection_ranges(cx), &[empty_range(3, "abcd".len())]);
3257
3258 view.move_down(&MoveDown, cx);
3259 assert_eq!(view.selection_ranges(cx), &[empty_range(4, "ⓐⓑⓒⓓⓔ".len())]);
3260
3261 view.move_up(&MoveUp, cx);
3262 assert_eq!(view.selection_ranges(cx), &[empty_range(3, "abcd".len())]);
3263
3264 view.move_up(&MoveUp, cx);
3265 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβγ".len())]);
3266 });
3267 }
3268
3269 #[gpui::test]
3270 fn test_beginning_end_of_line(cx: &mut gpui::MutableAppContext) {
3271 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\n def", cx));
3272 let settings = EditorSettings::test(&cx);
3273 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3274 view.update(cx, |view, cx| {
3275 view.select_display_ranges(
3276 &[
3277 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3278 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4),
3279 ],
3280 cx,
3281 )
3282 .unwrap();
3283 });
3284
3285 view.update(cx, |view, cx| {
3286 view.move_to_beginning_of_line(&MoveToBeginningOfLine, cx);
3287 assert_eq!(
3288 view.selection_ranges(cx),
3289 &[
3290 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3291 DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
3292 ]
3293 );
3294 });
3295
3296 view.update(cx, |view, cx| {
3297 view.move_to_beginning_of_line(&MoveToBeginningOfLine, cx);
3298 assert_eq!(
3299 view.selection_ranges(cx),
3300 &[
3301 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3302 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
3303 ]
3304 );
3305 });
3306
3307 view.update(cx, |view, cx| {
3308 view.move_to_beginning_of_line(&MoveToBeginningOfLine, cx);
3309 assert_eq!(
3310 view.selection_ranges(cx),
3311 &[
3312 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3313 DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
3314 ]
3315 );
3316 });
3317
3318 view.update(cx, |view, cx| {
3319 view.move_to_end_of_line(&MoveToEndOfLine, cx);
3320 assert_eq!(
3321 view.selection_ranges(cx),
3322 &[
3323 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
3324 DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
3325 ]
3326 );
3327 });
3328
3329 // Moving to the end of line again is a no-op.
3330 view.update(cx, |view, cx| {
3331 view.move_to_end_of_line(&MoveToEndOfLine, cx);
3332 assert_eq!(
3333 view.selection_ranges(cx),
3334 &[
3335 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
3336 DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
3337 ]
3338 );
3339 });
3340
3341 view.update(cx, |view, cx| {
3342 view.move_left(&MoveLeft, cx);
3343 view.select_to_beginning_of_line(&SelectToBeginningOfLine(true), cx);
3344 assert_eq!(
3345 view.selection_ranges(cx),
3346 &[
3347 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
3348 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2),
3349 ]
3350 );
3351 });
3352
3353 view.update(cx, |view, cx| {
3354 view.select_to_beginning_of_line(&SelectToBeginningOfLine(true), cx);
3355 assert_eq!(
3356 view.selection_ranges(cx),
3357 &[
3358 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
3359 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 0),
3360 ]
3361 );
3362 });
3363
3364 view.update(cx, |view, cx| {
3365 view.select_to_beginning_of_line(&SelectToBeginningOfLine(true), cx);
3366 assert_eq!(
3367 view.selection_ranges(cx),
3368 &[
3369 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
3370 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2),
3371 ]
3372 );
3373 });
3374
3375 view.update(cx, |view, cx| {
3376 view.select_to_end_of_line(&SelectToEndOfLine, cx);
3377 assert_eq!(
3378 view.selection_ranges(cx),
3379 &[
3380 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3),
3381 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 5),
3382 ]
3383 );
3384 });
3385
3386 view.update(cx, |view, cx| {
3387 view.delete_to_end_of_line(&DeleteToEndOfLine, cx);
3388 assert_eq!(view.display_text(cx), "ab\n de");
3389 assert_eq!(
3390 view.selection_ranges(cx),
3391 &[
3392 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3393 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4),
3394 ]
3395 );
3396 });
3397
3398 view.update(cx, |view, cx| {
3399 view.delete_to_beginning_of_line(&DeleteToBeginningOfLine, cx);
3400 assert_eq!(view.display_text(cx), "\n");
3401 assert_eq!(
3402 view.selection_ranges(cx),
3403 &[
3404 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3405 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
3406 ]
3407 );
3408 });
3409 }
3410
3411 #[gpui::test]
3412 fn test_prev_next_word_boundary(cx: &mut gpui::MutableAppContext) {
3413 let buffer =
3414 cx.add_model(|cx| Buffer::new(0, "use std::str::{foo, bar}\n\n {baz.qux()}", cx));
3415 let settings = EditorSettings::test(&cx);
3416 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3417 view.update(cx, |view, cx| {
3418 view.select_display_ranges(
3419 &[
3420 DisplayPoint::new(0, 11)..DisplayPoint::new(0, 11),
3421 DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4),
3422 ],
3423 cx,
3424 )
3425 .unwrap();
3426 });
3427
3428 view.update(cx, |view, cx| {
3429 view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
3430 assert_eq!(
3431 view.selection_ranges(cx),
3432 &[
3433 DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9),
3434 DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3),
3435 ]
3436 );
3437 });
3438
3439 view.update(cx, |view, cx| {
3440 view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
3441 assert_eq!(
3442 view.selection_ranges(cx),
3443 &[
3444 DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7),
3445 DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2),
3446 ]
3447 );
3448 });
3449
3450 view.update(cx, |view, cx| {
3451 view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
3452 assert_eq!(
3453 view.selection_ranges(cx),
3454 &[
3455 DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4),
3456 DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0),
3457 ]
3458 );
3459 });
3460
3461 view.update(cx, |view, cx| {
3462 view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
3463 assert_eq!(
3464 view.selection_ranges(cx),
3465 &[
3466 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3467 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
3468 ]
3469 );
3470 });
3471
3472 view.update(cx, |view, cx| {
3473 view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
3474 assert_eq!(
3475 view.selection_ranges(cx),
3476 &[
3477 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3478 DisplayPoint::new(0, 23)..DisplayPoint::new(0, 23),
3479 ]
3480 );
3481 });
3482
3483 view.update(cx, |view, cx| {
3484 view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
3485 assert_eq!(
3486 view.selection_ranges(cx),
3487 &[
3488 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
3489 DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24),
3490 ]
3491 );
3492 });
3493
3494 view.update(cx, |view, cx| {
3495 view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
3496 assert_eq!(
3497 view.selection_ranges(cx),
3498 &[
3499 DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7),
3500 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
3501 ]
3502 );
3503 });
3504
3505 view.update(cx, |view, cx| {
3506 view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
3507 assert_eq!(
3508 view.selection_ranges(cx),
3509 &[
3510 DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9),
3511 DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3),
3512 ]
3513 );
3514 });
3515
3516 view.update(cx, |view, cx| {
3517 view.move_right(&MoveRight, cx);
3518 view.select_to_previous_word_boundary(&SelectToPreviousWordBoundary, cx);
3519 assert_eq!(
3520 view.selection_ranges(cx),
3521 &[
3522 DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9),
3523 DisplayPoint::new(2, 4)..DisplayPoint::new(2, 3),
3524 ]
3525 );
3526 });
3527
3528 view.update(cx, |view, cx| {
3529 view.select_to_previous_word_boundary(&SelectToPreviousWordBoundary, cx);
3530 assert_eq!(
3531 view.selection_ranges(cx),
3532 &[
3533 DisplayPoint::new(0, 10)..DisplayPoint::new(0, 7),
3534 DisplayPoint::new(2, 4)..DisplayPoint::new(2, 2),
3535 ]
3536 );
3537 });
3538
3539 view.update(cx, |view, cx| {
3540 view.select_to_next_word_boundary(&SelectToNextWordBoundary, cx);
3541 assert_eq!(
3542 view.selection_ranges(cx),
3543 &[
3544 DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9),
3545 DisplayPoint::new(2, 4)..DisplayPoint::new(2, 3),
3546 ]
3547 );
3548 });
3549 }
3550
3551 #[gpui::test]
3552 fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut gpui::MutableAppContext) {
3553 let buffer =
3554 cx.add_model(|cx| Buffer::new(0, "use one::{\n two::three::four::five\n};", cx));
3555 let settings = EditorSettings::test(&cx);
3556 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3557
3558 view.update(cx, |view, cx| {
3559 view.set_wrap_width(140., cx);
3560 assert_eq!(
3561 view.display_text(cx),
3562 "use one::{\n two::three::\n four::five\n};"
3563 );
3564
3565 view.select_display_ranges(&[DisplayPoint::new(1, 7)..DisplayPoint::new(1, 7)], cx)
3566 .unwrap();
3567
3568 view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
3569 assert_eq!(
3570 view.selection_ranges(cx),
3571 &[DisplayPoint::new(1, 9)..DisplayPoint::new(1, 9)]
3572 );
3573
3574 view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
3575 assert_eq!(
3576 view.selection_ranges(cx),
3577 &[DisplayPoint::new(1, 14)..DisplayPoint::new(1, 14)]
3578 );
3579
3580 view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
3581 assert_eq!(
3582 view.selection_ranges(cx),
3583 &[DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4)]
3584 );
3585
3586 view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
3587 assert_eq!(
3588 view.selection_ranges(cx),
3589 &[DisplayPoint::new(2, 8)..DisplayPoint::new(2, 8)]
3590 );
3591
3592 view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
3593 assert_eq!(
3594 view.selection_ranges(cx),
3595 &[DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4)]
3596 );
3597
3598 view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
3599 assert_eq!(
3600 view.selection_ranges(cx),
3601 &[DisplayPoint::new(1, 14)..DisplayPoint::new(1, 14)]
3602 );
3603 });
3604 }
3605
3606 #[gpui::test]
3607 fn test_delete_to_word_boundary(cx: &mut gpui::MutableAppContext) {
3608 let buffer = cx.add_model(|cx| Buffer::new(0, "one two three four", cx));
3609 let settings = EditorSettings::test(&cx);
3610 let (_, view) = cx.add_window(Default::default(), |cx| {
3611 build_editor(buffer.clone(), settings, cx)
3612 });
3613
3614 view.update(cx, |view, cx| {
3615 view.select_display_ranges(
3616 &[
3617 // an empty selection - the preceding word fragment is deleted
3618 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3619 // characters selected - they are deleted
3620 DisplayPoint::new(0, 9)..DisplayPoint::new(0, 12),
3621 ],
3622 cx,
3623 )
3624 .unwrap();
3625 view.delete_to_previous_word_boundary(&DeleteToPreviousWordBoundary, cx);
3626 });
3627
3628 assert_eq!(buffer.read(cx).text(), "e two te four");
3629
3630 view.update(cx, |view, cx| {
3631 view.select_display_ranges(
3632 &[
3633 // an empty selection - the following word fragment is deleted
3634 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
3635 // characters selected - they are deleted
3636 DisplayPoint::new(0, 9)..DisplayPoint::new(0, 10),
3637 ],
3638 cx,
3639 )
3640 .unwrap();
3641 view.delete_to_next_word_boundary(&DeleteToNextWordBoundary, cx);
3642 });
3643
3644 assert_eq!(buffer.read(cx).text(), "e t te our");
3645 }
3646
3647 #[gpui::test]
3648 fn test_newline(cx: &mut gpui::MutableAppContext) {
3649 let buffer = cx.add_model(|cx| Buffer::new(0, "aaaa\n bbbb\n", cx));
3650 let settings = EditorSettings::test(&cx);
3651 let (_, view) = cx.add_window(Default::default(), |cx| {
3652 build_editor(buffer.clone(), settings, cx)
3653 });
3654
3655 view.update(cx, |view, cx| {
3656 view.select_display_ranges(
3657 &[
3658 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3659 DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
3660 DisplayPoint::new(1, 6)..DisplayPoint::new(1, 6),
3661 ],
3662 cx,
3663 )
3664 .unwrap();
3665
3666 view.newline(&Newline, cx);
3667 assert_eq!(view.text(cx), "aa\naa\n \n bb\n bb\n");
3668 });
3669 }
3670
3671 #[gpui::test]
3672 fn test_backspace(cx: &mut gpui::MutableAppContext) {
3673 let buffer = cx.add_model(|cx| {
3674 Buffer::new(
3675 0,
3676 "one two three\nfour five six\nseven eight nine\nten\n",
3677 cx,
3678 )
3679 });
3680 let settings = EditorSettings::test(&cx);
3681 let (_, view) = cx.add_window(Default::default(), |cx| {
3682 build_editor(buffer.clone(), settings, cx)
3683 });
3684
3685 view.update(cx, |view, cx| {
3686 view.select_display_ranges(
3687 &[
3688 // an empty selection - the preceding character is deleted
3689 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3690 // one character selected - it is deleted
3691 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
3692 // a line suffix selected - it is deleted
3693 DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
3694 ],
3695 cx,
3696 )
3697 .unwrap();
3698 view.backspace(&Backspace, cx);
3699 });
3700
3701 assert_eq!(
3702 buffer.read(cx).text(),
3703 "oe two three\nfou five six\nseven ten\n"
3704 );
3705 }
3706
3707 #[gpui::test]
3708 fn test_delete(cx: &mut gpui::MutableAppContext) {
3709 let buffer = cx.add_model(|cx| {
3710 Buffer::new(
3711 0,
3712 "one two three\nfour five six\nseven eight nine\nten\n",
3713 cx,
3714 )
3715 });
3716 let settings = EditorSettings::test(&cx);
3717 let (_, view) = cx.add_window(Default::default(), |cx| {
3718 build_editor(buffer.clone(), settings, cx)
3719 });
3720
3721 view.update(cx, |view, cx| {
3722 view.select_display_ranges(
3723 &[
3724 // an empty selection - the following character is deleted
3725 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3726 // one character selected - it is deleted
3727 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
3728 // a line suffix selected - it is deleted
3729 DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
3730 ],
3731 cx,
3732 )
3733 .unwrap();
3734 view.delete(&Delete, cx);
3735 });
3736
3737 assert_eq!(
3738 buffer.read(cx).text(),
3739 "on two three\nfou five six\nseven ten\n"
3740 );
3741 }
3742
3743 #[gpui::test]
3744 fn test_delete_line(cx: &mut gpui::MutableAppContext) {
3745 let settings = EditorSettings::test(&cx);
3746 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx));
3747 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3748 view.update(cx, |view, cx| {
3749 view.select_display_ranges(
3750 &[
3751 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3752 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
3753 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
3754 ],
3755 cx,
3756 )
3757 .unwrap();
3758 view.delete_line(&DeleteLine, cx);
3759 assert_eq!(view.display_text(cx), "ghi");
3760 assert_eq!(
3761 view.selection_ranges(cx),
3762 vec![
3763 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3764 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)
3765 ]
3766 );
3767 });
3768
3769 let settings = EditorSettings::test(&cx);
3770 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx));
3771 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3772 view.update(cx, |view, cx| {
3773 view.select_display_ranges(&[DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)], cx)
3774 .unwrap();
3775 view.delete_line(&DeleteLine, cx);
3776 assert_eq!(view.display_text(cx), "ghi\n");
3777 assert_eq!(
3778 view.selection_ranges(cx),
3779 vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)]
3780 );
3781 });
3782 }
3783
3784 #[gpui::test]
3785 fn test_duplicate_line(cx: &mut gpui::MutableAppContext) {
3786 let settings = EditorSettings::test(&cx);
3787 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx));
3788 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3789 view.update(cx, |view, cx| {
3790 view.select_display_ranges(
3791 &[
3792 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
3793 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3794 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
3795 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
3796 ],
3797 cx,
3798 )
3799 .unwrap();
3800 view.duplicate_line(&DuplicateLine, cx);
3801 assert_eq!(view.display_text(cx), "abc\nabc\ndef\ndef\nghi\n\n");
3802 assert_eq!(
3803 view.selection_ranges(cx),
3804 vec![
3805 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
3806 DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
3807 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
3808 DisplayPoint::new(6, 0)..DisplayPoint::new(6, 0),
3809 ]
3810 );
3811 });
3812
3813 let settings = EditorSettings::test(&cx);
3814 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx));
3815 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3816 view.update(cx, |view, cx| {
3817 view.select_display_ranges(
3818 &[
3819 DisplayPoint::new(0, 1)..DisplayPoint::new(1, 1),
3820 DisplayPoint::new(1, 2)..DisplayPoint::new(2, 1),
3821 ],
3822 cx,
3823 )
3824 .unwrap();
3825 view.duplicate_line(&DuplicateLine, cx);
3826 assert_eq!(view.display_text(cx), "abc\ndef\nghi\nabc\ndef\nghi\n");
3827 assert_eq!(
3828 view.selection_ranges(cx),
3829 vec![
3830 DisplayPoint::new(3, 1)..DisplayPoint::new(4, 1),
3831 DisplayPoint::new(4, 2)..DisplayPoint::new(5, 1),
3832 ]
3833 );
3834 });
3835 }
3836
3837 #[gpui::test]
3838 fn test_move_line_up_down(cx: &mut gpui::MutableAppContext) {
3839 let settings = EditorSettings::test(&cx);
3840 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(10, 5), cx));
3841 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3842 view.update(cx, |view, cx| {
3843 view.fold_ranges(
3844 vec![
3845 Point::new(0, 2)..Point::new(1, 2),
3846 Point::new(2, 3)..Point::new(4, 1),
3847 Point::new(7, 0)..Point::new(8, 4),
3848 ],
3849 cx,
3850 );
3851 view.select_display_ranges(
3852 &[
3853 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3854 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
3855 DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
3856 DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2),
3857 ],
3858 cx,
3859 )
3860 .unwrap();
3861 assert_eq!(
3862 view.display_text(cx),
3863 "aa…bbb\nccc…eeee\nfffff\nggggg\n…i\njjjjj"
3864 );
3865
3866 view.move_line_up(&MoveLineUp, cx);
3867 assert_eq!(
3868 view.display_text(cx),
3869 "aa…bbb\nccc…eeee\nggggg\n…i\njjjjj\nfffff"
3870 );
3871 assert_eq!(
3872 view.selection_ranges(cx),
3873 vec![
3874 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3875 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
3876 DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3),
3877 DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2)
3878 ]
3879 );
3880 });
3881
3882 view.update(cx, |view, cx| {
3883 view.move_line_down(&MoveLineDown, cx);
3884 assert_eq!(
3885 view.display_text(cx),
3886 "ccc…eeee\naa…bbb\nfffff\nggggg\n…i\njjjjj"
3887 );
3888 assert_eq!(
3889 view.selection_ranges(cx),
3890 vec![
3891 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
3892 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
3893 DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
3894 DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2)
3895 ]
3896 );
3897 });
3898
3899 view.update(cx, |view, cx| {
3900 view.move_line_down(&MoveLineDown, cx);
3901 assert_eq!(
3902 view.display_text(cx),
3903 "ccc…eeee\nfffff\naa…bbb\nggggg\n…i\njjjjj"
3904 );
3905 assert_eq!(
3906 view.selection_ranges(cx),
3907 vec![
3908 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
3909 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
3910 DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
3911 DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2)
3912 ]
3913 );
3914 });
3915
3916 view.update(cx, |view, cx| {
3917 view.move_line_up(&MoveLineUp, cx);
3918 assert_eq!(
3919 view.display_text(cx),
3920 "ccc…eeee\naa…bbb\nggggg\n…i\njjjjj\nfffff"
3921 );
3922 assert_eq!(
3923 view.selection_ranges(cx),
3924 vec![
3925 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
3926 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
3927 DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3),
3928 DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2)
3929 ]
3930 );
3931 });
3932 }
3933
3934 #[gpui::test]
3935 fn test_clipboard(cx: &mut gpui::MutableAppContext) {
3936 let buffer = cx.add_model(|cx| Buffer::new(0, "one✅ two three four five six ", cx));
3937 let settings = EditorSettings::test(&cx);
3938 let view = cx
3939 .add_window(Default::default(), |cx| {
3940 build_editor(buffer.clone(), settings, cx)
3941 })
3942 .1;
3943
3944 // Cut with three selections. Clipboard text is divided into three slices.
3945 view.update(cx, |view, cx| {
3946 view.select_ranges(vec![0..7, 11..17, 22..27], false, cx);
3947 view.cut(&Cut, cx);
3948 assert_eq!(view.display_text(cx), "two four six ");
3949 });
3950
3951 // Paste with three cursors. Each cursor pastes one slice of the clipboard text.
3952 view.update(cx, |view, cx| {
3953 view.select_ranges(vec![4..4, 9..9, 13..13], false, cx);
3954 view.paste(&Paste, cx);
3955 assert_eq!(view.display_text(cx), "two one✅ four three six five ");
3956 assert_eq!(
3957 view.selection_ranges(cx),
3958 &[
3959 DisplayPoint::new(0, 11)..DisplayPoint::new(0, 11),
3960 DisplayPoint::new(0, 22)..DisplayPoint::new(0, 22),
3961 DisplayPoint::new(0, 31)..DisplayPoint::new(0, 31)
3962 ]
3963 );
3964 });
3965
3966 // Paste again but with only two cursors. Since the number of cursors doesn't
3967 // match the number of slices in the clipboard, the entire clipboard text
3968 // is pasted at each cursor.
3969 view.update(cx, |view, cx| {
3970 view.select_ranges(vec![0..0, 31..31], false, cx);
3971 view.handle_input(&Input("( ".into()), cx);
3972 view.paste(&Paste, cx);
3973 view.handle_input(&Input(") ".into()), cx);
3974 assert_eq!(
3975 view.display_text(cx),
3976 "( one✅ three five ) two one✅ four three six five ( one✅ three five ) "
3977 );
3978 });
3979
3980 view.update(cx, |view, cx| {
3981 view.select_ranges(vec![0..0], false, cx);
3982 view.handle_input(&Input("123\n4567\n89\n".into()), cx);
3983 assert_eq!(
3984 view.display_text(cx),
3985 "123\n4567\n89\n( one✅ three five ) two one✅ four three six five ( one✅ three five ) "
3986 );
3987 });
3988
3989 // Cut with three selections, one of which is full-line.
3990 view.update(cx, |view, cx| {
3991 view.select_display_ranges(
3992 &[
3993 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2),
3994 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
3995 DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1),
3996 ],
3997 cx,
3998 )
3999 .unwrap();
4000 view.cut(&Cut, cx);
4001 assert_eq!(
4002 view.display_text(cx),
4003 "13\n9\n( one✅ three five ) two one✅ four three six five ( one✅ three five ) "
4004 );
4005 });
4006
4007 // Paste with three selections, noticing how the copied selection that was full-line
4008 // gets inserted before the second cursor.
4009 view.update(cx, |view, cx| {
4010 view.select_display_ranges(
4011 &[
4012 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
4013 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
4014 DisplayPoint::new(2, 2)..DisplayPoint::new(2, 3),
4015 ],
4016 cx,
4017 )
4018 .unwrap();
4019 view.paste(&Paste, cx);
4020 assert_eq!(
4021 view.display_text(cx),
4022 "123\n4567\n9\n( 8ne✅ three five ) two one✅ four three six five ( one✅ three five ) "
4023 );
4024 assert_eq!(
4025 view.selection_ranges(cx),
4026 &[
4027 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
4028 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
4029 DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3),
4030 ]
4031 );
4032 });
4033
4034 // Copy with a single cursor only, which writes the whole line into the clipboard.
4035 view.update(cx, |view, cx| {
4036 view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)], cx)
4037 .unwrap();
4038 view.copy(&Copy, cx);
4039 });
4040
4041 // Paste with three selections, noticing how the copied full-line selection is inserted
4042 // before the empty selections but replaces the selection that is non-empty.
4043 view.update(cx, |view, cx| {
4044 view.select_display_ranges(
4045 &[
4046 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
4047 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 2),
4048 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
4049 ],
4050 cx,
4051 )
4052 .unwrap();
4053 view.paste(&Paste, cx);
4054 assert_eq!(
4055 view.display_text(cx),
4056 "123\n123\n123\n67\n123\n9\n( 8ne✅ three five ) two one✅ four three six five ( one✅ three five ) "
4057 );
4058 assert_eq!(
4059 view.selection_ranges(cx),
4060 &[
4061 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
4062 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
4063 DisplayPoint::new(5, 1)..DisplayPoint::new(5, 1),
4064 ]
4065 );
4066 });
4067 }
4068
4069 #[gpui::test]
4070 fn test_select_all(cx: &mut gpui::MutableAppContext) {
4071 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\nde\nfgh", cx));
4072 let settings = EditorSettings::test(&cx);
4073 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
4074 view.update(cx, |view, cx| {
4075 view.select_all(&SelectAll, cx);
4076 assert_eq!(
4077 view.selection_ranges(cx),
4078 &[DisplayPoint::new(0, 0)..DisplayPoint::new(2, 3)]
4079 );
4080 });
4081 }
4082
4083 #[gpui::test]
4084 fn test_select_line(cx: &mut gpui::MutableAppContext) {
4085 let settings = EditorSettings::test(&cx);
4086 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 5), cx));
4087 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
4088 view.update(cx, |view, cx| {
4089 view.select_display_ranges(
4090 &[
4091 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
4092 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
4093 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
4094 DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2),
4095 ],
4096 cx,
4097 )
4098 .unwrap();
4099 view.select_line(&SelectLine, cx);
4100 assert_eq!(
4101 view.selection_ranges(cx),
4102 vec![
4103 DisplayPoint::new(0, 0)..DisplayPoint::new(2, 0),
4104 DisplayPoint::new(4, 0)..DisplayPoint::new(5, 0),
4105 ]
4106 );
4107 });
4108
4109 view.update(cx, |view, cx| {
4110 view.select_line(&SelectLine, cx);
4111 assert_eq!(
4112 view.selection_ranges(cx),
4113 vec![
4114 DisplayPoint::new(0, 0)..DisplayPoint::new(3, 0),
4115 DisplayPoint::new(4, 0)..DisplayPoint::new(5, 5),
4116 ]
4117 );
4118 });
4119
4120 view.update(cx, |view, cx| {
4121 view.select_line(&SelectLine, cx);
4122 assert_eq!(
4123 view.selection_ranges(cx),
4124 vec![DisplayPoint::new(0, 0)..DisplayPoint::new(5, 5)]
4125 );
4126 });
4127 }
4128
4129 #[gpui::test]
4130 fn test_split_selection_into_lines(cx: &mut gpui::MutableAppContext) {
4131 let settings = EditorSettings::test(&cx);
4132 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(9, 5), cx));
4133 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
4134 view.update(cx, |view, cx| {
4135 view.fold_ranges(
4136 vec![
4137 Point::new(0, 2)..Point::new(1, 2),
4138 Point::new(2, 3)..Point::new(4, 1),
4139 Point::new(7, 0)..Point::new(8, 4),
4140 ],
4141 cx,
4142 );
4143 view.select_display_ranges(
4144 &[
4145 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
4146 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
4147 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
4148 DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4),
4149 ],
4150 cx,
4151 )
4152 .unwrap();
4153 assert_eq!(view.display_text(cx), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i");
4154 });
4155
4156 view.update(cx, |view, cx| {
4157 view.split_selection_into_lines(&SplitSelectionIntoLines, cx);
4158 assert_eq!(
4159 view.display_text(cx),
4160 "aaaaa\nbbbbb\nccc…eeee\nfffff\nggggg\n…i"
4161 );
4162 assert_eq!(
4163 view.selection_ranges(cx),
4164 [
4165 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
4166 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
4167 DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0),
4168 DisplayPoint::new(5, 4)..DisplayPoint::new(5, 4)
4169 ]
4170 );
4171 });
4172
4173 view.update(cx, |view, cx| {
4174 view.select_display_ranges(&[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 1)], cx)
4175 .unwrap();
4176 view.split_selection_into_lines(&SplitSelectionIntoLines, cx);
4177 assert_eq!(
4178 view.display_text(cx),
4179 "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\nhhhhh\niiiii"
4180 );
4181 assert_eq!(
4182 view.selection_ranges(cx),
4183 [
4184 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
4185 DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
4186 DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5),
4187 DisplayPoint::new(3, 5)..DisplayPoint::new(3, 5),
4188 DisplayPoint::new(4, 5)..DisplayPoint::new(4, 5),
4189 DisplayPoint::new(5, 5)..DisplayPoint::new(5, 5),
4190 DisplayPoint::new(6, 5)..DisplayPoint::new(6, 5),
4191 DisplayPoint::new(7, 0)..DisplayPoint::new(7, 0)
4192 ]
4193 );
4194 });
4195 }
4196
4197 #[gpui::test]
4198 fn test_add_selection_above_below(cx: &mut gpui::MutableAppContext) {
4199 let settings = EditorSettings::test(&cx);
4200 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndefghi\n\njk\nlmno\n", cx));
4201 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
4202
4203 view.update(cx, |view, cx| {
4204 view.select_display_ranges(&[DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)], cx)
4205 .unwrap();
4206 });
4207 view.update(cx, |view, cx| {
4208 view.add_selection_above(&AddSelectionAbove, cx);
4209 assert_eq!(
4210 view.selection_ranges(cx),
4211 vec![
4212 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
4213 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
4214 ]
4215 );
4216 });
4217
4218 view.update(cx, |view, cx| {
4219 view.add_selection_above(&AddSelectionAbove, cx);
4220 assert_eq!(
4221 view.selection_ranges(cx),
4222 vec![
4223 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
4224 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
4225 ]
4226 );
4227 });
4228
4229 view.update(cx, |view, cx| {
4230 view.add_selection_below(&AddSelectionBelow, cx);
4231 assert_eq!(
4232 view.selection_ranges(cx),
4233 vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)]
4234 );
4235 });
4236
4237 view.update(cx, |view, cx| {
4238 view.add_selection_below(&AddSelectionBelow, cx);
4239 assert_eq!(
4240 view.selection_ranges(cx),
4241 vec![
4242 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3),
4243 DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3)
4244 ]
4245 );
4246 });
4247
4248 view.update(cx, |view, cx| {
4249 view.add_selection_below(&AddSelectionBelow, cx);
4250 assert_eq!(
4251 view.selection_ranges(cx),
4252 vec![
4253 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3),
4254 DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3)
4255 ]
4256 );
4257 });
4258
4259 view.update(cx, |view, cx| {
4260 view.select_display_ranges(&[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)], cx)
4261 .unwrap();
4262 });
4263 view.update(cx, |view, cx| {
4264 view.add_selection_below(&AddSelectionBelow, cx);
4265 assert_eq!(
4266 view.selection_ranges(cx),
4267 vec![
4268 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
4269 DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3)
4270 ]
4271 );
4272 });
4273
4274 view.update(cx, |view, cx| {
4275 view.add_selection_below(&AddSelectionBelow, cx);
4276 assert_eq!(
4277 view.selection_ranges(cx),
4278 vec![
4279 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
4280 DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3)
4281 ]
4282 );
4283 });
4284
4285 view.update(cx, |view, cx| {
4286 view.add_selection_above(&AddSelectionAbove, cx);
4287 assert_eq!(
4288 view.selection_ranges(cx),
4289 vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)]
4290 );
4291 });
4292
4293 view.update(cx, |view, cx| {
4294 view.add_selection_above(&AddSelectionAbove, cx);
4295 assert_eq!(
4296 view.selection_ranges(cx),
4297 vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)]
4298 );
4299 });
4300
4301 view.update(cx, |view, cx| {
4302 view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(1, 4)], cx)
4303 .unwrap();
4304 view.add_selection_below(&AddSelectionBelow, cx);
4305 assert_eq!(
4306 view.selection_ranges(cx),
4307 vec![
4308 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
4309 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
4310 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
4311 ]
4312 );
4313 });
4314
4315 view.update(cx, |view, cx| {
4316 view.add_selection_below(&AddSelectionBelow, cx);
4317 assert_eq!(
4318 view.selection_ranges(cx),
4319 vec![
4320 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
4321 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
4322 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
4323 DisplayPoint::new(4, 1)..DisplayPoint::new(4, 4),
4324 ]
4325 );
4326 });
4327
4328 view.update(cx, |view, cx| {
4329 view.add_selection_above(&AddSelectionAbove, cx);
4330 assert_eq!(
4331 view.selection_ranges(cx),
4332 vec![
4333 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
4334 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
4335 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
4336 ]
4337 );
4338 });
4339
4340 view.update(cx, |view, cx| {
4341 view.select_display_ranges(&[DisplayPoint::new(4, 3)..DisplayPoint::new(1, 1)], cx)
4342 .unwrap();
4343 });
4344 view.update(cx, |view, cx| {
4345 view.add_selection_above(&AddSelectionAbove, cx);
4346 assert_eq!(
4347 view.selection_ranges(cx),
4348 vec![
4349 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 1),
4350 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1),
4351 DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1),
4352 DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1),
4353 ]
4354 );
4355 });
4356
4357 view.update(cx, |view, cx| {
4358 view.add_selection_below(&AddSelectionBelow, cx);
4359 assert_eq!(
4360 view.selection_ranges(cx),
4361 vec![
4362 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1),
4363 DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1),
4364 DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1),
4365 ]
4366 );
4367 });
4368 }
4369
4370 #[gpui::test]
4371 async fn test_select_larger_smaller_syntax_node(mut cx: gpui::TestAppContext) {
4372 let settings = cx.read(EditorSettings::test);
4373 let language = Some(Arc::new(Language::new(
4374 LanguageConfig::default(),
4375 tree_sitter_rust::language(),
4376 )));
4377
4378 let text = r#"
4379 use mod1::mod2::{mod3, mod4};
4380
4381 fn fn_1(param1: bool, param2: &str) {
4382 let var1 = "text";
4383 }
4384 "#
4385 .unindent();
4386
4387 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, None, cx));
4388 let (_, view) = cx.add_window(|cx| build_editor(buffer, settings, cx));
4389 view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing())
4390 .await;
4391
4392 view.update(&mut cx, |view, cx| {
4393 view.select_display_ranges(
4394 &[
4395 DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
4396 DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
4397 DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
4398 ],
4399 cx,
4400 )
4401 .unwrap();
4402 view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
4403 });
4404 assert_eq!(
4405 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4406 &[
4407 DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27),
4408 DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
4409 DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21),
4410 ]
4411 );
4412
4413 view.update(&mut cx, |view, cx| {
4414 view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
4415 });
4416 assert_eq!(
4417 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4418 &[
4419 DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28),
4420 DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0),
4421 ]
4422 );
4423
4424 view.update(&mut cx, |view, cx| {
4425 view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
4426 });
4427 assert_eq!(
4428 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4429 &[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 0)]
4430 );
4431
4432 // Trying to expand the selected syntax node one more time has no effect.
4433 view.update(&mut cx, |view, cx| {
4434 view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
4435 });
4436 assert_eq!(
4437 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4438 &[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 0)]
4439 );
4440
4441 view.update(&mut cx, |view, cx| {
4442 view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
4443 });
4444 assert_eq!(
4445 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4446 &[
4447 DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28),
4448 DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0),
4449 ]
4450 );
4451
4452 view.update(&mut cx, |view, cx| {
4453 view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
4454 });
4455 assert_eq!(
4456 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4457 &[
4458 DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27),
4459 DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
4460 DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21),
4461 ]
4462 );
4463
4464 view.update(&mut cx, |view, cx| {
4465 view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
4466 });
4467 assert_eq!(
4468 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4469 &[
4470 DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
4471 DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
4472 DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
4473 ]
4474 );
4475
4476 // Trying to shrink the selected syntax node one more time has no effect.
4477 view.update(&mut cx, |view, cx| {
4478 view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
4479 });
4480 assert_eq!(
4481 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4482 &[
4483 DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
4484 DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
4485 DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
4486 ]
4487 );
4488
4489 // Ensure that we keep expanding the selection if the larger selection starts or ends within
4490 // a fold.
4491 view.update(&mut cx, |view, cx| {
4492 view.fold_ranges(
4493 vec![
4494 Point::new(0, 21)..Point::new(0, 24),
4495 Point::new(3, 20)..Point::new(3, 22),
4496 ],
4497 cx,
4498 );
4499 view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
4500 });
4501 assert_eq!(
4502 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4503 &[
4504 DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28),
4505 DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
4506 DisplayPoint::new(3, 4)..DisplayPoint::new(3, 23),
4507 ]
4508 );
4509 }
4510
4511 #[gpui::test]
4512 async fn test_autoclose_pairs(mut cx: gpui::TestAppContext) {
4513 let settings = cx.read(EditorSettings::test);
4514 let language = Some(Arc::new(Language::new(
4515 LanguageConfig {
4516 brackets: vec![
4517 BracketPair {
4518 start: "{".to_string(),
4519 end: "}".to_string(),
4520 close: true,
4521 newline: true,
4522 },
4523 BracketPair {
4524 start: "/*".to_string(),
4525 end: " */".to_string(),
4526 close: true,
4527 newline: true,
4528 },
4529 ],
4530 ..Default::default()
4531 },
4532 tree_sitter_rust::language(),
4533 )));
4534
4535 let text = r#"
4536 a
4537
4538 /
4539
4540 "#
4541 .unindent();
4542
4543 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, None, cx));
4544 let (_, view) = cx.add_window(|cx| build_editor(buffer, settings, cx));
4545 view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing())
4546 .await;
4547
4548 view.update(&mut cx, |view, cx| {
4549 view.select_display_ranges(
4550 &[
4551 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
4552 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
4553 ],
4554 cx,
4555 )
4556 .unwrap();
4557 view.handle_input(&Input("{".to_string()), cx);
4558 view.handle_input(&Input("{".to_string()), cx);
4559 view.handle_input(&Input("{".to_string()), cx);
4560 assert_eq!(
4561 view.text(cx),
4562 "
4563 {{{}}}
4564 {{{}}}
4565 /
4566
4567 "
4568 .unindent()
4569 );
4570
4571 view.move_right(&MoveRight, cx);
4572 view.handle_input(&Input("}".to_string()), cx);
4573 view.handle_input(&Input("}".to_string()), cx);
4574 view.handle_input(&Input("}".to_string()), cx);
4575 assert_eq!(
4576 view.text(cx),
4577 "
4578 {{{}}}}
4579 {{{}}}}
4580 /
4581
4582 "
4583 .unindent()
4584 );
4585
4586 view.undo(&Undo, cx);
4587 view.handle_input(&Input("/".to_string()), cx);
4588 view.handle_input(&Input("*".to_string()), cx);
4589 assert_eq!(
4590 view.text(cx),
4591 "
4592 /* */
4593 /* */
4594 /
4595
4596 "
4597 .unindent()
4598 );
4599
4600 view.undo(&Undo, cx);
4601 view.select_display_ranges(
4602 &[
4603 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
4604 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
4605 ],
4606 cx,
4607 )
4608 .unwrap();
4609 view.handle_input(&Input("*".to_string()), cx);
4610 assert_eq!(
4611 view.text(cx),
4612 "
4613 a
4614
4615 /*
4616 *
4617 "
4618 .unindent()
4619 );
4620 });
4621 }
4622
4623 #[gpui::test]
4624 async fn test_extra_newline_insertion(mut cx: gpui::TestAppContext) {
4625 let settings = cx.read(EditorSettings::test);
4626 let language = Some(Arc::new(Language::new(
4627 LanguageConfig {
4628 brackets: vec![
4629 BracketPair {
4630 start: "{".to_string(),
4631 end: "}".to_string(),
4632 close: true,
4633 newline: true,
4634 },
4635 BracketPair {
4636 start: "/* ".to_string(),
4637 end: " */".to_string(),
4638 close: true,
4639 newline: true,
4640 },
4641 ],
4642 ..Default::default()
4643 },
4644 tree_sitter_rust::language(),
4645 )));
4646
4647 let text = concat!(
4648 "{ }\n", // Suppress rustfmt
4649 " x\n", //
4650 " /* */\n", //
4651 "x\n", //
4652 "{{} }\n", //
4653 );
4654
4655 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, None, cx));
4656 let (_, view) = cx.add_window(|cx| build_editor(buffer, settings, cx));
4657 view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing())
4658 .await;
4659
4660 view.update(&mut cx, |view, cx| {
4661 view.select_display_ranges(
4662 &[
4663 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3),
4664 DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5),
4665 DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4),
4666 ],
4667 cx,
4668 )
4669 .unwrap();
4670 view.newline(&Newline, cx);
4671
4672 assert_eq!(
4673 view.buffer().read(cx).text(),
4674 concat!(
4675 "{ \n", // Suppress rustfmt
4676 "\n", //
4677 "}\n", //
4678 " x\n", //
4679 " /* \n", //
4680 " \n", //
4681 " */\n", //
4682 "x\n", //
4683 "{{} \n", //
4684 "}\n", //
4685 )
4686 );
4687 });
4688 }
4689
4690 impl Editor {
4691 fn selection_ranges(&self, cx: &mut MutableAppContext) -> Vec<Range<DisplayPoint>> {
4692 self.selections_in_range(
4693 self.selection_set_id,
4694 DisplayPoint::zero()..self.max_point(cx),
4695 cx,
4696 )
4697 .collect::<Vec<_>>()
4698 }
4699 }
4700
4701 fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
4702 let point = DisplayPoint::new(row as u32, column as u32);
4703 point..point
4704 }
4705
4706 fn build_editor(
4707 buffer: ModelHandle<Buffer>,
4708 settings: EditorSettings,
4709 cx: &mut ViewContext<Editor>,
4710 ) -> Editor {
4711 Editor::for_buffer(buffer, move |_| settings.clone(), cx)
4712 }
4713}
4714
4715trait RangeExt<T> {
4716 fn sorted(&self) -> Range<T>;
4717 fn to_inclusive(&self) -> RangeInclusive<T>;
4718}
4719
4720impl<T: Ord + Clone> RangeExt<T> for Range<T> {
4721 fn sorted(&self) -> Self {
4722 cmp::min(&self.start, &self.end).clone()..cmp::max(&self.start, &self.end).clone()
4723 }
4724
4725 fn to_inclusive(&self) -> RangeInclusive<T> {
4726 self.start.clone()..=self.end.clone()
4727 }
4728}