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