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