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