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