1use super::{
2 buffer, movement, Anchor, Bias, Buffer, BufferElement, DisplayMap, DisplayPoint, Point,
3 Selection, SelectionSetId, ToOffset, ToPoint,
4};
5use crate::{settings::Settings, watch, workspace};
6use anyhow::Result;
7use futures_core::future::LocalBoxFuture;
8use gpui::{
9 fonts::Properties as FontProperties, keymap::Binding, text_layout, AppContext, ClipboardItem,
10 Element, ElementBox, Entity, FontCache, ModelHandle, MutableAppContext, View, ViewContext,
11 WeakViewHandle,
12};
13use gpui::{geometry::vector::Vector2F, TextLayoutCache};
14use parking_lot::Mutex;
15use serde::{Deserialize, Serialize};
16use smallvec::SmallVec;
17use smol::Timer;
18use std::{
19 cmp::{self, Ordering},
20 fmt::Write,
21 iter::FromIterator,
22 ops::Range,
23 path::Path,
24 sync::Arc,
25 time::Duration,
26};
27
28const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
29
30pub fn init(app: &mut MutableAppContext) {
31 app.add_bindings(vec![
32 Binding::new("backspace", "buffer:backspace", Some("BufferView")),
33 Binding::new("delete", "buffer:delete", Some("BufferView")),
34 Binding::new("ctrl-d", "buffer:delete", Some("BufferView")),
35 Binding::new("enter", "buffer:newline", Some("BufferView")),
36 Binding::new("ctrl-shift-K", "buffer:delete_line", Some("BufferView")),
37 Binding::new("cmd-x", "buffer:cut", Some("BufferView")),
38 Binding::new("cmd-c", "buffer:copy", Some("BufferView")),
39 Binding::new("cmd-v", "buffer:paste", Some("BufferView")),
40 Binding::new("cmd-z", "buffer:undo", Some("BufferView")),
41 Binding::new("cmd-shift-Z", "buffer:redo", Some("BufferView")),
42 Binding::new("up", "buffer:move_up", Some("BufferView")),
43 Binding::new("down", "buffer:move_down", Some("BufferView")),
44 Binding::new("left", "buffer:move_left", Some("BufferView")),
45 Binding::new("right", "buffer:move_right", Some("BufferView")),
46 Binding::new("cmd-up", "buffer:move_to_beginning", Some("BufferView")),
47 Binding::new("cmd-down", "buffer:move_to_end", Some("BufferView")),
48 Binding::new("shift-up", "buffer:select_up", Some("BufferView")),
49 Binding::new("shift-down", "buffer:select_down", Some("BufferView")),
50 Binding::new("shift-left", "buffer:select_left", Some("BufferView")),
51 Binding::new("shift-right", "buffer:select_right", Some("BufferView")),
52 Binding::new(
53 "cmd-shift-up",
54 "buffer:select_to_beginning",
55 Some("BufferView"),
56 ),
57 Binding::new("cmd-shift-down", "buffer:select_to_end", Some("BufferView")),
58 Binding::new("cmd-a", "buffer:select_all", Some("BufferView")),
59 Binding::new("pageup", "buffer:page_up", Some("BufferView")),
60 Binding::new("pagedown", "buffer:page_down", Some("BufferView")),
61 Binding::new("alt-cmd-[", "buffer:fold", Some("BufferView")),
62 Binding::new("alt-cmd-]", "buffer:unfold", Some("BufferView")),
63 Binding::new(
64 "alt-cmd-f",
65 "buffer:fold_selected_ranges",
66 Some("BufferView"),
67 ),
68 ]);
69
70 app.add_action("buffer:scroll", BufferView::scroll);
71 app.add_action("buffer:select", BufferView::select);
72 app.add_action("buffer:insert", BufferView::insert);
73 app.add_action("buffer:newline", BufferView::newline);
74 app.add_action("buffer:backspace", BufferView::backspace);
75 app.add_action("buffer:delete", BufferView::delete);
76 app.add_action("buffer:delete_line", BufferView::delete_line);
77 app.add_action("buffer:cut", BufferView::cut);
78 app.add_action("buffer:copy", BufferView::copy);
79 app.add_action("buffer:paste", BufferView::paste);
80 app.add_action("buffer:undo", BufferView::undo);
81 app.add_action("buffer:redo", BufferView::redo);
82 app.add_action("buffer:move_up", BufferView::move_up);
83 app.add_action("buffer:move_down", BufferView::move_down);
84 app.add_action("buffer:move_left", BufferView::move_left);
85 app.add_action("buffer:move_right", BufferView::move_right);
86 app.add_action("buffer:move_to_beginning", BufferView::move_to_beginning);
87 app.add_action("buffer:move_to_end", BufferView::move_to_end);
88 app.add_action("buffer:select_up", BufferView::select_up);
89 app.add_action("buffer:select_down", BufferView::select_down);
90 app.add_action("buffer:select_left", BufferView::select_left);
91 app.add_action("buffer:select_right", BufferView::select_right);
92 app.add_action(
93 "buffer:select_to_beginning",
94 BufferView::select_to_beginning,
95 );
96 app.add_action("buffer:select_to_end", BufferView::select_to_end);
97 app.add_action("buffer:select_all", BufferView::select_all);
98 app.add_action("buffer:page_up", BufferView::page_up);
99 app.add_action("buffer:page_down", BufferView::page_down);
100 app.add_action("buffer:fold", BufferView::fold);
101 app.add_action("buffer:unfold", BufferView::unfold);
102 app.add_action(
103 "buffer:fold_selected_ranges",
104 BufferView::fold_selected_ranges,
105 );
106}
107
108pub enum SelectAction {
109 Begin {
110 position: DisplayPoint,
111 add: bool,
112 },
113 Update {
114 position: DisplayPoint,
115 scroll_position: Vector2F,
116 },
117 End,
118}
119
120pub struct BufferView {
121 handle: WeakViewHandle<Self>,
122 buffer: ModelHandle<Buffer>,
123 display_map: ModelHandle<DisplayMap>,
124 selection_set_id: SelectionSetId,
125 pending_selection: Option<Selection>,
126 scroll_position: Mutex<Vector2F>,
127 autoscroll_requested: Mutex<bool>,
128 settings: watch::Receiver<Settings>,
129 focused: bool,
130 cursors_visible: bool,
131 blink_epoch: usize,
132 blinking_paused: bool,
133 single_line: bool,
134}
135
136#[derive(Serialize, Deserialize)]
137struct ClipboardSelection {
138 len: usize,
139 is_entire_line: bool,
140}
141
142impl BufferView {
143 pub fn single_line(settings: watch::Receiver<Settings>, ctx: &mut ViewContext<Self>) -> Self {
144 let buffer = ctx.add_model(|ctx| Buffer::new(0, String::new(), ctx));
145 let mut view = Self::for_buffer(buffer, settings, ctx);
146 view.single_line = true;
147 view
148 }
149
150 pub fn for_buffer(
151 buffer: ModelHandle<Buffer>,
152 settings: watch::Receiver<Settings>,
153 ctx: &mut ViewContext<Self>,
154 ) -> Self {
155 settings.notify_view_on_change(ctx);
156
157 ctx.observe(&buffer, Self::on_buffer_changed);
158 ctx.subscribe_to_model(&buffer, Self::on_buffer_event);
159 let display_map = ctx.add_model(|ctx| {
160 DisplayMap::new(
161 buffer.clone(),
162 smol::block_on(settings.read()).tab_size,
163 ctx,
164 )
165 });
166 ctx.observe(&display_map, Self::on_display_map_changed);
167
168 let (selection_set_id, _) = buffer.update(ctx, |buffer, ctx| {
169 buffer.add_selection_set(
170 vec![Selection {
171 start: buffer.anchor_before(0).unwrap(),
172 end: buffer.anchor_before(0).unwrap(),
173 reversed: false,
174 goal_column: None,
175 }],
176 Some(ctx),
177 )
178 });
179 Self {
180 handle: ctx.handle().downgrade(),
181 buffer,
182 display_map,
183 selection_set_id,
184 pending_selection: None,
185 scroll_position: Mutex::new(Vector2F::zero()),
186 autoscroll_requested: Mutex::new(false),
187 settings,
188 focused: false,
189 cursors_visible: false,
190 blink_epoch: 0,
191 blinking_paused: false,
192 single_line: false,
193 }
194 }
195
196 pub fn buffer(&self) -> &ModelHandle<Buffer> {
197 &self.buffer
198 }
199
200 pub fn is_gutter_visible(&self) -> bool {
201 !self.single_line
202 }
203
204 fn scroll(&mut self, scroll_position: &Vector2F, ctx: &mut ViewContext<Self>) {
205 *self.scroll_position.lock() = *scroll_position;
206 ctx.notify();
207 }
208
209 pub fn scroll_position(&self) -> Vector2F {
210 *self.scroll_position.lock()
211 }
212
213 pub fn clamp_scroll_left(&self, max: f32) {
214 let mut scroll_position = self.scroll_position.lock();
215 let scroll_left = scroll_position.x();
216 scroll_position.set_x(scroll_left.min(max));
217 }
218
219 pub fn autoscroll_vertically(
220 &self,
221 viewport_height: f32,
222 line_height: f32,
223 app: &AppContext,
224 ) -> bool {
225 let mut scroll_position = self.scroll_position.lock();
226 let scroll_top = scroll_position.y();
227 scroll_position.set_y(scroll_top.min(self.max_point(app).row().saturating_sub(1) as f32));
228
229 let mut autoscroll_requested = self.autoscroll_requested.lock();
230 if *autoscroll_requested {
231 *autoscroll_requested = false;
232 } else {
233 return false;
234 }
235
236 let map = self.display_map.read(app);
237 let visible_lines = viewport_height / line_height;
238 let first_cursor_top = self
239 .selections(app)
240 .first()
241 .unwrap()
242 .head()
243 .to_display_point(map, app)
244 .unwrap()
245 .row() as f32;
246 let last_cursor_bottom = self
247 .selections(app)
248 .last()
249 .unwrap()
250 .head()
251 .to_display_point(map, app)
252 .unwrap()
253 .row() as f32
254 + 1.0;
255
256 let margin = ((visible_lines - (last_cursor_bottom - first_cursor_top)) / 2.0)
257 .floor()
258 .min(3.0);
259 if margin < 0.0 {
260 return false;
261 }
262
263 let target_top = (first_cursor_top - margin).max(0.0);
264 let target_bottom = last_cursor_bottom + margin;
265 let start_row = scroll_position.y();
266 let end_row = start_row + visible_lines;
267
268 if target_top < start_row {
269 scroll_position.set_y(target_top);
270 } else if target_bottom >= end_row {
271 scroll_position.set_y(target_bottom - visible_lines);
272 }
273
274 true
275 }
276
277 pub fn autoscroll_horizontally(
278 &self,
279 start_row: u32,
280 viewport_width: f32,
281 scroll_width: f32,
282 max_glyph_width: f32,
283 layouts: &[Arc<text_layout::Line>],
284 app: &AppContext,
285 ) {
286 let map = self.display_map.read(app);
287
288 let mut target_left = std::f32::INFINITY;
289 let mut target_right = 0.0_f32;
290 for selection in self.selections(app) {
291 let head = selection.head().to_display_point(map, app).unwrap();
292 let start_column = head.column().saturating_sub(3);
293 let end_column = cmp::min(map.line_len(head.row(), app).unwrap(), head.column() + 3);
294 target_left = target_left
295 .min(layouts[(head.row() - start_row) as usize].x_for_index(start_column as usize));
296 target_right = target_right.max(
297 layouts[(head.row() - start_row) as usize].x_for_index(end_column as usize)
298 + max_glyph_width,
299 );
300 }
301 target_right = target_right.min(scroll_width);
302
303 if target_right - target_left > viewport_width {
304 return;
305 }
306
307 let mut scroll_position = self.scroll_position.lock();
308 let scroll_left = scroll_position.x() * max_glyph_width;
309 let scroll_right = scroll_left + viewport_width;
310
311 if target_left < scroll_left {
312 scroll_position.set_x(target_left / max_glyph_width);
313 } else if target_right > scroll_right {
314 scroll_position.set_x((target_right - viewport_width) / max_glyph_width);
315 }
316 }
317
318 fn select(&mut self, arg: &SelectAction, ctx: &mut ViewContext<Self>) {
319 match arg {
320 SelectAction::Begin { position, add } => self.begin_selection(*position, *add, ctx),
321 SelectAction::Update {
322 position,
323 scroll_position,
324 } => self.update_selection(*position, *scroll_position, ctx),
325 SelectAction::End => self.end_selection(ctx),
326 }
327 }
328
329 fn begin_selection(&mut self, position: DisplayPoint, add: bool, ctx: &mut ViewContext<Self>) {
330 if !self.focused {
331 ctx.focus_self();
332 ctx.emit(Event::Activate);
333 }
334
335 let display_map = self.display_map.read(ctx);
336 let cursor = display_map
337 .anchor_before(position, Bias::Left, ctx.as_ref())
338 .unwrap();
339 let selection = Selection {
340 start: cursor.clone(),
341 end: cursor,
342 reversed: false,
343 goal_column: None,
344 };
345
346 if !add {
347 self.update_selections(Vec::new(), false, ctx);
348 }
349 self.pending_selection = Some(selection);
350
351 ctx.notify();
352 }
353
354 fn update_selection(
355 &mut self,
356 position: DisplayPoint,
357 scroll_position: Vector2F,
358 ctx: &mut ViewContext<Self>,
359 ) {
360 let buffer = self.buffer.read(ctx);
361 let map = self.display_map.read(ctx);
362 let cursor = map
363 .anchor_before(position, Bias::Left, ctx.as_ref())
364 .unwrap();
365 if let Some(selection) = self.pending_selection.as_mut() {
366 selection.set_head(buffer, cursor);
367 } else {
368 log::error!("update_selection dispatched with no pending selection");
369 return;
370 }
371
372 *self.scroll_position.lock() = scroll_position;
373
374 ctx.notify();
375 }
376
377 fn end_selection(&mut self, ctx: &mut ViewContext<Self>) {
378 if let Some(selection) = self.pending_selection.take() {
379 let ix = self.selection_insertion_index(&selection.start, ctx.as_ref());
380 let mut selections = self.selections(ctx.as_ref()).to_vec();
381 selections.insert(ix, selection);
382 self.update_selections(selections, false, ctx);
383 } else {
384 log::error!("end_selection dispatched with no pending selection");
385 }
386 }
387
388 pub fn is_selecting(&self) -> bool {
389 self.pending_selection.is_some()
390 }
391
392 #[cfg(test)]
393 fn select_ranges<'a, T>(&mut self, ranges: T, ctx: &mut ViewContext<Self>) -> Result<()>
394 where
395 T: IntoIterator<Item = &'a Range<usize>>,
396 {
397 let buffer = self.buffer.read(ctx);
398 let mut selections = Vec::new();
399 for range in ranges {
400 selections.push(Selection {
401 start: buffer.anchor_before(range.start)?,
402 end: buffer.anchor_before(range.end)?,
403 reversed: false,
404 goal_column: None,
405 });
406 }
407 self.update_selections(selections, false, ctx);
408 Ok(())
409 }
410
411 #[cfg(test)]
412 fn select_display_ranges<'a, T>(&mut self, ranges: T, ctx: &mut ViewContext<Self>) -> Result<()>
413 where
414 T: IntoIterator<Item = &'a Range<DisplayPoint>>,
415 {
416 use std::mem;
417
418 let map = self.display_map.read(ctx);
419 let mut selections = Vec::new();
420 for range in ranges {
421 let mut start = range.start;
422 let mut end = range.end;
423 let reversed = if start > end {
424 mem::swap(&mut start, &mut end);
425 true
426 } else {
427 false
428 };
429
430 selections.push(Selection {
431 start: map.anchor_before(start, Bias::Left, ctx.as_ref())?,
432 end: map.anchor_before(end, Bias::Left, ctx.as_ref())?,
433 reversed,
434 goal_column: None,
435 });
436 }
437 self.update_selections(selections, false, ctx);
438 Ok(())
439 }
440
441 fn insert(&mut self, text: &String, ctx: &mut ViewContext<Self>) {
442 let mut offset_ranges = SmallVec::<[Range<usize>; 32]>::new();
443 {
444 let buffer = self.buffer.read(ctx);
445 for selection in self.selections(ctx.as_ref()) {
446 let start = selection.start.to_offset(buffer).unwrap();
447 let end = selection.end.to_offset(buffer).unwrap();
448 offset_ranges.push(start..end);
449 }
450 }
451
452 self.start_transaction(ctx);
453 let mut new_selections = Vec::new();
454 self.buffer.update(ctx, |buffer, ctx| {
455 if let Err(error) = buffer.edit(offset_ranges.iter().cloned(), text.as_str(), Some(ctx))
456 {
457 log::error!("error inserting text: {}", error);
458 };
459 let char_count = text.chars().count() as isize;
460 let mut delta = 0_isize;
461 new_selections = offset_ranges
462 .into_iter()
463 .map(|range| {
464 let start = range.start as isize;
465 let end = range.end as isize;
466 let anchor = buffer
467 .anchor_before((start + delta + char_count) as usize)
468 .unwrap();
469 let deleted_count = end - start;
470 delta += char_count - deleted_count;
471 Selection {
472 start: anchor.clone(),
473 end: anchor,
474 reversed: false,
475 goal_column: None,
476 }
477 })
478 .collect();
479 });
480
481 self.update_selections(new_selections, true, ctx);
482 self.end_transaction(ctx);
483 }
484
485 fn newline(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
486 if self.single_line {
487 ctx.propagate_action();
488 } else {
489 self.insert(&"\n".into(), ctx);
490 }
491 }
492
493 pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
494 self.start_transaction(ctx);
495 let mut selections = self.selections(ctx.as_ref()).to_vec();
496 {
497 let buffer = self.buffer.read(ctx);
498 let map = self.display_map.read(ctx);
499 for selection in &mut selections {
500 if selection.range(buffer).is_empty() {
501 let head = selection
502 .head()
503 .to_display_point(map, ctx.as_ref())
504 .unwrap();
505 let cursor = map
506 .anchor_before(
507 movement::left(map, head, ctx.as_ref()).unwrap(),
508 Bias::Left,
509 ctx.as_ref(),
510 )
511 .unwrap();
512 selection.set_head(&buffer, cursor);
513 selection.goal_column = None;
514 }
515 }
516 }
517
518 self.update_selections(selections, true, ctx);
519 self.insert(&String::new(), ctx);
520 self.end_transaction(ctx);
521 }
522
523 pub fn delete(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
524 self.start_transaction(ctx);
525 let mut selections = self.selections(ctx.as_ref()).to_vec();
526 {
527 let buffer = self.buffer.read(ctx);
528 let map = self.display_map.read(ctx);
529 for selection in &mut selections {
530 if selection.range(buffer).is_empty() {
531 let head = selection
532 .head()
533 .to_display_point(map, ctx.as_ref())
534 .unwrap();
535 let cursor = map
536 .anchor_before(
537 movement::right(map, head, ctx.as_ref()).unwrap(),
538 Bias::Right,
539 ctx.as_ref(),
540 )
541 .unwrap();
542 selection.set_head(&buffer, cursor);
543 selection.goal_column = None;
544 }
545 }
546 }
547
548 self.update_selections(selections, true, ctx);
549 self.insert(&String::new(), ctx);
550 self.end_transaction(ctx);
551 }
552
553 pub fn delete_line(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
554 self.start_transaction(ctx);
555
556 let app = ctx.as_ref();
557 let map = self.display_map.read(app);
558 let buffer = self.buffer.read(app);
559
560 let mut new_cursors = Vec::new();
561 let mut edit_ranges = Vec::new();
562
563 let mut selections = self.selections(app).iter().peekable();
564 while let Some(selection) = selections.next() {
565 let mut range = selection.buffer_row_range(map, app);
566 let goal_display_column = selection
567 .head()
568 .to_display_point(map, app)
569 .unwrap()
570 .column();
571
572 // Accumulate contiguous regions of rows that we want to delete.
573 while let Some(next_selection) = selections.peek() {
574 let next_range = next_selection.buffer_row_range(map, app);
575 if next_range.start <= range.end {
576 range.end = next_range.end;
577 selections.next().unwrap();
578 } else {
579 break;
580 }
581 }
582
583 let mut edit_start = Point::new(range.start, 0).to_offset(buffer).unwrap();
584 let edit_end;
585 let cursor_buffer_row;
586 if let Ok(end_offset) = Point::new(range.end, 0).to_offset(buffer) {
587 // If there's a line after the range, delete the \n from the end of the row range
588 // and position the cursor on the next line.
589 edit_end = end_offset;
590 cursor_buffer_row = range.end;
591 } else {
592 // If there isn't a line after the range, delete the \n from the line before the
593 // start of the row range and position the cursor there.
594 edit_start = edit_start.saturating_sub(1);
595 edit_end = buffer.len();
596 cursor_buffer_row = range.start.saturating_sub(1);
597 }
598
599 let mut cursor = Point::new(cursor_buffer_row, 0)
600 .to_display_point(map, app)
601 .unwrap();
602 *cursor.column_mut() = cmp::min(
603 goal_display_column,
604 map.line_len(cursor.row(), app).unwrap(),
605 );
606
607 new_cursors.push(cursor.to_buffer_point(map, Bias::Left, app).unwrap());
608 edit_ranges.push(edit_start..edit_end);
609 }
610
611 new_cursors.sort_unstable();
612 let new_selections = new_cursors
613 .into_iter()
614 .map(|cursor| buffer.anchor_before(cursor).unwrap())
615 .map(|anchor| Selection {
616 start: anchor.clone(),
617 end: anchor,
618 reversed: false,
619 goal_column: None,
620 })
621 .collect();
622 self.update_selections(new_selections, true, ctx);
623 self.buffer
624 .update(ctx, |buffer, ctx| buffer.edit(edit_ranges, "", Some(ctx)))
625 .unwrap();
626 self.end_transaction(ctx);
627 }
628
629 pub fn cut(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
630 self.start_transaction(ctx);
631 let mut text = String::new();
632 let mut selections = self.selections(ctx.as_ref()).to_vec();
633 let mut clipboard_selections = Vec::with_capacity(selections.len());
634 {
635 let buffer = self.buffer.read(ctx);
636 let max_point = buffer.max_point();
637 for selection in &mut selections {
638 let mut start = selection.start.to_point(buffer).expect("invalid start");
639 let mut end = selection.end.to_point(buffer).expect("invalid end");
640 let is_entire_line = start == end;
641 if is_entire_line {
642 start = Point::new(start.row, 0);
643 end = cmp::min(max_point, Point::new(start.row + 1, 0));
644 selection.start = buffer.anchor_before(start).unwrap();
645 selection.end = buffer.anchor_before(end).unwrap();
646 }
647 let mut len = 0;
648 for ch in buffer.text_for_range(start..end).unwrap() {
649 text.push(ch);
650 len += 1;
651 }
652 clipboard_selections.push(ClipboardSelection {
653 len,
654 is_entire_line,
655 });
656 }
657 }
658 self.update_selections(selections, true, ctx);
659 self.insert(&String::new(), ctx);
660 self.end_transaction(ctx);
661
662 ctx.as_mut()
663 .write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
664 }
665
666 pub fn copy(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
667 let buffer = self.buffer.read(ctx);
668 let max_point = buffer.max_point();
669 let mut text = String::new();
670 let selections = self.selections(ctx.as_ref());
671 let mut clipboard_selections = Vec::with_capacity(selections.len());
672 for selection in selections {
673 let mut start = selection.start.to_point(buffer).expect("invalid start");
674 let mut end = selection.end.to_point(buffer).expect("invalid end");
675 let is_entire_line = start == end;
676 if is_entire_line {
677 start = Point::new(start.row, 0);
678 end = cmp::min(max_point, Point::new(start.row + 1, 0));
679 }
680 let mut len = 0;
681 for ch in buffer.text_for_range(start..end).unwrap() {
682 text.push(ch);
683 len += 1;
684 }
685 clipboard_selections.push(ClipboardSelection {
686 len,
687 is_entire_line,
688 });
689 }
690
691 ctx.as_mut()
692 .write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
693 }
694
695 pub fn paste(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
696 if let Some(item) = ctx.as_mut().read_from_clipboard() {
697 let clipboard_text = item.text();
698 if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
699 let selections = self.selections(ctx.as_ref()).to_vec();
700 if clipboard_selections.len() != selections.len() {
701 let merged_selection = ClipboardSelection {
702 len: clipboard_selections.iter().map(|s| s.len).sum(),
703 is_entire_line: clipboard_selections.iter().all(|s| s.is_entire_line),
704 };
705 clipboard_selections.clear();
706 clipboard_selections.push(merged_selection);
707 }
708
709 self.start_transaction(ctx);
710 let mut new_selections = Vec::with_capacity(selections.len());
711 let mut clipboard_chars = clipboard_text.chars().cycle();
712 for (selection, clipboard_selection) in
713 selections.iter().zip(clipboard_selections.iter().cycle())
714 {
715 let to_insert =
716 String::from_iter(clipboard_chars.by_ref().take(clipboard_selection.len));
717
718 self.buffer.update(ctx, |buffer, ctx| {
719 let selection_start = selection.start.to_point(buffer).unwrap();
720 let selection_end = selection.end.to_point(buffer).unwrap();
721
722 // If the corresponding selection was empty when this slice of the
723 // clipboard text was written, then the entire line containing the
724 // selection was copied. If this selection is also currently empty,
725 // then paste the line before the current line of the buffer.
726 let new_selection_start = selection.end.bias_right(buffer).unwrap();
727 if selection_start == selection_end && clipboard_selection.is_entire_line {
728 let line_start = Point::new(selection_start.row, 0);
729 buffer
730 .edit(Some(line_start..line_start), to_insert, Some(ctx))
731 .unwrap();
732 } else {
733 buffer
734 .edit(Some(&selection.start..&selection.end), to_insert, Some(ctx))
735 .unwrap();
736 };
737
738 let new_selection_start = new_selection_start.bias_left(buffer).unwrap();
739 new_selections.push(Selection {
740 start: new_selection_start.clone(),
741 end: new_selection_start,
742 reversed: false,
743 goal_column: None,
744 });
745 });
746 }
747 self.update_selections(new_selections, true, ctx);
748 self.end_transaction(ctx);
749 } else {
750 self.insert(clipboard_text, ctx);
751 }
752 }
753 }
754
755 pub fn undo(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
756 self.buffer
757 .update(ctx, |buffer, ctx| buffer.undo(Some(ctx)));
758 }
759
760 pub fn redo(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
761 self.buffer
762 .update(ctx, |buffer, ctx| buffer.redo(Some(ctx)));
763 }
764
765 pub fn move_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
766 let app = ctx.as_ref();
767 let mut selections = self.selections(app).to_vec();
768 {
769 let map = self.display_map.read(app);
770 for selection in &mut selections {
771 let start = selection.start.to_display_point(map, app).unwrap();
772 let end = selection.end.to_display_point(map, app).unwrap();
773
774 if start != end {
775 selection.end = selection.start.clone();
776 } else {
777 let cursor = map
778 .anchor_before(movement::left(map, start, app).unwrap(), Bias::Left, app)
779 .unwrap();
780 selection.start = cursor.clone();
781 selection.end = cursor;
782 }
783 selection.reversed = false;
784 selection.goal_column = None;
785 }
786 }
787 self.update_selections(selections, true, ctx);
788 }
789
790 pub fn select_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
791 let mut selections = self.selections(ctx.as_ref()).to_vec();
792 {
793 let buffer = self.buffer.read(ctx);
794 let map = self.display_map.read(ctx);
795 for selection in &mut selections {
796 let head = selection
797 .head()
798 .to_display_point(map, ctx.as_ref())
799 .unwrap();
800 let cursor = map
801 .anchor_before(
802 movement::left(map, head, ctx.as_ref()).unwrap(),
803 Bias::Left,
804 ctx.as_ref(),
805 )
806 .unwrap();
807 selection.set_head(&buffer, cursor);
808 selection.goal_column = None;
809 }
810 }
811 self.update_selections(selections, true, ctx);
812 }
813
814 pub fn move_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
815 let mut selections = self.selections(ctx.as_ref()).to_vec();
816 {
817 let app = ctx.as_ref();
818 let map = self.display_map.read(app);
819 for selection in &mut selections {
820 let start = selection.start.to_display_point(map, app).unwrap();
821 let end = selection.end.to_display_point(map, app).unwrap();
822
823 if start != end {
824 selection.start = selection.end.clone();
825 } else {
826 let cursor = map
827 .anchor_before(movement::right(map, end, app).unwrap(), Bias::Right, app)
828 .unwrap();
829 selection.start = cursor.clone();
830 selection.end = cursor;
831 }
832 selection.reversed = false;
833 selection.goal_column = None;
834 }
835 }
836 self.update_selections(selections, true, ctx);
837 }
838
839 pub fn select_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
840 let mut selections = self.selections(ctx.as_ref()).to_vec();
841 {
842 let app = ctx.as_ref();
843 let buffer = self.buffer.read(app);
844 let map = self.display_map.read(app);
845 for selection in &mut selections {
846 let head = selection
847 .head()
848 .to_display_point(map, ctx.as_ref())
849 .unwrap();
850 let cursor = map
851 .anchor_before(movement::right(map, head, app).unwrap(), Bias::Right, app)
852 .unwrap();
853 selection.set_head(&buffer, cursor);
854 selection.goal_column = None;
855 }
856 }
857 self.update_selections(selections, true, ctx);
858 }
859
860 pub fn move_up(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
861 if self.single_line {
862 ctx.propagate_action();
863 } else {
864 let mut selections = self.selections(ctx.as_ref()).to_vec();
865 {
866 let app = ctx.as_ref();
867 let map = self.display_map.read(app);
868 for selection in &mut selections {
869 let start = selection.start.to_display_point(map, app).unwrap();
870 let end = selection.end.to_display_point(map, app).unwrap();
871 if start != end {
872 selection.goal_column = None;
873 }
874
875 let (start, goal_column) =
876 movement::up(map, start, selection.goal_column, app).unwrap();
877 let cursor = map.anchor_before(start, Bias::Left, app).unwrap();
878 selection.start = cursor.clone();
879 selection.end = cursor;
880 selection.goal_column = goal_column;
881 selection.reversed = false;
882 }
883 }
884 self.update_selections(selections, true, ctx);
885 }
886 }
887
888 pub fn select_up(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
889 let mut selections = self.selections(ctx.as_ref()).to_vec();
890 {
891 let app = ctx.as_ref();
892 let buffer = self.buffer.read(app);
893 let map = self.display_map.read(app);
894 for selection in &mut selections {
895 let head = selection.head().to_display_point(map, app).unwrap();
896 let (head, goal_column) =
897 movement::up(map, head, selection.goal_column, app).unwrap();
898 selection.set_head(&buffer, map.anchor_before(head, Bias::Left, app).unwrap());
899 selection.goal_column = goal_column;
900 }
901 }
902 self.update_selections(selections, true, ctx);
903 }
904
905 pub fn move_down(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
906 if self.single_line {
907 ctx.propagate_action();
908 } else {
909 let mut selections = self.selections(ctx.as_ref()).to_vec();
910 {
911 let app = ctx.as_ref();
912 let map = self.display_map.read(app);
913 for selection in &mut selections {
914 let start = selection.start.to_display_point(map, app).unwrap();
915 let end = selection.end.to_display_point(map, app).unwrap();
916 if start != end {
917 selection.goal_column = None;
918 }
919
920 let (start, goal_column) =
921 movement::down(map, end, selection.goal_column, app).unwrap();
922 let cursor = map.anchor_before(start, Bias::Right, app).unwrap();
923 selection.start = cursor.clone();
924 selection.end = cursor;
925 selection.goal_column = goal_column;
926 selection.reversed = false;
927 }
928 }
929 self.update_selections(selections, true, ctx);
930 }
931 }
932
933 pub fn select_down(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
934 let mut selections = self.selections(ctx.as_ref()).to_vec();
935 {
936 let app = ctx.as_ref();
937 let buffer = self.buffer.read(app);
938 let map = self.display_map.read(app);
939 for selection in &mut selections {
940 let head = selection.head().to_display_point(map, app).unwrap();
941 let (head, goal_column) =
942 movement::down(map, head, selection.goal_column, app).unwrap();
943 selection.set_head(&buffer, map.anchor_before(head, Bias::Right, app).unwrap());
944 selection.goal_column = goal_column;
945 }
946 }
947 self.update_selections(selections, true, ctx);
948 }
949
950 pub fn move_to_beginning(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
951 let selection = Selection {
952 start: Anchor::Start,
953 end: Anchor::Start,
954 reversed: false,
955 goal_column: None,
956 };
957 self.update_selections(vec![selection], true, ctx);
958 }
959
960 pub fn select_to_beginning(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
961 let mut selection = self.selections(ctx.as_ref()).last().unwrap().clone();
962 selection.set_head(self.buffer.read(ctx), Anchor::Start);
963 self.update_selections(vec![selection], true, ctx);
964 }
965
966 pub fn move_to_end(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
967 let selection = Selection {
968 start: Anchor::End,
969 end: Anchor::End,
970 reversed: false,
971 goal_column: None,
972 };
973 self.update_selections(vec![selection], true, ctx);
974 }
975
976 pub fn select_to_end(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
977 let mut selection = self.selections(ctx.as_ref()).last().unwrap().clone();
978 selection.set_head(self.buffer.read(ctx), Anchor::End);
979 self.update_selections(vec![selection], true, ctx);
980 }
981
982 pub fn select_all(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
983 let selection = Selection {
984 start: Anchor::Start,
985 end: Anchor::End,
986 reversed: false,
987 goal_column: None,
988 };
989 self.update_selections(vec![selection], false, ctx);
990 }
991
992 pub fn selections_in_range<'a>(
993 &'a self,
994 range: Range<DisplayPoint>,
995 app: &'a AppContext,
996 ) -> impl 'a + Iterator<Item = Range<DisplayPoint>> {
997 let map = self.display_map.read(app);
998
999 let start = map.anchor_before(range.start, Bias::Left, app).unwrap();
1000 let start_index = self.selection_insertion_index(&start, app);
1001 let pending_selection = self.pending_selection.as_ref().and_then(|s| {
1002 let selection_range = s.display_range(map, app);
1003 if selection_range.start <= range.end || selection_range.end <= range.end {
1004 Some(selection_range)
1005 } else {
1006 None
1007 }
1008 });
1009 self.selections(app)[start_index..]
1010 .iter()
1011 .map(move |s| s.display_range(map, app))
1012 .take_while(move |r| r.start <= range.end || r.end <= range.end)
1013 .chain(pending_selection)
1014 }
1015
1016 fn selection_insertion_index(&self, start: &Anchor, app: &AppContext) -> usize {
1017 let buffer = self.buffer.read(app);
1018 let selections = self.selections(app);
1019 match selections.binary_search_by(|probe| probe.start.cmp(&start, buffer).unwrap()) {
1020 Ok(index) => index,
1021 Err(index) => {
1022 if index > 0
1023 && selections[index - 1].end.cmp(&start, buffer).unwrap() == Ordering::Greater
1024 {
1025 index - 1
1026 } else {
1027 index
1028 }
1029 }
1030 }
1031 }
1032
1033 fn selections<'a>(&self, app: &'a AppContext) -> &'a [Selection] {
1034 self.buffer
1035 .read(app)
1036 .selections(self.selection_set_id)
1037 .unwrap()
1038 }
1039
1040 fn update_selections(
1041 &mut self,
1042 mut selections: Vec<Selection>,
1043 autoscroll: bool,
1044 ctx: &mut ViewContext<Self>,
1045 ) {
1046 // Merge overlapping selections.
1047 let buffer = self.buffer.read(ctx);
1048 let mut i = 1;
1049 while i < selections.len() {
1050 if selections[i - 1]
1051 .end
1052 .cmp(&selections[i].start, buffer)
1053 .unwrap()
1054 >= Ordering::Equal
1055 {
1056 let removed = selections.remove(i);
1057 if removed.start.cmp(&selections[i - 1].start, buffer).unwrap() < Ordering::Equal {
1058 selections[i - 1].start = removed.start;
1059 }
1060 if removed.end.cmp(&selections[i - 1].end, buffer).unwrap() > Ordering::Equal {
1061 selections[i - 1].end = removed.end;
1062 }
1063 } else {
1064 i += 1;
1065 }
1066 }
1067
1068 self.buffer.update(ctx, |buffer, ctx| {
1069 buffer
1070 .update_selection_set(self.selection_set_id, selections, Some(ctx))
1071 .unwrap()
1072 });
1073 self.pause_cursor_blinking(ctx);
1074
1075 if autoscroll {
1076 *self.autoscroll_requested.lock() = true;
1077 ctx.notify();
1078 }
1079 }
1080
1081 fn start_transaction(&self, ctx: &mut ViewContext<Self>) {
1082 self.buffer.update(ctx, |buffer, _| {
1083 buffer
1084 .start_transaction(Some(self.selection_set_id))
1085 .unwrap()
1086 });
1087 }
1088
1089 fn end_transaction(&self, ctx: &mut ViewContext<Self>) {
1090 self.buffer.update(ctx, |buffer, ctx| {
1091 buffer
1092 .end_transaction(Some(self.selection_set_id), Some(ctx))
1093 .unwrap()
1094 });
1095 }
1096
1097 pub fn page_up(&mut self, _: &(), _: &mut ViewContext<Self>) {
1098 log::info!("BufferView::page_up");
1099 }
1100
1101 pub fn page_down(&mut self, _: &(), _: &mut ViewContext<Self>) {
1102 log::info!("BufferView::page_down");
1103 }
1104
1105 pub fn fold(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
1106 use super::RangeExt;
1107
1108 let mut fold_ranges = Vec::new();
1109
1110 let app = ctx.as_ref();
1111 let map = self.display_map.read(app);
1112 for selection in self.selections(app) {
1113 let (start, end) = selection.display_range(map, app).sorted();
1114 let buffer_start_row = start.to_buffer_point(map, Bias::Left, app).unwrap().row;
1115
1116 for row in (0..=end.row()).rev() {
1117 if self.is_line_foldable(row, app) && !map.is_line_folded(row) {
1118 let fold_range = self.foldable_range_for_line(row, app).unwrap();
1119 if fold_range.end.row >= buffer_start_row {
1120 fold_ranges.push(fold_range);
1121 if row <= start.row() {
1122 break;
1123 }
1124 }
1125 }
1126 }
1127 }
1128
1129 if !fold_ranges.is_empty() {
1130 self.display_map.update(ctx, |map, ctx| {
1131 map.fold(fold_ranges, ctx).unwrap();
1132 });
1133 *self.autoscroll_requested.lock() = true;
1134 }
1135 }
1136
1137 pub fn unfold(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
1138 use super::RangeExt;
1139
1140 let app = ctx.as_ref();
1141 let map = self.display_map.read(app);
1142 let buffer = self.buffer.read(app);
1143 let ranges = self
1144 .selections(app)
1145 .iter()
1146 .map(|s| {
1147 let (start, end) = s.display_range(map, app).sorted();
1148 let mut start = start.to_buffer_point(map, Bias::Left, app).unwrap();
1149 let mut end = end.to_buffer_point(map, Bias::Left, app).unwrap();
1150 start.column = 0;
1151 end.column = buffer.line_len(end.row).unwrap();
1152 start..end
1153 })
1154 .collect::<Vec<_>>();
1155
1156 self.display_map.update(ctx, |map, ctx| {
1157 map.unfold(ranges, ctx).unwrap();
1158 });
1159 *self.autoscroll_requested.lock() = true;
1160 }
1161
1162 fn is_line_foldable(&self, display_row: u32, app: &AppContext) -> bool {
1163 let max_point = self.max_point(app);
1164 if display_row >= max_point.row() {
1165 false
1166 } else {
1167 let (start_indent, is_blank) = self.line_indent(display_row, app).unwrap();
1168 if is_blank {
1169 false
1170 } else {
1171 for display_row in display_row + 1..=max_point.row() {
1172 let (indent, is_blank) = self.line_indent(display_row, app).unwrap();
1173 if !is_blank {
1174 return indent > start_indent;
1175 }
1176 }
1177 false
1178 }
1179 }
1180 }
1181
1182 fn line_indent(&self, display_row: u32, app: &AppContext) -> Result<(usize, bool)> {
1183 let mut indent = 0;
1184 let mut is_blank = true;
1185 for c in self
1186 .display_map
1187 .read(app)
1188 .chars_at(DisplayPoint::new(display_row, 0), app)?
1189 {
1190 if c == ' ' {
1191 indent += 1;
1192 } else {
1193 is_blank = c == '\n';
1194 break;
1195 }
1196 }
1197 Ok((indent, is_blank))
1198 }
1199
1200 fn foldable_range_for_line(&self, start_row: u32, app: &AppContext) -> Result<Range<Point>> {
1201 let map = self.display_map.read(app);
1202 let max_point = self.max_point(app);
1203
1204 let (start_indent, _) = self.line_indent(start_row, app)?;
1205 let start = DisplayPoint::new(start_row, self.line_len(start_row, app)?);
1206 let mut end = None;
1207 for row in start_row + 1..=max_point.row() {
1208 let (indent, is_blank) = self.line_indent(row, app)?;
1209 if !is_blank && indent <= start_indent {
1210 end = Some(DisplayPoint::new(row - 1, self.line_len(row - 1, app)?));
1211 break;
1212 }
1213 }
1214
1215 let end = end.unwrap_or(max_point);
1216 return Ok(start.to_buffer_point(map, Bias::Left, app)?
1217 ..end.to_buffer_point(map, Bias::Left, app)?);
1218 }
1219
1220 pub fn fold_selected_ranges(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
1221 self.display_map.update(ctx, |map, ctx| {
1222 let buffer = self.buffer.read(ctx);
1223 let ranges = self
1224 .selections(ctx.as_ref())
1225 .iter()
1226 .map(|s| s.range(buffer))
1227 .collect::<Vec<_>>();
1228 map.fold(ranges, ctx).unwrap();
1229 });
1230 }
1231
1232 pub fn line(&self, display_row: u32, app: &AppContext) -> Result<String> {
1233 self.display_map.read(app).line(display_row, app)
1234 }
1235
1236 pub fn line_len(&self, display_row: u32, app: &AppContext) -> Result<u32> {
1237 self.display_map.read(app).line_len(display_row, app)
1238 }
1239
1240 pub fn rightmost_point(&self, app: &AppContext) -> DisplayPoint {
1241 self.display_map.read(app).rightmost_point()
1242 }
1243
1244 pub fn max_point(&self, app: &AppContext) -> DisplayPoint {
1245 self.display_map.read(app).max_point(app)
1246 }
1247
1248 pub fn text(&self, app: &AppContext) -> String {
1249 self.display_map.read(app).text(app)
1250 }
1251
1252 pub fn font_size(&self) -> f32 {
1253 smol::block_on(self.settings.read()).buffer_font_size
1254 }
1255
1256 pub fn font_ascent(&self, font_cache: &FontCache) -> f32 {
1257 let settings = smol::block_on(self.settings.read());
1258 let font_id = font_cache.default_font(settings.buffer_font_family);
1259 let ascent = font_cache.metric(font_id, |m| m.ascent);
1260 font_cache.scale_metric(ascent, font_id, settings.buffer_font_size)
1261 }
1262
1263 pub fn font_descent(&self, font_cache: &FontCache) -> f32 {
1264 let settings = smol::block_on(self.settings.read());
1265 let font_id = font_cache.default_font(settings.buffer_font_family);
1266 let ascent = font_cache.metric(font_id, |m| m.descent);
1267 font_cache.scale_metric(ascent, font_id, settings.buffer_font_size)
1268 }
1269
1270 pub fn line_height(&self, font_cache: &FontCache) -> f32 {
1271 let settings = smol::block_on(self.settings.read());
1272 let font_id = font_cache.default_font(settings.buffer_font_family);
1273 font_cache.line_height(font_id, settings.buffer_font_size)
1274 }
1275
1276 pub fn em_width(&self, font_cache: &FontCache) -> f32 {
1277 let settings = smol::block_on(self.settings.read());
1278 let font_id = font_cache.default_font(settings.buffer_font_family);
1279 font_cache.em_width(font_id, settings.buffer_font_size)
1280 }
1281
1282 // TODO: Can we make this not return a result?
1283 pub fn max_line_number_width(
1284 &self,
1285 font_cache: &FontCache,
1286 layout_cache: &TextLayoutCache,
1287 app: &AppContext,
1288 ) -> Result<f32> {
1289 let settings = smol::block_on(self.settings.read());
1290 let font_size = settings.buffer_font_size;
1291 let font_id =
1292 font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
1293 let digit_count = ((self.buffer.read(app).max_point().row + 1) as f32)
1294 .log10()
1295 .floor() as usize
1296 + 1;
1297
1298 Ok(layout_cache
1299 .layout_str(
1300 "1".repeat(digit_count).as_str(),
1301 font_size,
1302 &[(0..digit_count, font_id)],
1303 )
1304 .width)
1305 }
1306
1307 pub fn layout_line_numbers(
1308 &self,
1309 viewport_height: f32,
1310 font_cache: &FontCache,
1311 layout_cache: &TextLayoutCache,
1312 app: &AppContext,
1313 ) -> Result<Vec<Arc<text_layout::Line>>> {
1314 let display_map = self.display_map.read(app);
1315
1316 let settings = smol::block_on(self.settings.read());
1317 let font_size = settings.buffer_font_size;
1318 let font_id =
1319 font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
1320
1321 let start_row = self.scroll_position().y() as usize;
1322 let end_row = cmp::min(
1323 self.max_point(app).row() as usize,
1324 start_row + (viewport_height / self.line_height(font_cache)).ceil() as usize,
1325 );
1326 let line_count = end_row - start_row + 1;
1327
1328 let mut layouts = Vec::with_capacity(line_count);
1329 let mut line_number = String::new();
1330 for buffer_row in display_map.buffer_rows(start_row as u32)?.take(line_count) {
1331 line_number.clear();
1332 write!(&mut line_number, "{}", buffer_row + 1).unwrap();
1333 layouts.push(layout_cache.layout_str(
1334 &line_number,
1335 font_size,
1336 &[(0..line_number.len(), font_id)],
1337 ));
1338 }
1339
1340 Ok(layouts)
1341 }
1342
1343 pub fn layout_lines(
1344 &self,
1345 mut rows: Range<u32>,
1346 font_cache: &FontCache,
1347 layout_cache: &TextLayoutCache,
1348 app: &AppContext,
1349 ) -> Result<Vec<Arc<text_layout::Line>>> {
1350 let display_map = self.display_map.read(app);
1351
1352 rows.end = cmp::min(rows.end, display_map.max_point(app).row() + 1);
1353 if rows.start >= rows.end {
1354 return Ok(Vec::new());
1355 }
1356
1357 let settings = smol::block_on(self.settings.read());
1358 let font_id =
1359 font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
1360 let font_size = settings.buffer_font_size;
1361
1362 let mut layouts = Vec::with_capacity(rows.len());
1363 let mut line = String::new();
1364 let mut line_len = 0;
1365 let mut row = rows.start;
1366 let chars = display_map
1367 .chars_at(DisplayPoint::new(rows.start, 0), app)
1368 .unwrap();
1369 for char in chars.chain(Some('\n')) {
1370 if char == '\n' {
1371 layouts.push(layout_cache.layout_str(&line, font_size, &[(0..line_len, font_id)]));
1372 line.clear();
1373 line_len = 0;
1374 row += 1;
1375 if row == rows.end {
1376 break;
1377 }
1378 } else {
1379 line_len += 1;
1380 line.push(char);
1381 }
1382 }
1383
1384 Ok(layouts)
1385 }
1386
1387 pub fn layout_line(
1388 &self,
1389 row: u32,
1390 font_cache: &FontCache,
1391 layout_cache: &TextLayoutCache,
1392 app: &AppContext,
1393 ) -> Result<Arc<text_layout::Line>> {
1394 let settings = smol::block_on(self.settings.read());
1395 let font_id =
1396 font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
1397
1398 let line = self.line(row, app)?;
1399
1400 Ok(layout_cache.layout_str(
1401 &line,
1402 settings.buffer_font_size,
1403 &[(0..self.line_len(row, app)? as usize, font_id)],
1404 ))
1405 }
1406
1407 fn next_blink_epoch(&mut self) -> usize {
1408 self.blink_epoch += 1;
1409 self.blink_epoch
1410 }
1411
1412 fn pause_cursor_blinking(&mut self, ctx: &mut ViewContext<Self>) {
1413 self.cursors_visible = true;
1414 ctx.notify();
1415
1416 let epoch = self.next_blink_epoch();
1417 ctx.spawn(
1418 async move {
1419 Timer::after(CURSOR_BLINK_INTERVAL).await;
1420 epoch
1421 },
1422 Self::resume_cursor_blinking,
1423 )
1424 .detach();
1425 }
1426
1427 fn resume_cursor_blinking(&mut self, epoch: usize, ctx: &mut ViewContext<Self>) {
1428 if epoch == self.blink_epoch {
1429 self.blinking_paused = false;
1430 self.blink_cursors(epoch, ctx);
1431 }
1432 }
1433
1434 fn blink_cursors(&mut self, epoch: usize, ctx: &mut ViewContext<Self>) {
1435 if epoch == self.blink_epoch && self.focused && !self.blinking_paused {
1436 self.cursors_visible = !self.cursors_visible;
1437 ctx.notify();
1438
1439 let epoch = self.next_blink_epoch();
1440 ctx.spawn(
1441 async move {
1442 Timer::after(CURSOR_BLINK_INTERVAL).await;
1443 epoch
1444 },
1445 Self::blink_cursors,
1446 )
1447 .detach();
1448 }
1449 }
1450
1451 pub fn cursors_visible(&self) -> bool {
1452 self.cursors_visible
1453 }
1454
1455 fn on_buffer_changed(&mut self, _: ModelHandle<Buffer>, ctx: &mut ViewContext<Self>) {
1456 ctx.notify();
1457 }
1458
1459 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, ctx: &mut ViewContext<Self>) {
1460 ctx.notify();
1461 }
1462
1463 fn on_buffer_event(
1464 &mut self,
1465 _: ModelHandle<Buffer>,
1466 event: &buffer::Event,
1467 ctx: &mut ViewContext<Self>,
1468 ) {
1469 match event {
1470 buffer::Event::Edited(_) => ctx.emit(Event::Edited),
1471 buffer::Event::Dirtied => ctx.emit(Event::Dirtied),
1472 buffer::Event::Saved => ctx.emit(Event::Saved),
1473 buffer::Event::FileHandleChanged => ctx.emit(Event::FileHandleChanged),
1474 }
1475 }
1476}
1477
1478pub enum Event {
1479 Activate,
1480 Edited,
1481 Blurred,
1482 Dirtied,
1483 Saved,
1484 FileHandleChanged,
1485}
1486
1487impl Entity for BufferView {
1488 type Event = Event;
1489}
1490
1491impl View for BufferView {
1492 fn render<'a>(&self, app: &AppContext) -> ElementBox {
1493 BufferElement::new(self.handle.upgrade(app).unwrap()).boxed()
1494 }
1495
1496 fn ui_name() -> &'static str {
1497 "BufferView"
1498 }
1499
1500 fn on_focus(&mut self, ctx: &mut ViewContext<Self>) {
1501 self.focused = true;
1502 self.blink_cursors(self.blink_epoch, ctx);
1503 }
1504
1505 fn on_blur(&mut self, ctx: &mut ViewContext<Self>) {
1506 self.focused = false;
1507 self.cursors_visible = false;
1508 ctx.emit(Event::Blurred);
1509 ctx.notify();
1510 }
1511}
1512
1513impl workspace::Item for Buffer {
1514 type View = BufferView;
1515
1516 fn build_view(
1517 buffer: ModelHandle<Self>,
1518 settings: watch::Receiver<Settings>,
1519 ctx: &mut ViewContext<Self::View>,
1520 ) -> Self::View {
1521 BufferView::for_buffer(buffer, settings, ctx)
1522 }
1523}
1524
1525impl workspace::ItemView for BufferView {
1526 fn should_activate_item_on_event(event: &Self::Event) -> bool {
1527 matches!(event, Event::Activate)
1528 }
1529
1530 fn should_update_tab_on_event(event: &Self::Event) -> bool {
1531 matches!(
1532 event,
1533 Event::Saved | Event::Dirtied | Event::FileHandleChanged
1534 )
1535 }
1536
1537 fn title(&self, app: &AppContext) -> std::string::String {
1538 if let Some(path) = self.buffer.read(app).path() {
1539 path.file_name()
1540 .expect("buffer's path is always to a file")
1541 .to_string_lossy()
1542 .into()
1543 } else {
1544 "untitled".into()
1545 }
1546 }
1547
1548 fn entry_id(&self, app: &AppContext) -> Option<(usize, Arc<Path>)> {
1549 self.buffer.read(app).entry_id()
1550 }
1551
1552 fn clone_on_split(&self, ctx: &mut ViewContext<Self>) -> Option<Self>
1553 where
1554 Self: Sized,
1555 {
1556 let clone = BufferView::for_buffer(self.buffer.clone(), self.settings.clone(), ctx);
1557 *clone.scroll_position.lock() = *self.scroll_position.lock();
1558 Some(clone)
1559 }
1560
1561 fn save(&self, ctx: &mut ViewContext<Self>) -> LocalBoxFuture<'static, Result<()>> {
1562 self.buffer.update(ctx, |buffer, ctx| buffer.save(ctx))
1563 }
1564
1565 fn is_dirty(&self, ctx: &AppContext) -> bool {
1566 self.buffer.read(ctx).is_dirty()
1567 }
1568}
1569
1570#[cfg(test)]
1571mod tests {
1572 use super::*;
1573 use crate::{editor::Point, settings, test::sample_text};
1574 use gpui::App;
1575 use unindent::Unindent;
1576
1577 #[test]
1578 fn test_selection_with_mouse() {
1579 App::test((), |app| {
1580 let buffer =
1581 app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx));
1582 let settings = settings::channel(&app.font_cache()).unwrap().1;
1583 let (_, buffer_view) =
1584 app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
1585
1586 buffer_view.update(app, |view, ctx| {
1587 view.begin_selection(DisplayPoint::new(2, 2), false, ctx);
1588 });
1589
1590 let view = buffer_view.read(app);
1591 let selections = view
1592 .selections_in_range(
1593 DisplayPoint::zero()..view.max_point(app.as_ref()),
1594 app.as_ref(),
1595 )
1596 .collect::<Vec<_>>();
1597 assert_eq!(
1598 selections,
1599 [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
1600 );
1601
1602 buffer_view.update(app, |view, ctx| {
1603 view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
1604 });
1605
1606 let view = buffer_view.read(app);
1607 let selections = view
1608 .selections_in_range(
1609 DisplayPoint::zero()..view.max_point(app.as_ref()),
1610 app.as_ref(),
1611 )
1612 .collect::<Vec<_>>();
1613 assert_eq!(
1614 selections,
1615 [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
1616 );
1617
1618 buffer_view.update(app, |view, ctx| {
1619 view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx);
1620 });
1621
1622 let view = buffer_view.read(app);
1623 let selections = view
1624 .selections_in_range(
1625 DisplayPoint::zero()..view.max_point(app.as_ref()),
1626 app.as_ref(),
1627 )
1628 .collect::<Vec<_>>();
1629 assert_eq!(
1630 selections,
1631 [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
1632 );
1633
1634 buffer_view.update(app, |view, ctx| {
1635 view.end_selection(ctx);
1636 view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
1637 });
1638
1639 let view = buffer_view.read(app);
1640 let selections = view
1641 .selections_in_range(
1642 DisplayPoint::zero()..view.max_point(app.as_ref()),
1643 app.as_ref(),
1644 )
1645 .collect::<Vec<_>>();
1646 assert_eq!(
1647 selections,
1648 [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
1649 );
1650
1651 buffer_view.update(app, |view, ctx| {
1652 view.begin_selection(DisplayPoint::new(3, 3), true, ctx);
1653 view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), ctx);
1654 });
1655
1656 let view = buffer_view.read(app);
1657 let selections = view
1658 .selections_in_range(
1659 DisplayPoint::zero()..view.max_point(app.as_ref()),
1660 app.as_ref(),
1661 )
1662 .collect::<Vec<_>>();
1663 assert_eq!(
1664 selections,
1665 [
1666 DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1),
1667 DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)
1668 ]
1669 );
1670
1671 buffer_view.update(app, |view, ctx| {
1672 view.end_selection(ctx);
1673 });
1674
1675 let view = buffer_view.read(app);
1676 let selections = view
1677 .selections_in_range(
1678 DisplayPoint::zero()..view.max_point(app.as_ref()),
1679 app.as_ref(),
1680 )
1681 .collect::<Vec<_>>();
1682 assert_eq!(
1683 selections,
1684 [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)]
1685 );
1686 });
1687 }
1688
1689 #[test]
1690 fn test_layout_line_numbers() {
1691 App::test((), |app| {
1692 let layout_cache = TextLayoutCache::new(app.platform().fonts());
1693 let font_cache = app.font_cache().clone();
1694
1695 let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx));
1696
1697 let settings = settings::channel(&font_cache).unwrap().1;
1698 let (_, view) =
1699 app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1700
1701 let layouts = view
1702 .read(app)
1703 .layout_line_numbers(1000.0, &font_cache, &layout_cache, app.as_ref())
1704 .unwrap();
1705 assert_eq!(layouts.len(), 6);
1706 })
1707 }
1708
1709 #[test]
1710 fn test_fold() {
1711 App::test((), |app| {
1712 let buffer = app.add_model(|ctx| {
1713 Buffer::new(
1714 0,
1715 "
1716 impl Foo {
1717 // Hello!
1718
1719 fn a() {
1720 1
1721 }
1722
1723 fn b() {
1724 2
1725 }
1726
1727 fn c() {
1728 3
1729 }
1730 }
1731 "
1732 .unindent(),
1733 ctx,
1734 )
1735 });
1736 let settings = settings::channel(&app.font_cache()).unwrap().1;
1737 let (_, view) =
1738 app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1739
1740 view.update(app, |view, ctx| {
1741 view.select_display_ranges(
1742 &[DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)],
1743 ctx,
1744 )
1745 .unwrap();
1746 view.fold(&(), ctx);
1747 assert_eq!(
1748 view.text(ctx.as_ref()),
1749 "
1750 impl Foo {
1751 // Hello!
1752
1753 fn a() {
1754 1
1755 }
1756
1757 fn b() {…
1758 }
1759
1760 fn c() {…
1761 }
1762 }
1763 "
1764 .unindent(),
1765 );
1766
1767 view.fold(&(), ctx);
1768 assert_eq!(
1769 view.text(ctx.as_ref()),
1770 "
1771 impl Foo {…
1772 }
1773 "
1774 .unindent(),
1775 );
1776
1777 view.unfold(&(), ctx);
1778 assert_eq!(
1779 view.text(ctx.as_ref()),
1780 "
1781 impl Foo {
1782 // Hello!
1783
1784 fn a() {
1785 1
1786 }
1787
1788 fn b() {…
1789 }
1790
1791 fn c() {…
1792 }
1793 }
1794 "
1795 .unindent(),
1796 );
1797
1798 view.unfold(&(), ctx);
1799 assert_eq!(view.text(ctx.as_ref()), buffer.read(ctx).text());
1800 });
1801 });
1802 }
1803
1804 #[test]
1805 fn test_move_cursor() {
1806 App::test((), |app| {
1807 let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx));
1808 let settings = settings::channel(&app.font_cache()).unwrap().1;
1809 let (_, view) =
1810 app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1811
1812 buffer.update(app, |buffer, ctx| {
1813 buffer
1814 .edit(
1815 vec![
1816 Point::new(1, 0)..Point::new(1, 0),
1817 Point::new(1, 1)..Point::new(1, 1),
1818 ],
1819 "\t",
1820 Some(ctx),
1821 )
1822 .unwrap();
1823 });
1824
1825 view.update(app, |view, ctx| {
1826 view.move_down(&(), ctx);
1827 assert_eq!(
1828 view.selection_ranges(ctx.as_ref()),
1829 &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
1830 );
1831
1832 view.move_right(&(), ctx);
1833 assert_eq!(
1834 view.selection_ranges(ctx.as_ref()),
1835 &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)]
1836 );
1837
1838 view.move_left(&(), ctx);
1839 assert_eq!(
1840 view.selection_ranges(ctx.as_ref()),
1841 &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
1842 );
1843
1844 view.move_up(&(), ctx);
1845 assert_eq!(
1846 view.selection_ranges(ctx.as_ref()),
1847 &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
1848 );
1849
1850 view.move_to_end(&(), ctx);
1851 assert_eq!(
1852 view.selection_ranges(ctx.as_ref()),
1853 &[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 6)]
1854 );
1855
1856 view.move_to_beginning(&(), ctx);
1857 assert_eq!(
1858 view.selection_ranges(ctx.as_ref()),
1859 &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
1860 );
1861
1862 view.select_display_ranges(
1863 &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)],
1864 ctx,
1865 )
1866 .unwrap();
1867 view.select_to_beginning(&(), ctx);
1868 assert_eq!(
1869 view.selection_ranges(ctx.as_ref()),
1870 &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 0)]
1871 );
1872
1873 view.select_to_end(&(), ctx);
1874 assert_eq!(
1875 view.selection_ranges(ctx.as_ref()),
1876 &[DisplayPoint::new(0, 1)..DisplayPoint::new(5, 6)]
1877 );
1878 });
1879 });
1880 }
1881
1882 #[test]
1883 fn test_backspace() {
1884 App::test((), |app| {
1885 let buffer = app.add_model(|ctx| {
1886 Buffer::new(
1887 0,
1888 "one two three\nfour five six\nseven eight nine\nten\n",
1889 ctx,
1890 )
1891 });
1892 let settings = settings::channel(&app.font_cache()).unwrap().1;
1893 let (_, view) =
1894 app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1895
1896 view.update(app, |view, ctx| {
1897 view.select_display_ranges(
1898 &[
1899 // an empty selection - the preceding character is deleted
1900 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
1901 // one character selected - it is deleted
1902 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 4),
1903 // a line suffix selected - it is deleted
1904 DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
1905 ],
1906 ctx,
1907 )
1908 .unwrap();
1909 view.backspace(&(), ctx);
1910 });
1911
1912 assert_eq!(
1913 buffer.read(app).text(),
1914 "oe two three\nfou five six\nseven ten\n"
1915 );
1916 })
1917 }
1918
1919 #[test]
1920 fn test_delete() {
1921 App::test((), |app| {
1922 let buffer = app.add_model(|ctx| {
1923 Buffer::new(
1924 0,
1925 "one two three\nfour five six\nseven eight nine\nten\n",
1926 ctx,
1927 )
1928 });
1929 let settings = settings::channel(&app.font_cache()).unwrap().1;
1930 let (_, view) =
1931 app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1932
1933 view.update(app, |view, ctx| {
1934 view.select_display_ranges(
1935 &[
1936 // an empty selection - the following character is deleted
1937 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
1938 // one character selected - it is deleted
1939 DisplayPoint::new(1, 3)..DisplayPoint::new(1, 4),
1940 // a line suffix selected - it is deleted
1941 DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
1942 ],
1943 ctx,
1944 )
1945 .unwrap();
1946 view.delete(&(), ctx);
1947 });
1948
1949 assert_eq!(
1950 buffer.read(app).text(),
1951 "on two three\nfou five six\nseven ten\n"
1952 );
1953 })
1954 }
1955
1956 #[test]
1957 fn test_delete_line() {
1958 App::test((), |app| {
1959 let settings = settings::channel(&app.font_cache()).unwrap().1;
1960 let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx));
1961 let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
1962 view.update(app, |view, ctx| {
1963 view.select_display_ranges(
1964 &[
1965 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
1966 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
1967 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
1968 ],
1969 ctx,
1970 )
1971 .unwrap();
1972 view.delete_line(&(), ctx);
1973 });
1974 assert_eq!(view.read(app).text(app.as_ref()), "ghi");
1975 assert_eq!(
1976 view.read(app).selection_ranges(app.as_ref()),
1977 vec![
1978 DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
1979 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)
1980 ]
1981 );
1982
1983 let settings = settings::channel(&app.font_cache()).unwrap().1;
1984 let buffer = app.add_model(|ctx| Buffer::new(0, "abc\ndef\nghi\n", ctx));
1985 let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
1986 view.update(app, |view, ctx| {
1987 view.select_display_ranges(
1988 &[DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)],
1989 ctx,
1990 )
1991 .unwrap();
1992 view.delete_line(&(), ctx);
1993 });
1994 assert_eq!(view.read(app).text(app.as_ref()), "ghi\n");
1995 assert_eq!(
1996 view.read(app).selection_ranges(app.as_ref()),
1997 vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)]
1998 );
1999 });
2000 }
2001
2002 #[test]
2003 fn test_clipboard() {
2004 App::test((), |app| {
2005 let buffer = app.add_model(|ctx| Buffer::new(0, "one two three four five six ", ctx));
2006 let settings = settings::channel(&app.font_cache()).unwrap().1;
2007 let view = app
2008 .add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx))
2009 .1;
2010
2011 // Cut with three selections. Clipboard text is divided into three slices.
2012 view.update(app, |view, ctx| {
2013 view.select_ranges(&[0..4, 8..14, 19..24], ctx).unwrap();
2014 view.cut(&(), ctx);
2015 });
2016 assert_eq!(view.read(app).text(app.as_ref()), "two four six ");
2017
2018 // Paste with three cursors. Each cursor pastes one slice of the clipboard text.
2019 view.update(app, |view, ctx| {
2020 view.select_ranges(&[4..4, 9..9, 13..13], ctx).unwrap();
2021 view.paste(&(), ctx);
2022 });
2023 assert_eq!(
2024 view.read(app).text(app.as_ref()),
2025 "two one four three six five "
2026 );
2027 assert_eq!(
2028 view.read(app).selection_ranges(app.as_ref()),
2029 &[
2030 DisplayPoint::new(0, 8)..DisplayPoint::new(0, 8),
2031 DisplayPoint::new(0, 19)..DisplayPoint::new(0, 19),
2032 DisplayPoint::new(0, 28)..DisplayPoint::new(0, 28)
2033 ]
2034 );
2035
2036 // Paste again but with only two cursors. Since the number of cursors doesn't
2037 // match the number of slices in the clipboard, the entire clipboard text
2038 // is pasted at each cursor.
2039 view.update(app, |view, ctx| {
2040 view.select_ranges(&[0..0, 28..28], ctx).unwrap();
2041 view.insert(&"( ".to_string(), ctx);
2042 view.paste(&(), ctx);
2043 view.insert(&") ".to_string(), ctx);
2044 });
2045 assert_eq!(
2046 view.read(app).text(app.as_ref()),
2047 "( one three five ) two one four three six five ( one three five ) "
2048 );
2049
2050 view.update(app, |view, ctx| {
2051 view.select_ranges(&[0..0], ctx).unwrap();
2052 view.insert(&"123\n4567\n89\n".to_string(), ctx);
2053 });
2054 assert_eq!(
2055 view.read(app).text(app.as_ref()),
2056 "123\n4567\n89\n( one three five ) two one four three six five ( one three five ) "
2057 );
2058
2059 // Cut with three selections, one of which is full-line.
2060 view.update(app, |view, ctx| {
2061 view.select_display_ranges(
2062 &[
2063 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2),
2064 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
2065 DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1),
2066 ],
2067 ctx,
2068 )
2069 .unwrap();
2070 view.cut(&(), ctx);
2071 });
2072 assert_eq!(
2073 view.read(app).text(app.as_ref()),
2074 "13\n9\n( one three five ) two one four three six five ( one three five ) "
2075 );
2076
2077 // Paste with three selections, noticing how the copied selection that was full-line
2078 // gets inserted before the second cursor.
2079 view.update(app, |view, ctx| {
2080 view.select_display_ranges(
2081 &[
2082 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
2083 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
2084 DisplayPoint::new(2, 2)..DisplayPoint::new(2, 3),
2085 ],
2086 ctx,
2087 )
2088 .unwrap();
2089 view.paste(&(), ctx);
2090 });
2091 assert_eq!(
2092 view.read(app).text(app.as_ref()),
2093 "123\n4567\n9\n( 8ne three five ) two one four three six five ( one three five ) "
2094 );
2095 assert_eq!(
2096 view.read(app).selection_ranges(app.as_ref()),
2097 &[
2098 DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
2099 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
2100 DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3),
2101 ]
2102 );
2103
2104 // Copy with a single cursor only, which writes the whole line into the clipboard.
2105 view.update(app, |view, ctx| {
2106 view.select_display_ranges(
2107 &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)],
2108 ctx,
2109 )
2110 .unwrap();
2111 view.copy(&(), ctx);
2112 });
2113
2114 // Paste with three selections, noticing how the copied full-line selection is inserted
2115 // before the empty selections but replaces the selection that is non-empty.
2116 view.update(app, |view, ctx| {
2117 view.select_display_ranges(
2118 &[
2119 DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
2120 DisplayPoint::new(1, 0)..DisplayPoint::new(1, 2),
2121 DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
2122 ],
2123 ctx,
2124 )
2125 .unwrap();
2126 view.paste(&(), ctx);
2127 });
2128 assert_eq!(
2129 view.read(app).text(app.as_ref()),
2130 "123\n123\n123\n67\n123\n9\n( 8ne three five ) two one four three six five ( one three five ) "
2131 );
2132 assert_eq!(
2133 view.read(app).selection_ranges(app.as_ref()),
2134 &[
2135 DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
2136 DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
2137 DisplayPoint::new(5, 1)..DisplayPoint::new(5, 1),
2138 ]
2139 );
2140 });
2141 }
2142
2143 #[test]
2144 fn test_select_all() {
2145 App::test((), |app| {
2146 let buffer = app.add_model(|ctx| Buffer::new(0, "abc\nde\nfgh", ctx));
2147 let settings = settings::channel(&app.font_cache()).unwrap().1;
2148 let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
2149 view.update(app, |b, ctx| b.select_all(&(), ctx));
2150 assert_eq!(
2151 view.read(app).selection_ranges(app.as_ref()),
2152 &[DisplayPoint::new(0, 0)..DisplayPoint::new(2, 3)]
2153 );
2154 });
2155 }
2156
2157 impl BufferView {
2158 fn selection_ranges(&self, app: &AppContext) -> Vec<Range<DisplayPoint>> {
2159 self.selections_in_range(DisplayPoint::zero()..self.max_point(app), app)
2160 .collect::<Vec<_>>()
2161 }
2162 }
2163}