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