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