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