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