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