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