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).buffer_rows;
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).buffer_rows;
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).buffer_rows;
946 while let Some(next_selection) = selections_iter.peek() {
947 let next_rows = next_selection.spanned_rows(false, &display_map).buffer_rows;
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 SpannedRows {
1001 mut buffer_rows,
1002 mut display_rows,
1003 } = selection.spanned_rows(false, &display_map);
1004
1005 while let Some(next_selection) = selections.peek() {
1006 let SpannedRows {
1007 buffer_rows: next_buffer_rows,
1008 display_rows: next_display_rows,
1009 } = next_selection.spanned_rows(false, &display_map);
1010 if next_buffer_rows.start <= buffer_rows.end {
1011 buffer_rows.end = next_buffer_rows.end;
1012 display_rows.end = next_display_rows.end;
1013 contiguous_selections.push(next_selection.point_range(buffer));
1014 selections.next().unwrap();
1015 } else {
1016 break;
1017 }
1018 }
1019
1020 // Cut the text from the selected rows and paste it at the start of the previous line.
1021 if display_rows.start != 0 {
1022 let start = Point::new(buffer_rows.start, 0).to_offset(buffer);
1023 let end = Point::new(buffer_rows.end - 1, buffer.line_len(buffer_rows.end - 1))
1024 .to_offset(buffer);
1025
1026 let prev_row_display_start = DisplayPoint::new(display_rows.start - 1, 0);
1027 let prev_row_buffer_start = display_map.prev_row_boundary(prev_row_display_start).1;
1028 let prev_row_buffer_start_offset = prev_row_buffer_start.to_offset(buffer);
1029
1030 let mut text = String::new();
1031 text.extend(buffer.text_for_range(start..end));
1032 text.push('\n');
1033 edits.push((
1034 prev_row_buffer_start_offset..prev_row_buffer_start_offset,
1035 text,
1036 ));
1037 edits.push((start - 1..end, String::new()));
1038
1039 let row_delta = buffer_rows.start - prev_row_buffer_start.row;
1040
1041 // Move selections up.
1042 for range in &mut contiguous_selections {
1043 range.start.row -= row_delta;
1044 range.end.row -= row_delta;
1045 }
1046
1047 // Move folds up.
1048 old_folds.push(start..end);
1049 for fold in display_map.folds_in_range(start..end) {
1050 let mut start = fold.start.to_point(buffer);
1051 let mut end = fold.end.to_point(buffer);
1052 start.row -= row_delta;
1053 end.row -= row_delta;
1054 new_folds.push(start..end);
1055 }
1056 }
1057
1058 new_selection_ranges.extend(contiguous_selections.drain(..));
1059 }
1060
1061 self.unfold_ranges(old_folds, cx);
1062 self.buffer.update(cx, |buffer, cx| {
1063 for (range, text) in edits.into_iter().rev() {
1064 buffer.edit(Some(range), text, cx);
1065 }
1066 });
1067 self.fold_ranges(new_folds, cx);
1068 self.select_ranges(new_selection_ranges, true, cx);
1069
1070 self.end_transaction(cx);
1071 }
1072
1073 pub fn move_line_down(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1074 self.start_transaction(cx);
1075
1076 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1077 let app = cx.as_ref();
1078 let buffer = self.buffer.read(cx);
1079
1080 let mut edits = Vec::new();
1081 let mut new_selection_ranges = Vec::new();
1082 let mut old_folds = Vec::new();
1083 let mut new_folds = Vec::new();
1084
1085 let mut selections = self.selections(app).iter().peekable();
1086 let mut contiguous_selections = Vec::new();
1087 while let Some(selection) = selections.next() {
1088 // Accumulate contiguous regions of rows that we want to move.
1089 contiguous_selections.push(selection.point_range(buffer));
1090 let SpannedRows {
1091 mut buffer_rows,
1092 mut display_rows,
1093 } = selection.spanned_rows(false, &display_map);
1094 while let Some(next_selection) = selections.peek() {
1095 let SpannedRows {
1096 buffer_rows: next_buffer_rows,
1097 display_rows: next_display_rows,
1098 } = next_selection.spanned_rows(false, &display_map);
1099 if next_buffer_rows.start <= buffer_rows.end {
1100 buffer_rows.end = next_buffer_rows.end;
1101 display_rows.end = next_display_rows.end;
1102 contiguous_selections.push(next_selection.point_range(buffer));
1103 selections.next().unwrap();
1104 } else {
1105 break;
1106 }
1107 }
1108
1109 // Cut the text from the selected rows and paste it at the end of the next line.
1110 if display_rows.end <= display_map.max_point().row() {
1111 let start = Point::new(buffer_rows.start, 0).to_offset(buffer);
1112 let end = Point::new(buffer_rows.end - 1, buffer.line_len(buffer_rows.end - 1))
1113 .to_offset(buffer);
1114
1115 let next_row_display_end =
1116 DisplayPoint::new(display_rows.end, display_map.line_len(display_rows.end));
1117 let next_row_buffer_end = display_map.next_row_boundary(next_row_display_end).1;
1118 let next_row_buffer_end_offset = next_row_buffer_end.to_offset(buffer);
1119
1120 let mut text = String::new();
1121 text.push('\n');
1122 text.extend(buffer.text_for_range(start..end));
1123 edits.push((start..end + 1, String::new()));
1124 edits.push((next_row_buffer_end_offset..next_row_buffer_end_offset, text));
1125
1126 let row_delta = next_row_buffer_end.row - buffer_rows.end + 1;
1127
1128 // Move selections down.
1129 for range in &mut contiguous_selections {
1130 range.start.row += row_delta;
1131 range.end.row += row_delta;
1132 }
1133
1134 // Move folds down.
1135 old_folds.push(start..end);
1136 for fold in display_map.folds_in_range(start..end) {
1137 let mut start = fold.start.to_point(buffer);
1138 let mut end = fold.end.to_point(buffer);
1139 start.row += row_delta;
1140 end.row += row_delta;
1141 new_folds.push(start..end);
1142 }
1143 }
1144
1145 new_selection_ranges.extend(contiguous_selections.drain(..));
1146 }
1147
1148 self.unfold_ranges(old_folds, cx);
1149 self.buffer.update(cx, |buffer, cx| {
1150 for (range, text) in edits.into_iter().rev() {
1151 buffer.edit(Some(range), text, cx);
1152 }
1153 });
1154 self.fold_ranges(new_folds, cx);
1155 self.select_ranges(new_selection_ranges, true, cx);
1156
1157 self.end_transaction(cx);
1158 }
1159
1160 pub fn cut(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1161 self.start_transaction(cx);
1162 let mut text = String::new();
1163 let mut selections = self.selections(cx.as_ref()).to_vec();
1164 let mut clipboard_selections = Vec::with_capacity(selections.len());
1165 {
1166 let buffer = self.buffer.read(cx);
1167 let max_point = buffer.max_point();
1168 for selection in &mut selections {
1169 let mut start = selection.start.to_point(buffer);
1170 let mut end = selection.end.to_point(buffer);
1171 let is_entire_line = start == end;
1172 if is_entire_line {
1173 start = Point::new(start.row, 0);
1174 end = cmp::min(max_point, Point::new(start.row + 1, 0));
1175 selection.start = buffer.anchor_before(start);
1176 selection.end = buffer.anchor_before(end);
1177 }
1178 let mut len = 0;
1179 for chunk in buffer.text_for_range(start..end) {
1180 text.push_str(chunk);
1181 len += chunk.len();
1182 }
1183 clipboard_selections.push(ClipboardSelection {
1184 len,
1185 is_entire_line,
1186 });
1187 }
1188 }
1189 self.update_selections(selections, true, cx);
1190 self.insert(&String::new(), cx);
1191 self.end_transaction(cx);
1192
1193 cx.as_mut()
1194 .write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
1195 }
1196
1197 pub fn copy(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1198 let buffer = self.buffer.read(cx);
1199 let max_point = buffer.max_point();
1200 let mut text = String::new();
1201 let selections = self.selections(cx.as_ref());
1202 let mut clipboard_selections = Vec::with_capacity(selections.len());
1203 for selection in selections {
1204 let mut start = selection.start.to_point(buffer);
1205 let mut end = selection.end.to_point(buffer);
1206 let is_entire_line = start == end;
1207 if is_entire_line {
1208 start = Point::new(start.row, 0);
1209 end = cmp::min(max_point, Point::new(start.row + 1, 0));
1210 }
1211 let mut len = 0;
1212 for chunk in buffer.text_for_range(start..end) {
1213 text.push_str(chunk);
1214 len += chunk.len();
1215 }
1216 clipboard_selections.push(ClipboardSelection {
1217 len,
1218 is_entire_line,
1219 });
1220 }
1221
1222 cx.as_mut()
1223 .write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
1224 }
1225
1226 pub fn paste(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1227 if let Some(item) = cx.as_mut().read_from_clipboard() {
1228 let clipboard_text = item.text();
1229 if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
1230 let selections = self.selections(cx.as_ref()).to_vec();
1231 if clipboard_selections.len() != selections.len() {
1232 let merged_selection = ClipboardSelection {
1233 len: clipboard_selections.iter().map(|s| s.len).sum(),
1234 is_entire_line: clipboard_selections.iter().all(|s| s.is_entire_line),
1235 };
1236 clipboard_selections.clear();
1237 clipboard_selections.push(merged_selection);
1238 }
1239
1240 self.start_transaction(cx);
1241 let mut new_selections = Vec::with_capacity(selections.len());
1242 let mut clipboard_chars = clipboard_text.chars().cycle();
1243 for (selection, clipboard_selection) in
1244 selections.iter().zip(clipboard_selections.iter().cycle())
1245 {
1246 let to_insert =
1247 String::from_iter(clipboard_chars.by_ref().take(clipboard_selection.len));
1248
1249 self.buffer.update(cx, |buffer, cx| {
1250 let selection_start = selection.start.to_point(&*buffer);
1251 let selection_end = selection.end.to_point(&*buffer);
1252
1253 // If the corresponding selection was empty when this slice of the
1254 // clipboard text was written, then the entire line containing the
1255 // selection was copied. If this selection is also currently empty,
1256 // then paste the line before the current line of the buffer.
1257 let new_selection_start = selection.end.bias_right(buffer);
1258 if selection_start == selection_end && clipboard_selection.is_entire_line {
1259 let line_start = Point::new(selection_start.row, 0);
1260 buffer.edit(Some(line_start..line_start), to_insert, cx);
1261 } else {
1262 buffer.edit(Some(&selection.start..&selection.end), to_insert, cx);
1263 };
1264
1265 let new_selection_start = new_selection_start.bias_left(buffer);
1266 new_selections.push(Selection {
1267 id: selection.id,
1268 start: new_selection_start.clone(),
1269 end: new_selection_start,
1270 reversed: false,
1271 goal: SelectionGoal::None,
1272 });
1273 });
1274 }
1275 self.update_selections(new_selections, true, cx);
1276 self.end_transaction(cx);
1277 } else {
1278 self.insert(clipboard_text, cx);
1279 }
1280 }
1281 }
1282
1283 pub fn undo(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1284 self.buffer.update(cx, |buffer, cx| buffer.undo(cx));
1285 }
1286
1287 pub fn redo(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1288 self.buffer.update(cx, |buffer, cx| buffer.redo(cx));
1289 }
1290
1291 pub fn move_left(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1292 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1293 let app = cx.as_ref();
1294 let mut selections = self.selections(app).to_vec();
1295 {
1296 for selection in &mut selections {
1297 let start = selection.start.to_display_point(&display_map, Bias::Left);
1298 let end = selection.end.to_display_point(&display_map, Bias::Left);
1299
1300 if start != end {
1301 selection.end = selection.start.clone();
1302 } else {
1303 let cursor = display_map
1304 .anchor_before(movement::left(&display_map, start).unwrap(), Bias::Left);
1305 selection.start = cursor.clone();
1306 selection.end = cursor;
1307 }
1308 selection.reversed = false;
1309 selection.goal = SelectionGoal::None;
1310 }
1311 }
1312 self.update_selections(selections, true, cx);
1313 }
1314
1315 pub fn select_left(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1316 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1317 let mut selections = self.selections(cx.as_ref()).to_vec();
1318 {
1319 let buffer = self.buffer.read(cx);
1320 for selection in &mut selections {
1321 let head = selection.head().to_display_point(&display_map, Bias::Left);
1322 let cursor = display_map
1323 .anchor_before(movement::left(&display_map, head).unwrap(), Bias::Left);
1324 selection.set_head(&buffer, cursor);
1325 selection.goal = SelectionGoal::None;
1326 }
1327 }
1328 self.update_selections(selections, true, cx);
1329 }
1330
1331 pub fn move_right(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1332 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1333 let mut selections = self.selections(cx.as_ref()).to_vec();
1334 {
1335 for selection in &mut selections {
1336 let start = selection.start.to_display_point(&display_map, Bias::Left);
1337 let end = selection.end.to_display_point(&display_map, Bias::Left);
1338
1339 if start != end {
1340 selection.start = selection.end.clone();
1341 } else {
1342 let cursor = display_map
1343 .anchor_before(movement::right(&display_map, end).unwrap(), Bias::Right);
1344 selection.start = cursor.clone();
1345 selection.end = cursor;
1346 }
1347 selection.reversed = false;
1348 selection.goal = SelectionGoal::None;
1349 }
1350 }
1351 self.update_selections(selections, true, cx);
1352 }
1353
1354 pub fn select_right(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1355 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1356 let mut selections = self.selections(cx.as_ref()).to_vec();
1357 {
1358 let app = cx.as_ref();
1359 let buffer = self.buffer.read(app);
1360 for selection in &mut selections {
1361 let head = selection.head().to_display_point(&display_map, Bias::Left);
1362 let cursor = display_map
1363 .anchor_before(movement::right(&display_map, head).unwrap(), Bias::Right);
1364 selection.set_head(&buffer, cursor);
1365 selection.goal = SelectionGoal::None;
1366 }
1367 }
1368 self.update_selections(selections, true, cx);
1369 }
1370
1371 pub fn move_up(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1372 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1373 if self.single_line {
1374 cx.propagate_action();
1375 } else {
1376 let mut selections = self.selections(cx.as_ref()).to_vec();
1377 {
1378 for selection in &mut selections {
1379 let start = selection.start.to_display_point(&display_map, Bias::Left);
1380 let end = selection.end.to_display_point(&display_map, Bias::Left);
1381 if start != end {
1382 selection.goal = SelectionGoal::None;
1383 }
1384
1385 let (start, goal) = movement::up(&display_map, start, selection.goal).unwrap();
1386 let cursor = display_map.anchor_before(start, Bias::Left);
1387 selection.start = cursor.clone();
1388 selection.end = cursor;
1389 selection.goal = goal;
1390 selection.reversed = false;
1391 }
1392 }
1393 self.update_selections(selections, true, cx);
1394 }
1395 }
1396
1397 pub fn select_up(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1398 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1399 let mut selections = self.selections(cx.as_ref()).to_vec();
1400 {
1401 let app = cx.as_ref();
1402 let buffer = self.buffer.read(app);
1403 for selection in &mut selections {
1404 let head = selection.head().to_display_point(&display_map, Bias::Left);
1405 let (head, goal) = movement::up(&display_map, head, selection.goal).unwrap();
1406 selection.set_head(&buffer, display_map.anchor_before(head, Bias::Left));
1407 selection.goal = goal;
1408 }
1409 }
1410 self.update_selections(selections, true, cx);
1411 }
1412
1413 pub fn move_down(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1414 if self.single_line {
1415 cx.propagate_action();
1416 } else {
1417 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1418 let mut selections = self.selections(cx.as_ref()).to_vec();
1419 {
1420 for selection in &mut selections {
1421 let start = selection.start.to_display_point(&display_map, Bias::Left);
1422 let end = selection.end.to_display_point(&display_map, Bias::Left);
1423 if start != end {
1424 selection.goal = SelectionGoal::None;
1425 }
1426
1427 let (start, goal) = movement::down(&display_map, end, selection.goal).unwrap();
1428 let cursor = display_map.anchor_before(start, Bias::Right);
1429 selection.start = cursor.clone();
1430 selection.end = cursor;
1431 selection.goal = goal;
1432 selection.reversed = false;
1433 }
1434 }
1435 self.update_selections(selections, true, cx);
1436 }
1437 }
1438
1439 pub fn select_down(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1440 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1441 let mut selections = self.selections(cx).to_vec();
1442 {
1443 let app = cx.as_ref();
1444 let buffer = self.buffer.read(app);
1445 for selection in &mut selections {
1446 let head = selection.head().to_display_point(&display_map, Bias::Left);
1447 let (head, goal) = movement::down(&display_map, head, selection.goal).unwrap();
1448 selection.set_head(&buffer, display_map.anchor_before(head, Bias::Right));
1449 selection.goal = goal;
1450 }
1451 }
1452 self.update_selections(selections, true, cx);
1453 }
1454
1455 pub fn move_to_previous_word_boundary(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1456 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1457 let mut selections = self.selections(cx).to_vec();
1458 {
1459 for selection in &mut selections {
1460 let head = selection.head().to_display_point(&display_map, Bias::Left);
1461 let new_head = movement::prev_word_boundary(&display_map, head).unwrap();
1462 let anchor = display_map.anchor_before(new_head, Bias::Left);
1463 selection.start = anchor.clone();
1464 selection.end = anchor;
1465 selection.reversed = false;
1466 selection.goal = SelectionGoal::None;
1467 }
1468 }
1469 self.update_selections(selections, true, cx);
1470 }
1471
1472 pub fn select_to_previous_word_boundary(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1473 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1474 let mut selections = self.selections(cx).to_vec();
1475 {
1476 let buffer = self.buffer.read(cx);
1477 for selection in &mut selections {
1478 let head = selection.head().to_display_point(&display_map, Bias::Left);
1479 let new_head = movement::prev_word_boundary(&display_map, head).unwrap();
1480 let anchor = display_map.anchor_before(new_head, Bias::Left);
1481 selection.set_head(buffer, anchor);
1482 selection.goal = SelectionGoal::None;
1483 }
1484 }
1485 self.update_selections(selections, true, cx);
1486 }
1487
1488 pub fn delete_to_previous_word_boundary(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1489 self.start_transaction(cx);
1490 self.select_to_previous_word_boundary(&(), cx);
1491 self.backspace(&(), cx);
1492 self.end_transaction(cx);
1493 }
1494
1495 pub fn move_to_next_word_boundary(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1496 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1497 let mut selections = self.selections(cx).to_vec();
1498 {
1499 for selection in &mut selections {
1500 let head = selection.head().to_display_point(&display_map, Bias::Left);
1501 let new_head = movement::next_word_boundary(&display_map, head).unwrap();
1502 let anchor = display_map.anchor_before(new_head, Bias::Left);
1503 selection.start = anchor.clone();
1504 selection.end = anchor;
1505 selection.reversed = false;
1506 selection.goal = SelectionGoal::None;
1507 }
1508 }
1509 self.update_selections(selections, true, cx);
1510 }
1511
1512 pub fn select_to_next_word_boundary(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1513 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1514 let mut selections = self.selections(cx).to_vec();
1515 {
1516 let buffer = self.buffer.read(cx);
1517 for selection in &mut selections {
1518 let head = selection.head().to_display_point(&display_map, Bias::Left);
1519 let new_head = movement::next_word_boundary(&display_map, head).unwrap();
1520 let anchor = display_map.anchor_before(new_head, Bias::Left);
1521 selection.set_head(buffer, anchor);
1522 selection.goal = SelectionGoal::None;
1523 }
1524 }
1525 self.update_selections(selections, true, cx);
1526 }
1527
1528 pub fn delete_to_next_word_boundary(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1529 self.start_transaction(cx);
1530 self.select_to_next_word_boundary(&(), cx);
1531 self.delete(&(), cx);
1532 self.end_transaction(cx);
1533 }
1534
1535 pub fn move_to_beginning_of_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1536 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1537 let mut selections = self.selections(cx).to_vec();
1538 {
1539 for selection in &mut selections {
1540 let head = selection.head().to_display_point(&display_map, Bias::Left);
1541 let new_head = movement::line_beginning(&display_map, head, true).unwrap();
1542 let anchor = display_map.anchor_before(new_head, Bias::Left);
1543 selection.start = anchor.clone();
1544 selection.end = anchor;
1545 selection.reversed = false;
1546 selection.goal = SelectionGoal::None;
1547 }
1548 }
1549 self.update_selections(selections, true, cx);
1550 }
1551
1552 pub fn select_to_beginning_of_line(
1553 &mut self,
1554 toggle_indent: &bool,
1555 cx: &mut ViewContext<Self>,
1556 ) {
1557 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1558 let mut selections = self.selections(cx).to_vec();
1559 {
1560 let buffer = self.buffer.read(cx);
1561 for selection in &mut selections {
1562 let head = selection.head().to_display_point(&display_map, Bias::Left);
1563 let new_head =
1564 movement::line_beginning(&display_map, head, *toggle_indent).unwrap();
1565 let anchor = display_map.anchor_before(new_head, Bias::Left);
1566 selection.set_head(buffer, anchor);
1567 selection.goal = SelectionGoal::None;
1568 }
1569 }
1570 self.update_selections(selections, true, cx);
1571 }
1572
1573 pub fn delete_to_beginning_of_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1574 self.start_transaction(cx);
1575 self.select_to_beginning_of_line(&false, cx);
1576 self.backspace(&(), cx);
1577 self.end_transaction(cx);
1578 }
1579
1580 pub fn move_to_end_of_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1581 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1582 let mut selections = self.selections(cx).to_vec();
1583 {
1584 for selection in &mut selections {
1585 let head = selection.head().to_display_point(&display_map, Bias::Left);
1586 let new_head = movement::line_end(&display_map, head).unwrap();
1587 let anchor = display_map.anchor_before(new_head, Bias::Left);
1588 selection.start = anchor.clone();
1589 selection.end = anchor;
1590 selection.reversed = false;
1591 selection.goal = SelectionGoal::None;
1592 }
1593 }
1594 self.update_selections(selections, true, cx);
1595 }
1596
1597 pub fn select_to_end_of_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1598 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1599 let mut selections = self.selections(cx).to_vec();
1600 {
1601 let buffer = self.buffer.read(cx);
1602 for selection in &mut selections {
1603 let head = selection.head().to_display_point(&display_map, Bias::Left);
1604 let new_head = movement::line_end(&display_map, head).unwrap();
1605 let anchor = display_map.anchor_before(new_head, Bias::Left);
1606 selection.set_head(buffer, anchor);
1607 selection.goal = SelectionGoal::None;
1608 }
1609 }
1610 self.update_selections(selections, true, cx);
1611 }
1612
1613 pub fn delete_to_end_of_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1614 self.start_transaction(cx);
1615 self.select_to_end_of_line(&(), cx);
1616 self.delete(&(), cx);
1617 self.end_transaction(cx);
1618 }
1619
1620 pub fn cut_to_end_of_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1621 self.start_transaction(cx);
1622 self.select_to_end_of_line(&(), cx);
1623 self.cut(&(), cx);
1624 self.end_transaction(cx);
1625 }
1626
1627 pub fn move_to_beginning(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1628 let buffer = self.buffer.read(cx);
1629 let cursor = buffer.anchor_before(Point::new(0, 0));
1630 let selection = Selection {
1631 id: post_inc(&mut self.next_selection_id),
1632 start: cursor.clone(),
1633 end: cursor,
1634 reversed: false,
1635 goal: SelectionGoal::None,
1636 };
1637 self.update_selections(vec![selection], true, cx);
1638 }
1639
1640 pub fn select_to_beginning(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1641 let mut selection = self.selections(cx.as_ref()).last().unwrap().clone();
1642 selection.set_head(self.buffer.read(cx), Anchor::min());
1643 self.update_selections(vec![selection], true, cx);
1644 }
1645
1646 pub fn move_to_end(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1647 let buffer = self.buffer.read(cx);
1648 let cursor = buffer.anchor_before(buffer.max_point());
1649 let selection = Selection {
1650 id: post_inc(&mut self.next_selection_id),
1651 start: cursor.clone(),
1652 end: cursor,
1653 reversed: false,
1654 goal: SelectionGoal::None,
1655 };
1656 self.update_selections(vec![selection], true, cx);
1657 }
1658
1659 pub fn select_to_end(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1660 let mut selection = self.selections(cx.as_ref()).last().unwrap().clone();
1661 selection.set_head(self.buffer.read(cx), Anchor::max());
1662 self.update_selections(vec![selection], true, cx);
1663 }
1664
1665 pub fn select_all(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1666 let selection = Selection {
1667 id: post_inc(&mut self.next_selection_id),
1668 start: Anchor::min(),
1669 end: Anchor::max(),
1670 reversed: false,
1671 goal: SelectionGoal::None,
1672 };
1673 self.update_selections(vec![selection], false, cx);
1674 }
1675
1676 pub fn select_line(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1677 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1678 let buffer = self.buffer.read(cx);
1679 let mut selections = self.selections(cx).to_vec();
1680 let max_point = buffer.max_point();
1681 for selection in &mut selections {
1682 let rows = selection.spanned_rows(true, &display_map).buffer_rows;
1683 selection.start = buffer.anchor_before(Point::new(rows.start, 0));
1684 selection.end = buffer.anchor_before(cmp::min(max_point, Point::new(rows.end, 0)));
1685 selection.reversed = false;
1686 }
1687 self.update_selections(selections, true, cx);
1688 }
1689
1690 pub fn split_selection_into_lines(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1691 let app = cx.as_ref();
1692 let buffer = self.buffer.read(app);
1693
1694 let mut to_unfold = Vec::new();
1695 let mut new_selections = Vec::new();
1696 for selection in self.selections(app) {
1697 let range = selection.point_range(buffer).sorted();
1698 if range.start.row != range.end.row {
1699 new_selections.push(Selection {
1700 id: post_inc(&mut self.next_selection_id),
1701 start: selection.start.clone(),
1702 end: selection.start.clone(),
1703 reversed: false,
1704 goal: SelectionGoal::None,
1705 });
1706 }
1707 for row in range.start.row + 1..range.end.row {
1708 let cursor = buffer.anchor_before(Point::new(row, buffer.line_len(row)));
1709 new_selections.push(Selection {
1710 id: post_inc(&mut self.next_selection_id),
1711 start: cursor.clone(),
1712 end: cursor,
1713 reversed: false,
1714 goal: SelectionGoal::None,
1715 });
1716 }
1717 new_selections.push(Selection {
1718 id: selection.id,
1719 start: selection.end.clone(),
1720 end: selection.end.clone(),
1721 reversed: false,
1722 goal: SelectionGoal::None,
1723 });
1724 to_unfold.push(range);
1725 }
1726 self.unfold_ranges(to_unfold, cx);
1727 self.update_selections(new_selections, true, cx);
1728 }
1729
1730 pub fn add_selection_above(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1731 self.add_selection(true, cx);
1732 }
1733
1734 pub fn add_selection_below(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1735 self.add_selection(false, cx);
1736 }
1737
1738 fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
1739 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1740 let mut selections = self.selections(cx).to_vec();
1741 let mut state = self.add_selections_state.take().unwrap_or_else(|| {
1742 let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
1743 let range = oldest_selection.display_range(&display_map).sorted();
1744 let columns = cmp::min(range.start.column(), range.end.column())
1745 ..cmp::max(range.start.column(), range.end.column());
1746
1747 selections.clear();
1748 let mut stack = Vec::new();
1749 for row in range.start.row()..=range.end.row() {
1750 if let Some(selection) = self.build_columnar_selection(
1751 &display_map,
1752 row,
1753 &columns,
1754 oldest_selection.reversed,
1755 ) {
1756 stack.push(selection.id);
1757 selections.push(selection);
1758 }
1759 }
1760
1761 if above {
1762 stack.reverse();
1763 }
1764
1765 AddSelectionsState { above, stack }
1766 });
1767
1768 let last_added_selection = *state.stack.last().unwrap();
1769 let mut new_selections = Vec::new();
1770 if above == state.above {
1771 let end_row = if above {
1772 0
1773 } else {
1774 display_map.max_point().row()
1775 };
1776
1777 'outer: for selection in selections {
1778 if selection.id == last_added_selection {
1779 let range = selection.display_range(&display_map).sorted();
1780 debug_assert_eq!(range.start.row(), range.end.row());
1781 let mut row = range.start.row();
1782 let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
1783 {
1784 start..end
1785 } else {
1786 cmp::min(range.start.column(), range.end.column())
1787 ..cmp::max(range.start.column(), range.end.column())
1788 };
1789
1790 while row != end_row {
1791 if above {
1792 row -= 1;
1793 } else {
1794 row += 1;
1795 }
1796
1797 if let Some(new_selection) = self.build_columnar_selection(
1798 &display_map,
1799 row,
1800 &columns,
1801 selection.reversed,
1802 ) {
1803 state.stack.push(new_selection.id);
1804 if above {
1805 new_selections.push(new_selection);
1806 new_selections.push(selection);
1807 } else {
1808 new_selections.push(selection);
1809 new_selections.push(new_selection);
1810 }
1811
1812 continue 'outer;
1813 }
1814 }
1815 }
1816
1817 new_selections.push(selection);
1818 }
1819 } else {
1820 new_selections = selections;
1821 new_selections.retain(|s| s.id != last_added_selection);
1822 state.stack.pop();
1823 }
1824
1825 self.update_selections(new_selections, true, cx);
1826 if state.stack.len() > 1 {
1827 self.add_selections_state = Some(state);
1828 }
1829 }
1830
1831 pub fn select_larger_syntax_node(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1832 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1833 let buffer = self.buffer.read(cx);
1834
1835 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
1836 let mut selected_larger_node = false;
1837 let old_selections = self.selections(cx).to_vec();
1838 let mut new_selection_ranges = Vec::new();
1839 for selection in &old_selections {
1840 let old_range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
1841 let mut new_range = old_range.clone();
1842 while let Some(containing_range) = buffer.range_for_syntax_ancestor(new_range.clone()) {
1843 new_range = containing_range;
1844 if !display_map.intersects_fold(new_range.start)
1845 && !display_map.intersects_fold(new_range.end)
1846 {
1847 break;
1848 }
1849 }
1850
1851 selected_larger_node |= new_range != old_range;
1852 new_selection_ranges.push((selection.id, new_range, selection.reversed));
1853 }
1854
1855 if selected_larger_node {
1856 stack.push(old_selections);
1857 new_selection_ranges.sort_unstable_by_key(|(_, range, _)| range.start.clone());
1858 let new_selections = new_selection_ranges
1859 .into_iter()
1860 .map(|(id, range, reversed)| Selection {
1861 id,
1862 start: buffer.anchor_before(range.start),
1863 end: buffer.anchor_before(range.end),
1864 reversed,
1865 goal: SelectionGoal::None,
1866 })
1867 .collect();
1868 self.update_selections(new_selections, true, cx);
1869 }
1870 self.select_larger_syntax_node_stack = stack;
1871 }
1872
1873 pub fn select_smaller_syntax_node(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1874 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
1875 if let Some(selections) = stack.pop() {
1876 self.update_selections(selections, true, cx);
1877 }
1878 self.select_larger_syntax_node_stack = stack;
1879 }
1880
1881 pub fn move_to_enclosing_bracket(&mut self, _: &(), cx: &mut ViewContext<Self>) {
1882 let buffer = self.buffer.read(cx.as_ref());
1883 let mut selections = self.selections(cx.as_ref()).to_vec();
1884 for selection in &mut selections {
1885 let selection_range = selection.offset_range(buffer);
1886 if let Some((open_range, close_range)) =
1887 buffer.enclosing_bracket_ranges(selection_range.clone())
1888 {
1889 let close_range = close_range.to_inclusive();
1890 let destination = if close_range.contains(&selection_range.start)
1891 && close_range.contains(&selection_range.end)
1892 {
1893 open_range.end
1894 } else {
1895 *close_range.start()
1896 };
1897 selection.start = buffer.anchor_before(destination);
1898 selection.end = selection.start.clone();
1899 }
1900 }
1901
1902 self.update_selections(selections, true, cx);
1903 }
1904
1905 fn build_columnar_selection(
1906 &mut self,
1907 display_map: &DisplayMapSnapshot,
1908 row: u32,
1909 columns: &Range<u32>,
1910 reversed: bool,
1911 ) -> Option<Selection> {
1912 let is_empty = columns.start == columns.end;
1913 let line_len = display_map.line_len(row);
1914 if columns.start < line_len || (is_empty && columns.start == line_len) {
1915 let start = DisplayPoint::new(row, columns.start);
1916 let end = DisplayPoint::new(row, cmp::min(columns.end, line_len));
1917 Some(Selection {
1918 id: post_inc(&mut self.next_selection_id),
1919 start: display_map.anchor_before(start, Bias::Left),
1920 end: display_map.anchor_before(end, Bias::Left),
1921 reversed,
1922 goal: SelectionGoal::ColumnRange {
1923 start: columns.start,
1924 end: columns.end,
1925 },
1926 })
1927 } else {
1928 None
1929 }
1930 }
1931
1932 pub fn active_selection_sets<'a>(
1933 &'a self,
1934 cx: &'a AppContext,
1935 ) -> impl 'a + Iterator<Item = SelectionSetId> {
1936 self.buffer
1937 .read(cx)
1938 .selection_sets()
1939 .filter(|(_, set)| set.active)
1940 .map(|(set_id, _)| *set_id)
1941 }
1942
1943 pub fn selections_in_range<'a>(
1944 &'a self,
1945 set_id: SelectionSetId,
1946 range: Range<DisplayPoint>,
1947 cx: &'a mut MutableAppContext,
1948 ) -> impl 'a + Iterator<Item = Range<DisplayPoint>> {
1949 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1950 let buffer = self.buffer.read(cx);
1951 let selections = &buffer.selection_set(set_id).unwrap().selections;
1952 let start = display_map.anchor_before(range.start, Bias::Left);
1953 let start_index = self.selection_insertion_index(selections, &start, cx);
1954 let pending_selection = if set_id.replica_id == self.buffer.read(cx).replica_id() {
1955 self.pending_selection.as_ref().and_then(|s| {
1956 let selection_range = s.display_range(&display_map);
1957 if selection_range.start <= range.end || selection_range.end <= range.end {
1958 Some(selection_range)
1959 } else {
1960 None
1961 }
1962 })
1963 } else {
1964 None
1965 };
1966 selections[start_index..]
1967 .iter()
1968 .map(move |s| s.display_range(&display_map))
1969 .take_while(move |r| r.start <= range.end || r.end <= range.end)
1970 .chain(pending_selection)
1971 }
1972
1973 fn selection_insertion_index(
1974 &self,
1975 selections: &[Selection],
1976 start: &Anchor,
1977 cx: &AppContext,
1978 ) -> usize {
1979 let buffer = self.buffer.read(cx);
1980 match selections.binary_search_by(|probe| probe.start.cmp(&start, buffer).unwrap()) {
1981 Ok(index) => index,
1982 Err(index) => {
1983 if index > 0
1984 && selections[index - 1].end.cmp(&start, buffer).unwrap() == Ordering::Greater
1985 {
1986 index - 1
1987 } else {
1988 index
1989 }
1990 }
1991 }
1992 }
1993
1994 fn selections<'a>(&self, cx: &'a AppContext) -> &'a [Selection] {
1995 let buffer = self.buffer.read(cx);
1996 &buffer
1997 .selection_set(self.selection_set_id)
1998 .unwrap()
1999 .selections
2000 }
2001
2002 fn update_selections(
2003 &mut self,
2004 mut selections: Vec<Selection>,
2005 autoscroll: bool,
2006 cx: &mut ViewContext<Self>,
2007 ) {
2008 // Merge overlapping selections.
2009 let buffer = self.buffer.read(cx);
2010 let mut i = 1;
2011 while i < selections.len() {
2012 if selections[i - 1]
2013 .end
2014 .cmp(&selections[i].start, buffer)
2015 .unwrap()
2016 >= Ordering::Equal
2017 {
2018 let removed = selections.remove(i);
2019 if removed.start.cmp(&selections[i - 1].start, buffer).unwrap() < Ordering::Equal {
2020 selections[i - 1].start = removed.start;
2021 }
2022 if removed.end.cmp(&selections[i - 1].end, buffer).unwrap() > Ordering::Equal {
2023 selections[i - 1].end = removed.end;
2024 }
2025 } else {
2026 i += 1;
2027 }
2028 }
2029
2030 self.buffer.update(cx, |buffer, cx| {
2031 buffer
2032 .update_selection_set(self.selection_set_id, selections, cx)
2033 .unwrap();
2034 });
2035 self.pause_cursor_blinking(cx);
2036
2037 if autoscroll {
2038 self.autoscroll_requested = true;
2039 cx.notify();
2040 }
2041
2042 self.add_selections_state = None;
2043 self.select_larger_syntax_node_stack.clear();
2044 }
2045
2046 fn start_transaction(&self, cx: &mut ViewContext<Self>) {
2047 self.buffer.update(cx, |buffer, _| {
2048 buffer
2049 .start_transaction(Some(self.selection_set_id))
2050 .unwrap()
2051 });
2052 }
2053
2054 fn end_transaction(&self, cx: &mut ViewContext<Self>) {
2055 self.buffer.update(cx, |buffer, cx| {
2056 buffer
2057 .end_transaction(Some(self.selection_set_id), cx)
2058 .unwrap()
2059 });
2060 }
2061
2062 pub fn page_up(&mut self, _: &(), _: &mut ViewContext<Self>) {
2063 log::info!("BufferView::page_up");
2064 }
2065
2066 pub fn page_down(&mut self, _: &(), _: &mut ViewContext<Self>) {
2067 log::info!("BufferView::page_down");
2068 }
2069
2070 pub fn fold(&mut self, _: &(), cx: &mut ViewContext<Self>) {
2071 let mut fold_ranges = Vec::new();
2072
2073 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2074 for selection in self.selections(cx) {
2075 let range = selection.display_range(&display_map).sorted();
2076 let buffer_start_row = range.start.to_buffer_point(&display_map, Bias::Left).row;
2077
2078 for row in (0..=range.end.row()).rev() {
2079 if self.is_line_foldable(&display_map, row) && !display_map.is_line_folded(row) {
2080 let fold_range = self.foldable_range_for_line(&display_map, row);
2081 if fold_range.end.row >= buffer_start_row {
2082 fold_ranges.push(fold_range);
2083 if row <= range.start.row() {
2084 break;
2085 }
2086 }
2087 }
2088 }
2089 }
2090
2091 self.fold_ranges(fold_ranges, cx);
2092 }
2093
2094 pub fn unfold(&mut self, _: &(), cx: &mut ViewContext<Self>) {
2095 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2096 let buffer = self.buffer.read(cx);
2097 let ranges = self
2098 .selections(cx)
2099 .iter()
2100 .map(|s| {
2101 let range = s.display_range(&display_map).sorted();
2102 let mut start = range.start.to_buffer_point(&display_map, Bias::Left);
2103 let mut end = range.end.to_buffer_point(&display_map, Bias::Left);
2104 start.column = 0;
2105 end.column = buffer.line_len(end.row);
2106 start..end
2107 })
2108 .collect::<Vec<_>>();
2109 self.unfold_ranges(ranges, cx);
2110 }
2111
2112 fn is_line_foldable(&self, display_map: &DisplayMapSnapshot, display_row: u32) -> bool {
2113 let max_point = display_map.max_point();
2114 if display_row >= max_point.row() {
2115 false
2116 } else {
2117 let (start_indent, is_blank) = display_map.line_indent(display_row);
2118 if is_blank {
2119 false
2120 } else {
2121 for display_row in display_row + 1..=max_point.row() {
2122 let (indent, is_blank) = display_map.line_indent(display_row);
2123 if !is_blank {
2124 return indent > start_indent;
2125 }
2126 }
2127 false
2128 }
2129 }
2130 }
2131
2132 fn foldable_range_for_line(
2133 &self,
2134 display_map: &DisplayMapSnapshot,
2135 start_row: u32,
2136 ) -> Range<Point> {
2137 let max_point = display_map.max_point();
2138
2139 let (start_indent, _) = display_map.line_indent(start_row);
2140 let start = DisplayPoint::new(start_row, display_map.line_len(start_row));
2141 let mut end = None;
2142 for row in start_row + 1..=max_point.row() {
2143 let (indent, is_blank) = display_map.line_indent(row);
2144 if !is_blank && indent <= start_indent {
2145 end = Some(DisplayPoint::new(row - 1, display_map.line_len(row - 1)));
2146 break;
2147 }
2148 }
2149
2150 let end = end.unwrap_or(max_point);
2151 return start.to_buffer_point(display_map, Bias::Left)
2152 ..end.to_buffer_point(display_map, Bias::Left);
2153 }
2154
2155 pub fn fold_selected_ranges(&mut self, _: &(), cx: &mut ViewContext<Self>) {
2156 let buffer = self.buffer.read(cx);
2157 let ranges = self
2158 .selections(cx.as_ref())
2159 .iter()
2160 .map(|s| s.point_range(buffer).sorted())
2161 .collect();
2162 self.fold_ranges(ranges, cx);
2163 }
2164
2165 fn fold_ranges<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, cx: &mut ViewContext<Self>) {
2166 if !ranges.is_empty() {
2167 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
2168 self.autoscroll_requested = true;
2169 cx.notify();
2170 }
2171 }
2172
2173 fn unfold_ranges<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, cx: &mut ViewContext<Self>) {
2174 if !ranges.is_empty() {
2175 self.display_map
2176 .update(cx, |map, cx| map.unfold(ranges, cx));
2177 self.autoscroll_requested = true;
2178 cx.notify();
2179 }
2180 }
2181
2182 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
2183 self.display_map
2184 .update(cx, |map, cx| map.snapshot(cx))
2185 .longest_row()
2186 }
2187
2188 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
2189 self.display_map
2190 .update(cx, |map, cx| map.snapshot(cx))
2191 .max_point()
2192 }
2193
2194 pub fn text(&self, cx: &mut MutableAppContext) -> String {
2195 self.display_map
2196 .update(cx, |map, cx| map.snapshot(cx))
2197 .text()
2198 }
2199
2200 pub fn font_size(&self) -> f32 {
2201 self.settings.borrow().buffer_font_size
2202 }
2203
2204 pub fn set_wrap_width(&self, width: f32, cx: &mut MutableAppContext) -> bool {
2205 self.display_map
2206 .update(cx, |map, cx| map.set_wrap_width(Some(width), cx))
2207 }
2208
2209 fn next_blink_epoch(&mut self) -> usize {
2210 self.blink_epoch += 1;
2211 self.blink_epoch
2212 }
2213
2214 fn pause_cursor_blinking(&mut self, cx: &mut ViewContext<Self>) {
2215 self.cursors_visible = true;
2216 cx.notify();
2217
2218 let epoch = self.next_blink_epoch();
2219 cx.spawn(|this, mut cx| {
2220 let this = this.downgrade();
2221 async move {
2222 Timer::after(CURSOR_BLINK_INTERVAL).await;
2223 if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
2224 this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
2225 }
2226 }
2227 })
2228 .detach();
2229 }
2230
2231 fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
2232 if epoch == self.blink_epoch {
2233 self.blinking_paused = false;
2234 self.blink_cursors(epoch, cx);
2235 }
2236 }
2237
2238 fn blink_cursors(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
2239 if epoch == self.blink_epoch && self.focused && !self.blinking_paused {
2240 self.cursors_visible = !self.cursors_visible;
2241 cx.notify();
2242
2243 let epoch = self.next_blink_epoch();
2244 cx.spawn(|this, mut cx| {
2245 let this = this.downgrade();
2246 async move {
2247 Timer::after(CURSOR_BLINK_INTERVAL).await;
2248 if let Some(this) = cx.read(|cx| this.upgrade(cx)) {
2249 this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx));
2250 }
2251 }
2252 })
2253 .detach();
2254 }
2255 }
2256
2257 pub fn cursors_visible(&self) -> bool {
2258 self.cursors_visible
2259 }
2260
2261 fn on_buffer_changed(&mut self, _: ModelHandle<Buffer>, cx: &mut ViewContext<Self>) {
2262 cx.notify();
2263 }
2264
2265 fn on_buffer_event(
2266 &mut self,
2267 _: ModelHandle<Buffer>,
2268 event: &buffer::Event,
2269 cx: &mut ViewContext<Self>,
2270 ) {
2271 match event {
2272 buffer::Event::Edited => cx.emit(Event::Edited),
2273 buffer::Event::Dirtied => cx.emit(Event::Dirtied),
2274 buffer::Event::Saved => cx.emit(Event::Saved),
2275 buffer::Event::FileHandleChanged => cx.emit(Event::FileHandleChanged),
2276 buffer::Event::Reloaded => cx.emit(Event::FileHandleChanged),
2277 buffer::Event::Reparsed => {}
2278 }
2279 }
2280
2281 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
2282 cx.notify();
2283 }
2284}
2285
2286impl Snapshot {
2287 pub fn scroll_position(&self) -> Vector2F {
2288 compute_scroll_position(
2289 &self.display_snapshot,
2290 self.scroll_position,
2291 &self.scroll_top_anchor,
2292 )
2293 }
2294
2295 pub fn max_point(&self) -> DisplayPoint {
2296 self.display_snapshot.max_point()
2297 }
2298
2299 pub fn longest_row(&self) -> u32 {
2300 self.display_snapshot.longest_row()
2301 }
2302
2303 pub fn line_len(&self, display_row: u32) -> u32 {
2304 self.display_snapshot.line_len(display_row)
2305 }
2306
2307 pub fn font_ascent(&self, font_cache: &FontCache) -> f32 {
2308 let font_id = font_cache.default_font(self.font_family);
2309 let ascent = font_cache.metric(font_id, |m| m.ascent);
2310 font_cache.scale_metric(ascent, font_id, self.font_size)
2311 }
2312
2313 pub fn font_descent(&self, font_cache: &FontCache) -> f32 {
2314 let font_id = font_cache.default_font(self.font_family);
2315 let descent = font_cache.metric(font_id, |m| m.descent);
2316 font_cache.scale_metric(descent, font_id, self.font_size)
2317 }
2318
2319 pub fn line_height(&self, font_cache: &FontCache) -> f32 {
2320 let font_id = font_cache.default_font(self.font_family);
2321 font_cache.line_height(font_id, self.font_size)
2322 }
2323
2324 pub fn em_width(&self, font_cache: &FontCache) -> f32 {
2325 let font_id = font_cache.default_font(self.font_family);
2326 font_cache.em_width(font_id, self.font_size)
2327 }
2328
2329 // TODO: Can we make this not return a result?
2330 pub fn max_line_number_width(
2331 &self,
2332 font_cache: &FontCache,
2333 layout_cache: &TextLayoutCache,
2334 ) -> Result<f32> {
2335 let font_size = self.font_size;
2336 let font_id = font_cache.select_font(self.font_family, &FontProperties::new())?;
2337 let digit_count = (self.display_snapshot.buffer_row_count() as f32)
2338 .log10()
2339 .floor() as usize
2340 + 1;
2341
2342 Ok(layout_cache
2343 .layout_str(
2344 "1".repeat(digit_count).as_str(),
2345 font_size,
2346 &[(digit_count, font_id, ColorU::black())],
2347 )
2348 .width())
2349 }
2350
2351 pub fn layout_line_numbers(
2352 &self,
2353 viewport_height: f32,
2354 font_cache: &FontCache,
2355 layout_cache: &TextLayoutCache,
2356 ) -> Result<Vec<Option<text_layout::Line>>> {
2357 let font_id = font_cache.select_font(self.font_family, &FontProperties::new())?;
2358
2359 let start_row = self.scroll_position().y() as usize;
2360 let end_row = cmp::min(
2361 self.display_snapshot.max_point().row() as usize,
2362 start_row + (viewport_height / self.line_height(font_cache)).ceil() as usize,
2363 );
2364 let line_count = end_row - start_row + 1;
2365
2366 let mut layouts = Vec::with_capacity(line_count);
2367 let mut line_number = String::new();
2368 for (buffer_row, soft_wrapped) in self
2369 .display_snapshot
2370 .buffer_rows(start_row as u32)
2371 .take(line_count)
2372 {
2373 if soft_wrapped {
2374 layouts.push(None);
2375 } else {
2376 line_number.clear();
2377 write!(&mut line_number, "{}", buffer_row + 1).unwrap();
2378 layouts.push(Some(layout_cache.layout_str(
2379 &line_number,
2380 self.font_size,
2381 &[(line_number.len(), font_id, ColorU::black())],
2382 )));
2383 }
2384 }
2385
2386 Ok(layouts)
2387 }
2388
2389 pub fn layout_lines(
2390 &mut self,
2391 mut rows: Range<u32>,
2392 font_cache: &FontCache,
2393 layout_cache: &TextLayoutCache,
2394 ) -> Result<Vec<text_layout::Line>> {
2395 rows.end = cmp::min(rows.end, self.display_snapshot.max_point().row() + 1);
2396 if rows.start >= rows.end {
2397 return Ok(Vec::new());
2398 }
2399
2400 let mut prev_font_properties = FontProperties::new();
2401 let mut prev_font_id = font_cache
2402 .select_font(self.font_family, &prev_font_properties)
2403 .unwrap();
2404
2405 let mut layouts = Vec::with_capacity(rows.len());
2406 let mut line = String::new();
2407 let mut styles = Vec::new();
2408 let mut row = rows.start;
2409 let mut line_exceeded_max_len = false;
2410 let chunks = self
2411 .display_snapshot
2412 .highlighted_chunks_for_rows(rows.clone());
2413
2414 'outer: for (chunk, style_ix) in chunks.chain(Some(("\n", StyleId::default()))) {
2415 for (ix, mut line_chunk) in chunk.split('\n').enumerate() {
2416 if ix > 0 {
2417 layouts.push(layout_cache.layout_str(&line, self.font_size, &styles));
2418 line.clear();
2419 styles.clear();
2420 row += 1;
2421 line_exceeded_max_len = false;
2422 if row == rows.end {
2423 break 'outer;
2424 }
2425 }
2426
2427 if !line_chunk.is_empty() && !line_exceeded_max_len {
2428 let (color, font_properties) = self.theme.syntax_style(style_ix);
2429 // Avoid a lookup if the font properties match the previous ones.
2430 let font_id = if font_properties == prev_font_properties {
2431 prev_font_id
2432 } else {
2433 font_cache.select_font(self.font_family, &font_properties)?
2434 };
2435
2436 if line.len() + line_chunk.len() > MAX_LINE_LEN {
2437 let mut chunk_len = MAX_LINE_LEN - line.len();
2438 while !line_chunk.is_char_boundary(chunk_len) {
2439 chunk_len -= 1;
2440 }
2441 line_chunk = &line_chunk[..chunk_len];
2442 line_exceeded_max_len = true;
2443 }
2444
2445 line.push_str(line_chunk);
2446 styles.push((line_chunk.len(), font_id, color));
2447 prev_font_id = font_id;
2448 prev_font_properties = font_properties;
2449 }
2450 }
2451 }
2452
2453 Ok(layouts)
2454 }
2455
2456 pub fn layout_line(
2457 &self,
2458 row: u32,
2459 font_cache: &FontCache,
2460 layout_cache: &TextLayoutCache,
2461 ) -> Result<text_layout::Line> {
2462 let font_id = font_cache.select_font(self.font_family, &FontProperties::new())?;
2463
2464 let mut line = self.display_snapshot.line(row);
2465
2466 if line.len() > MAX_LINE_LEN {
2467 let mut len = MAX_LINE_LEN;
2468 while !line.is_char_boundary(len) {
2469 len -= 1;
2470 }
2471 line.truncate(len);
2472 }
2473
2474 Ok(layout_cache.layout_str(
2475 &line,
2476 self.font_size,
2477 &[(
2478 self.display_snapshot.line_len(row) as usize,
2479 font_id,
2480 ColorU::black(),
2481 )],
2482 ))
2483 }
2484}
2485
2486fn compute_scroll_position(
2487 snapshot: &DisplayMapSnapshot,
2488 mut scroll_position: Vector2F,
2489 scroll_top_anchor: &Anchor,
2490) -> Vector2F {
2491 let scroll_top = scroll_top_anchor
2492 .to_display_point(snapshot, Bias::Left)
2493 .row() as f32;
2494 scroll_position.set_y(scroll_top + scroll_position.y());
2495 scroll_position
2496}
2497
2498pub enum Event {
2499 Activate,
2500 Edited,
2501 Blurred,
2502 Dirtied,
2503 Saved,
2504 FileHandleChanged,
2505}
2506
2507impl Entity for Editor {
2508 type Event = Event;
2509
2510 fn release(&mut self, cx: &mut MutableAppContext) {
2511 self.buffer.update(cx, |buffer, cx| {
2512 buffer
2513 .remove_selection_set(self.selection_set_id, cx)
2514 .unwrap();
2515 });
2516 }
2517}
2518
2519impl View for Editor {
2520 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2521 EditorElement::new(self.handle.clone()).boxed()
2522 }
2523
2524 fn ui_name() -> &'static str {
2525 "BufferView"
2526 }
2527
2528 fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
2529 self.focused = true;
2530 self.blink_cursors(self.blink_epoch, cx);
2531 self.buffer.update(cx, |buffer, cx| {
2532 buffer
2533 .set_active_selection_set(Some(self.selection_set_id), cx)
2534 .unwrap();
2535 });
2536 }
2537
2538 fn on_blur(&mut self, cx: &mut ViewContext<Self>) {
2539 self.focused = false;
2540 self.cursors_visible = false;
2541 self.buffer.update(cx, |buffer, cx| {
2542 buffer.set_active_selection_set(None, cx).unwrap();
2543 });
2544 cx.emit(Event::Blurred);
2545 cx.notify();
2546 }
2547}
2548
2549impl workspace::Item for Buffer {
2550 type View = Editor;
2551
2552 fn file(&self) -> Option<&File> {
2553 self.file()
2554 }
2555
2556 fn build_view(
2557 handle: ModelHandle<Self>,
2558 settings: watch::Receiver<Settings>,
2559 cx: &mut ViewContext<Self::View>,
2560 ) -> Self::View {
2561 Editor::for_buffer(handle, settings, cx)
2562 }
2563}
2564
2565impl workspace::ItemView for Editor {
2566 fn should_activate_item_on_event(event: &Self::Event) -> bool {
2567 matches!(event, Event::Activate)
2568 }
2569
2570 fn should_update_tab_on_event(event: &Self::Event) -> bool {
2571 matches!(
2572 event,
2573 Event::Saved | Event::Dirtied | Event::FileHandleChanged
2574 )
2575 }
2576
2577 fn title(&self, cx: &AppContext) -> std::string::String {
2578 let filename = self
2579 .buffer
2580 .read(cx)
2581 .file()
2582 .and_then(|file| file.file_name(cx));
2583 if let Some(name) = filename {
2584 name.to_string_lossy().into()
2585 } else {
2586 "untitled".into()
2587 }
2588 }
2589
2590 fn entry_id(&self, cx: &AppContext) -> Option<(usize, Arc<Path>)> {
2591 self.buffer.read(cx).file().map(|file| file.entry_id())
2592 }
2593
2594 fn clone_on_split(&self, cx: &mut ViewContext<Self>) -> Option<Self>
2595 where
2596 Self: Sized,
2597 {
2598 let mut clone = Editor::for_buffer(self.buffer.clone(), self.settings.clone(), cx);
2599 clone.scroll_position = self.scroll_position;
2600 clone.scroll_top_anchor = self.scroll_top_anchor.clone();
2601 Some(clone)
2602 }
2603
2604 fn save(&mut self, cx: &mut ViewContext<Self>) -> Result<Task<Result<()>>> {
2605 let save = self.buffer.update(cx, |b, cx| b.save(cx))?;
2606 Ok(cx.spawn(|_, _| async move {
2607 save.await?;
2608 Ok(())
2609 }))
2610 }
2611
2612 fn save_as(
2613 &mut self,
2614 worktree: &ModelHandle<Worktree>,
2615 path: &Path,
2616 cx: &mut ViewContext<Self>,
2617 ) -> Task<Result<()>> {
2618 self.buffer
2619 .update(cx, |b, cx| b.save_as(worktree, path, cx))
2620 }
2621
2622 fn is_dirty(&self, cx: &AppContext) -> bool {
2623 self.buffer.read(cx).is_dirty()
2624 }
2625
2626 fn has_conflict(&self, cx: &AppContext) -> bool {
2627 self.buffer.read(cx).has_conflict()
2628 }
2629}
2630
2631#[cfg(test)]
2632mod tests {
2633 use super::*;
2634 use crate::{
2635 editor::Point,
2636 settings,
2637 test::{build_app_state, sample_text},
2638 };
2639 use buffer::History;
2640 use unindent::Unindent;
2641
2642 #[gpui::test]
2643 fn test_selection_with_mouse(cx: &mut gpui::MutableAppContext) {
2644 let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx));
2645 let settings = settings::channel(&cx.font_cache()).unwrap().1;
2646 let (_, editor) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx));
2647
2648 editor.update(cx, |view, cx| {
2649 view.begin_selection(DisplayPoint::new(2, 2), false, cx);
2650 });
2651
2652 assert_eq!(
2653 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2654 [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
2655 );
2656
2657 editor.update(cx, |view, cx| {
2658 view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx);
2659 });
2660
2661 assert_eq!(
2662 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2663 [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
2664 );
2665
2666 editor.update(cx, |view, cx| {
2667 view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx);
2668 });
2669
2670 assert_eq!(
2671 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2672 [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
2673 );
2674
2675 editor.update(cx, |view, cx| {
2676 view.end_selection(cx);
2677 view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx);
2678 });
2679
2680 assert_eq!(
2681 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2682 [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
2683 );
2684
2685 editor.update(cx, |view, cx| {
2686 view.begin_selection(DisplayPoint::new(3, 3), true, cx);
2687 view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), cx);
2688 });
2689
2690 assert_eq!(
2691 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2692 [
2693 DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1),
2694 DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)
2695 ]
2696 );
2697
2698 editor.update(cx, |view, cx| {
2699 view.end_selection(cx);
2700 });
2701
2702 assert_eq!(
2703 editor.update(cx, |view, cx| view.selection_ranges(cx)),
2704 [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)]
2705 );
2706 }
2707
2708 #[gpui::test]
2709 fn test_canceling_pending_selection(cx: &mut gpui::MutableAppContext) {
2710 let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx));
2711 let settings = settings::channel(&cx.font_cache()).unwrap().1;
2712 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx));
2713
2714 view.update(cx, |view, cx| {
2715 view.begin_selection(DisplayPoint::new(2, 2), false, cx);
2716 assert_eq!(
2717 view.selection_ranges(cx),
2718 [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
2719 );
2720 });
2721
2722 view.update(cx, |view, cx| {
2723 view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), cx);
2724 assert_eq!(
2725 view.selection_ranges(cx),
2726 [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
2727 );
2728 });
2729
2730 view.update(cx, |view, cx| {
2731 view.cancel(&(), cx);
2732 view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx);
2733 assert_eq!(
2734 view.selection_ranges(cx),
2735 [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
2736 );
2737 });
2738 }
2739
2740 #[gpui::test]
2741 fn test_cancel(cx: &mut gpui::MutableAppContext) {
2742 let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx));
2743 let settings = settings::channel(&cx.font_cache()).unwrap().1;
2744 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx));
2745
2746 view.update(cx, |view, cx| {
2747 view.begin_selection(DisplayPoint::new(3, 4), false, cx);
2748 view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx);
2749 view.end_selection(cx);
2750
2751 view.begin_selection(DisplayPoint::new(0, 1), true, cx);
2752 view.update_selection(DisplayPoint::new(0, 3), Vector2F::zero(), cx);
2753 view.end_selection(cx);
2754 assert_eq!(
2755 view.selection_ranges(cx),
2756 [
2757 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
2758 DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1),
2759 ]
2760 );
2761 });
2762
2763 view.update(cx, |view, cx| {
2764 view.cancel(&(), cx);
2765 assert_eq!(
2766 view.selection_ranges(cx),
2767 [DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)]
2768 );
2769 });
2770
2771 view.update(cx, |view, cx| {
2772 view.cancel(&(), cx);
2773 assert_eq!(
2774 view.selection_ranges(cx),
2775 [DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)]
2776 );
2777 });
2778 }
2779
2780 #[gpui::test]
2781 fn test_layout_line_numbers(cx: &mut gpui::MutableAppContext) {
2782 let layout_cache = TextLayoutCache::new(cx.platform().fonts());
2783 let font_cache = cx.font_cache().clone();
2784
2785 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6), cx));
2786
2787 let settings = settings::channel(&font_cache).unwrap().1;
2788 let (_, editor) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx));
2789
2790 let layouts = editor.update(cx, |editor, cx| {
2791 editor
2792 .snapshot(cx)
2793 .layout_line_numbers(1000.0, &font_cache, &layout_cache)
2794 .unwrap()
2795 });
2796 assert_eq!(layouts.len(), 6);
2797 }
2798
2799 #[gpui::test]
2800 fn test_fold(cx: &mut gpui::MutableAppContext) {
2801 let buffer = cx.add_model(|cx| {
2802 Buffer::new(
2803 0,
2804 "
2805 impl Foo {
2806 // Hello!
2807
2808 fn a() {
2809 1
2810 }
2811
2812 fn b() {
2813 2
2814 }
2815
2816 fn c() {
2817 3
2818 }
2819 }
2820 "
2821 .unindent(),
2822 cx,
2823 )
2824 });
2825 let settings = settings::channel(&cx.font_cache()).unwrap().1;
2826 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx));
2827
2828 view.update(cx, |view, cx| {
2829 view.select_display_ranges(&[DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)], cx)
2830 .unwrap();
2831 view.fold(&(), cx);
2832 assert_eq!(
2833 view.text(cx),
2834 "
2835 impl Foo {
2836 // Hello!
2837
2838 fn a() {
2839 1
2840 }
2841
2842 fn b() {…
2843 }
2844
2845 fn c() {…
2846 }
2847 }
2848 "
2849 .unindent(),
2850 );
2851
2852 view.fold(&(), cx);
2853 assert_eq!(
2854 view.text(cx),
2855 "
2856 impl Foo {…
2857 }
2858 "
2859 .unindent(),
2860 );
2861
2862 view.unfold(&(), cx);
2863 assert_eq!(
2864 view.text(cx),
2865 "
2866 impl Foo {
2867 // Hello!
2868
2869 fn a() {
2870 1
2871 }
2872
2873 fn b() {…
2874 }
2875
2876 fn c() {…
2877 }
2878 }
2879 "
2880 .unindent(),
2881 );
2882
2883 view.unfold(&(), cx);
2884 assert_eq!(view.text(cx), buffer.read(cx).text());
2885 });
2886 }
2887
2888 #[gpui::test]
2889 fn test_move_cursor(cx: &mut gpui::MutableAppContext) {
2890 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6), cx));
2891 let settings = settings::channel(&cx.font_cache()).unwrap().1;
2892 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx));
2893
2894 buffer.update(cx, |buffer, cx| {
2895 buffer.edit(
2896 vec![
2897 Point::new(1, 0)..Point::new(1, 0),
2898 Point::new(1, 1)..Point::new(1, 1),
2899 ],
2900 "\t",
2901 cx,
2902 );
2903 });
2904
2905 view.update(cx, |view, cx| {
2906 assert_eq!(
2907 view.selection_ranges(cx),
2908 &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
2909 );
2910
2911 view.move_down(&(), cx);
2912 assert_eq!(
2913 view.selection_ranges(cx),
2914 &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
2915 );
2916
2917 view.move_right(&(), cx);
2918 assert_eq!(
2919 view.selection_ranges(cx),
2920 &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)]
2921 );
2922
2923 view.move_left(&(), cx);
2924 assert_eq!(
2925 view.selection_ranges(cx),
2926 &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
2927 );
2928
2929 view.move_up(&(), cx);
2930 assert_eq!(
2931 view.selection_ranges(cx),
2932 &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
2933 );
2934
2935 view.move_to_end(&(), cx);
2936 assert_eq!(
2937 view.selection_ranges(cx),
2938 &[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 6)]
2939 );
2940
2941 view.move_to_beginning(&(), cx);
2942 assert_eq!(
2943 view.selection_ranges(cx),
2944 &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
2945 );
2946
2947 view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)], cx)
2948 .unwrap();
2949 view.select_to_beginning(&(), cx);
2950 assert_eq!(
2951 view.selection_ranges(cx),
2952 &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 0)]
2953 );
2954
2955 view.select_to_end(&(), cx);
2956 assert_eq!(
2957 view.selection_ranges(cx),
2958 &[DisplayPoint::new(0, 1)..DisplayPoint::new(5, 6)]
2959 );
2960 });
2961 }
2962
2963 #[gpui::test]
2964 fn test_move_cursor_multibyte(cx: &mut gpui::MutableAppContext) {
2965 let buffer = cx.add_model(|cx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", cx));
2966 let settings = settings::channel(&cx.font_cache()).unwrap().1;
2967 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx));
2968
2969 assert_eq!('ⓐ'.len_utf8(), 3);
2970 assert_eq!('α'.len_utf8(), 2);
2971
2972 view.update(cx, |view, cx| {
2973 view.fold_ranges(
2974 vec![
2975 Point::new(0, 6)..Point::new(0, 12),
2976 Point::new(1, 2)..Point::new(1, 4),
2977 Point::new(2, 4)..Point::new(2, 8),
2978 ],
2979 cx,
2980 );
2981 assert_eq!(view.text(cx), "ⓐⓑ…ⓔ\nab…e\nαβ…ε\n");
2982
2983 view.move_right(&(), cx);
2984 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐ".len())]);
2985 view.move_right(&(), cx);
2986 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ".len())]);
2987 view.move_right(&(), cx);
2988 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ…".len())]);
2989
2990 view.move_down(&(), cx);
2991 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "ab…".len())]);
2992 view.move_left(&(), cx);
2993 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "ab".len())]);
2994 view.move_left(&(), cx);
2995 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "a".len())]);
2996
2997 view.move_down(&(), cx);
2998 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "α".len())]);
2999 view.move_right(&(), cx);
3000 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβ".len())]);
3001 view.move_right(&(), cx);
3002 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβ…".len())]);
3003 view.move_right(&(), cx);
3004 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβ…ε".len())]);
3005
3006 view.move_up(&(), cx);
3007 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "ab…e".len())]);
3008 view.move_up(&(), cx);
3009 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ…ⓔ".len())]);
3010 view.move_left(&(), cx);
3011 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ…".len())]);
3012 view.move_left(&(), cx);
3013 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐⓑ".len())]);
3014 view.move_left(&(), cx);
3015 assert_eq!(view.selection_ranges(cx), &[empty_range(0, "ⓐ".len())]);
3016 });
3017 }
3018
3019 #[gpui::test]
3020 fn test_move_cursor_different_line_lengths(cx: &mut gpui::MutableAppContext) {
3021 let buffer = cx.add_model(|cx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", cx));
3022 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3023 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx));
3024 view.update(cx, |view, cx| {
3025 view.select_display_ranges(&[empty_range(0, "ⓐⓑⓒⓓⓔ".len())], cx)
3026 .unwrap();
3027
3028 view.move_down(&(), cx);
3029 assert_eq!(view.selection_ranges(cx), &[empty_range(1, "abcd".len())]);
3030
3031 view.move_down(&(), cx);
3032 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβγ".len())]);
3033
3034 view.move_down(&(), cx);
3035 assert_eq!(view.selection_ranges(cx), &[empty_range(3, "abcd".len())]);
3036
3037 view.move_down(&(), cx);
3038 assert_eq!(view.selection_ranges(cx), &[empty_range(4, "ⓐⓑⓒⓓⓔ".len())]);
3039
3040 view.move_up(&(), cx);
3041 assert_eq!(view.selection_ranges(cx), &[empty_range(3, "abcd".len())]);
3042
3043 view.move_up(&(), cx);
3044 assert_eq!(view.selection_ranges(cx), &[empty_range(2, "αβγ".len())]);
3045 });
3046 }
3047
3048 #[gpui::test]
3049 fn test_beginning_end_of_line(cx: &mut gpui::MutableAppContext) {
3050 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\n def", cx));
3051 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3052 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx));
3053 view.update(cx, |view, cx| {
3054 view.select_display_ranges(
3055 &[
3056 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3057 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4),
3058 ],
3059 cx,
3060 )
3061 .unwrap();
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, 2)..DisplayPoint::new(1, 2),
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, 0)..DisplayPoint::new(1, 0),
3082 ]
3083 );
3084 });
3085
3086 view.update(cx, |view, cx| {
3087 view.move_to_beginning_of_line(&(), cx);
3088 assert_eq!(
3089 view.selection_ranges(cx),
3090 &[
3091 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3092 DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
3093 ]
3094 );
3095 });
3096
3097 view.update(cx, |view, cx| {
3098 view.move_to_end_of_line(&(), cx);
3099 assert_eq!(
3100 view.selection_ranges(cx),
3101 &[
3102 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
3103 DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
3104 ]
3105 );
3106 });
3107
3108 // Moving to the end of line again is a no-op.
3109 view.update(cx, |view, cx| {
3110 view.move_to_end_of_line(&(), cx);
3111 assert_eq!(
3112 view.selection_ranges(cx),
3113 &[
3114 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
3115 DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
3116 ]
3117 );
3118 });
3119
3120 view.update(cx, |view, cx| {
3121 view.move_left(&(), 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, 2),
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, 0),
3139 ]
3140 );
3141 });
3142
3143 view.update(cx, |view, cx| {
3144 view.select_to_beginning_of_line(&true, cx);
3145 assert_eq!(
3146 view.selection_ranges(cx),
3147 &[
3148 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
3149 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2),
3150 ]
3151 );
3152 });
3153
3154 view.update(cx, |view, cx| {
3155 view.select_to_end_of_line(&(), cx);
3156 assert_eq!(
3157 view.selection_ranges(cx),
3158 &[
3159 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3),
3160 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 5),
3161 ]
3162 );
3163 });
3164
3165 view.update(cx, |view, cx| {
3166 view.delete_to_end_of_line(&(), cx);
3167 assert_eq!(view.text(cx), "ab\n de");
3168 assert_eq!(
3169 view.selection_ranges(cx),
3170 &[
3171 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3172 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4),
3173 ]
3174 );
3175 });
3176
3177 view.update(cx, |view, cx| {
3178 view.delete_to_beginning_of_line(&(), cx);
3179 assert_eq!(view.text(cx), "\n");
3180 assert_eq!(
3181 view.selection_ranges(cx),
3182 &[
3183 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3184 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
3185 ]
3186 );
3187 });
3188 }
3189
3190 #[gpui::test]
3191 fn test_prev_next_word_boundary(cx: &mut gpui::MutableAppContext) {
3192 let buffer =
3193 cx.add_model(|cx| Buffer::new(0, "use std::str::{foo, bar}\n\n {baz.qux()}", cx));
3194 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3195 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx));
3196 view.update(cx, |view, cx| {
3197 view.select_display_ranges(
3198 &[
3199 DisplayPoint::new(0, 11)..DisplayPoint::new(0, 11),
3200 DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4),
3201 ],
3202 cx,
3203 )
3204 .unwrap();
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, 9)..DisplayPoint::new(0, 9),
3213 DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3),
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, 7)..DisplayPoint::new(0, 7),
3224 DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2),
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, 4)..DisplayPoint::new(0, 4),
3235 DisplayPoint::new(2, 0)..DisplayPoint::new(2, 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, 3)..DisplayPoint::new(0, 3),
3246 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
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, 24)..DisplayPoint::new(0, 24),
3258 ]
3259 );
3260 });
3261
3262 view.update(cx, |view, cx| {
3263 view.move_to_previous_word_boundary(&(), cx);
3264 assert_eq!(
3265 view.selection_ranges(cx),
3266 &[
3267 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3268 DisplayPoint::new(0, 23)..DisplayPoint::new(0, 23),
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, 3)..DisplayPoint::new(0, 3),
3279 DisplayPoint::new(0, 24)..DisplayPoint::new(0, 24),
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, 4)..DisplayPoint::new(0, 4),
3290 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 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, 7)..DisplayPoint::new(0, 7),
3301 DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0),
3302 ]
3303 );
3304 });
3305
3306 view.update(cx, |view, cx| {
3307 view.move_to_next_word_boundary(&(), cx);
3308 assert_eq!(
3309 view.selection_ranges(cx),
3310 &[
3311 DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9),
3312 DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2),
3313 ]
3314 );
3315 });
3316
3317 view.update(cx, |view, cx| {
3318 view.move_right(&(), 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, 9),
3324 DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2),
3325 ]
3326 );
3327 });
3328
3329 view.update(cx, |view, cx| {
3330 view.select_to_previous_word_boundary(&(), cx);
3331 assert_eq!(
3332 view.selection_ranges(cx),
3333 &[
3334 DisplayPoint::new(0, 10)..DisplayPoint::new(0, 7),
3335 DisplayPoint::new(2, 3)..DisplayPoint::new(2, 0),
3336 ]
3337 );
3338 });
3339
3340 view.update(cx, |view, cx| {
3341 view.select_to_next_word_boundary(&(), cx);
3342 assert_eq!(
3343 view.selection_ranges(cx),
3344 &[
3345 DisplayPoint::new(0, 10)..DisplayPoint::new(0, 9),
3346 DisplayPoint::new(2, 3)..DisplayPoint::new(2, 2),
3347 ]
3348 );
3349 });
3350
3351 view.update(cx, |view, cx| {
3352 view.delete_to_next_word_boundary(&(), cx);
3353 assert_eq!(view.text(cx), "use std::s::{foo, bar}\n\n {az.qux()}");
3354 assert_eq!(
3355 view.selection_ranges(cx),
3356 &[
3357 DisplayPoint::new(0, 10)..DisplayPoint::new(0, 10),
3358 DisplayPoint::new(2, 3)..DisplayPoint::new(2, 3),
3359 ]
3360 );
3361 });
3362
3363 view.update(cx, |view, cx| {
3364 view.delete_to_previous_word_boundary(&(), cx);
3365 assert_eq!(view.text(cx), "use std::::{foo, bar}\n\n az.qux()}");
3366 assert_eq!(
3367 view.selection_ranges(cx),
3368 &[
3369 DisplayPoint::new(0, 9)..DisplayPoint::new(0, 9),
3370 DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2),
3371 ]
3372 );
3373 });
3374 }
3375
3376 #[gpui::test]
3377 fn test_backspace(cx: &mut gpui::MutableAppContext) {
3378 let buffer = cx.add_model(|cx| {
3379 Buffer::new(
3380 0,
3381 "one two three\nfour five six\nseven eight nine\nten\n",
3382 cx,
3383 )
3384 });
3385 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3386 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx));
3387
3388 view.update(cx, |view, cx| {
3389 view.select_display_ranges(
3390 &[
3391 // an empty selection - the preceding character is deleted
3392 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3393 // one character selected - it is deleted
3394 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
3395 // a line suffix selected - it is deleted
3396 DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
3397 ],
3398 cx,
3399 )
3400 .unwrap();
3401 view.backspace(&(), cx);
3402 });
3403
3404 assert_eq!(
3405 buffer.read(cx).text(),
3406 "oe two three\nfou five six\nseven ten\n"
3407 );
3408 }
3409
3410 #[gpui::test]
3411 fn test_delete(cx: &mut gpui::MutableAppContext) {
3412 let buffer = cx.add_model(|cx| {
3413 Buffer::new(
3414 0,
3415 "one two three\nfour five six\nseven eight nine\nten\n",
3416 cx,
3417 )
3418 });
3419 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3420 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx));
3421
3422 view.update(cx, |view, cx| {
3423 view.select_display_ranges(
3424 &[
3425 // an empty selection - the following character is deleted
3426 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3427 // one character selected - it is deleted
3428 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
3429 // a line suffix selected - it is deleted
3430 DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
3431 ],
3432 cx,
3433 )
3434 .unwrap();
3435 view.delete(&(), cx);
3436 });
3437
3438 assert_eq!(
3439 buffer.read(cx).text(),
3440 "on two three\nfou five six\nseven ten\n"
3441 );
3442 }
3443
3444 #[gpui::test]
3445 fn test_delete_line(cx: &mut gpui::MutableAppContext) {
3446 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3447 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx));
3448 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx));
3449 view.update(cx, |view, cx| {
3450 view.select_display_ranges(
3451 &[
3452 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3453 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
3454 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
3455 ],
3456 cx,
3457 )
3458 .unwrap();
3459 view.delete_line(&(), cx);
3460 assert_eq!(view.text(cx), "ghi");
3461 assert_eq!(
3462 view.selection_ranges(cx),
3463 vec![
3464 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
3465 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)
3466 ]
3467 );
3468 });
3469
3470 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3471 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx));
3472 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx));
3473 view.update(cx, |view, cx| {
3474 view.select_display_ranges(&[DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)], cx)
3475 .unwrap();
3476 view.delete_line(&(), cx);
3477 assert_eq!(view.text(cx), "ghi\n");
3478 assert_eq!(
3479 view.selection_ranges(cx),
3480 vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)]
3481 );
3482 });
3483 }
3484
3485 #[gpui::test]
3486 fn test_duplicate_line(cx: &mut gpui::MutableAppContext) {
3487 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3488 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx));
3489 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx));
3490 view.update(cx, |view, cx| {
3491 view.select_display_ranges(
3492 &[
3493 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
3494 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3495 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
3496 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
3497 ],
3498 cx,
3499 )
3500 .unwrap();
3501 view.duplicate_line(&(), cx);
3502 assert_eq!(view.text(cx), "abc\nabc\ndef\ndef\nghi\n\n");
3503 assert_eq!(
3504 view.selection_ranges(cx),
3505 vec![
3506 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
3507 DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
3508 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
3509 DisplayPoint::new(6, 0)..DisplayPoint::new(6, 0),
3510 ]
3511 );
3512 });
3513
3514 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3515 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx));
3516 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx));
3517 view.update(cx, |view, cx| {
3518 view.select_display_ranges(
3519 &[
3520 DisplayPoint::new(0, 1)..DisplayPoint::new(1, 1),
3521 DisplayPoint::new(1, 2)..DisplayPoint::new(2, 1),
3522 ],
3523 cx,
3524 )
3525 .unwrap();
3526 view.duplicate_line(&(), cx);
3527 assert_eq!(view.text(cx), "abc\ndef\nghi\nabc\ndef\nghi\n");
3528 assert_eq!(
3529 view.selection_ranges(cx),
3530 vec![
3531 DisplayPoint::new(3, 1)..DisplayPoint::new(4, 1),
3532 DisplayPoint::new(4, 2)..DisplayPoint::new(5, 1),
3533 ]
3534 );
3535 });
3536 }
3537
3538 #[gpui::test]
3539 fn test_move_line_up_down(cx: &mut gpui::MutableAppContext) {
3540 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3541 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(10, 5), cx));
3542 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx));
3543 view.update(cx, |view, cx| {
3544 view.fold_ranges(
3545 vec![
3546 Point::new(0, 2)..Point::new(1, 2),
3547 Point::new(2, 3)..Point::new(4, 1),
3548 Point::new(7, 0)..Point::new(8, 4),
3549 ],
3550 cx,
3551 );
3552 view.select_display_ranges(
3553 &[
3554 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3555 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
3556 DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
3557 DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2),
3558 ],
3559 cx,
3560 )
3561 .unwrap();
3562 assert_eq!(view.text(cx), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i\njjjjj");
3563
3564 view.move_line_up(&(), cx);
3565 assert_eq!(view.text(cx), "aa…bbb\nccc…eeee\nggggg\n…i\njjjjj\nfffff");
3566 assert_eq!(
3567 view.selection_ranges(cx),
3568 vec![
3569 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3570 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
3571 DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3),
3572 DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2)
3573 ]
3574 );
3575 });
3576
3577 view.update(cx, |view, cx| {
3578 view.move_line_down(&(), cx);
3579 assert_eq!(view.text(cx), "ccc…eeee\naa…bbb\nfffff\nggggg\n…i\njjjjj");
3580 assert_eq!(
3581 view.selection_ranges(cx),
3582 vec![
3583 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
3584 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
3585 DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
3586 DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2)
3587 ]
3588 );
3589 });
3590
3591 view.update(cx, |view, cx| {
3592 view.move_line_down(&(), cx);
3593 assert_eq!(view.text(cx), "ccc…eeee\nfffff\naa…bbb\nggggg\n…i\njjjjj");
3594 assert_eq!(
3595 view.selection_ranges(cx),
3596 vec![
3597 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
3598 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
3599 DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
3600 DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2)
3601 ]
3602 );
3603 });
3604
3605 view.update(cx, |view, cx| {
3606 view.move_line_up(&(), cx);
3607 assert_eq!(view.text(cx), "ccc…eeee\naa…bbb\nggggg\n…i\njjjjj\nfffff");
3608 assert_eq!(
3609 view.selection_ranges(cx),
3610 vec![
3611 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
3612 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
3613 DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3),
3614 DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2)
3615 ]
3616 );
3617 });
3618 }
3619
3620 #[gpui::test]
3621 fn test_clipboard(cx: &mut gpui::MutableAppContext) {
3622 let buffer = cx.add_model(|cx| Buffer::new(0, "one two three four five six ", cx));
3623 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3624 let view = cx
3625 .add_window(|cx| Editor::for_buffer(buffer.clone(), settings, cx))
3626 .1;
3627
3628 // Cut with three selections. Clipboard text is divided into three slices.
3629 view.update(cx, |view, cx| {
3630 view.select_ranges(vec![0..4, 8..14, 19..24], false, cx);
3631 view.cut(&(), cx);
3632 assert_eq!(view.text(cx), "two four six ");
3633 });
3634
3635 // Paste with three cursors. Each cursor pastes one slice of the clipboard text.
3636 view.update(cx, |view, cx| {
3637 view.select_ranges(vec![4..4, 9..9, 13..13], false, cx);
3638 view.paste(&(), cx);
3639 assert_eq!(view.text(cx), "two one four three six five ");
3640 assert_eq!(
3641 view.selection_ranges(cx),
3642 &[
3643 DisplayPoint::new(0, 8)..DisplayPoint::new(0, 8),
3644 DisplayPoint::new(0, 19)..DisplayPoint::new(0, 19),
3645 DisplayPoint::new(0, 28)..DisplayPoint::new(0, 28)
3646 ]
3647 );
3648 });
3649
3650 // Paste again but with only two cursors. Since the number of cursors doesn't
3651 // match the number of slices in the clipboard, the entire clipboard text
3652 // is pasted at each cursor.
3653 view.update(cx, |view, cx| {
3654 view.select_ranges(vec![0..0, 28..28], false, cx);
3655 view.insert(&"( ".to_string(), cx);
3656 view.paste(&(), cx);
3657 view.insert(&") ".to_string(), cx);
3658 assert_eq!(
3659 view.text(cx),
3660 "( one three five ) two one four three six five ( one three five ) "
3661 );
3662 });
3663
3664 view.update(cx, |view, cx| {
3665 view.select_ranges(vec![0..0], false, cx);
3666 view.insert(&"123\n4567\n89\n".to_string(), cx);
3667 assert_eq!(
3668 view.text(cx),
3669 "123\n4567\n89\n( one three five ) two one four three six five ( one three five ) "
3670 );
3671 });
3672
3673 // Cut with three selections, one of which is full-line.
3674 view.update(cx, |view, cx| {
3675 view.select_display_ranges(
3676 &[
3677 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2),
3678 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
3679 DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1),
3680 ],
3681 cx,
3682 )
3683 .unwrap();
3684 view.cut(&(), cx);
3685 assert_eq!(
3686 view.text(cx),
3687 "13\n9\n( one three five ) two one four three six five ( one three five ) "
3688 );
3689 });
3690
3691 // Paste with three selections, noticing how the copied selection that was full-line
3692 // gets inserted before the second cursor.
3693 view.update(cx, |view, cx| {
3694 view.select_display_ranges(
3695 &[
3696 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3697 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
3698 DisplayPoint::new(2, 2)..DisplayPoint::new(2, 3),
3699 ],
3700 cx,
3701 )
3702 .unwrap();
3703 view.paste(&(), cx);
3704 assert_eq!(
3705 view.text(cx),
3706 "123\n4567\n9\n( 8ne three five ) two one four three six five ( one three five ) "
3707 );
3708 assert_eq!(
3709 view.selection_ranges(cx),
3710 &[
3711 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3712 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
3713 DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3),
3714 ]
3715 );
3716 });
3717
3718 // Copy with a single cursor only, which writes the whole line into the clipboard.
3719 view.update(cx, |view, cx| {
3720 view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)], cx)
3721 .unwrap();
3722 view.copy(&(), cx);
3723 });
3724
3725 // Paste with three selections, noticing how the copied full-line selection is inserted
3726 // before the empty selections but replaces the selection that is non-empty.
3727 view.update(cx, |view, cx| {
3728 view.select_display_ranges(
3729 &[
3730 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3731 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 2),
3732 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
3733 ],
3734 cx,
3735 )
3736 .unwrap();
3737 view.paste(&(), cx);
3738 assert_eq!(
3739 view.text(cx),
3740 "123\n123\n123\n67\n123\n9\n( 8ne three five ) two one four three six five ( one three five ) "
3741 );
3742 assert_eq!(
3743 view.selection_ranges(cx),
3744 &[
3745 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
3746 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
3747 DisplayPoint::new(5, 1)..DisplayPoint::new(5, 1),
3748 ]
3749 );
3750 });
3751 }
3752
3753 #[gpui::test]
3754 fn test_select_all(cx: &mut gpui::MutableAppContext) {
3755 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\nde\nfgh", cx));
3756 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3757 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx));
3758 view.update(cx, |view, cx| {
3759 view.select_all(&(), cx);
3760 assert_eq!(
3761 view.selection_ranges(cx),
3762 &[DisplayPoint::new(0, 0)..DisplayPoint::new(2, 3)]
3763 );
3764 });
3765 }
3766
3767 #[gpui::test]
3768 fn test_select_line(cx: &mut gpui::MutableAppContext) {
3769 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3770 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 5), cx));
3771 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx));
3772 view.update(cx, |view, cx| {
3773 view.select_display_ranges(
3774 &[
3775 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
3776 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3777 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
3778 DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2),
3779 ],
3780 cx,
3781 )
3782 .unwrap();
3783 view.select_line(&(), cx);
3784 assert_eq!(
3785 view.selection_ranges(cx),
3786 vec![
3787 DisplayPoint::new(0, 0)..DisplayPoint::new(2, 0),
3788 DisplayPoint::new(4, 0)..DisplayPoint::new(5, 0),
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![
3798 DisplayPoint::new(0, 0)..DisplayPoint::new(3, 0),
3799 DisplayPoint::new(4, 0)..DisplayPoint::new(5, 5),
3800 ]
3801 );
3802 });
3803
3804 view.update(cx, |view, cx| {
3805 view.select_line(&(), cx);
3806 assert_eq!(
3807 view.selection_ranges(cx),
3808 vec![DisplayPoint::new(0, 0)..DisplayPoint::new(5, 5)]
3809 );
3810 });
3811 }
3812
3813 #[gpui::test]
3814 fn test_split_selection_into_lines(cx: &mut gpui::MutableAppContext) {
3815 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3816 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(9, 5), cx));
3817 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx));
3818 view.update(cx, |view, cx| {
3819 view.fold_ranges(
3820 vec![
3821 Point::new(0, 2)..Point::new(1, 2),
3822 Point::new(2, 3)..Point::new(4, 1),
3823 Point::new(7, 0)..Point::new(8, 4),
3824 ],
3825 cx,
3826 );
3827 view.select_display_ranges(
3828 &[
3829 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
3830 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3831 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
3832 DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4),
3833 ],
3834 cx,
3835 )
3836 .unwrap();
3837 assert_eq!(view.text(cx), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i");
3838 });
3839
3840 view.update(cx, |view, cx| {
3841 view.split_selection_into_lines(&(), cx);
3842 assert_eq!(view.text(cx), "aaaaa\nbbbbb\nccc…eeee\nfffff\nggggg\n…i");
3843 assert_eq!(
3844 view.selection_ranges(cx),
3845 [
3846 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3847 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
3848 DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0),
3849 DisplayPoint::new(5, 4)..DisplayPoint::new(5, 4)
3850 ]
3851 );
3852 });
3853
3854 view.update(cx, |view, cx| {
3855 view.select_display_ranges(&[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 1)], cx)
3856 .unwrap();
3857 view.split_selection_into_lines(&(), cx);
3858 assert_eq!(
3859 view.text(cx),
3860 "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\nhhhhh\niiiii"
3861 );
3862 assert_eq!(
3863 view.selection_ranges(cx),
3864 [
3865 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
3866 DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
3867 DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5),
3868 DisplayPoint::new(3, 5)..DisplayPoint::new(3, 5),
3869 DisplayPoint::new(4, 5)..DisplayPoint::new(4, 5),
3870 DisplayPoint::new(5, 5)..DisplayPoint::new(5, 5),
3871 DisplayPoint::new(6, 5)..DisplayPoint::new(6, 5),
3872 DisplayPoint::new(7, 0)..DisplayPoint::new(7, 0)
3873 ]
3874 );
3875 });
3876 }
3877
3878 #[gpui::test]
3879 fn test_add_selection_above_below(cx: &mut gpui::MutableAppContext) {
3880 let settings = settings::channel(&cx.font_cache()).unwrap().1;
3881 let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndefghi\n\njk\nlmno\n", cx));
3882 let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings, cx));
3883
3884 view.update(cx, |view, cx| {
3885 view.select_display_ranges(&[DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)], cx)
3886 .unwrap();
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_above(&(), cx);
3901 assert_eq!(
3902 view.selection_ranges(cx),
3903 vec![
3904 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
3905 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
3906 ]
3907 );
3908 });
3909
3910 view.update(cx, |view, cx| {
3911 view.add_selection_below(&(), cx);
3912 assert_eq!(
3913 view.selection_ranges(cx),
3914 vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)]
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.add_selection_below(&(), cx);
3931 assert_eq!(
3932 view.selection_ranges(cx),
3933 vec![
3934 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3),
3935 DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3)
3936 ]
3937 );
3938 });
3939
3940 view.update(cx, |view, cx| {
3941 view.select_display_ranges(&[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)], cx)
3942 .unwrap();
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_below(&(), cx);
3957 assert_eq!(
3958 view.selection_ranges(cx),
3959 vec![
3960 DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
3961 DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3)
3962 ]
3963 );
3964 });
3965
3966 view.update(cx, |view, cx| {
3967 view.add_selection_above(&(), cx);
3968 assert_eq!(
3969 view.selection_ranges(cx),
3970 vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)]
3971 );
3972 });
3973
3974 view.update(cx, |view, cx| {
3975 view.add_selection_above(&(), cx);
3976 assert_eq!(
3977 view.selection_ranges(cx),
3978 vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)]
3979 );
3980 });
3981
3982 view.update(cx, |view, cx| {
3983 view.select_display_ranges(&[DisplayPoint::new(0, 1)..DisplayPoint::new(1, 4)], cx)
3984 .unwrap();
3985 view.add_selection_below(&(), cx);
3986 assert_eq!(
3987 view.selection_ranges(cx),
3988 vec![
3989 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
3990 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
3991 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
3992 ]
3993 );
3994 });
3995
3996 view.update(cx, |view, cx| {
3997 view.add_selection_below(&(), cx);
3998 assert_eq!(
3999 view.selection_ranges(cx),
4000 vec![
4001 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
4002 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
4003 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
4004 DisplayPoint::new(4, 1)..DisplayPoint::new(4, 4),
4005 ]
4006 );
4007 });
4008
4009 view.update(cx, |view, cx| {
4010 view.add_selection_above(&(), cx);
4011 assert_eq!(
4012 view.selection_ranges(cx),
4013 vec![
4014 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
4015 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
4016 DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
4017 ]
4018 );
4019 });
4020
4021 view.update(cx, |view, cx| {
4022 view.select_display_ranges(&[DisplayPoint::new(4, 3)..DisplayPoint::new(1, 1)], cx)
4023 .unwrap();
4024 });
4025 view.update(cx, |view, cx| {
4026 view.add_selection_above(&(), cx);
4027 assert_eq!(
4028 view.selection_ranges(cx),
4029 vec![
4030 DisplayPoint::new(0, 3)..DisplayPoint::new(0, 1),
4031 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1),
4032 DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1),
4033 DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1),
4034 ]
4035 );
4036 });
4037
4038 view.update(cx, |view, cx| {
4039 view.add_selection_below(&(), cx);
4040 assert_eq!(
4041 view.selection_ranges(cx),
4042 vec![
4043 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1),
4044 DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1),
4045 DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1),
4046 ]
4047 );
4048 });
4049 }
4050
4051 #[gpui::test]
4052 async fn test_select_larger_smaller_syntax_node(mut cx: gpui::TestAppContext) {
4053 let app_state = cx.read(build_app_state);
4054 let lang = app_state.languages.select_language("z.rs");
4055 let text = r#"
4056 use mod1::mod2::{mod3, mod4};
4057
4058 fn fn_1(param1: bool, param2: &str) {
4059 let var1 = "text";
4060 }
4061 "#
4062 .unindent();
4063 let buffer = cx.add_model(|cx| {
4064 let history = History::new(text.into());
4065 Buffer::from_history(0, history, None, lang.cloned(), cx)
4066 });
4067 let (_, view) =
4068 cx.add_window(|cx| Editor::for_buffer(buffer, app_state.settings.clone(), cx));
4069 view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing())
4070 .await;
4071
4072 view.update(&mut cx, |view, cx| {
4073 view.select_display_ranges(
4074 &[
4075 DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
4076 DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
4077 DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
4078 ],
4079 cx,
4080 )
4081 .unwrap();
4082 view.select_larger_syntax_node(&(), cx);
4083 });
4084 assert_eq!(
4085 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4086 &[
4087 DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27),
4088 DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
4089 DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21),
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 &[
4099 DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28),
4100 DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0),
4101 ]
4102 );
4103
4104 view.update(&mut cx, |view, cx| {
4105 view.select_larger_syntax_node(&(), cx);
4106 });
4107 assert_eq!(
4108 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4109 &[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 0)]
4110 );
4111
4112 // Trying to expand the selected syntax node one more time has no effect.
4113 view.update(&mut cx, |view, cx| {
4114 view.select_larger_syntax_node(&(), cx);
4115 });
4116 assert_eq!(
4117 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4118 &[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 0)]
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, 16)..DisplayPoint::new(0, 28),
4128 DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0),
4129 ]
4130 );
4131
4132 view.update(&mut cx, |view, cx| {
4133 view.select_smaller_syntax_node(&(), cx);
4134 });
4135 assert_eq!(
4136 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4137 &[
4138 DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27),
4139 DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
4140 DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21),
4141 ]
4142 );
4143
4144 view.update(&mut cx, |view, cx| {
4145 view.select_smaller_syntax_node(&(), cx);
4146 });
4147 assert_eq!(
4148 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4149 &[
4150 DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
4151 DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
4152 DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
4153 ]
4154 );
4155
4156 // Trying to shrink the selected syntax node one more time has no effect.
4157 view.update(&mut cx, |view, cx| {
4158 view.select_smaller_syntax_node(&(), cx);
4159 });
4160 assert_eq!(
4161 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4162 &[
4163 DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
4164 DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
4165 DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
4166 ]
4167 );
4168
4169 // Ensure that we keep expanding the selection if the larger selection starts or ends within
4170 // a fold.
4171 view.update(&mut cx, |view, cx| {
4172 view.fold_ranges(
4173 vec![
4174 Point::new(0, 21)..Point::new(0, 24),
4175 Point::new(3, 20)..Point::new(3, 22),
4176 ],
4177 cx,
4178 );
4179 view.select_larger_syntax_node(&(), cx);
4180 });
4181 assert_eq!(
4182 view.update(&mut cx, |view, cx| view.selection_ranges(cx)),
4183 &[
4184 DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28),
4185 DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
4186 DisplayPoint::new(3, 4)..DisplayPoint::new(3, 23),
4187 ]
4188 );
4189 }
4190
4191 impl Editor {
4192 fn selection_ranges(&self, cx: &mut MutableAppContext) -> Vec<Range<DisplayPoint>> {
4193 self.selections_in_range(
4194 self.selection_set_id,
4195 DisplayPoint::zero()..self.max_point(cx),
4196 cx,
4197 )
4198 .collect::<Vec<_>>()
4199 }
4200 }
4201
4202 fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
4203 let point = DisplayPoint::new(row as u32, column as u32);
4204 point..point
4205 }
4206}
4207
4208trait RangeExt<T> {
4209 fn sorted(&self) -> Range<T>;
4210 fn to_inclusive(&self) -> RangeInclusive<T>;
4211}
4212
4213impl<T: Ord + Clone> RangeExt<T> for Range<T> {
4214 fn sorted(&self) -> Self {
4215 cmp::min(&self.start, &self.end).clone()..cmp::max(&self.start, &self.end).clone()
4216 }
4217
4218 fn to_inclusive(&self) -> RangeInclusive<T> {
4219 self.start.clone()..=self.end.clone()
4220 }
4221}