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