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 .next())
2213 .map(|(_, diagnostic)| diagnostic.group_id);
2214
2215 if let Some(group_id) = diagnostic_group_id {
2216 self.display_map.update(cx, |display_map, cx| {
2217 let buffer = self.buffer.read(cx);
2218 let diagnostic_group = buffer
2219 .diagnostic_group::<Point>(group_id)
2220 .map(|(range, diagnostic)| (range, diagnostic.message.clone()))
2221 .collect::<Vec<_>>();
2222
2223 dbg!(group_id, &diagnostic_group);
2224
2225 display_map.insert_blocks(
2226 diagnostic_group
2227 .iter()
2228 .map(|(range, message)| BlockProperties {
2229 position: range.start,
2230 text: message.as_str(),
2231 runs: vec![],
2232 disposition: BlockDisposition::Above,
2233 }),
2234 cx,
2235 );
2236 });
2237 }
2238 }
2239
2240 fn build_columnar_selection(
2241 &mut self,
2242 display_map: &DisplayMapSnapshot,
2243 row: u32,
2244 columns: &Range<u32>,
2245 reversed: bool,
2246 ) -> Option<Selection<Point>> {
2247 let is_empty = columns.start == columns.end;
2248 let line_len = display_map.line_len(row);
2249 if columns.start < line_len || (is_empty && columns.start == line_len) {
2250 let start = DisplayPoint::new(row, columns.start);
2251 let end = DisplayPoint::new(row, cmp::min(columns.end, line_len));
2252 Some(Selection {
2253 id: post_inc(&mut self.next_selection_id),
2254 start: start.to_point(display_map),
2255 end: end.to_point(display_map),
2256 reversed,
2257 goal: SelectionGoal::ColumnRange {
2258 start: columns.start,
2259 end: columns.end,
2260 },
2261 })
2262 } else {
2263 None
2264 }
2265 }
2266
2267 pub fn active_selection_sets<'a>(
2268 &'a self,
2269 cx: &'a AppContext,
2270 ) -> impl 'a + Iterator<Item = SelectionSetId> {
2271 let buffer = self.buffer.read(cx);
2272 let replica_id = buffer.replica_id();
2273 buffer
2274 .selection_sets()
2275 .filter(move |(set_id, set)| {
2276 set.active && (set_id.replica_id != replica_id || **set_id == self.selection_set_id)
2277 })
2278 .map(|(set_id, _)| *set_id)
2279 }
2280
2281 pub fn selections_in_range<'a>(
2282 &'a self,
2283 set_id: SelectionSetId,
2284 range: Range<DisplayPoint>,
2285 cx: &'a mut MutableAppContext,
2286 ) -> impl 'a + Iterator<Item = Range<DisplayPoint>> {
2287 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2288 let buffer = self.buffer.read(cx);
2289 let selections = self
2290 .selection_set(cx)
2291 .selections::<Point, _>(buffer)
2292 .collect::<Vec<_>>();
2293 let start = range.start.to_point(&display_map);
2294 let start_index = self.selection_insertion_index(&selections, start);
2295 let pending_selection = if set_id.replica_id == self.buffer.read(cx).replica_id() {
2296 self.pending_selection.as_ref().and_then(|pending| {
2297 let mut selection_start = pending.start.to_display_point(&display_map);
2298 let mut selection_end = pending.end.to_display_point(&display_map);
2299 if pending.reversed {
2300 mem::swap(&mut selection_start, &mut selection_end);
2301 }
2302 if selection_start <= range.end || selection_end <= range.end {
2303 Some(selection_start..selection_end)
2304 } else {
2305 None
2306 }
2307 })
2308 } else {
2309 None
2310 };
2311 selections
2312 .into_iter()
2313 .skip(start_index)
2314 .map(move |s| s.display_range(&display_map))
2315 .take_while(move |r| r.start <= range.end || r.end <= range.end)
2316 .chain(pending_selection)
2317 }
2318
2319 fn selection_insertion_index(&self, selections: &[Selection<Point>], start: Point) -> usize {
2320 match selections.binary_search_by_key(&start, |probe| probe.start) {
2321 Ok(index) => index,
2322 Err(index) => {
2323 if index > 0 && selections[index - 1].end > start {
2324 index - 1
2325 } else {
2326 index
2327 }
2328 }
2329 }
2330 }
2331
2332 pub fn selections<'a, D>(&self, cx: &'a AppContext) -> impl 'a + Iterator<Item = Selection<D>>
2333 where
2334 D: 'a + TextDimension<'a> + Ord,
2335 {
2336 let buffer = self.buffer.read(cx);
2337 let mut selections = self.selection_set(cx).selections::<D, _>(buffer).peekable();
2338 let mut pending_selection = self.pending_selection(cx);
2339 iter::from_fn(move || {
2340 if let Some(pending) = pending_selection.as_mut() {
2341 while let Some(next_selection) = selections.peek() {
2342 if pending.start <= next_selection.end && pending.end >= next_selection.start {
2343 let next_selection = selections.next().unwrap();
2344 if next_selection.start < pending.start {
2345 pending.start = next_selection.start;
2346 }
2347 if next_selection.end > pending.end {
2348 pending.end = next_selection.end;
2349 }
2350 } else if next_selection.end < pending.start {
2351 return selections.next();
2352 } else {
2353 break;
2354 }
2355 }
2356
2357 pending_selection.take()
2358 } else {
2359 selections.next()
2360 }
2361 })
2362 }
2363
2364 fn pending_selection<'a, D>(&self, cx: &'a AppContext) -> Option<Selection<D>>
2365 where
2366 D: 'a + TextDimension<'a>,
2367 {
2368 let buffer = self.buffer.read(cx);
2369 self.pending_selection.as_ref().map(|selection| Selection {
2370 id: selection.id,
2371 start: selection.start.summary::<D, _>(buffer),
2372 end: selection.end.summary::<D, _>(buffer),
2373 reversed: selection.reversed,
2374 goal: selection.goal,
2375 })
2376 }
2377
2378 fn selection_count<'a>(&self, cx: &'a AppContext) -> usize {
2379 let mut selection_count = self.selection_set(cx).len();
2380 if self.pending_selection.is_some() {
2381 selection_count += 1;
2382 }
2383 selection_count
2384 }
2385
2386 pub fn oldest_selection<'a, T>(&self, cx: &'a AppContext) -> Selection<T>
2387 where
2388 T: 'a + TextDimension<'a>,
2389 {
2390 let buffer = self.buffer.read(cx);
2391 self.selection_set(cx)
2392 .oldest_selection(buffer)
2393 .or_else(|| self.pending_selection(cx))
2394 .unwrap()
2395 }
2396
2397 pub fn newest_selection<'a, T>(&self, cx: &'a AppContext) -> Selection<T>
2398 where
2399 T: 'a + TextDimension<'a>,
2400 {
2401 let buffer = self.buffer.read(cx);
2402 self.pending_selection(cx)
2403 .or_else(|| self.selection_set(cx).newest_selection(buffer))
2404 .unwrap()
2405 }
2406
2407 fn selection_set<'a>(&self, cx: &'a AppContext) -> &'a SelectionSet {
2408 self.buffer
2409 .read(cx)
2410 .selection_set(self.selection_set_id)
2411 .unwrap()
2412 }
2413
2414 fn update_selections<T>(
2415 &mut self,
2416 mut selections: Vec<Selection<T>>,
2417 autoscroll: bool,
2418 cx: &mut ViewContext<Self>,
2419 ) where
2420 T: ToOffset + ToPoint + Ord + std::marker::Copy + std::fmt::Debug,
2421 {
2422 // Merge overlapping selections.
2423 let buffer = self.buffer.read(cx);
2424 let mut i = 1;
2425 while i < selections.len() {
2426 if selections[i - 1].end >= selections[i].start {
2427 let removed = selections.remove(i);
2428 if removed.start < selections[i - 1].start {
2429 selections[i - 1].start = removed.start;
2430 }
2431 if removed.end > selections[i - 1].end {
2432 selections[i - 1].end = removed.end;
2433 }
2434 } else {
2435 i += 1;
2436 }
2437 }
2438
2439 self.pending_selection = None;
2440 self.add_selections_state = None;
2441 self.select_larger_syntax_node_stack.clear();
2442 while let Some(autoclose_pair_state) = self.autoclose_stack.last() {
2443 let all_selections_inside_autoclose_ranges =
2444 if selections.len() == autoclose_pair_state.ranges.len() {
2445 selections
2446 .iter()
2447 .zip(autoclose_pair_state.ranges.ranges::<Point, _>(buffer))
2448 .all(|(selection, autoclose_range)| {
2449 let head = selection.head().to_point(&*buffer);
2450 autoclose_range.start <= head && autoclose_range.end >= head
2451 })
2452 } else {
2453 false
2454 };
2455
2456 if all_selections_inside_autoclose_ranges {
2457 break;
2458 } else {
2459 self.autoclose_stack.pop();
2460 }
2461 }
2462
2463 if autoscroll {
2464 self.request_autoscroll(cx);
2465 }
2466 self.pause_cursor_blinking(cx);
2467
2468 self.buffer.update(cx, |buffer, cx| {
2469 buffer
2470 .update_selection_set(self.selection_set_id, &selections, cx)
2471 .unwrap();
2472 });
2473 }
2474
2475 fn request_autoscroll(&mut self, cx: &mut ViewContext<Self>) {
2476 self.autoscroll_requested = true;
2477 cx.notify();
2478 }
2479
2480 fn start_transaction(&mut self, cx: &mut ViewContext<Self>) {
2481 self.end_selection(cx);
2482 self.buffer.update(cx, |buffer, _| {
2483 buffer
2484 .start_transaction(Some(self.selection_set_id))
2485 .unwrap()
2486 });
2487 }
2488
2489 fn end_transaction(&self, cx: &mut ViewContext<Self>) {
2490 self.buffer.update(cx, |buffer, cx| {
2491 buffer
2492 .end_transaction(Some(self.selection_set_id), cx)
2493 .unwrap()
2494 });
2495 }
2496
2497 pub fn page_up(&mut self, _: &PageUp, _: &mut ViewContext<Self>) {
2498 log::info!("Editor::page_up");
2499 }
2500
2501 pub fn page_down(&mut self, _: &PageDown, _: &mut ViewContext<Self>) {
2502 log::info!("Editor::page_down");
2503 }
2504
2505 pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
2506 let mut fold_ranges = Vec::new();
2507
2508 let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
2509 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2510 for selection in selections {
2511 let range = selection.display_range(&display_map).sorted();
2512 let buffer_start_row = range.start.to_point(&display_map).row;
2513
2514 for row in (0..=range.end.row()).rev() {
2515 if self.is_line_foldable(&display_map, row) && !display_map.is_line_folded(row) {
2516 let fold_range = self.foldable_range_for_line(&display_map, row);
2517 if fold_range.end.row >= buffer_start_row {
2518 fold_ranges.push(fold_range);
2519 if row <= range.start.row() {
2520 break;
2521 }
2522 }
2523 }
2524 }
2525 }
2526
2527 self.fold_ranges(fold_ranges, cx);
2528 }
2529
2530 pub fn unfold(&mut self, _: &Unfold, cx: &mut ViewContext<Self>) {
2531 let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
2532 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2533 let buffer = self.buffer.read(cx);
2534 let ranges = selections
2535 .iter()
2536 .map(|s| {
2537 let range = s.display_range(&display_map).sorted();
2538 let mut start = range.start.to_point(&display_map);
2539 let mut end = range.end.to_point(&display_map);
2540 start.column = 0;
2541 end.column = buffer.line_len(end.row);
2542 start..end
2543 })
2544 .collect::<Vec<_>>();
2545 self.unfold_ranges(ranges, cx);
2546 }
2547
2548 fn is_line_foldable(&self, display_map: &DisplayMapSnapshot, display_row: u32) -> bool {
2549 let max_point = display_map.max_point();
2550 if display_row >= max_point.row() {
2551 false
2552 } else {
2553 let (start_indent, is_blank) = display_map.line_indent(display_row);
2554 if is_blank {
2555 false
2556 } else {
2557 for display_row in display_row + 1..=max_point.row() {
2558 let (indent, is_blank) = display_map.line_indent(display_row);
2559 if !is_blank {
2560 return indent > start_indent;
2561 }
2562 }
2563 false
2564 }
2565 }
2566 }
2567
2568 fn foldable_range_for_line(
2569 &self,
2570 display_map: &DisplayMapSnapshot,
2571 start_row: u32,
2572 ) -> Range<Point> {
2573 let max_point = display_map.max_point();
2574
2575 let (start_indent, _) = display_map.line_indent(start_row);
2576 let start = DisplayPoint::new(start_row, display_map.line_len(start_row));
2577 let mut end = None;
2578 for row in start_row + 1..=max_point.row() {
2579 let (indent, is_blank) = display_map.line_indent(row);
2580 if !is_blank && indent <= start_indent {
2581 end = Some(DisplayPoint::new(row - 1, display_map.line_len(row - 1)));
2582 break;
2583 }
2584 }
2585
2586 let end = end.unwrap_or(max_point);
2587 return start.to_point(display_map)..end.to_point(display_map);
2588 }
2589
2590 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
2591 let selections = self.selections::<Point>(cx);
2592 let ranges = selections.map(|s| s.start..s.end).collect();
2593 self.fold_ranges(ranges, cx);
2594 }
2595
2596 fn fold_ranges<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, cx: &mut ViewContext<Self>) {
2597 if !ranges.is_empty() {
2598 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
2599 self.autoscroll_requested = true;
2600 cx.notify();
2601 }
2602 }
2603
2604 fn unfold_ranges<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, cx: &mut ViewContext<Self>) {
2605 if !ranges.is_empty() {
2606 self.display_map
2607 .update(cx, |map, cx| map.unfold(ranges, cx));
2608 self.autoscroll_requested = true;
2609 cx.notify();
2610 }
2611 }
2612
2613 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
2614 self.display_map
2615 .update(cx, |map, cx| map.snapshot(cx))
2616 .longest_row()
2617 }
2618
2619 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
2620 self.display_map
2621 .update(cx, |map, cx| map.snapshot(cx))
2622 .max_point()
2623 }
2624
2625 pub fn text(&self, cx: &AppContext) -> String {
2626 self.buffer.read(cx).text()
2627 }
2628
2629 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
2630 self.display_map
2631 .update(cx, |map, cx| map.snapshot(cx))
2632 .text()
2633 }
2634
2635 // pub fn font_size(&self) -> f32 {
2636 // self.settings.font_size
2637 // }
2638
2639 pub fn set_wrap_width(&self, width: f32, cx: &mut MutableAppContext) -> bool {
2640 self.display_map
2641 .update(cx, |map, cx| map.set_wrap_width(Some(width), cx))
2642 }
2643
2644 fn next_blink_epoch(&mut self) -> usize {
2645 self.blink_epoch += 1;
2646 self.blink_epoch
2647 }
2648
2649 fn pause_cursor_blinking(&mut self, cx: &mut ViewContext<Self>) {
2650 self.show_local_cursors = true;
2651 cx.notify();
2652
2653 let epoch = self.next_blink_epoch();
2654 cx.spawn(|this, mut cx| {
2655 let this = this.downgrade();
2656 async move {
2657 Timer::after(CURSOR_BLINK_INTERVAL).await;
2658 if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
2659 this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
2660 }
2661 }
2662 })
2663 .detach();
2664 }
2665
2666 fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
2667 if epoch == self.blink_epoch {
2668 self.blinking_paused = false;
2669 self.blink_cursors(epoch, cx);
2670 }
2671 }
2672
2673 fn blink_cursors(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
2674 if epoch == self.blink_epoch && self.focused && !self.blinking_paused {
2675 self.show_local_cursors = !self.show_local_cursors;
2676 cx.notify();
2677
2678 let epoch = self.next_blink_epoch();
2679 cx.spawn(|this, mut cx| {
2680 let this = this.downgrade();
2681 async move {
2682 Timer::after(CURSOR_BLINK_INTERVAL).await;
2683 if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
2684 this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx));
2685 }
2686 }
2687 })
2688 .detach();
2689 }
2690 }
2691
2692 pub fn show_local_cursors(&self) -> bool {
2693 self.show_local_cursors
2694 }
2695
2696 fn on_buffer_changed(&mut self, _: ModelHandle<Buffer>, cx: &mut ViewContext<Self>) {
2697 cx.notify();
2698 }
2699
2700 fn on_buffer_event(
2701 &mut self,
2702 _: ModelHandle<Buffer>,
2703 event: &language::Event,
2704 cx: &mut ViewContext<Self>,
2705 ) {
2706 match event {
2707 language::Event::Edited => cx.emit(Event::Edited),
2708 language::Event::Dirtied => cx.emit(Event::Dirtied),
2709 language::Event::Saved => cx.emit(Event::Saved),
2710 language::Event::FileHandleChanged => cx.emit(Event::FileHandleChanged),
2711 language::Event::Reloaded => cx.emit(Event::FileHandleChanged),
2712 language::Event::Closed => cx.emit(Event::Closed),
2713 language::Event::Reparsed => {}
2714 }
2715 }
2716
2717 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
2718 cx.notify();
2719 }
2720}
2721
2722impl Snapshot {
2723 pub fn is_empty(&self) -> bool {
2724 self.display_snapshot.is_empty()
2725 }
2726
2727 pub fn is_focused(&self) -> bool {
2728 self.is_focused
2729 }
2730
2731 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
2732 self.placeholder_text.as_ref()
2733 }
2734
2735 pub fn buffer_row_count(&self) -> u32 {
2736 self.display_snapshot.buffer_row_count()
2737 }
2738
2739 pub fn buffer_rows(&self, start_row: u32) -> BufferRows {
2740 self.display_snapshot.buffer_rows(start_row)
2741 }
2742
2743 pub fn chunks<'a>(
2744 &'a self,
2745 display_rows: Range<u32>,
2746 theme: Option<&'a SyntaxTheme>,
2747 ) -> display_map::Chunks<'a> {
2748 self.display_snapshot.chunks(display_rows, theme)
2749 }
2750
2751 pub fn scroll_position(&self) -> Vector2F {
2752 compute_scroll_position(
2753 &self.display_snapshot,
2754 self.scroll_position,
2755 &self.scroll_top_anchor,
2756 )
2757 }
2758
2759 pub fn max_point(&self) -> DisplayPoint {
2760 self.display_snapshot.max_point()
2761 }
2762
2763 pub fn longest_row(&self) -> u32 {
2764 self.display_snapshot.longest_row()
2765 }
2766
2767 pub fn line_len(&self, display_row: u32) -> u32 {
2768 self.display_snapshot.line_len(display_row)
2769 }
2770
2771 pub fn line(&self, display_row: u32) -> String {
2772 self.display_snapshot.line(display_row)
2773 }
2774
2775 pub fn prev_row_boundary(&self, point: DisplayPoint) -> (DisplayPoint, Point) {
2776 self.display_snapshot.prev_row_boundary(point)
2777 }
2778
2779 pub fn next_row_boundary(&self, point: DisplayPoint) -> (DisplayPoint, Point) {
2780 self.display_snapshot.next_row_boundary(point)
2781 }
2782}
2783
2784impl EditorSettings {
2785 #[cfg(any(test, feature = "test-support"))]
2786 pub fn test(cx: &AppContext) -> Self {
2787 Self {
2788 tab_size: 4,
2789 style: {
2790 let font_cache: &gpui::FontCache = cx.font_cache();
2791 let font_family_name = Arc::from("Monaco");
2792 let font_properties = Default::default();
2793 let font_family_id = font_cache.load_family(&[&font_family_name]).unwrap();
2794 let font_id = font_cache
2795 .select_font(font_family_id, &font_properties)
2796 .unwrap();
2797 EditorStyle {
2798 text: gpui::fonts::TextStyle {
2799 font_family_name,
2800 font_family_id,
2801 font_id,
2802 font_size: 14.,
2803 color: gpui::color::Color::from_u32(0xff0000ff),
2804 font_properties,
2805 underline: None,
2806 },
2807 placeholder_text: None,
2808 background: Default::default(),
2809 gutter_background: Default::default(),
2810 active_line_background: Default::default(),
2811 line_number: Default::default(),
2812 line_number_active: Default::default(),
2813 selection: Default::default(),
2814 guest_selections: Default::default(),
2815 syntax: Default::default(),
2816 error_underline: Default::default(),
2817 warning_underline: Default::default(),
2818 information_underline: Default::default(),
2819 hint_underline: Default::default(),
2820 }
2821 },
2822 }
2823 }
2824}
2825
2826fn compute_scroll_position(
2827 snapshot: &DisplayMapSnapshot,
2828 mut scroll_position: Vector2F,
2829 scroll_top_anchor: &Anchor,
2830) -> Vector2F {
2831 let scroll_top = scroll_top_anchor.to_display_point(snapshot).row() as f32;
2832 scroll_position.set_y(scroll_top + scroll_position.y());
2833 scroll_position
2834}
2835
2836pub enum Event {
2837 Activate,
2838 Edited,
2839 Blurred,
2840 Dirtied,
2841 Saved,
2842 FileHandleChanged,
2843 Closed,
2844}
2845
2846impl Entity for Editor {
2847 type Event = Event;
2848
2849 fn release(&mut self, cx: &mut MutableAppContext) {
2850 self.buffer.update(cx, |buffer, cx| {
2851 buffer
2852 .remove_selection_set(self.selection_set_id, cx)
2853 .unwrap();
2854 });
2855 }
2856}
2857
2858impl View for Editor {
2859 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
2860 let settings = self.build_settings.borrow_mut()(cx);
2861 self.display_map.update(cx, |map, cx| {
2862 map.set_font(
2863 settings.style.text.font_id,
2864 settings.style.text.font_size,
2865 cx,
2866 )
2867 });
2868 EditorElement::new(self.handle.clone(), settings).boxed()
2869 }
2870
2871 fn ui_name() -> &'static str {
2872 "Editor"
2873 }
2874
2875 fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
2876 self.focused = true;
2877 self.blink_cursors(self.blink_epoch, cx);
2878 self.buffer.update(cx, |buffer, cx| {
2879 buffer
2880 .set_active_selection_set(Some(self.selection_set_id), cx)
2881 .unwrap();
2882 });
2883 }
2884
2885 fn on_blur(&mut self, cx: &mut ViewContext<Self>) {
2886 self.focused = false;
2887 self.show_local_cursors = false;
2888 self.buffer.update(cx, |buffer, cx| {
2889 buffer.set_active_selection_set(None, cx).unwrap();
2890 });
2891 cx.emit(Event::Blurred);
2892 cx.notify();
2893 }
2894
2895 fn keymap_context(&self, _: &AppContext) -> gpui::keymap::Context {
2896 let mut cx = Self::default_keymap_context();
2897 let mode = match self.mode {
2898 EditorMode::SingleLine => "single_line",
2899 EditorMode::AutoHeight { .. } => "auto_height",
2900 EditorMode::Full => "full",
2901 };
2902 cx.map.insert("mode".into(), mode.into());
2903 cx
2904 }
2905}
2906
2907impl SelectionExt for Selection<Point> {
2908 fn display_range(&self, map: &DisplayMapSnapshot) -> Range<DisplayPoint> {
2909 let start = self.start.to_display_point(map);
2910 let end = self.end.to_display_point(map);
2911 if self.reversed {
2912 end..start
2913 } else {
2914 start..end
2915 }
2916 }
2917
2918 fn spanned_rows(
2919 &self,
2920 include_end_if_at_line_start: bool,
2921 map: &DisplayMapSnapshot,
2922 ) -> SpannedRows {
2923 let display_start = self.start.to_display_point(map);
2924 let mut display_end = self.end.to_display_point(map);
2925 if !include_end_if_at_line_start
2926 && display_end.row() != map.max_point().row()
2927 && display_start.row() != display_end.row()
2928 && display_end.column() == 0
2929 {
2930 *display_end.row_mut() -= 1;
2931 }
2932
2933 let (display_start, buffer_start) = map.prev_row_boundary(display_start);
2934 let (display_end, buffer_end) = map.next_row_boundary(display_end);
2935
2936 SpannedRows {
2937 buffer_rows: buffer_start.row..buffer_end.row + 1,
2938 display_rows: display_start.row()..display_end.row() + 1,
2939 }
2940 }
2941}
2942
2943#[cfg(test)]
2944mod tests {
2945 use super::*;
2946 use crate::test::sample_text;
2947 use buffer::Point;
2948 use unindent::Unindent;
2949
2950 #[gpui::test]
2951 fn test_selection_with_mouse(cx: &mut gpui::MutableAppContext) {
2952 let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx));
2953 let settings = EditorSettings::test(cx);
2954 let (_, editor) =
2955 cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
2956
2957 editor.update(cx, |view, cx| {
2958 view.begin_selection(DisplayPoint::new(2, 2), false, cx);
2959 });
2960
2961 assert_eq!(
2962 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2963 [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
2964 );
2965
2966 editor.update(cx, |view, cx| {
2967 view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx);
2968 });
2969
2970 assert_eq!(
2971 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2972 [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
2973 );
2974
2975 editor.update(cx, |view, cx| {
2976 view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx);
2977 });
2978
2979 assert_eq!(
2980 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2981 [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
2982 );
2983
2984 editor.update(cx, |view, cx| {
2985 view.end_selection(cx);
2986 view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx);
2987 });
2988
2989 assert_eq!(
2990 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2991 [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
2992 );
2993
2994 editor.update(cx, |view, cx| {
2995 view.begin_selection(DisplayPoint::new(3, 3), true, cx);
2996 view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), cx);
2997 });
2998
2999 assert_eq!(
3000 editor.update(cx, |view, cx| view.selection_ranges(cx)),
3001 [
3002 DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1),
3003 DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)
3004 ]
3005 );
3006
3007 editor.update(cx, |view, cx| {
3008 view.end_selection(cx);
3009 });
3010
3011 assert_eq!(
3012 editor.update(cx, |view, cx| view.selection_ranges(cx)),
3013 [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)]
3014 );
3015 }
3016
3017 #[gpui::test]
3018 fn test_canceling_pending_selection(cx: &mut gpui::MutableAppContext) {
3019 let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx));
3020 let settings = EditorSettings::test(cx);
3021 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3022
3023 view.update(cx, |view, cx| {
3024 view.begin_selection(DisplayPoint::new(2, 2), false, cx);
3025 assert_eq!(
3026 view.selection_ranges(cx),
3027 [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
3028 );
3029 });
3030
3031 view.update(cx, |view, cx| {
3032 view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx);
3033 assert_eq!(
3034 view.selection_ranges(cx),
3035 [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
3036 );
3037 });
3038
3039 view.update(cx, |view, cx| {
3040 view.cancel(&Cancel, cx);
3041 view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx);
3042 assert_eq!(
3043 view.selection_ranges(cx),
3044 [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
3045 );
3046 });
3047 }
3048
3049 #[gpui::test]
3050 fn test_cancel(cx: &mut gpui::MutableAppContext) {
3051 let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx));
3052 let settings = EditorSettings::test(cx);
3053 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3054
3055 view.update(cx, |view, cx| {
3056 view.begin_selection(DisplayPoint::new(3, 4), false, cx);
3057 view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx);
3058 view.end_selection(cx);
3059
3060 view.begin_selection(DisplayPoint::new(0, 1), true, cx);
3061 view.update_selection(DisplayPoint::new(0, 3), Vector2F::zero(), cx);
3062 view.end_selection(cx);
3063 assert_eq!(
3064 view.selection_ranges(cx),
3065 [
3066 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
3067 DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1),
3068 ]
3069 );
3070 });
3071
3072 view.update(cx, |view, cx| {
3073 view.cancel(&Cancel, cx);
3074 assert_eq!(
3075 view.selection_ranges(cx),
3076 [DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)]
3077 );
3078 });
3079
3080 view.update(cx, |view, cx| {
3081 view.cancel(&Cancel, cx);
3082 assert_eq!(
3083 view.selection_ranges(cx),
3084 [DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)]
3085 );
3086 });
3087 }
3088
3089 #[gpui::test]
3090 fn test_fold(cx: &mut gpui::MutableAppContext) {
3091 let buffer = cx.add_model(|cx| {
3092 Buffer::new(
3093 0,
3094 "
3095 impl Foo {
3096 // Hello!
3097
3098 fn a() {
3099 1
3100 }
3101
3102 fn b() {
3103 2
3104 }
3105
3106 fn c() {
3107 3
3108 }
3109 }
3110 "
3111 .unindent(),
3112 cx,
3113 )
3114 });
3115 let settings = EditorSettings::test(&cx);
3116 let (_, view) = cx.add_window(Default::default(), |cx| {
3117 build_editor(buffer.clone(), settings, cx)
3118 });
3119
3120 view.update(cx, |view, cx| {
3121 view.select_display_ranges(&[DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)], cx)
3122 .unwrap();
3123 view.fold(&Fold, cx);
3124 assert_eq!(
3125 view.display_text(cx),
3126 "
3127 impl Foo {
3128 // Hello!
3129
3130 fn a() {
3131 1
3132 }
3133
3134 fn b() {…
3135 }
3136
3137 fn c() {…
3138 }
3139 }
3140 "
3141 .unindent(),
3142 );
3143
3144 view.fold(&Fold, cx);
3145 assert_eq!(
3146 view.display_text(cx),
3147 "
3148 impl Foo {…
3149 }
3150 "
3151 .unindent(),
3152 );
3153
3154 view.unfold(&Unfold, cx);
3155 assert_eq!(
3156 view.display_text(cx),
3157 "
3158 impl Foo {
3159 // Hello!
3160
3161 fn a() {
3162 1
3163 }
3164
3165 fn b() {…
3166 }
3167
3168 fn c() {…
3169 }
3170 }
3171 "
3172 .unindent(),
3173 );
3174
3175 view.unfold(&Unfold, cx);
3176 assert_eq!(view.display_text(cx), buffer.read(cx).text());
3177 });
3178 }
3179
3180 #[gpui::test]
3181 fn test_move_cursor(cx: &mut gpui::MutableAppContext) {
3182 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6), cx));
3183 let settings = EditorSettings::test(&cx);
3184 let (_, view) = cx.add_window(Default::default(), |cx| {
3185 build_editor(buffer.clone(), settings, cx)
3186 });
3187
3188 buffer.update(cx, |buffer, cx| {
3189 buffer.edit(
3190 vec![
3191 Point::new(1, 0)..Point::new(1, 0),
3192 Point::new(1, 1)..Point::new(1, 1),
3193 ],
3194 "\t",
3195 cx,
3196 );
3197 });
3198
3199 view.update(cx, |view, cx| {
3200 assert_eq!(
3201 view.selection_ranges(cx),
3202 &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
3203 );
3204
3205 view.move_down(&MoveDown, cx);
3206 assert_eq!(
3207 view.selection_ranges(cx),
3208 &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
3209 );
3210
3211 view.move_right(&MoveRight, cx);
3212 assert_eq!(
3213 view.selection_ranges(cx),
3214 &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)]
3215 );
3216
3217 view.move_left(&MoveLeft, cx);
3218 assert_eq!(
3219 view.selection_ranges(cx),
3220 &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
3221 );
3222
3223 view.move_up(&MoveUp, cx);
3224 assert_eq!(
3225 view.selection_ranges(cx),
3226 &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
3227 );
3228
3229 view.move_to_end(&MoveToEnd, cx);
3230 assert_eq!(
3231 view.selection_ranges(cx),
3232 &[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 6)]
3233 );
3234
3235 view.move_to_beginning(&MoveToBeginning, cx);
3236 assert_eq!(
3237 view.selection_ranges(cx),
3238 &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
3239 );
3240
3241 view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)], cx)
3242 .unwrap();
3243 view.select_to_beginning(&SelectToBeginning, cx);
3244 assert_eq!(
3245 view.selection_ranges(cx),
3246 &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 0)]
3247 );
3248
3249 view.select_to_end(&SelectToEnd, cx);
3250 assert_eq!(
3251 view.selection_ranges(cx),
3252 &[DisplayPoint::new(0, 1)..DisplayPoint::new(5, 6)]
3253 );
3254 });
3255 }
3256
3257 #[gpui::test]
3258 fn test_move_cursor_multibyte(cx: &mut gpui::MutableAppContext) {
3259 let buffer = cx.add_model(|cx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", cx));
3260 let settings = EditorSettings::test(&cx);
3261 let (_, view) = cx.add_window(Default::default(), |cx| {
3262 build_editor(buffer.clone(), settings, cx)
3263 });
3264
3265 assert_eq!('ⓐ'.len_utf8(), 3);
3266 assert_eq!('α'.len_utf8(), 2);
3267
3268 view.update(cx, |view, cx| {
3269 view.fold_ranges(
3270 vec![
3271 Point::new(0, 6)..Point::new(0, 12),
3272 Point::new(1, 2)..Point::new(1, 4),
3273 Point::new(2, 4)..Point::new(2, 8),
3274 ],
3275 cx,
3276 );
3277 assert_eq!(view.display_text(cx), "ⓐⓑ…ⓔ\nab…e\nαβ…ε\n");
3278
3279 view.move_right(&MoveRight, cx);
3280 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐ".len())]);
3281 view.move_right(&MoveRight, cx);
3282 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ".len())]);
3283 view.move_right(&MoveRight, cx);
3284 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ…".len())]);
3285
3286 view.move_down(&MoveDown, cx);
3287 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "ab…".len())]);
3288 view.move_left(&MoveLeft, cx);
3289 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "ab".len())]);
3290 view.move_left(&MoveLeft, cx);
3291 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "a".len())]);
3292
3293 view.move_down(&MoveDown, cx);
3294 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "α".len())]);
3295 view.move_right(&MoveRight, cx);
3296 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβ".len())]);
3297 view.move_right(&MoveRight, cx);
3298 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβ…".len())]);
3299 view.move_right(&MoveRight, cx);
3300 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβ…ε".len())]);
3301
3302 view.move_up(&MoveUp, cx);
3303 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "ab…e".len())]);
3304 view.move_up(&MoveUp, cx);
3305 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ…ⓔ".len())]);
3306 view.move_left(&MoveLeft, cx);
3307 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ…".len())]);
3308 view.move_left(&MoveLeft, cx);
3309 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ".len())]);
3310 view.move_left(&MoveLeft, cx);
3311 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐ".len())]);
3312 });
3313 }
3314
3315 #[gpui::test]
3316 fn test_move_cursor_different_line_lengths(cx: &mut gpui::MutableAppContext) {
3317 let buffer = cx.add_model(|cx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", cx));
3318 let settings = EditorSettings::test(&cx);
3319 let (_, view) = cx.add_window(Default::default(), |cx| {
3320 build_editor(buffer.clone(), settings, cx)
3321 });
3322 view.update(cx, |view, cx| {
3323 view.select_display_ranges(&[empty_range(0, "ⓐⓑⓒⓓⓔ".len())], cx)
3324 .unwrap();
3325
3326 view.move_down(&MoveDown, cx);
3327 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "abcd".len())]);
3328
3329 view.move_down(&MoveDown, cx);
3330 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβγ".len())]);
3331
3332 view.move_down(&MoveDown, cx);
3333 assert_eq!(view.selection_ranges(cx), &[empty_range(3, "abcd".len())]);
3334
3335 view.move_down(&MoveDown, cx);
3336 assert_eq!(view.selection_ranges(cx), &[empty_range(4, "ⓐⓑⓒⓓⓔ".len())]);
3337
3338 view.move_up(&MoveUp, cx);
3339 assert_eq!(view.selection_ranges(cx), &[empty_range(3, "abcd".len())]);
3340
3341 view.move_up(&MoveUp, cx);
3342 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβγ".len())]);
3343 });
3344 }
3345
3346 #[gpui::test]
3347 fn test_beginning_end_of_line(cx: &mut gpui::MutableAppContext) {
3348 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\n def", cx));
3349 let settings = EditorSettings::test(&cx);
3350 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3351 view.update(cx, |view, cx| {
3352 view.select_display_ranges(
3353 &[
3354 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3355 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4),
3356 ],
3357 cx,
3358 )
3359 .unwrap();
3360 });
3361
3362 view.update(cx, |view, cx| {
3363 view.move_to_beginning_of_line(&MoveToBeginningOfLine, cx);
3364 assert_eq!(
3365 view.selection_ranges(cx),
3366 &[
3367 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3368 DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
3369 ]
3370 );
3371 });
3372
3373 view.update(cx, |view, cx| {
3374 view.move_to_beginning_of_line(&MoveToBeginningOfLine, cx);
3375 assert_eq!(
3376 view.selection_ranges(cx),
3377 &[
3378 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3379 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
3380 ]
3381 );
3382 });
3383
3384 view.update(cx, |view, cx| {
3385 view.move_to_beginning_of_line(&MoveToBeginningOfLine, cx);
3386 assert_eq!(
3387 view.selection_ranges(cx),
3388 &[
3389 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3390 DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
3391 ]
3392 );
3393 });
3394
3395 view.update(cx, |view, cx| {
3396 view.move_to_end_of_line(&MoveToEndOfLine, cx);
3397 assert_eq!(
3398 view.selection_ranges(cx),
3399 &[
3400 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
3401 DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
3402 ]
3403 );
3404 });
3405
3406 // Moving to the end of line again is a no-op.
3407 view.update(cx, |view, cx| {
3408 view.move_to_end_of_line(&MoveToEndOfLine, cx);
3409 assert_eq!(
3410 view.selection_ranges(cx),
3411 &[
3412 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
3413 DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
3414 ]
3415 );
3416 });
3417
3418 view.update(cx, |view, cx| {
3419 view.move_left(&MoveLeft, cx);
3420 view.select_to_beginning_of_line(&SelectToBeginningOfLine(true), cx);
3421 assert_eq!(
3422 view.selection_ranges(cx),
3423 &[
3424 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
3425 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2),
3426 ]
3427 );
3428 });
3429
3430 view.update(cx, |view, cx| {
3431 view.select_to_beginning_of_line(&SelectToBeginningOfLine(true), cx);
3432 assert_eq!(
3433 view.selection_ranges(cx),
3434 &[
3435 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
3436 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 0),
3437 ]
3438 );
3439 });
3440
3441 view.update(cx, |view, cx| {
3442 view.select_to_beginning_of_line(&SelectToBeginningOfLine(true), cx);
3443 assert_eq!(
3444 view.selection_ranges(cx),
3445 &[
3446 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
3447 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2),
3448 ]
3449 );
3450 });
3451
3452 view.update(cx, |view, cx| {
3453 view.select_to_end_of_line(&SelectToEndOfLine, cx);
3454 assert_eq!(
3455 view.selection_ranges(cx),
3456 &[
3457 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3),
3458 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 5),
3459 ]
3460 );
3461 });
3462
3463 view.update(cx, |view, cx| {
3464 view.delete_to_end_of_line(&DeleteToEndOfLine, cx);
3465 assert_eq!(view.display_text(cx), "ab\n de");
3466 assert_eq!(
3467 view.selection_ranges(cx),
3468 &[
3469 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3470 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4),
3471 ]
3472 );
3473 });
3474
3475 view.update(cx, |view, cx| {
3476 view.delete_to_beginning_of_line(&DeleteToBeginningOfLine, cx);
3477 assert_eq!(view.display_text(cx), "\n");
3478 assert_eq!(
3479 view.selection_ranges(cx),
3480 &[
3481 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3482 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
3483 ]
3484 );
3485 });
3486 }
3487
3488 #[gpui::test]
3489 fn test_prev_next_word_boundary(cx: &mut gpui::MutableAppContext) {
3490 let buffer =
3491 cx.add_model(|cx| Buffer::new(0, "use std::str::{foo, bar}\n\n {baz.qux()}", cx));
3492 let settings = EditorSettings::test(&cx);
3493 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3494 view.update(cx, |view, cx| {
3495 view.select_display_ranges(
3496 &[
3497 DisplayPoint::new(0, 11)..DisplayPoint::new(0, 11),
3498 DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4),
3499 ],
3500 cx,
3501 )
3502 .unwrap();
3503 });
3504
3505 view.update(cx, |view, cx| {
3506 view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
3507 assert_eq!(
3508 view.selection_ranges(cx),
3509 &[
3510 DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9),
3511 DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3),
3512 ]
3513 );
3514 });
3515
3516 view.update(cx, |view, cx| {
3517 view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
3518 assert_eq!(
3519 view.selection_ranges(cx),
3520 &[
3521 DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7),
3522 DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2),
3523 ]
3524 );
3525 });
3526
3527 view.update(cx, |view, cx| {
3528 view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
3529 assert_eq!(
3530 view.selection_ranges(cx),
3531 &[
3532 DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4),
3533 DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0),
3534 ]
3535 );
3536 });
3537
3538 view.update(cx, |view, cx| {
3539 view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
3540 assert_eq!(
3541 view.selection_ranges(cx),
3542 &[
3543 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3544 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
3545 ]
3546 );
3547 });
3548
3549 view.update(cx, |view, cx| {
3550 view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
3551 assert_eq!(
3552 view.selection_ranges(cx),
3553 &[
3554 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3555 DisplayPoint::new(0, 23)..DisplayPoint::new(0, 23),
3556 ]
3557 );
3558 });
3559
3560 view.update(cx, |view, cx| {
3561 view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
3562 assert_eq!(
3563 view.selection_ranges(cx),
3564 &[
3565 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
3566 DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24),
3567 ]
3568 );
3569 });
3570
3571 view.update(cx, |view, cx| {
3572 view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
3573 assert_eq!(
3574 view.selection_ranges(cx),
3575 &[
3576 DisplayPoint::new(0, 7)..DisplayPoint::new(0, 7),
3577 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
3578 ]
3579 );
3580 });
3581
3582 view.update(cx, |view, cx| {
3583 view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
3584 assert_eq!(
3585 view.selection_ranges(cx),
3586 &[
3587 DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9),
3588 DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3),
3589 ]
3590 );
3591 });
3592
3593 view.update(cx, |view, cx| {
3594 view.move_right(&MoveRight, cx);
3595 view.select_to_previous_word_boundary(&SelectToPreviousWordBoundary, cx);
3596 assert_eq!(
3597 view.selection_ranges(cx),
3598 &[
3599 DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9),
3600 DisplayPoint::new(2, 4)..DisplayPoint::new(2, 3),
3601 ]
3602 );
3603 });
3604
3605 view.update(cx, |view, cx| {
3606 view.select_to_previous_word_boundary(&SelectToPreviousWordBoundary, cx);
3607 assert_eq!(
3608 view.selection_ranges(cx),
3609 &[
3610 DisplayPoint::new(0, 10)..DisplayPoint::new(0, 7),
3611 DisplayPoint::new(2, 4)..DisplayPoint::new(2, 2),
3612 ]
3613 );
3614 });
3615
3616 view.update(cx, |view, cx| {
3617 view.select_to_next_word_boundary(&SelectToNextWordBoundary, cx);
3618 assert_eq!(
3619 view.selection_ranges(cx),
3620 &[
3621 DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9),
3622 DisplayPoint::new(2, 4)..DisplayPoint::new(2, 3),
3623 ]
3624 );
3625 });
3626 }
3627
3628 #[gpui::test]
3629 fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut gpui::MutableAppContext) {
3630 let buffer =
3631 cx.add_model(|cx| Buffer::new(0, "use one::{\n two::three::four::five\n};", cx));
3632 let settings = EditorSettings::test(&cx);
3633 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3634
3635 view.update(cx, |view, cx| {
3636 view.set_wrap_width(140., cx);
3637 assert_eq!(
3638 view.display_text(cx),
3639 "use one::{\n two::three::\n four::five\n};"
3640 );
3641
3642 view.select_display_ranges(&[DisplayPoint::new(1, 7)..DisplayPoint::new(1, 7)], cx)
3643 .unwrap();
3644
3645 view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
3646 assert_eq!(
3647 view.selection_ranges(cx),
3648 &[DisplayPoint::new(1, 9)..DisplayPoint::new(1, 9)]
3649 );
3650
3651 view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
3652 assert_eq!(
3653 view.selection_ranges(cx),
3654 &[DisplayPoint::new(1, 14)..DisplayPoint::new(1, 14)]
3655 );
3656
3657 view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
3658 assert_eq!(
3659 view.selection_ranges(cx),
3660 &[DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4)]
3661 );
3662
3663 view.move_to_next_word_boundary(&MoveToNextWordBoundary, cx);
3664 assert_eq!(
3665 view.selection_ranges(cx),
3666 &[DisplayPoint::new(2, 8)..DisplayPoint::new(2, 8)]
3667 );
3668
3669 view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
3670 assert_eq!(
3671 view.selection_ranges(cx),
3672 &[DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4)]
3673 );
3674
3675 view.move_to_previous_word_boundary(&MoveToPreviousWordBoundary, cx);
3676 assert_eq!(
3677 view.selection_ranges(cx),
3678 &[DisplayPoint::new(1, 14)..DisplayPoint::new(1, 14)]
3679 );
3680 });
3681 }
3682
3683 #[gpui::test]
3684 fn test_delete_to_word_boundary(cx: &mut gpui::MutableAppContext) {
3685 let buffer = cx.add_model(|cx| Buffer::new(0, "one two three four", cx));
3686 let settings = EditorSettings::test(&cx);
3687 let (_, view) = cx.add_window(Default::default(), |cx| {
3688 build_editor(buffer.clone(), settings, cx)
3689 });
3690
3691 view.update(cx, |view, cx| {
3692 view.select_display_ranges(
3693 &[
3694 // an empty selection - the preceding word fragment is deleted
3695 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3696 // characters selected - they are deleted
3697 DisplayPoint::new(0, 9)..DisplayPoint::new(0, 12),
3698 ],
3699 cx,
3700 )
3701 .unwrap();
3702 view.delete_to_previous_word_boundary(&DeleteToPreviousWordBoundary, cx);
3703 });
3704
3705 assert_eq!(buffer.read(cx).text(), "e two te four");
3706
3707 view.update(cx, |view, cx| {
3708 view.select_display_ranges(
3709 &[
3710 // an empty selection - the following word fragment is deleted
3711 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
3712 // characters selected - they are deleted
3713 DisplayPoint::new(0, 9)..DisplayPoint::new(0, 10),
3714 ],
3715 cx,
3716 )
3717 .unwrap();
3718 view.delete_to_next_word_boundary(&DeleteToNextWordBoundary, cx);
3719 });
3720
3721 assert_eq!(buffer.read(cx).text(), "e t te our");
3722 }
3723
3724 #[gpui::test]
3725 fn test_newline(cx: &mut gpui::MutableAppContext) {
3726 let buffer = cx.add_model(|cx| Buffer::new(0, "aaaa\n bbbb\n", cx));
3727 let settings = EditorSettings::test(&cx);
3728 let (_, view) = cx.add_window(Default::default(), |cx| {
3729 build_editor(buffer.clone(), settings, cx)
3730 });
3731
3732 view.update(cx, |view, cx| {
3733 view.select_display_ranges(
3734 &[
3735 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3736 DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
3737 DisplayPoint::new(1, 6)..DisplayPoint::new(1, 6),
3738 ],
3739 cx,
3740 )
3741 .unwrap();
3742
3743 view.newline(&Newline, cx);
3744 assert_eq!(view.text(cx), "aa\naa\n \n bb\n bb\n");
3745 });
3746 }
3747
3748 #[gpui::test]
3749 fn test_backspace(cx: &mut gpui::MutableAppContext) {
3750 let buffer = cx.add_model(|cx| {
3751 Buffer::new(
3752 0,
3753 "one two three\nfour five six\nseven eight nine\nten\n",
3754 cx,
3755 )
3756 });
3757 let settings = EditorSettings::test(&cx);
3758 let (_, view) = cx.add_window(Default::default(), |cx| {
3759 build_editor(buffer.clone(), settings, cx)
3760 });
3761
3762 view.update(cx, |view, cx| {
3763 view.select_display_ranges(
3764 &[
3765 // an empty selection - the preceding character is deleted
3766 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3767 // one character selected - it is deleted
3768 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
3769 // a line suffix selected - it is deleted
3770 DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
3771 ],
3772 cx,
3773 )
3774 .unwrap();
3775 view.backspace(&Backspace, cx);
3776 });
3777
3778 assert_eq!(
3779 buffer.read(cx).text(),
3780 "oe two three\nfou five six\nseven ten\n"
3781 );
3782 }
3783
3784 #[gpui::test]
3785 fn test_delete(cx: &mut gpui::MutableAppContext) {
3786 let buffer = cx.add_model(|cx| {
3787 Buffer::new(
3788 0,
3789 "one two three\nfour five six\nseven eight nine\nten\n",
3790 cx,
3791 )
3792 });
3793 let settings = EditorSettings::test(&cx);
3794 let (_, view) = cx.add_window(Default::default(), |cx| {
3795 build_editor(buffer.clone(), settings, cx)
3796 });
3797
3798 view.update(cx, |view, cx| {
3799 view.select_display_ranges(
3800 &[
3801 // an empty selection - the following character is deleted
3802 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3803 // one character selected - it is deleted
3804 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
3805 // a line suffix selected - it is deleted
3806 DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
3807 ],
3808 cx,
3809 )
3810 .unwrap();
3811 view.delete(&Delete, cx);
3812 });
3813
3814 assert_eq!(
3815 buffer.read(cx).text(),
3816 "on two three\nfou five six\nseven ten\n"
3817 );
3818 }
3819
3820 #[gpui::test]
3821 fn test_delete_line(cx: &mut gpui::MutableAppContext) {
3822 let settings = EditorSettings::test(&cx);
3823 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx));
3824 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3825 view.update(cx, |view, cx| {
3826 view.select_display_ranges(
3827 &[
3828 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3829 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
3830 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
3831 ],
3832 cx,
3833 )
3834 .unwrap();
3835 view.delete_line(&DeleteLine, cx);
3836 assert_eq!(view.display_text(cx), "ghi");
3837 assert_eq!(
3838 view.selection_ranges(cx),
3839 vec![
3840 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3841 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)
3842 ]
3843 );
3844 });
3845
3846 let settings = EditorSettings::test(&cx);
3847 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx));
3848 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3849 view.update(cx, |view, cx| {
3850 view.select_display_ranges(&[DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)], cx)
3851 .unwrap();
3852 view.delete_line(&DeleteLine, cx);
3853 assert_eq!(view.display_text(cx), "ghi\n");
3854 assert_eq!(
3855 view.selection_ranges(cx),
3856 vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)]
3857 );
3858 });
3859 }
3860
3861 #[gpui::test]
3862 fn test_duplicate_line(cx: &mut gpui::MutableAppContext) {
3863 let settings = EditorSettings::test(&cx);
3864 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx));
3865 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3866 view.update(cx, |view, cx| {
3867 view.select_display_ranges(
3868 &[
3869 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
3870 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3871 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
3872 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
3873 ],
3874 cx,
3875 )
3876 .unwrap();
3877 view.duplicate_line(&DuplicateLine, cx);
3878 assert_eq!(view.display_text(cx), "abc\nabc\ndef\ndef\nghi\n\n");
3879 assert_eq!(
3880 view.selection_ranges(cx),
3881 vec![
3882 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
3883 DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
3884 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
3885 DisplayPoint::new(6, 0)..DisplayPoint::new(6, 0),
3886 ]
3887 );
3888 });
3889
3890 let settings = EditorSettings::test(&cx);
3891 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx));
3892 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3893 view.update(cx, |view, cx| {
3894 view.select_display_ranges(
3895 &[
3896 DisplayPoint::new(0, 1)..DisplayPoint::new(1, 1),
3897 DisplayPoint::new(1, 2)..DisplayPoint::new(2, 1),
3898 ],
3899 cx,
3900 )
3901 .unwrap();
3902 view.duplicate_line(&DuplicateLine, cx);
3903 assert_eq!(view.display_text(cx), "abc\ndef\nghi\nabc\ndef\nghi\n");
3904 assert_eq!(
3905 view.selection_ranges(cx),
3906 vec![
3907 DisplayPoint::new(3, 1)..DisplayPoint::new(4, 1),
3908 DisplayPoint::new(4, 2)..DisplayPoint::new(5, 1),
3909 ]
3910 );
3911 });
3912 }
3913
3914 #[gpui::test]
3915 fn test_move_line_up_down(cx: &mut gpui::MutableAppContext) {
3916 let settings = EditorSettings::test(&cx);
3917 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(10, 5), cx));
3918 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
3919 view.update(cx, |view, cx| {
3920 view.fold_ranges(
3921 vec![
3922 Point::new(0, 2)..Point::new(1, 2),
3923 Point::new(2, 3)..Point::new(4, 1),
3924 Point::new(7, 0)..Point::new(8, 4),
3925 ],
3926 cx,
3927 );
3928 view.select_display_ranges(
3929 &[
3930 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3931 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
3932 DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
3933 DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2),
3934 ],
3935 cx,
3936 )
3937 .unwrap();
3938 assert_eq!(
3939 view.display_text(cx),
3940 "aa…bbb\nccc…eeee\nfffff\nggggg\n…i\njjjjj"
3941 );
3942
3943 view.move_line_up(&MoveLineUp, cx);
3944 assert_eq!(
3945 view.display_text(cx),
3946 "aa…bbb\nccc…eeee\nggggg\n…i\njjjjj\nfffff"
3947 );
3948 assert_eq!(
3949 view.selection_ranges(cx),
3950 vec![
3951 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3952 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
3953 DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3),
3954 DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2)
3955 ]
3956 );
3957 });
3958
3959 view.update(cx, |view, cx| {
3960 view.move_line_down(&MoveLineDown, cx);
3961 assert_eq!(
3962 view.display_text(cx),
3963 "ccc…eeee\naa…bbb\nfffff\nggggg\n…i\njjjjj"
3964 );
3965 assert_eq!(
3966 view.selection_ranges(cx),
3967 vec![
3968 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
3969 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
3970 DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
3971 DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2)
3972 ]
3973 );
3974 });
3975
3976 view.update(cx, |view, cx| {
3977 view.move_line_down(&MoveLineDown, cx);
3978 assert_eq!(
3979 view.display_text(cx),
3980 "ccc…eeee\nfffff\naa…bbb\nggggg\n…i\njjjjj"
3981 );
3982 assert_eq!(
3983 view.selection_ranges(cx),
3984 vec![
3985 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
3986 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
3987 DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
3988 DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2)
3989 ]
3990 );
3991 });
3992
3993 view.update(cx, |view, cx| {
3994 view.move_line_up(&MoveLineUp, cx);
3995 assert_eq!(
3996 view.display_text(cx),
3997 "ccc…eeee\naa…bbb\nggggg\n…i\njjjjj\nfffff"
3998 );
3999 assert_eq!(
4000 view.selection_ranges(cx),
4001 vec![
4002 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
4003 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
4004 DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3),
4005 DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2)
4006 ]
4007 );
4008 });
4009 }
4010
4011 #[gpui::test]
4012 fn test_clipboard(cx: &mut gpui::MutableAppContext) {
4013 let buffer = cx.add_model(|cx| Buffer::new(0, "one✅ two three four five six ", cx));
4014 let settings = EditorSettings::test(&cx);
4015 let view = cx
4016 .add_window(Default::default(), |cx| {
4017 build_editor(buffer.clone(), settings, cx)
4018 })
4019 .1;
4020
4021 // Cut with three selections. Clipboard text is divided into three slices.
4022 view.update(cx, |view, cx| {
4023 view.select_ranges(vec![0..7, 11..17, 22..27], false, cx);
4024 view.cut(&Cut, cx);
4025 assert_eq!(view.display_text(cx), "two four six ");
4026 });
4027
4028 // Paste with three cursors. Each cursor pastes one slice of the clipboard text.
4029 view.update(cx, |view, cx| {
4030 view.select_ranges(vec![4..4, 9..9, 13..13], false, cx);
4031 view.paste(&Paste, cx);
4032 assert_eq!(view.display_text(cx), "two one✅ four three six five ");
4033 assert_eq!(
4034 view.selection_ranges(cx),
4035 &[
4036 DisplayPoint::new(0, 11)..DisplayPoint::new(0, 11),
4037 DisplayPoint::new(0, 22)..DisplayPoint::new(0, 22),
4038 DisplayPoint::new(0, 31)..DisplayPoint::new(0, 31)
4039 ]
4040 );
4041 });
4042
4043 // Paste again but with only two cursors. Since the number of cursors doesn't
4044 // match the number of slices in the clipboard, the entire clipboard text
4045 // is pasted at each cursor.
4046 view.update(cx, |view, cx| {
4047 view.select_ranges(vec![0..0, 31..31], false, cx);
4048 view.handle_input(&Input("( ".into()), cx);
4049 view.paste(&Paste, cx);
4050 view.handle_input(&Input(") ".into()), cx);
4051 assert_eq!(
4052 view.display_text(cx),
4053 "( one✅ three five ) two one✅ four three six five ( one✅ three five ) "
4054 );
4055 });
4056
4057 view.update(cx, |view, cx| {
4058 view.select_ranges(vec![0..0], false, cx);
4059 view.handle_input(&Input("123\n4567\n89\n".into()), cx);
4060 assert_eq!(
4061 view.display_text(cx),
4062 "123\n4567\n89\n( one✅ three five ) two one✅ four three six five ( one✅ three five ) "
4063 );
4064 });
4065
4066 // Cut with three selections, one of which is full-line.
4067 view.update(cx, |view, cx| {
4068 view.select_display_ranges(
4069 &[
4070 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2),
4071 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
4072 DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1),
4073 ],
4074 cx,
4075 )
4076 .unwrap();
4077 view.cut(&Cut, cx);
4078 assert_eq!(
4079 view.display_text(cx),
4080 "13\n9\n( one✅ three five ) two one✅ four three six five ( one✅ three five ) "
4081 );
4082 });
4083
4084 // Paste with three selections, noticing how the copied selection that was full-line
4085 // gets inserted before the second cursor.
4086 view.update(cx, |view, cx| {
4087 view.select_display_ranges(
4088 &[
4089 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
4090 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
4091 DisplayPoint::new(2, 2)..DisplayPoint::new(2, 3),
4092 ],
4093 cx,
4094 )
4095 .unwrap();
4096 view.paste(&Paste, cx);
4097 assert_eq!(
4098 view.display_text(cx),
4099 "123\n4567\n9\n( 8ne✅ three five ) two one✅ four three six five ( one✅ three five ) "
4100 );
4101 assert_eq!(
4102 view.selection_ranges(cx),
4103 &[
4104 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
4105 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
4106 DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3),
4107 ]
4108 );
4109 });
4110
4111 // Copy with a single cursor only, which writes the whole line into the clipboard.
4112 view.update(cx, |view, cx| {
4113 view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)], cx)
4114 .unwrap();
4115 view.copy(&Copy, cx);
4116 });
4117
4118 // Paste with three selections, noticing how the copied full-line selection is inserted
4119 // before the empty selections but replaces the selection that is non-empty.
4120 view.update(cx, |view, cx| {
4121 view.select_display_ranges(
4122 &[
4123 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
4124 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 2),
4125 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
4126 ],
4127 cx,
4128 )
4129 .unwrap();
4130 view.paste(&Paste, cx);
4131 assert_eq!(
4132 view.display_text(cx),
4133 "123\n123\n123\n67\n123\n9\n( 8ne✅ three five ) two one✅ four three six five ( one✅ three five ) "
4134 );
4135 assert_eq!(
4136 view.selection_ranges(cx),
4137 &[
4138 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
4139 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
4140 DisplayPoint::new(5, 1)..DisplayPoint::new(5, 1),
4141 ]
4142 );
4143 });
4144 }
4145
4146 #[gpui::test]
4147 fn test_select_all(cx: &mut gpui::MutableAppContext) {
4148 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\nde\nfgh", cx));
4149 let settings = EditorSettings::test(&cx);
4150 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
4151 view.update(cx, |view, cx| {
4152 view.select_all(&SelectAll, cx);
4153 assert_eq!(
4154 view.selection_ranges(cx),
4155 &[DisplayPoint::new(0, 0)..DisplayPoint::new(2, 3)]
4156 );
4157 });
4158 }
4159
4160 #[gpui::test]
4161 fn test_select_line(cx: &mut gpui::MutableAppContext) {
4162 let settings = EditorSettings::test(&cx);
4163 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 5), cx));
4164 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
4165 view.update(cx, |view, cx| {
4166 view.select_display_ranges(
4167 &[
4168 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
4169 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
4170 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
4171 DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2),
4172 ],
4173 cx,
4174 )
4175 .unwrap();
4176 view.select_line(&SelectLine, cx);
4177 assert_eq!(
4178 view.selection_ranges(cx),
4179 vec![
4180 DisplayPoint::new(0, 0)..DisplayPoint::new(2, 0),
4181 DisplayPoint::new(4, 0)..DisplayPoint::new(5, 0),
4182 ]
4183 );
4184 });
4185
4186 view.update(cx, |view, cx| {
4187 view.select_line(&SelectLine, cx);
4188 assert_eq!(
4189 view.selection_ranges(cx),
4190 vec![
4191 DisplayPoint::new(0, 0)..DisplayPoint::new(3, 0),
4192 DisplayPoint::new(4, 0)..DisplayPoint::new(5, 5),
4193 ]
4194 );
4195 });
4196
4197 view.update(cx, |view, cx| {
4198 view.select_line(&SelectLine, cx);
4199 assert_eq!(
4200 view.selection_ranges(cx),
4201 vec![DisplayPoint::new(0, 0)..DisplayPoint::new(5, 5)]
4202 );
4203 });
4204 }
4205
4206 #[gpui::test]
4207 fn test_split_selection_into_lines(cx: &mut gpui::MutableAppContext) {
4208 let settings = EditorSettings::test(&cx);
4209 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(9, 5), cx));
4210 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
4211 view.update(cx, |view, cx| {
4212 view.fold_ranges(
4213 vec![
4214 Point::new(0, 2)..Point::new(1, 2),
4215 Point::new(2, 3)..Point::new(4, 1),
4216 Point::new(7, 0)..Point::new(8, 4),
4217 ],
4218 cx,
4219 );
4220 view.select_display_ranges(
4221 &[
4222 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
4223 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
4224 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
4225 DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4),
4226 ],
4227 cx,
4228 )
4229 .unwrap();
4230 assert_eq!(view.display_text(cx), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i");
4231 });
4232
4233 view.update(cx, |view, cx| {
4234 view.split_selection_into_lines(&SplitSelectionIntoLines, cx);
4235 assert_eq!(
4236 view.display_text(cx),
4237 "aaaaa\nbbbbb\nccc…eeee\nfffff\nggggg\n…i"
4238 );
4239 assert_eq!(
4240 view.selection_ranges(cx),
4241 [
4242 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
4243 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
4244 DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0),
4245 DisplayPoint::new(5, 4)..DisplayPoint::new(5, 4)
4246 ]
4247 );
4248 });
4249
4250 view.update(cx, |view, cx| {
4251 view.select_display_ranges(&[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 1)], cx)
4252 .unwrap();
4253 view.split_selection_into_lines(&SplitSelectionIntoLines, cx);
4254 assert_eq!(
4255 view.display_text(cx),
4256 "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\nhhhhh\niiiii"
4257 );
4258 assert_eq!(
4259 view.selection_ranges(cx),
4260 [
4261 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
4262 DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
4263 DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5),
4264 DisplayPoint::new(3, 5)..DisplayPoint::new(3, 5),
4265 DisplayPoint::new(4, 5)..DisplayPoint::new(4, 5),
4266 DisplayPoint::new(5, 5)..DisplayPoint::new(5, 5),
4267 DisplayPoint::new(6, 5)..DisplayPoint::new(6, 5),
4268 DisplayPoint::new(7, 0)..DisplayPoint::new(7, 0)
4269 ]
4270 );
4271 });
4272 }
4273
4274 #[gpui::test]
4275 fn test_add_selection_above_below(cx: &mut gpui::MutableAppContext) {
4276 let settings = EditorSettings::test(&cx);
4277 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndefghi\n\njk\nlmno\n", cx));
4278 let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
4279
4280 view.update(cx, |view, cx| {
4281 view.select_display_ranges(&[DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)], cx)
4282 .unwrap();
4283 });
4284 view.update(cx, |view, cx| {
4285 view.add_selection_above(&AddSelectionAbove, cx);
4286 assert_eq!(
4287 view.selection_ranges(cx),
4288 vec![
4289 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
4290 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
4291 ]
4292 );
4293 });
4294
4295 view.update(cx, |view, cx| {
4296 view.add_selection_above(&AddSelectionAbove, cx);
4297 assert_eq!(
4298 view.selection_ranges(cx),
4299 vec![
4300 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
4301 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
4302 ]
4303 );
4304 });
4305
4306 view.update(cx, |view, cx| {
4307 view.add_selection_below(&AddSelectionBelow, cx);
4308 assert_eq!(
4309 view.selection_ranges(cx),
4310 vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)]
4311 );
4312 });
4313
4314 view.update(cx, |view, cx| {
4315 view.add_selection_below(&AddSelectionBelow, cx);
4316 assert_eq!(
4317 view.selection_ranges(cx),
4318 vec![
4319 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3),
4320 DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3)
4321 ]
4322 );
4323 });
4324
4325 view.update(cx, |view, cx| {
4326 view.add_selection_below(&AddSelectionBelow, cx);
4327 assert_eq!(
4328 view.selection_ranges(cx),
4329 vec![
4330 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3),
4331 DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3)
4332 ]
4333 );
4334 });
4335
4336 view.update(cx, |view, cx| {
4337 view.select_display_ranges(&[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)], cx)
4338 .unwrap();
4339 });
4340 view.update(cx, |view, cx| {
4341 view.add_selection_below(&AddSelectionBelow, cx);
4342 assert_eq!(
4343 view.selection_ranges(cx),
4344 vec![
4345 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
4346 DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3)
4347 ]
4348 );
4349 });
4350
4351 view.update(cx, |view, cx| {
4352 view.add_selection_below(&AddSelectionBelow, cx);
4353 assert_eq!(
4354 view.selection_ranges(cx),
4355 vec![
4356 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
4357 DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3)
4358 ]
4359 );
4360 });
4361
4362 view.update(cx, |view, cx| {
4363 view.add_selection_above(&AddSelectionAbove, cx);
4364 assert_eq!(
4365 view.selection_ranges(cx),
4366 vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)]
4367 );
4368 });
4369
4370 view.update(cx, |view, cx| {
4371 view.add_selection_above(&AddSelectionAbove, cx);
4372 assert_eq!(
4373 view.selection_ranges(cx),
4374 vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)]
4375 );
4376 });
4377
4378 view.update(cx, |view, cx| {
4379 view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(1, 4)], cx)
4380 .unwrap();
4381 view.add_selection_below(&AddSelectionBelow, cx);
4382 assert_eq!(
4383 view.selection_ranges(cx),
4384 vec![
4385 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
4386 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
4387 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
4388 ]
4389 );
4390 });
4391
4392 view.update(cx, |view, cx| {
4393 view.add_selection_below(&AddSelectionBelow, cx);
4394 assert_eq!(
4395 view.selection_ranges(cx),
4396 vec![
4397 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
4398 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
4399 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
4400 DisplayPoint::new(4, 1)..DisplayPoint::new(4, 4),
4401 ]
4402 );
4403 });
4404
4405 view.update(cx, |view, cx| {
4406 view.add_selection_above(&AddSelectionAbove, cx);
4407 assert_eq!(
4408 view.selection_ranges(cx),
4409 vec![
4410 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
4411 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
4412 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
4413 ]
4414 );
4415 });
4416
4417 view.update(cx, |view, cx| {
4418 view.select_display_ranges(&[DisplayPoint::new(4, 3)..DisplayPoint::new(1, 1)], cx)
4419 .unwrap();
4420 });
4421 view.update(cx, |view, cx| {
4422 view.add_selection_above(&AddSelectionAbove, cx);
4423 assert_eq!(
4424 view.selection_ranges(cx),
4425 vec![
4426 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 1),
4427 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1),
4428 DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1),
4429 DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1),
4430 ]
4431 );
4432 });
4433
4434 view.update(cx, |view, cx| {
4435 view.add_selection_below(&AddSelectionBelow, cx);
4436 assert_eq!(
4437 view.selection_ranges(cx),
4438 vec![
4439 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1),
4440 DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1),
4441 DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1),
4442 ]
4443 );
4444 });
4445 }
4446
4447 #[gpui::test]
4448 async fn test_select_larger_smaller_syntax_node(mut cx: gpui::TestAppContext) {
4449 let settings = cx.read(EditorSettings::test);
4450 let language = Some(Arc::new(Language::new(
4451 LanguageConfig::default(),
4452 tree_sitter_rust::language(),
4453 )));
4454
4455 let text = r#"
4456 use mod1::mod2::{mod3, mod4};
4457
4458 fn fn_1(param1: bool, param2: &str) {
4459 let var1 = "text";
4460 }
4461 "#
4462 .unindent();
4463
4464 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, None, cx));
4465 let (_, view) = cx.add_window(|cx| build_editor(buffer, settings, cx));
4466 view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing())
4467 .await;
4468
4469 view.update(&mut cx, |view, cx| {
4470 view.select_display_ranges(
4471 &[
4472 DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
4473 DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
4474 DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
4475 ],
4476 cx,
4477 )
4478 .unwrap();
4479 view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
4480 });
4481 assert_eq!(
4482 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4483 &[
4484 DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27),
4485 DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
4486 DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21),
4487 ]
4488 );
4489
4490 view.update(&mut cx, |view, cx| {
4491 view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
4492 });
4493 assert_eq!(
4494 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4495 &[
4496 DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28),
4497 DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0),
4498 ]
4499 );
4500
4501 view.update(&mut cx, |view, cx| {
4502 view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
4503 });
4504 assert_eq!(
4505 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4506 &[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 0)]
4507 );
4508
4509 // Trying to expand the selected syntax node one more time has no effect.
4510 view.update(&mut cx, |view, cx| {
4511 view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
4512 });
4513 assert_eq!(
4514 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4515 &[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 0)]
4516 );
4517
4518 view.update(&mut cx, |view, cx| {
4519 view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
4520 });
4521 assert_eq!(
4522 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4523 &[
4524 DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28),
4525 DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0),
4526 ]
4527 );
4528
4529 view.update(&mut cx, |view, cx| {
4530 view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
4531 });
4532 assert_eq!(
4533 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4534 &[
4535 DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27),
4536 DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
4537 DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21),
4538 ]
4539 );
4540
4541 view.update(&mut cx, |view, cx| {
4542 view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
4543 });
4544 assert_eq!(
4545 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4546 &[
4547 DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
4548 DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
4549 DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
4550 ]
4551 );
4552
4553 // Trying to shrink the selected syntax node one more time has no effect.
4554 view.update(&mut cx, |view, cx| {
4555 view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
4556 });
4557 assert_eq!(
4558 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4559 &[
4560 DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
4561 DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
4562 DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
4563 ]
4564 );
4565
4566 // Ensure that we keep expanding the selection if the larger selection starts or ends within
4567 // a fold.
4568 view.update(&mut cx, |view, cx| {
4569 view.fold_ranges(
4570 vec![
4571 Point::new(0, 21)..Point::new(0, 24),
4572 Point::new(3, 20)..Point::new(3, 22),
4573 ],
4574 cx,
4575 );
4576 view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
4577 });
4578 assert_eq!(
4579 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4580 &[
4581 DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28),
4582 DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
4583 DisplayPoint::new(3, 4)..DisplayPoint::new(3, 23),
4584 ]
4585 );
4586 }
4587
4588 #[gpui::test]
4589 async fn test_autoclose_pairs(mut cx: gpui::TestAppContext) {
4590 let settings = cx.read(EditorSettings::test);
4591 let language = Some(Arc::new(Language::new(
4592 LanguageConfig {
4593 brackets: vec![
4594 BracketPair {
4595 start: "{".to_string(),
4596 end: "}".to_string(),
4597 close: true,
4598 newline: true,
4599 },
4600 BracketPair {
4601 start: "/*".to_string(),
4602 end: " */".to_string(),
4603 close: true,
4604 newline: true,
4605 },
4606 ],
4607 ..Default::default()
4608 },
4609 tree_sitter_rust::language(),
4610 )));
4611
4612 let text = r#"
4613 a
4614
4615 /
4616
4617 "#
4618 .unindent();
4619
4620 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, None, cx));
4621 let (_, view) = cx.add_window(|cx| build_editor(buffer, settings, cx));
4622 view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing())
4623 .await;
4624
4625 view.update(&mut cx, |view, cx| {
4626 view.select_display_ranges(
4627 &[
4628 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
4629 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
4630 ],
4631 cx,
4632 )
4633 .unwrap();
4634 view.handle_input(&Input("{".to_string()), cx);
4635 view.handle_input(&Input("{".to_string()), cx);
4636 view.handle_input(&Input("{".to_string()), cx);
4637 assert_eq!(
4638 view.text(cx),
4639 "
4640 {{{}}}
4641 {{{}}}
4642 /
4643
4644 "
4645 .unindent()
4646 );
4647
4648 view.move_right(&MoveRight, cx);
4649 view.handle_input(&Input("}".to_string()), cx);
4650 view.handle_input(&Input("}".to_string()), cx);
4651 view.handle_input(&Input("}".to_string()), cx);
4652 assert_eq!(
4653 view.text(cx),
4654 "
4655 {{{}}}}
4656 {{{}}}}
4657 /
4658
4659 "
4660 .unindent()
4661 );
4662
4663 view.undo(&Undo, cx);
4664 view.handle_input(&Input("/".to_string()), cx);
4665 view.handle_input(&Input("*".to_string()), cx);
4666 assert_eq!(
4667 view.text(cx),
4668 "
4669 /* */
4670 /* */
4671 /
4672
4673 "
4674 .unindent()
4675 );
4676
4677 view.undo(&Undo, cx);
4678 view.select_display_ranges(
4679 &[
4680 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
4681 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
4682 ],
4683 cx,
4684 )
4685 .unwrap();
4686 view.handle_input(&Input("*".to_string()), cx);
4687 assert_eq!(
4688 view.text(cx),
4689 "
4690 a
4691
4692 /*
4693 *
4694 "
4695 .unindent()
4696 );
4697 });
4698 }
4699
4700 #[gpui::test]
4701 async fn test_extra_newline_insertion(mut cx: gpui::TestAppContext) {
4702 let settings = cx.read(EditorSettings::test);
4703 let language = Some(Arc::new(Language::new(
4704 LanguageConfig {
4705 brackets: vec![
4706 BracketPair {
4707 start: "{".to_string(),
4708 end: "}".to_string(),
4709 close: true,
4710 newline: true,
4711 },
4712 BracketPair {
4713 start: "/* ".to_string(),
4714 end: " */".to_string(),
4715 close: true,
4716 newline: true,
4717 },
4718 ],
4719 ..Default::default()
4720 },
4721 tree_sitter_rust::language(),
4722 )));
4723
4724 let text = concat!(
4725 "{ }\n", // Suppress rustfmt
4726 " x\n", //
4727 " /* */\n", //
4728 "x\n", //
4729 "{{} }\n", //
4730 );
4731
4732 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, None, cx));
4733 let (_, view) = cx.add_window(|cx| build_editor(buffer, settings, cx));
4734 view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing())
4735 .await;
4736
4737 view.update(&mut cx, |view, cx| {
4738 view.select_display_ranges(
4739 &[
4740 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3),
4741 DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5),
4742 DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4),
4743 ],
4744 cx,
4745 )
4746 .unwrap();
4747 view.newline(&Newline, cx);
4748
4749 assert_eq!(
4750 view.buffer().read(cx).text(),
4751 concat!(
4752 "{ \n", // Suppress rustfmt
4753 "\n", //
4754 "}\n", //
4755 " x\n", //
4756 " /* \n", //
4757 " \n", //
4758 " */\n", //
4759 "x\n", //
4760 "{{} \n", //
4761 "}\n", //
4762 )
4763 );
4764 });
4765 }
4766
4767 impl Editor {
4768 fn selection_ranges(&self, cx: &mut MutableAppContext) -> Vec<Range<DisplayPoint>> {
4769 self.selections_in_range(
4770 self.selection_set_id,
4771 DisplayPoint::zero()..self.max_point(cx),
4772 cx,
4773 )
4774 .collect::<Vec<_>>()
4775 }
4776 }
4777
4778 fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
4779 let point = DisplayPoint::new(row as u32, column as u32);
4780 point..point
4781 }
4782
4783 fn build_editor(
4784 buffer: ModelHandle<Buffer>,
4785 settings: EditorSettings,
4786 cx: &mut ViewContext<Editor>,
4787 ) -> Editor {
4788 Editor::for_buffer(buffer, move |_| settings.clone(), cx)
4789 }
4790}
4791
4792trait RangeExt<T> {
4793 fn sorted(&self) -> Range<T>;
4794 fn to_inclusive(&self) -> RangeInclusive<T>;
4795}
4796
4797impl<T: Ord + Clone> RangeExt<T> for Range<T> {
4798 fn sorted(&self) -> Self {
4799 cmp::min(&self.start, &self.end).clone()..cmp::max(&self.start, &self.end).clone()
4800 }
4801
4802 fn to_inclusive(&self) -> RangeInclusive<T> {
4803 self.start.clone()..=self.end.clone()
4804 }
4805}