From 143c50f3212faa8bc718aa12b7caba1e56be7601 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 10 May 2021 16:10:41 +0200 Subject: [PATCH] Implement `cancel` for buffer --- zed/src/editor/buffer/mod.rs | 9 +++- zed/src/editor/buffer/selection.rs | 1 + zed/src/editor/buffer_view.rs | 67 +++++++++++++++++++++++------- 3 files changed, 60 insertions(+), 17 deletions(-) diff --git a/zed/src/editor/buffer/mod.rs b/zed/src/editor/buffer/mod.rs index 89c3d6c558..64aa91dfdc 100644 --- a/zed/src/editor/buffer/mod.rs +++ b/zed/src/editor/buffer/mod.rs @@ -2378,8 +2378,11 @@ mod tests { use super::*; use cmp::Ordering; use gpui::App; - use std::collections::BTreeMap; use std::{cell::RefCell, rc::Rc}; + use std::{ + collections::BTreeMap, + sync::atomic::{self, AtomicUsize}, + }; #[test] fn test_edit() { @@ -3275,6 +3278,8 @@ mod tests { where I: IntoIterator>, { + static NEXT_SELECTION_ID: AtomicUsize = AtomicUsize::new(0); + let mut ranges = ranges.into_iter().collect::>(); ranges.sort_unstable_by_key(|range| range.start); @@ -3282,6 +3287,7 @@ mod tests { for range in ranges { if range.start > range.end { selections.push(Selection { + id: NEXT_SELECTION_ID.fetch_add(1, atomic::Ordering::SeqCst), start: self.anchor_before(range.end)?, end: self.anchor_before(range.start)?, reversed: true, @@ -3289,6 +3295,7 @@ mod tests { }); } else { selections.push(Selection { + id: NEXT_SELECTION_ID.fetch_add(1, atomic::Ordering::SeqCst), start: self.anchor_after(range.start)?, end: self.anchor_before(range.end)?, reversed: false, diff --git a/zed/src/editor/buffer/selection.rs b/zed/src/editor/buffer/selection.rs index 91cb715ddc..bff91a83e9 100644 --- a/zed/src/editor/buffer/selection.rs +++ b/zed/src/editor/buffer/selection.rs @@ -21,6 +21,7 @@ pub enum SelectionGoal { #[derive(Clone, Debug, Eq, PartialEq)] pub struct Selection { + pub id: usize, pub start: Anchor, pub end: Anchor, pub reversed: bool, diff --git a/zed/src/editor/buffer_view.rs b/zed/src/editor/buffer_view.rs index 049b90f240..999ca64fd4 100644 --- a/zed/src/editor/buffer_view.rs +++ b/zed/src/editor/buffer_view.rs @@ -2,7 +2,7 @@ use super::{ buffer, movement, Anchor, Bias, Buffer, BufferElement, DisplayMap, DisplayPoint, Point, Selection, SelectionGoal, SelectionSetId, ToOffset, ToPoint, }; -use crate::{settings::Settings, workspace, worktree::FileHandle}; +use crate::{settings::Settings, util::post_inc, workspace, worktree::FileHandle}; use anyhow::Result; use futures_core::future::LocalBoxFuture; use gpui::{ @@ -30,6 +30,7 @@ const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500); pub fn init(app: &mut MutableAppContext) { app.add_bindings(vec![ + Binding::new("escape", "buffer:cancel", Some("BufferView")), Binding::new("backspace", "buffer:backspace", Some("BufferView")), Binding::new("ctrl-h", "buffer:backspace", Some("BufferView")), Binding::new("delete", "buffer:delete", Some("BufferView")), @@ -172,6 +173,7 @@ pub fn init(app: &mut MutableAppContext) { app.add_action("buffer:scroll", BufferView::scroll); app.add_action("buffer:select", BufferView::select); + app.add_action("buffer:cancel", BufferView::cancel); app.add_action("buffer:insert", BufferView::insert); app.add_action("buffer:newline", BufferView::newline); app.add_action("buffer:backspace", BufferView::backspace); @@ -284,6 +286,7 @@ pub struct BufferView { display_map: DisplayMap, selection_set_id: SelectionSetId, pending_selection: Option, + next_selection_id: usize, scroll_position: Mutex, autoscroll_requested: Mutex, settings: watch::Receiver, @@ -317,9 +320,11 @@ impl BufferView { ctx.subscribe_to_model(&buffer, Self::on_buffer_event); let display_map = DisplayMap::new(buffer.clone(), settings.borrow().tab_size, ctx.as_ref()); + let mut next_selection_id = 0; let (selection_set_id, _) = buffer.update(ctx, |buffer, ctx| { buffer.add_selection_set( vec![Selection { + id: post_inc(&mut next_selection_id), start: buffer.anchor_before(0).unwrap(), end: buffer.anchor_before(0).unwrap(), reversed: false, @@ -334,6 +339,7 @@ impl BufferView { display_map, selection_set_id, pending_selection: None, + next_selection_id, scroll_position: Mutex::new(Vector2F::zero()), autoscroll_requested: Mutex::new(false), settings, @@ -492,6 +498,7 @@ impl BufferView { .anchor_before(position, Bias::Left, ctx.as_ref()) .unwrap(); let selection = Selection { + id: post_inc(&mut self.next_selection_id), start: cursor.clone(), end: cursor, reversed: false, @@ -544,6 +551,18 @@ impl BufferView { self.pending_selection.is_some() } + pub fn cancel(&mut self, _: &(), ctx: &mut ViewContext) { + let selections = self.selections(ctx.as_ref()); + if let Some(pending_selection) = self.pending_selection.take() { + if selections.is_empty() { + self.update_selections(vec![pending_selection], true, ctx); + } + } else { + let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone(); + self.update_selections(vec![oldest_selection], true, ctx); + } + } + fn select_ranges(&mut self, ranges: I, autoscroll: bool, ctx: &mut ViewContext) where I: IntoIterator>, @@ -561,6 +580,7 @@ impl BufferView { false }; selections.push(Selection { + id: post_inc(&mut self.next_selection_id), start: buffer.anchor_before(start).unwrap(), end: buffer.anchor_before(end).unwrap(), reversed, @@ -587,6 +607,7 @@ impl BufferView { }; selections.push(Selection { + id: post_inc(&mut self.next_selection_id), start: self .display_map .anchor_before(start, Bias::Left, ctx.as_ref())?, @@ -602,28 +623,28 @@ impl BufferView { } pub fn insert(&mut self, text: &String, ctx: &mut ViewContext) { - let mut offset_ranges = SmallVec::<[Range; 32]>::new(); + let mut old_selections = SmallVec::<[_; 32]>::new(); { let buffer = self.buffer.read(ctx); for selection in self.selections(ctx.as_ref()) { let start = selection.start.to_offset(buffer).unwrap(); let end = selection.end.to_offset(buffer).unwrap(); - offset_ranges.push(start..end); + old_selections.push((selection.id, start..end)); } } self.start_transaction(ctx); let mut new_selections = Vec::new(); self.buffer.update(ctx, |buffer, ctx| { - if let Err(error) = buffer.edit(offset_ranges.iter().cloned(), text.as_str(), Some(ctx)) - { + let edit_ranges = old_selections.iter().map(|(_, range)| range.clone()); + if let Err(error) = buffer.edit(edit_ranges, text.as_str(), Some(ctx)) { log::error!("error inserting text: {}", error); }; let char_count = text.chars().count() as isize; let mut delta = 0_isize; - new_selections = offset_ranges + new_selections = old_selections .into_iter() - .map(|range| { + .map(|(id, range)| { let start = range.start as isize; let end = range.end as isize; let anchor = buffer @@ -632,6 +653,7 @@ impl BufferView { let deleted_count = end - start; delta += char_count - deleted_count; Selection { + id, start: anchor.clone(), end: anchor, reversed: false, @@ -770,23 +792,27 @@ impl BufferView { self.display_map.line_len(cursor.row(), app).unwrap(), ); - new_cursors.push( + new_cursors.push(( + selection.id, cursor .to_buffer_point(&self.display_map, Bias::Left, app) .unwrap(), - ); + )); edit_ranges.push(edit_start..edit_end); } - new_cursors.sort_unstable(); + new_cursors.sort_unstable_by_key(|(_, range)| range.clone()); let new_selections = new_cursors .into_iter() - .map(|cursor| buffer.anchor_before(cursor).unwrap()) - .map(|anchor| Selection { - start: anchor.clone(), - end: anchor, - reversed: false, - goal: SelectionGoal::None, + .map(|(id, cursor)| { + let anchor = buffer.anchor_before(cursor).unwrap(); + Selection { + id, + start: anchor.clone(), + end: anchor, + reversed: false, + goal: SelectionGoal::None, + } }) .collect(); self.buffer @@ -1154,6 +1180,7 @@ impl BufferView { let new_selection_start = new_selection_start.bias_left(buffer).unwrap(); new_selections.push(Selection { + id: selection.id, start: new_selection_start.clone(), end: new_selection_start, reversed: false, @@ -1636,6 +1663,7 @@ impl BufferView { let buffer = self.buffer.read(ctx); let cursor = buffer.anchor_before(Point::new(0, 0)).unwrap(); let selection = Selection { + id: post_inc(&mut self.next_selection_id), start: cursor.clone(), end: cursor, reversed: false, @@ -1654,6 +1682,7 @@ impl BufferView { let buffer = self.buffer.read(ctx); let cursor = buffer.anchor_before(buffer.max_point()).unwrap(); let selection = Selection { + id: post_inc(&mut self.next_selection_id), start: cursor.clone(), end: cursor, reversed: false, @@ -1670,6 +1699,7 @@ impl BufferView { pub fn select_all(&mut self, _: &(), ctx: &mut ViewContext) { let selection = Selection { + id: post_inc(&mut self.next_selection_id), start: Anchor::Start, end: Anchor::End, reversed: false, @@ -1706,6 +1736,7 @@ impl BufferView { let range = selection.range(buffer).sorted(); if range.start.row != range.end.row { new_selections.push(Selection { + id: post_inc(&mut self.next_selection_id), start: selection.start.clone(), end: selection.start.clone(), reversed: false, @@ -1717,6 +1748,7 @@ impl BufferView { .anchor_before(Point::new(row, buffer.line_len(row).unwrap())) .unwrap(); new_selections.push(Selection { + id: post_inc(&mut self.next_selection_id), start: cursor.clone(), end: cursor, reversed: false, @@ -1724,6 +1756,7 @@ impl BufferView { }); } new_selections.push(Selection { + id: selection.id, start: selection.end.clone(), end: selection.end.clone(), reversed: false, @@ -1762,6 +1795,7 @@ impl BufferView { let start = DisplayPoint::new(row, start_column); let end = DisplayPoint::new(row, cmp::min(end_column, line_len)); new_selections.push(Selection { + id: post_inc(&mut self.next_selection_id), start: self .display_map .anchor_before(start, Bias::Left, app) @@ -1815,6 +1849,7 @@ impl BufferView { let start = DisplayPoint::new(row, start_column); let end = DisplayPoint::new(row, cmp::min(end_column, line_len)); new_selections.push(Selection { + id: post_inc(&mut self.next_selection_id), start: self .display_map .anchor_before(start, Bias::Left, app)