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