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