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