1use super::{
2 buffer, movement, Anchor, Bias, Buffer, BufferElement, DisplayMap, DisplayPoint, Point,
3 ToOffset, ToPoint,
4};
5use crate::{settings::Settings, watch, workspace};
6use anyhow::Result;
7use easy_parallel::Parallel;
8use gpui::{
9 fonts::Properties as FontProperties, keymap::Binding, text_layout, App, AppContext, Element,
10 ElementBox, Entity, FontCache, ModelHandle, View, ViewContext, WeakViewHandle,
11};
12use gpui::{geometry::vector::Vector2F, TextLayoutCache};
13use parking_lot::Mutex;
14use smallvec::SmallVec;
15use smol::Timer;
16use std::{
17 cmp::{self, Ordering},
18 fmt::Write,
19 mem,
20 ops::Range,
21 sync::Arc,
22 time::Duration,
23};
24
25const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
26
27pub fn init(app: &mut App) {
28 app.add_bindings(vec![
29 Binding::new("backspace", "buffer:backspace", Some("BufferView")),
30 Binding::new("enter", "buffer:newline", Some("BufferView")),
31 Binding::new("up", "buffer:move_up", Some("BufferView")),
32 Binding::new("down", "buffer:move_down", Some("BufferView")),
33 Binding::new("left", "buffer:move_left", Some("BufferView")),
34 Binding::new("right", "buffer:move_right", Some("BufferView")),
35 Binding::new("shift-up", "buffer:select_up", Some("BufferView")),
36 Binding::new("shift-down", "buffer:select_down", Some("BufferView")),
37 Binding::new("shift-left", "buffer:select_left", Some("BufferView")),
38 Binding::new("shift-right", "buffer:select_right", Some("BufferView")),
39 Binding::new("pageup", "buffer:page_up", Some("BufferView")),
40 Binding::new("pagedown", "buffer:page_down", Some("BufferView")),
41 Binding::new("alt-cmd-[", "buffer:fold", Some("BufferView")),
42 Binding::new("alt-cmd-]", "buffer:unfold", Some("BufferView")),
43 Binding::new(
44 "alt-cmd-f",
45 "buffer:fold_selected_ranges",
46 Some("BufferView"),
47 ),
48 ]);
49
50 app.add_action("buffer:scroll", BufferView::scroll);
51 app.add_action("buffer:select", BufferView::select);
52 app.add_action("buffer:insert", BufferView::insert);
53 app.add_action("buffer:newline", BufferView::newline);
54 app.add_action("buffer:backspace", BufferView::backspace);
55 app.add_action("buffer:move_up", BufferView::move_up);
56 app.add_action("buffer:move_down", BufferView::move_down);
57 app.add_action("buffer:move_left", BufferView::move_left);
58 app.add_action("buffer:move_right", BufferView::move_right);
59 app.add_action("buffer:select_up", BufferView::select_up);
60 app.add_action("buffer:select_down", BufferView::select_down);
61 app.add_action("buffer:select_left", BufferView::select_left);
62 app.add_action("buffer:select_right", BufferView::select_right);
63 app.add_action("buffer:page_up", BufferView::page_up);
64 app.add_action("buffer:page_down", BufferView::page_down);
65 app.add_action("buffer:fold", BufferView::fold);
66 app.add_action("buffer:unfold", BufferView::unfold);
67 app.add_action(
68 "buffer:fold_selected_ranges",
69 BufferView::fold_selected_ranges,
70 );
71}
72
73pub enum SelectAction {
74 Begin {
75 position: DisplayPoint,
76 add: bool,
77 },
78 Update {
79 position: DisplayPoint,
80 scroll_position: Vector2F,
81 },
82 End,
83}
84
85// impl workspace::Item for Buffer {
86// type View = BufferView;
87
88// fn build_view(
89// buffer: ModelHandle<Self>,
90// settings: watch::Receiver<Settings>,
91// ctx: &mut ViewContext<Self::View>,
92// ) -> Self::View {
93// BufferView::for_buffer(buffer, settings, ctx)
94// }
95// }
96
97pub struct BufferView {
98 handle: WeakViewHandle<Self>,
99 buffer: ModelHandle<Buffer>,
100 display_map: ModelHandle<DisplayMap>,
101 selections: Vec<Selection>,
102 pending_selection: Option<Selection>,
103 scroll_position: Mutex<Vector2F>,
104 autoscroll_requested: Mutex<bool>,
105 settings: watch::Receiver<Settings>,
106 focused: bool,
107 cursors_visible: bool,
108 blink_epoch: usize,
109 blinking_paused: bool,
110 single_line: bool,
111}
112
113impl BufferView {
114 pub fn single_line(settings: watch::Receiver<Settings>, ctx: &mut ViewContext<Self>) -> Self {
115 let buffer = ctx.add_model(|_| Buffer::new(0, String::new()));
116 let mut view = Self::for_buffer(buffer, settings, ctx);
117 view.single_line = true;
118 view
119 }
120
121 pub fn for_buffer(
122 buffer: ModelHandle<Buffer>,
123 settings: watch::Receiver<Settings>,
124 ctx: &mut ViewContext<Self>,
125 ) -> Self {
126 settings.notify_view_on_change(ctx);
127
128 ctx.observe(&buffer, Self::on_buffer_changed);
129 ctx.subscribe_to_model(&buffer, Self::on_buffer_event);
130 let display_map = ctx.add_model(|ctx| {
131 DisplayMap::new(
132 buffer.clone(),
133 smol::block_on(settings.read()).tab_size,
134 ctx,
135 )
136 });
137 ctx.observe(&display_map, Self::on_display_map_changed);
138
139 let buffer_ref = buffer.as_ref(ctx);
140 Self {
141 handle: ctx.handle(),
142 buffer,
143 display_map,
144 selections: vec![Selection {
145 start: buffer_ref.anchor_before(0).unwrap(),
146 end: buffer_ref.anchor_before(0).unwrap(),
147 reversed: false,
148 goal_column: None,
149 }],
150 pending_selection: None,
151 scroll_position: Mutex::new(Vector2F::zero()),
152 autoscroll_requested: Mutex::new(false),
153 settings,
154 focused: false,
155 cursors_visible: false,
156 blink_epoch: 0,
157 blinking_paused: false,
158 single_line: false,
159 }
160 }
161
162 pub fn buffer(&self) -> &ModelHandle<Buffer> {
163 &self.buffer
164 }
165
166 pub fn is_gutter_visible(&self) -> bool {
167 !self.single_line
168 }
169
170 fn scroll(&mut self, scroll_position: &Vector2F, ctx: &mut ViewContext<Self>) {
171 *self.scroll_position.lock() = *scroll_position;
172 ctx.notify();
173 }
174
175 pub fn scroll_position(&self) -> Vector2F {
176 *self.scroll_position.lock()
177 }
178
179 pub fn clamp_scroll_left(&self, max: f32) {
180 let mut scroll_position = self.scroll_position.lock();
181 let scroll_left = scroll_position.x();
182 scroll_position.set_x(scroll_left.min(max));
183 }
184
185 pub fn autoscroll_vertically(
186 &self,
187 viewport_height: f32,
188 line_height: f32,
189 app: &AppContext,
190 ) -> bool {
191 let mut scroll_position = self.scroll_position.lock();
192 let scroll_top = scroll_position.y();
193 scroll_position.set_y(scroll_top.min(self.max_point(app).row().saturating_sub(1) as f32));
194
195 let mut autoscroll_requested = self.autoscroll_requested.lock();
196 if *autoscroll_requested {
197 *autoscroll_requested = false;
198 } else {
199 return false;
200 }
201
202 let map = self.display_map.as_ref(app);
203 let visible_lines = viewport_height / line_height;
204 let first_cursor_top = self
205 .selections
206 .first()
207 .unwrap()
208 .head()
209 .to_display_point(map, app)
210 .unwrap()
211 .row() as f32;
212 let last_cursor_bottom = self
213 .selections
214 .last()
215 .unwrap()
216 .head()
217 .to_display_point(map, app)
218 .unwrap()
219 .row() as f32
220 + 1.0;
221
222 let margin = ((visible_lines - (last_cursor_bottom - first_cursor_top)) / 2.0)
223 .floor()
224 .min(3.0);
225 if margin < 0.0 {
226 return false;
227 }
228
229 let target_top = (first_cursor_top - margin).max(0.0);
230 let target_bottom = last_cursor_bottom + margin;
231 let start_row = scroll_position.y();
232 let end_row = start_row + visible_lines;
233
234 if target_top < start_row {
235 scroll_position.set_y(target_top);
236 } else if target_bottom >= end_row {
237 scroll_position.set_y(target_bottom - visible_lines);
238 }
239
240 true
241 }
242
243 pub fn autoscroll_horizontally(
244 &self,
245 start_row: u32,
246 viewport_width: f32,
247 scroll_width: f32,
248 max_glyph_width: f32,
249 layouts: &[Arc<text_layout::Line>],
250 app: &AppContext,
251 ) {
252 let map = self.display_map.as_ref(app);
253
254 let mut target_left = std::f32::INFINITY;
255 let mut target_right = 0.0_f32;
256 for selection in &self.selections {
257 let head = selection.head().to_display_point(map, app).unwrap();
258 let start_column = head.column().saturating_sub(3);
259 let end_column = cmp::min(map.line_len(head.row(), app).unwrap(), head.column() + 3);
260 target_left = target_left
261 .min(layouts[(head.row() - start_row) as usize].x_for_index(start_column as usize));
262 target_right = target_right.max(
263 layouts[(head.row() - start_row) as usize].x_for_index(end_column as usize)
264 + max_glyph_width,
265 );
266 }
267 target_right = target_right.min(scroll_width);
268
269 if target_right - target_left > viewport_width {
270 return;
271 }
272
273 let mut scroll_position = self.scroll_position.lock();
274 let scroll_left = scroll_position.x() * max_glyph_width;
275 let scroll_right = scroll_left + viewport_width;
276
277 if target_left < scroll_left {
278 scroll_position.set_x(target_left / max_glyph_width);
279 } else if target_right > scroll_right {
280 scroll_position.set_x((target_right - viewport_width) / max_glyph_width);
281 }
282 }
283
284 fn select(&mut self, arg: &SelectAction, ctx: &mut ViewContext<Self>) {
285 match arg {
286 SelectAction::Begin { position, add } => self.begin_selection(*position, *add, ctx),
287 SelectAction::Update {
288 position,
289 scroll_position,
290 } => self.update_selection(*position, *scroll_position, ctx),
291 SelectAction::End => self.end_selection(ctx),
292 }
293 }
294
295 fn begin_selection(&mut self, position: DisplayPoint, add: bool, ctx: &mut ViewContext<Self>) {
296 if !self.focused {
297 ctx.focus_self();
298 ctx.emit(Event::Activate);
299 }
300
301 let display_map = self.display_map.as_ref(ctx);
302 let cursor = display_map
303 .anchor_before(position, Bias::Left, ctx.app())
304 .unwrap();
305 let selection = Selection {
306 start: cursor.clone(),
307 end: cursor,
308 reversed: false,
309 goal_column: None,
310 };
311
312 if !add {
313 self.selections.clear();
314 }
315 self.pending_selection = Some(selection);
316
317 ctx.notify();
318 }
319
320 fn update_selection(
321 &mut self,
322 position: DisplayPoint,
323 scroll_position: Vector2F,
324 ctx: &mut ViewContext<Self>,
325 ) {
326 let buffer = self.buffer.as_ref(ctx);
327 let map = self.display_map.as_ref(ctx);
328 let cursor = map.anchor_before(position, Bias::Left, ctx.app()).unwrap();
329 if let Some(selection) = self.pending_selection.as_mut() {
330 selection.set_head(buffer, cursor);
331 } else {
332 log::error!("update_selection dispatched with no pending selection");
333 return;
334 }
335
336 *self.scroll_position.lock() = scroll_position;
337
338 ctx.notify();
339 }
340
341 fn end_selection(&mut self, ctx: &mut ViewContext<Self>) {
342 if let Some(selection) = self.pending_selection.take() {
343 let ix = self.selection_insertion_index(&selection.start, ctx.app());
344 self.selections.insert(ix, selection);
345 self.merge_selections(ctx.app());
346 ctx.notify();
347 } else {
348 log::error!("end_selection dispatched with no pending selection");
349 }
350 }
351
352 pub fn is_selecting(&self) -> bool {
353 self.pending_selection.is_some()
354 }
355
356 #[cfg(test)]
357 fn select_ranges<T>(&mut self, ranges: T, ctx: &mut ViewContext<Self>) -> Result<()>
358 where
359 T: IntoIterator<Item = Range<DisplayPoint>>,
360 {
361 let buffer = self.buffer.as_ref(ctx);
362 let map = self.display_map.as_ref(ctx);
363 let mut selections = Vec::new();
364 for range in ranges {
365 selections.push(Selection {
366 start: map.anchor_after(range.start, Bias::Left, ctx.app())?,
367 end: map.anchor_before(range.end, Bias::Left, ctx.app())?,
368 reversed: false,
369 goal_column: None,
370 });
371 }
372 selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer).unwrap());
373 self.selections = selections;
374 self.merge_selections(ctx.app());
375 ctx.notify();
376 Ok(())
377 }
378
379 fn insert(&mut self, text: &String, ctx: &mut ViewContext<Self>) {
380 let buffer = self.buffer.as_ref(ctx);
381 let mut offset_ranges = SmallVec::<[Range<usize>; 32]>::new();
382 for selection in &self.selections {
383 let start = selection.start.to_offset(buffer).unwrap();
384 let end = selection.end.to_offset(buffer).unwrap();
385 offset_ranges.push(start..end);
386 }
387
388 self.buffer.update(ctx, |buffer, ctx| {
389 if let Err(error) = buffer.edit(offset_ranges.iter().cloned(), text.as_str(), Some(ctx))
390 {
391 log::error!("error inserting text: {}", error);
392 };
393 });
394
395 let buffer = self.buffer.as_ref(ctx);
396 let char_count = text.chars().count() as isize;
397 let mut delta = 0_isize;
398 self.selections = offset_ranges
399 .into_iter()
400 .map(|range| {
401 let start = range.start as isize;
402 let end = range.end as isize;
403 let anchor = buffer
404 .anchor_before((start + delta + char_count) as usize)
405 .unwrap();
406 let deleted_count = end - start;
407 delta += char_count - deleted_count;
408 Selection {
409 start: anchor.clone(),
410 end: anchor,
411 reversed: false,
412 goal_column: None,
413 }
414 })
415 .collect();
416
417 self.pause_cursor_blinking(ctx);
418 *self.autoscroll_requested.lock() = true;
419 }
420
421 fn newline(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
422 if self.single_line {
423 ctx.propagate_action();
424 } else {
425 self.insert(&"\n".into(), ctx);
426 }
427 }
428
429 pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
430 self.select_left(&(), ctx);
431 self.insert(&String::new(), ctx);
432 }
433
434 pub fn move_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
435 {
436 let app = ctx.app();
437 let map = self.display_map.as_ref(ctx);
438 for selection in &mut self.selections {
439 let start = selection.start.to_display_point(map, app).unwrap();
440 let end = selection.end.to_display_point(map, app).unwrap();
441
442 if start != end {
443 selection.end = selection.start.clone();
444 } else {
445 let cursor = map
446 .anchor_before(movement::left(map, start, app).unwrap(), Bias::Left, app)
447 .unwrap();
448 selection.start = cursor.clone();
449 selection.end = cursor;
450 }
451 selection.reversed = false;
452 selection.goal_column = None;
453 }
454 }
455 self.changed_selections(ctx);
456 }
457
458 pub fn select_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
459 {
460 let buffer = self.buffer.as_ref(ctx);
461 let map = self.display_map.as_ref(ctx);
462 for selection in &mut self.selections {
463 let head = selection.head().to_display_point(map, ctx.app()).unwrap();
464 let cursor = map
465 .anchor_before(
466 movement::left(map, head, ctx.app()).unwrap(),
467 Bias::Left,
468 ctx.app(),
469 )
470 .unwrap();
471 selection.set_head(&buffer, cursor);
472 selection.goal_column = None;
473 }
474 }
475 self.changed_selections(ctx);
476 }
477
478 pub fn move_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
479 {
480 let app = ctx.app();
481 let map = self.display_map.as_ref(app);
482 for selection in &mut self.selections {
483 let start = selection.start.to_display_point(map, app).unwrap();
484 let end = selection.end.to_display_point(map, app).unwrap();
485
486 if start != end {
487 selection.start = selection.end.clone();
488 } else {
489 let cursor = map
490 .anchor_before(movement::right(map, end, app).unwrap(), Bias::Right, app)
491 .unwrap();
492 selection.start = cursor.clone();
493 selection.end = cursor;
494 }
495 selection.reversed = false;
496 selection.goal_column = None;
497 }
498 }
499 self.changed_selections(ctx);
500 }
501
502 pub fn select_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
503 {
504 let buffer = self.buffer.as_ref(ctx);
505 let app = ctx.app();
506 let map = self.display_map.as_ref(app);
507 for selection in &mut self.selections {
508 let head = selection.head().to_display_point(map, ctx.app()).unwrap();
509 let cursor = map
510 .anchor_before(movement::right(map, head, app).unwrap(), Bias::Right, app)
511 .unwrap();
512 selection.set_head(&buffer, cursor);
513 selection.goal_column = None;
514 }
515 }
516 self.changed_selections(ctx);
517 }
518
519 pub fn move_up(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
520 if self.single_line {
521 ctx.propagate_action();
522 } else {
523 let app = ctx.app();
524 let map = self.display_map.as_ref(app);
525 for selection in &mut self.selections {
526 let start = selection.start.to_display_point(map, app).unwrap();
527 let end = selection.end.to_display_point(map, app).unwrap();
528 if start != end {
529 selection.goal_column = None;
530 }
531
532 let (start, goal_column) =
533 movement::up(map, start, selection.goal_column, app).unwrap();
534 let cursor = map.anchor_before(start, Bias::Left, app).unwrap();
535 selection.start = cursor.clone();
536 selection.end = cursor;
537 selection.goal_column = goal_column;
538 selection.reversed = false;
539 }
540 self.changed_selections(ctx);
541 }
542 }
543
544 pub fn select_up(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
545 if self.single_line {
546 ctx.propagate_action();
547 } else {
548 let app = ctx.app();
549 let buffer = self.buffer.as_ref(app);
550 let map = self.display_map.as_ref(app);
551 for selection in &mut self.selections {
552 let head = selection.head().to_display_point(map, app).unwrap();
553 let (head, goal_column) =
554 movement::up(map, head, selection.goal_column, app).unwrap();
555 selection.set_head(&buffer, map.anchor_before(head, Bias::Left, app).unwrap());
556 selection.goal_column = goal_column;
557 }
558 self.changed_selections(ctx);
559 }
560 }
561
562 pub fn move_down(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
563 if self.single_line {
564 ctx.propagate_action();
565 } else {
566 let app = ctx.app();
567 let map = self.display_map.as_ref(app);
568 for selection in &mut self.selections {
569 let start = selection.start.to_display_point(map, app).unwrap();
570 let end = selection.end.to_display_point(map, app).unwrap();
571 if start != end {
572 selection.goal_column = None;
573 }
574
575 let (start, goal_column) =
576 movement::down(map, end, selection.goal_column, app).unwrap();
577 let cursor = map.anchor_before(start, Bias::Right, app).unwrap();
578 selection.start = cursor.clone();
579 selection.end = cursor;
580 selection.goal_column = goal_column;
581 selection.reversed = false;
582 }
583 self.changed_selections(ctx);
584 }
585 }
586
587 pub fn select_down(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
588 if self.single_line {
589 ctx.propagate_action();
590 } else {
591 let app = ctx.app();
592 let buffer = self.buffer.as_ref(ctx);
593 let map = self.display_map.as_ref(ctx);
594 for selection in &mut self.selections {
595 let head = selection.head().to_display_point(map, app).unwrap();
596 let (head, goal_column) =
597 movement::down(map, head, selection.goal_column, app).unwrap();
598 selection.set_head(&buffer, map.anchor_before(head, Bias::Right, app).unwrap());
599 selection.goal_column = goal_column;
600 }
601 self.changed_selections(ctx);
602 }
603 }
604
605 pub fn changed_selections(&mut self, ctx: &mut ViewContext<Self>) {
606 self.merge_selections(ctx.app());
607 self.pause_cursor_blinking(ctx);
608 *self.autoscroll_requested.lock() = true;
609 ctx.notify();
610 }
611
612 fn merge_selections(&mut self, ctx: &AppContext) {
613 let buffer = self.buffer.as_ref(ctx);
614 let mut i = 1;
615 while i < self.selections.len() {
616 if self.selections[i - 1]
617 .end
618 .cmp(&self.selections[i].start, buffer)
619 .unwrap()
620 >= Ordering::Equal
621 {
622 let removed = self.selections.remove(i);
623 if removed
624 .start
625 .cmp(&self.selections[i - 1].start, buffer)
626 .unwrap()
627 < Ordering::Equal
628 {
629 self.selections[i - 1].start = removed.start;
630 }
631 if removed
632 .end
633 .cmp(&self.selections[i - 1].end, buffer)
634 .unwrap()
635 > Ordering::Equal
636 {
637 self.selections[i - 1].end = removed.end;
638 }
639 } else {
640 i += 1;
641 }
642 }
643 }
644
645 pub fn first_selection(&self, app: &AppContext) -> Range<DisplayPoint> {
646 self.selections
647 .first()
648 .unwrap()
649 .display_range(self.display_map.as_ref(app), app)
650 }
651
652 pub fn last_selection(&self, app: &AppContext) -> Range<DisplayPoint> {
653 self.selections
654 .last()
655 .unwrap()
656 .display_range(self.display_map.as_ref(app), app)
657 }
658
659 pub fn selections_in_range<'a>(
660 &'a self,
661 range: Range<DisplayPoint>,
662 app: &'a AppContext,
663 ) -> impl 'a + Iterator<Item = Range<DisplayPoint>> {
664 let map = self.display_map.as_ref(app);
665
666 let start = map.anchor_before(range.start, Bias::Left, app).unwrap();
667 let start_index = self.selection_insertion_index(&start, app);
668 let pending_selection = self.pending_selection.as_ref().and_then(|s| {
669 let selection_range = s.display_range(map, app);
670 if selection_range.start <= range.end || selection_range.end <= range.end {
671 Some(selection_range)
672 } else {
673 None
674 }
675 });
676 self.selections[start_index..]
677 .iter()
678 .map(move |s| s.display_range(map, app))
679 .take_while(move |r| r.start <= range.end || r.end <= range.end)
680 .chain(pending_selection)
681 }
682
683 fn selection_insertion_index(&self, start: &Anchor, app: &AppContext) -> usize {
684 let buffer = self.buffer.as_ref(app);
685
686 match self
687 .selections
688 .binary_search_by(|probe| probe.start.cmp(&start, buffer).unwrap())
689 {
690 Ok(index) => index,
691 Err(index) => {
692 if index > 0
693 && self.selections[index - 1].end.cmp(&start, buffer).unwrap()
694 == Ordering::Greater
695 {
696 index - 1
697 } else {
698 index
699 }
700 }
701 }
702 }
703
704 pub fn page_up(&mut self, _: &(), _: &mut ViewContext<Self>) {
705 log::info!("BufferView::page_up");
706 }
707
708 pub fn page_down(&mut self, _: &(), _: &mut ViewContext<Self>) {
709 log::info!("BufferView::page_down");
710 }
711
712 pub fn fold(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
713 use super::RangeExt;
714
715 let mut fold_ranges = Vec::new();
716
717 let app = ctx.app();
718 let map = self.display_map.as_ref(app);
719 for selection in &self.selections {
720 let (start, end) = selection.display_range(map, app).sorted();
721 let buffer_start_row = start.to_buffer_point(map, Bias::Left, app).unwrap().row;
722
723 for row in (0..=end.row()).rev() {
724 if self.is_line_foldable(row, app) && !map.is_line_folded(row) {
725 let fold_range = self.foldable_range_for_line(row, app).unwrap();
726 if fold_range.end.row >= buffer_start_row {
727 fold_ranges.push(fold_range);
728 if row <= start.row() {
729 break;
730 }
731 }
732 }
733 }
734 }
735
736 if !fold_ranges.is_empty() {
737 self.display_map.update(ctx, |map, ctx| {
738 map.fold(fold_ranges, ctx).unwrap();
739 });
740 *self.autoscroll_requested.lock() = true;
741 }
742 }
743
744 pub fn unfold(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
745 use super::RangeExt;
746
747 let app = ctx.app();
748 let map = self.display_map.as_ref(app);
749 let buffer = self.buffer.as_ref(app);
750 let ranges = self
751 .selections
752 .iter()
753 .map(|s| {
754 let (start, end) = s.display_range(map, app).sorted();
755 let mut start = start.to_buffer_point(map, Bias::Left, app).unwrap();
756 let mut end = end.to_buffer_point(map, Bias::Left, app).unwrap();
757 start.column = 0;
758 end.column = buffer.line_len(end.row).unwrap();
759 start..end
760 })
761 .collect::<Vec<_>>();
762
763 self.display_map.update(ctx, |map, ctx| {
764 map.unfold(ranges, ctx).unwrap();
765 });
766 *self.autoscroll_requested.lock() = true;
767 }
768
769 fn is_line_foldable(&self, display_row: u32, app: &AppContext) -> bool {
770 let max_point = self.max_point(app);
771 if display_row >= max_point.row() {
772 false
773 } else {
774 let (start_indent, is_blank) = self.line_indent(display_row, app).unwrap();
775 if is_blank {
776 false
777 } else {
778 for display_row in display_row + 1..=max_point.row() {
779 let (indent, is_blank) = self.line_indent(display_row, app).unwrap();
780 if !is_blank {
781 return indent > start_indent;
782 }
783 }
784 false
785 }
786 }
787 }
788
789 fn line_indent(&self, display_row: u32, app: &AppContext) -> Result<(usize, bool)> {
790 let mut indent = 0;
791 let mut is_blank = true;
792 for c in self
793 .display_map
794 .as_ref(app)
795 .chars_at(DisplayPoint::new(display_row, 0), app)?
796 {
797 if c == ' ' {
798 indent += 1;
799 } else {
800 is_blank = c == '\n';
801 break;
802 }
803 }
804 Ok((indent, is_blank))
805 }
806
807 fn foldable_range_for_line(&self, start_row: u32, app: &AppContext) -> Result<Range<Point>> {
808 let map = self.display_map.as_ref(app);
809 let max_point = self.max_point(app);
810
811 let (start_indent, _) = self.line_indent(start_row, app)?;
812 let start = DisplayPoint::new(start_row, self.line_len(start_row, app)?);
813 let mut end = None;
814 for row in start_row + 1..=max_point.row() {
815 let (indent, is_blank) = self.line_indent(row, app)?;
816 if !is_blank && indent <= start_indent {
817 end = Some(DisplayPoint::new(row - 1, self.line_len(row - 1, app)?));
818 break;
819 }
820 }
821
822 let end = end.unwrap_or(max_point);
823 return Ok(start.to_buffer_point(map, Bias::Left, app)?
824 ..end.to_buffer_point(map, Bias::Left, app)?);
825 }
826
827 pub fn fold_selected_ranges(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
828 self.display_map.update(ctx, |map, ctx| {
829 let buffer = self.buffer.as_ref(ctx);
830 let ranges = self
831 .selections
832 .iter()
833 .map(|s| s.range(buffer))
834 .collect::<Vec<_>>();
835 map.fold(ranges, ctx).unwrap();
836 });
837 }
838
839 pub fn line(&self, display_row: u32, app: &AppContext) -> Result<String> {
840 self.display_map.as_ref(app).line(display_row, app)
841 }
842
843 pub fn line_len(&self, display_row: u32, app: &AppContext) -> Result<u32> {
844 self.display_map.as_ref(app).line_len(display_row, app)
845 }
846
847 pub fn rightmost_point(&self, app: &AppContext) -> DisplayPoint {
848 self.display_map.as_ref(app).rightmost_point()
849 }
850
851 pub fn max_point(&self, app: &AppContext) -> DisplayPoint {
852 self.display_map.as_ref(app).max_point(app)
853 }
854
855 pub fn text(&self, app: &AppContext) -> String {
856 self.display_map.as_ref(app).text(app)
857 }
858
859 pub fn font_size(&self) -> f32 {
860 smol::block_on(self.settings.read()).buffer_font_size
861 }
862
863 pub fn font_ascent(&self, font_cache: &FontCache) -> f32 {
864 let settings = smol::block_on(self.settings.read());
865 let font_id = font_cache.default_font(settings.buffer_font_family);
866 let ascent = font_cache.metric(font_id, |m| m.ascent);
867 font_cache.scale_metric(ascent, font_id, settings.buffer_font_size)
868 }
869
870 pub fn font_descent(&self, font_cache: &FontCache) -> f32 {
871 let settings = smol::block_on(self.settings.read());
872 let font_id = font_cache.default_font(settings.buffer_font_family);
873 let ascent = font_cache.metric(font_id, |m| m.descent);
874 font_cache.scale_metric(ascent, font_id, settings.buffer_font_size)
875 }
876
877 pub fn line_height(&self, font_cache: &FontCache) -> f32 {
878 let settings = smol::block_on(self.settings.read());
879 let font_id = font_cache.default_font(settings.buffer_font_family);
880 font_cache
881 .bounding_box(font_id, settings.buffer_font_size)
882 .y()
883 }
884
885 pub fn em_width(&self, font_cache: &FontCache) -> f32 {
886 let settings = smol::block_on(self.settings.read());
887 let font_id = font_cache.default_font(settings.buffer_font_family);
888 font_cache.em_width(font_id, settings.buffer_font_size)
889 }
890
891 // TODO: Can we make this not return a result?
892 pub fn max_line_number_width(
893 &self,
894 font_cache: &FontCache,
895 layout_cache: &TextLayoutCache,
896 app: &AppContext,
897 ) -> Result<f32> {
898 let settings = smol::block_on(self.settings.read());
899 let font_size = settings.buffer_font_size;
900 let font_id =
901 font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
902 let digit_count = ((self.buffer.as_ref(app).max_point().row + 1) as f32)
903 .log10()
904 .floor() as usize
905 + 1;
906
907 Ok(layout_cache
908 .layout_str(
909 "1".repeat(digit_count).as_str(),
910 font_size,
911 &[(0..digit_count, font_id)],
912 )
913 .width)
914 }
915
916 pub fn layout_line_numbers(
917 &self,
918 viewport_height: f32,
919 font_cache: &FontCache,
920 layout_cache: &TextLayoutCache,
921 app: &AppContext,
922 ) -> Result<Vec<Arc<text_layout::Line>>> {
923 let display_map = self.display_map.as_ref(app);
924
925 let settings = smol::block_on(self.settings.read());
926 let font_size = settings.buffer_font_size;
927 let font_id =
928 font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
929
930 let start_row = self.scroll_position().y() as usize;
931 let end_row = cmp::min(
932 self.max_point(app).row() as usize,
933 start_row + (viewport_height / self.line_height(font_cache)).ceil() as usize,
934 );
935 let line_count = end_row - start_row + 1;
936 let cpus = num_cpus::get();
937 let chunk_size = (line_count + cpus - 1) / cpus;
938
939 let mut layouts = Vec::new();
940 layouts.resize_with(line_count, Default::default);
941
942 Parallel::<Result<()>>::new()
943 .each(
944 layouts.chunks_mut(chunk_size).enumerate(),
945 |(i, layouts)| {
946 let mut line_number = String::new();
947 let start = start_row + i * chunk_size;
948 let line_numbers = display_map.buffer_rows(start as u32)?.take(layouts.len());
949 for (j, buffer_row) in line_numbers.enumerate() {
950 line_number.clear();
951 write!(&mut line_number, "{}", buffer_row + 1).unwrap();
952 layouts[j] = layout_cache.layout_str(
953 &line_number,
954 font_size,
955 &[(0..line_number.len(), font_id)],
956 );
957 }
958 Ok(())
959 },
960 )
961 .run()
962 .into_iter()
963 .collect::<Result<()>>()?;
964
965 Ok(layouts)
966 }
967
968 pub fn layout_lines(
969 &self,
970 mut rows: Range<u32>,
971 font_cache: &FontCache,
972 layout_cache: &TextLayoutCache,
973 app: &AppContext,
974 ) -> Result<Vec<Arc<text_layout::Line>>> {
975 let display_map = self.display_map.as_ref(app);
976
977 rows.end = cmp::min(rows.end, display_map.max_point(app).row() + 1);
978 if rows.start >= rows.end {
979 return Ok(Vec::new());
980 }
981
982 let settings = smol::block_on(self.settings.read());
983 let font_id =
984 font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
985 let font_size = settings.buffer_font_size;
986
987 let cpus = num_cpus::get();
988 let chunk_size = (rows.len() + cpus - 1) / cpus;
989
990 let mut layouts = Vec::new();
991 layouts.resize_with(rows.len(), Default::default);
992
993 Parallel::new()
994 .each(
995 layouts.chunks_mut(chunk_size as usize).enumerate(),
996 |(ix, chunk)| {
997 let chunk_start = rows.start as usize + ix * chunk_size;
998 let chunk_end = cmp::min(chunk_start + chunk_size, rows.end as usize);
999
1000 let mut row = chunk_start;
1001 let mut line = String::new();
1002 let mut line_len = 0;
1003 let chars = display_map
1004 .chars_at(DisplayPoint::new(chunk_start as u32, 0), app)
1005 .unwrap();
1006 for char in chars.chain(Some('\n')) {
1007 if char == '\n' {
1008 chunk[(row - chunk_start) as usize] = layout_cache.layout_str(
1009 &line,
1010 font_size,
1011 &[(0..line_len, font_id)],
1012 );
1013 line.clear();
1014 line_len = 0;
1015 row += 1;
1016 if row == chunk_end {
1017 break;
1018 }
1019 } else {
1020 line_len += 1;
1021 line.push(char);
1022 }
1023 }
1024 },
1025 )
1026 .run();
1027
1028 Ok(layouts)
1029 }
1030
1031 pub fn layout_line(
1032 &self,
1033 row: u32,
1034 font_cache: &FontCache,
1035 layout_cache: &TextLayoutCache,
1036 app: &AppContext,
1037 ) -> Result<Arc<text_layout::Line>> {
1038 let settings = smol::block_on(self.settings.read());
1039 let font_id =
1040 font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
1041
1042 let line = self.line(row, app)?;
1043
1044 Ok(layout_cache.layout_str(
1045 &line,
1046 settings.buffer_font_size,
1047 &[(0..self.line_len(row, app)? as usize, font_id)],
1048 ))
1049 }
1050
1051 fn next_blink_epoch(&mut self) -> usize {
1052 self.blink_epoch += 1;
1053 self.blink_epoch
1054 }
1055
1056 fn pause_cursor_blinking(&mut self, ctx: &mut ViewContext<Self>) {
1057 self.cursors_visible = true;
1058 ctx.notify();
1059
1060 let epoch = self.next_blink_epoch();
1061 ctx.spawn(
1062 async move {
1063 Timer::after(CURSOR_BLINK_INTERVAL).await;
1064 epoch
1065 },
1066 Self::resume_cursor_blinking,
1067 )
1068 .detach();
1069 }
1070
1071 fn resume_cursor_blinking(&mut self, epoch: usize, ctx: &mut ViewContext<Self>) {
1072 if epoch == self.blink_epoch {
1073 self.blinking_paused = false;
1074 self.blink_cursors(epoch, ctx);
1075 }
1076 }
1077
1078 fn blink_cursors(&mut self, epoch: usize, ctx: &mut ViewContext<Self>) {
1079 if epoch == self.blink_epoch && self.focused && !self.blinking_paused {
1080 self.cursors_visible = !self.cursors_visible;
1081 ctx.notify();
1082
1083 let epoch = self.next_blink_epoch();
1084 ctx.spawn(
1085 async move {
1086 Timer::after(CURSOR_BLINK_INTERVAL).await;
1087 epoch
1088 },
1089 Self::blink_cursors,
1090 )
1091 .detach();
1092 }
1093 }
1094
1095 pub fn cursors_visible(&self) -> bool {
1096 self.cursors_visible
1097 }
1098
1099 fn on_buffer_changed(&mut self, _: ModelHandle<Buffer>, ctx: &mut ViewContext<Self>) {
1100 ctx.notify();
1101 }
1102
1103 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, ctx: &mut ViewContext<Self>) {
1104 ctx.notify();
1105 }
1106
1107 fn on_buffer_event(
1108 &mut self,
1109 _: ModelHandle<Buffer>,
1110 event: &buffer::Event,
1111 ctx: &mut ViewContext<Self>,
1112 ) {
1113 match event {
1114 buffer::Event::Edited(_) => ctx.emit(Event::Edited),
1115 }
1116 }
1117}
1118
1119struct Selection {
1120 start: Anchor,
1121 end: Anchor,
1122 reversed: bool,
1123 goal_column: Option<u32>,
1124}
1125
1126pub enum Event {
1127 Activate,
1128 Edited,
1129 Blurred,
1130}
1131
1132impl Entity for BufferView {
1133 type Event = Event;
1134}
1135
1136impl View for BufferView {
1137 fn render<'a>(&self, app: &AppContext) -> ElementBox {
1138 BufferElement::new(self.handle.upgrade(app).unwrap()).boxed()
1139 }
1140
1141 fn ui_name() -> &'static str {
1142 "BufferView"
1143 }
1144
1145 fn on_focus(&mut self, ctx: &mut ViewContext<Self>) {
1146 self.focused = true;
1147 self.blink_cursors(self.blink_epoch, ctx);
1148 }
1149
1150 fn on_blur(&mut self, ctx: &mut ViewContext<Self>) {
1151 self.focused = false;
1152 self.cursors_visible = false;
1153 ctx.emit(Event::Blurred);
1154 ctx.notify();
1155 }
1156}
1157
1158impl workspace::Item for Buffer {
1159 type View = BufferView;
1160
1161 fn build_view(
1162 buffer: ModelHandle<Self>,
1163 settings: watch::Receiver<Settings>,
1164 ctx: &mut ViewContext<Self::View>,
1165 ) -> Self::View {
1166 BufferView::for_buffer(buffer, settings, ctx)
1167 }
1168}
1169
1170impl workspace::ItemView for BufferView {
1171 fn is_activate_event(event: &Self::Event) -> bool {
1172 match event {
1173 Event::Activate => true,
1174 _ => false,
1175 }
1176 }
1177
1178 fn title(&self, app: &AppContext) -> std::string::String {
1179 if let Some(path) = self.buffer.as_ref(app).path(app) {
1180 path.file_name()
1181 .expect("buffer's path is always to a file")
1182 .to_string_lossy()
1183 .into()
1184 } else {
1185 "untitled".into()
1186 }
1187 }
1188
1189 fn entry_id(&self, app: &AppContext) -> Option<(usize, usize)> {
1190 self.buffer.as_ref(app).entry_id()
1191 }
1192
1193 fn clone_on_split(&self, ctx: &mut ViewContext<Self>) -> Option<Self>
1194 where
1195 Self: Sized,
1196 {
1197 let clone = BufferView::for_buffer(self.buffer.clone(), self.settings.clone(), ctx);
1198 *clone.scroll_position.lock() = *self.scroll_position.lock();
1199 Some(clone)
1200 }
1201}
1202
1203impl Selection {
1204 fn head(&self) -> &Anchor {
1205 if self.reversed {
1206 &self.start
1207 } else {
1208 &self.end
1209 }
1210 }
1211
1212 fn set_head(&mut self, buffer: &Buffer, cursor: Anchor) {
1213 if cursor.cmp(self.tail(), buffer).unwrap() < Ordering::Equal {
1214 if !self.reversed {
1215 mem::swap(&mut self.start, &mut self.end);
1216 self.reversed = true;
1217 }
1218 self.start = cursor;
1219 } else {
1220 if self.reversed {
1221 mem::swap(&mut self.start, &mut self.end);
1222 self.reversed = false;
1223 }
1224 self.end = cursor;
1225 }
1226 }
1227
1228 fn tail(&self) -> &Anchor {
1229 if self.reversed {
1230 &self.end
1231 } else {
1232 &self.start
1233 }
1234 }
1235
1236 fn range(&self, buffer: &Buffer) -> Range<Point> {
1237 let start = self.start.to_point(buffer).unwrap();
1238 let end = self.end.to_point(buffer).unwrap();
1239 if self.reversed {
1240 end..start
1241 } else {
1242 start..end
1243 }
1244 }
1245
1246 fn display_range(&self, map: &DisplayMap, app: &AppContext) -> Range<DisplayPoint> {
1247 let start = self.start.to_display_point(map, app).unwrap();
1248 let end = self.end.to_display_point(map, app).unwrap();
1249 if self.reversed {
1250 end..start
1251 } else {
1252 start..end
1253 }
1254 }
1255}
1256
1257#[cfg(test)]
1258mod tests {
1259 use super::*;
1260 use crate::{editor::Point, settings, test::sample_text};
1261 use anyhow::Error;
1262 use unindent::Unindent;
1263
1264 #[test]
1265 fn test_selection_with_mouse() {
1266 App::test((), |mut app| async move {
1267 let buffer = app.add_model(|_| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n"));
1268 let settings = settings::channel(&app.font_cache()).unwrap().1;
1269 let (_, buffer_view) =
1270 app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
1271
1272 buffer_view.update(&mut app, |view, ctx| {
1273 view.begin_selection(DisplayPoint::new(2, 2), false, ctx);
1274 });
1275
1276 buffer_view.read(&app, |view, app| {
1277 let selections = view
1278 .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1279 .collect::<Vec<_>>();
1280 assert_eq!(
1281 selections,
1282 [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
1283 );
1284 });
1285
1286 buffer_view.update(&mut app, |view, ctx| {
1287 view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
1288 });
1289
1290 buffer_view.read(&app, |view, app| {
1291 let selections = view
1292 .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1293 .collect::<Vec<_>>();
1294 assert_eq!(
1295 selections,
1296 [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
1297 );
1298 });
1299
1300 buffer_view.update(&mut app, |view, ctx| {
1301 view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx);
1302 });
1303
1304 buffer_view.read(&app, |view, app| {
1305 let selections = view
1306 .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1307 .collect::<Vec<_>>();
1308 assert_eq!(
1309 selections,
1310 [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
1311 );
1312 });
1313
1314 buffer_view.update(&mut app, |view, ctx| {
1315 view.end_selection(ctx);
1316 view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
1317 });
1318
1319 buffer_view.read(&app, |view, app| {
1320 let selections = view
1321 .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1322 .collect::<Vec<_>>();
1323 assert_eq!(
1324 selections,
1325 [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
1326 );
1327 });
1328
1329 buffer_view.update(&mut app, |view, ctx| {
1330 view.begin_selection(DisplayPoint::new(3, 3), true, ctx);
1331 view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), ctx);
1332 });
1333
1334 buffer_view.read(&app, |view, app| {
1335 let selections = view
1336 .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1337 .collect::<Vec<_>>();
1338 assert_eq!(
1339 selections,
1340 [
1341 DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1),
1342 DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)
1343 ]
1344 );
1345 });
1346
1347 buffer_view.update(&mut app, |view, ctx| {
1348 view.end_selection(ctx);
1349 });
1350
1351 buffer_view.read(&app, |view, app| {
1352 let selections = view
1353 .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1354 .collect::<Vec<_>>();
1355 assert_eq!(
1356 selections,
1357 [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)]
1358 );
1359 });
1360 });
1361 }
1362
1363 #[test]
1364 fn test_layout_line_numbers() -> Result<()> {
1365 App::test((), |mut app| async move {
1366 let layout_cache = TextLayoutCache::new(app.platform().fonts());
1367 let font_cache = app.font_cache();
1368
1369 let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6)));
1370
1371 let settings = settings::channel(&font_cache).unwrap().1;
1372 let (_, view) =
1373 app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1374
1375 view.read(&app, |view, app| {
1376 let layouts = view.layout_line_numbers(1000.0, &font_cache, &layout_cache, app)?;
1377 assert_eq!(layouts.len(), 6);
1378 Result::<()>::Ok(())
1379 })?;
1380
1381 Ok(())
1382 })
1383 }
1384
1385 #[test]
1386 fn test_fold() -> Result<()> {
1387 App::test((), |mut app| async move {
1388 let buffer = app.add_model(|_| {
1389 Buffer::new(
1390 0,
1391 "
1392 impl Foo {
1393 // Hello!
1394
1395 fn a() {
1396 1
1397 }
1398
1399 fn b() {
1400 2
1401 }
1402 3
1403 }
1404 }
1405 "
1406 .unindent(),
1407 )
1408 });
1409 let settings = settings::channel(&app.font_cache()).unwrap().1;
1410 let (_, view) =
1411 app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1412
1413 view.update(&mut app, |view, ctx| {
1414 view.select_ranges(Some(DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)), ctx)?;
1415 view.fold(&(), ctx);
1416 assert_eq!(
1417 view.text(ctx.app()),
1418 "
1419 impl Foo {
1420 // Hello!
1421
1422 fn a() {
1423 1
1424 }
1425
1426 fn b() {…
1427 }
1428
1429 fn c() {…
1430 }
1431 }
1432 "
1433 .unindent(),
1434 );
1435
1436 view.fold(&(), ctx);
1437 assert_eq!(
1438 view.text(ctx.app()),
1439 "
1440 impl Foo {…
1441 }
1442 "
1443 .unindent(),
1444 );
1445
1446 view.unfold(&(), ctx);
1447 assert_eq!(
1448 view.text(ctx.app()),
1449 "
1450 impl Foo {
1451 // Hello!
1452
1453 fn a() {
1454 1
1455 }
1456
1457 fn b() {…
1458 }
1459
1460 fn c() {…
1461 }
1462 }
1463 "
1464 .unindent(),
1465 );
1466
1467 view.unfold(&(), ctx);
1468 assert_eq!(view.text(ctx.app()), buffer.as_ref(ctx).text());
1469
1470 Ok::<(), Error>(())
1471 })?;
1472
1473 Ok(())
1474 })
1475 }
1476
1477 #[test]
1478 fn test_move_cursor() -> Result<()> {
1479 App::test((), |mut app| async move {
1480 let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6)));
1481 let settings = settings::channel(&app.font_cache()).unwrap().1;
1482 let (_, view) =
1483 app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1484
1485 buffer.update(&mut app, |buffer, ctx| {
1486 buffer.edit(
1487 vec![
1488 Point::new(1, 0)..Point::new(1, 0),
1489 Point::new(1, 1)..Point::new(1, 1),
1490 ],
1491 "\t",
1492 Some(ctx),
1493 )
1494 })?;
1495
1496 view.update(&mut app, |view, ctx| {
1497 view.move_down(&(), ctx);
1498 assert_eq!(
1499 view.selections(ctx.app()),
1500 &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
1501 );
1502 view.move_right(&(), ctx);
1503 assert_eq!(
1504 view.selections(ctx.app()),
1505 &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)]
1506 );
1507 Ok::<(), Error>(())
1508 })?;
1509
1510 Ok(())
1511 })
1512 }
1513
1514 impl BufferView {
1515 fn selections(&self, app: &AppContext) -> Vec<Range<DisplayPoint>> {
1516 self.selections_in_range(DisplayPoint::zero()..self.max_point(app), app)
1517 .collect::<Vec<_>>()
1518 }
1519 }
1520}