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