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