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