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