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