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