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