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