diff --git a/zed/src/editor/buffer/mod.rs b/zed/src/editor/buffer/mod.rs index dd87362004..f35bf41400 100644 --- a/zed/src/editor/buffer/mod.rs +++ b/zed/src/editor/buffer/mod.rs @@ -1,11 +1,13 @@ mod anchor; mod point; +mod selection; mod text; pub use anchor::*; use futures_core::future::LocalBoxFuture; pub use point::*; use seahash::SeaHasher; +pub use selection::*; pub use text::*; use crate::{ @@ -23,7 +25,6 @@ use std::{ cmp::{self, Ordering}, hash::BuildHasher, iter::{self, Iterator}, - mem, ops::{AddAssign, Range}, path::PathBuf, str, @@ -33,9 +34,6 @@ use std::{ const UNDO_GROUP_INTERVAL: Duration = Duration::from_millis(300); -pub type SelectionSetId = time::Lamport; -pub type SelectionsVersion = usize; - #[derive(Clone, Default)] struct DeterministicState; @@ -149,13 +147,6 @@ impl History { } } -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Selection { - pub start: Anchor, - pub end: Anchor, - pub reversed: bool, -} - #[derive(Clone, Default, Debug)] struct UndoMap(HashMap>); @@ -679,45 +670,46 @@ impl Buffer { (old_ranges, new_text, operations) } - pub fn add_selection_set(&mut self, ranges: I) -> Result<(SelectionSetId, Operation)> - where - I: IntoIterator>, - { - let selections = self.selections_from_ranges(ranges)?; + pub fn add_selection_set( + &mut self, + selections: Vec, + ctx: Option<&mut ModelContext>, + ) -> (SelectionSetId, Operation) { let lamport_timestamp = self.lamport_clock.tick(); self.selections .insert(lamport_timestamp, selections.clone()); self.selections_last_update += 1; - Ok(( + if let Some(ctx) = ctx { + ctx.notify(); + } + + ( lamport_timestamp, Operation::UpdateSelections { set_id: lamport_timestamp, selections: Some(selections), lamport_timestamp, }, - )) + ) } - pub fn replace_selection_set( + pub fn update_selection_set( &mut self, set_id: SelectionSetId, - ranges: I, - ) -> Result - where - I: IntoIterator>, - { - self.selections - .remove(&set_id) - .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?; - - let mut selections = self.selections_from_ranges(ranges)?; + mut selections: Vec, + ctx: Option<&mut ModelContext>, + ) -> Result { self.merge_selections(&mut selections); self.selections.insert(set_id, selections.clone()); let lamport_timestamp = self.lamport_clock.tick(); self.selections_last_update += 1; + if let Some(ctx) = ctx { + ctx.notify(); + } + Ok(Operation::UpdateSelections { set_id, selections: Some(selections), @@ -725,12 +717,21 @@ impl Buffer { }) } - pub fn remove_selection_set(&mut self, set_id: SelectionSetId) -> Result { + pub fn remove_selection_set( + &mut self, + set_id: SelectionSetId, + ctx: Option<&mut ModelContext>, + ) -> Result { self.selections .remove(&set_id) .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?; let lamport_timestamp = self.lamport_clock.tick(); self.selections_last_update += 1; + + if let Some(ctx) = ctx { + ctx.notify(); + } + Ok(Operation::UpdateSelections { set_id, selections: None, @@ -738,15 +739,18 @@ impl Buffer { }) } + pub fn selections(&self, set_id: SelectionSetId) -> Result<&[Selection]> { + self.selections + .get(&set_id) + .map(|s| s.as_slice()) + .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id)) + } + pub fn selection_ranges<'a>( &'a self, set_id: SelectionSetId, ) -> Result> + 'a> { - let selections = self - .selections - .get(&set_id) - .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?; - Ok(selections.iter().map(move |selection| { + Ok(self.selections(set_id)?.iter().map(move |selection| { let start = selection.start.to_point(self).unwrap(); let end = selection.end.to_point(self).unwrap(); if selection.reversed { @@ -770,49 +774,25 @@ impl Buffer { } fn merge_selections(&mut self, selections: &mut Vec) { - let mut new_selections = Vec::with_capacity(selections.len()); - { - let mut old_selections = selections.drain(..); - if let Some(mut prev_selection) = old_selections.next() { - for selection in old_selections { - if prev_selection.end.cmp(&selection.start, self).unwrap() >= Ordering::Equal { - if selection.end.cmp(&prev_selection.end, self).unwrap() > Ordering::Equal { - prev_selection.end = selection.end; - } - } else { - new_selections.push(mem::replace(&mut prev_selection, selection)); - } + let mut i = 1; + while i < selections.len() { + if selections[i - 1] + .end + .cmp(&selections[i].start, self) + .unwrap() + >= Ordering::Equal + { + let removed = selections.remove(i); + if removed.start.cmp(&selections[i - 1].start, self).unwrap() < Ordering::Equal { + selections[i - 1].start = removed.start; + } + if removed.end.cmp(&selections[i - 1].end, self).unwrap() > Ordering::Equal { + selections[i - 1].end = removed.end; } - new_selections.push(prev_selection); - } - } - *selections = new_selections; - } - - fn selections_from_ranges(&self, ranges: I) -> Result> - where - I: IntoIterator>, - { - let mut ranges = ranges.into_iter().collect::>(); - ranges.sort_unstable_by_key(|range| range.start); - - let mut selections = Vec::with_capacity(ranges.len()); - for range in ranges { - if range.start > range.end { - selections.push(Selection { - start: self.anchor_before(range.end)?, - end: self.anchor_before(range.start)?, - reversed: true, - }); } else { - selections.push(Selection { - start: self.anchor_after(range.start)?, - end: self.anchor_before(range.end)?, - reversed: false, - }); + i += 1; } } - Ok(selections) } pub fn apply_ops>( @@ -1927,48 +1907,6 @@ impl<'a, F: Fn(&FragmentSummary) -> bool> Iterator for Edits<'a, F> { // collector.into_inner().changes // } -impl Selection { - pub fn head(&self) -> &Anchor { - if self.reversed { - &self.start - } else { - &self.end - } - } - - pub fn set_head(&mut self, buffer: &Buffer, cursor: Anchor) { - if cursor.cmp(self.tail(), buffer).unwrap() < Ordering::Equal { - if !self.reversed { - mem::swap(&mut self.start, &mut self.end); - self.reversed = true; - } - self.start = cursor; - } else { - if self.reversed { - mem::swap(&mut self.start, &mut self.end); - self.reversed = false; - } - self.end = cursor; - } - } - - pub fn tail(&self) -> &Anchor { - if self.reversed { - &self.end - } else { - &self.start - } - } - - pub fn is_empty(&self, buffer: &Buffer) -> bool { - self.start.to_offset(buffer).unwrap() == self.end.to_offset(buffer).unwrap() - } - - pub fn anchor_range(&self) -> Range { - self.start.clone()..self.end.clone() - } -} - #[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Debug)] struct FragmentId(Arc<[u16]>); @@ -3049,7 +2987,7 @@ mod tests { .collect::>(); let set_id = replica_selection_sets.choose(rng); if set_id.is_some() && rng.gen_bool(1.0 / 6.0) { - let op = self.remove_selection_set(*set_id.unwrap()).unwrap(); + let op = self.remove_selection_set(*set_id.unwrap(), None).unwrap(); operations.push(op); } else { let mut ranges = Vec::new(); @@ -3060,11 +2998,12 @@ mod tests { let end_point = self.point_for_offset(end).unwrap(); ranges.push(start_point..end_point); } + let new_selections = self.selections_from_ranges(ranges).unwrap(); let op = if set_id.is_none() || rng.gen_bool(1.0 / 5.0) { - self.add_selection_set(ranges).unwrap().1 + self.add_selection_set(new_selections, None).1 } else { - self.replace_selection_set(*set_id.unwrap(), ranges) + self.update_selection_set(*set_id.unwrap(), new_selections, None) .unwrap() }; operations.push(op); @@ -3082,6 +3021,34 @@ mod tests { } ops } + + fn selections_from_ranges(&self, ranges: I) -> Result> + where + I: IntoIterator>, + { + let mut ranges = ranges.into_iter().collect::>(); + ranges.sort_unstable_by_key(|range| range.start); + + let mut selections = Vec::with_capacity(ranges.len()); + for range in ranges { + if range.start > range.end { + selections.push(Selection { + start: self.anchor_before(range.end)?, + end: self.anchor_before(range.start)?, + reversed: true, + goal_column: None, + }); + } else { + selections.push(Selection { + start: self.anchor_after(range.start)?, + end: self.anchor_before(range.end)?, + reversed: false, + goal_column: None, + }); + } + } + Ok(selections) + } } impl Operation { diff --git a/zed/src/editor/buffer/selection.rs b/zed/src/editor/buffer/selection.rs new file mode 100644 index 0000000000..99c71e0a44 --- /dev/null +++ b/zed/src/editor/buffer/selection.rs @@ -0,0 +1,75 @@ +use crate::{ + editor::{ + buffer::{Anchor, Buffer, Point, ToPoint}, + display_map::DisplayMap, + DisplayPoint, + }, + time, +}; +use gpui::AppContext; +use std::{cmp::Ordering, mem, ops::Range}; + +pub type SelectionSetId = time::Lamport; +pub type SelectionsVersion = usize; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Selection { + pub start: Anchor, + pub end: Anchor, + pub reversed: bool, + pub goal_column: Option, +} + +impl Selection { + pub fn head(&self) -> &Anchor { + if self.reversed { + &self.start + } else { + &self.end + } + } + + pub fn set_head(&mut self, buffer: &Buffer, cursor: Anchor) { + if cursor.cmp(self.tail(), buffer).unwrap() < Ordering::Equal { + if !self.reversed { + mem::swap(&mut self.start, &mut self.end); + self.reversed = true; + } + self.start = cursor; + } else { + if self.reversed { + mem::swap(&mut self.start, &mut self.end); + self.reversed = false; + } + self.end = cursor; + } + } + + pub fn tail(&self) -> &Anchor { + if self.reversed { + &self.end + } else { + &self.start + } + } + + pub fn range(&self, buffer: &Buffer) -> Range { + let start = self.start.to_point(buffer).unwrap(); + let end = self.end.to_point(buffer).unwrap(); + if self.reversed { + end..start + } else { + start..end + } + } + + pub fn display_range(&self, map: &DisplayMap, app: &AppContext) -> Range { + let start = self.start.to_display_point(map, app).unwrap(); + let end = self.end.to_display_point(map, app).unwrap(); + if self.reversed { + end..start + } else { + start..end + } + } +} diff --git a/zed/src/editor/buffer_view.rs b/zed/src/editor/buffer_view.rs index 15be98dad3..ebcd3a93d4 100644 --- a/zed/src/editor/buffer_view.rs +++ b/zed/src/editor/buffer_view.rs @@ -1,6 +1,6 @@ use super::{ buffer, movement, Anchor, Bias, Buffer, BufferElement, DisplayMap, DisplayPoint, Point, - ToOffset, ToPoint, + Selection, SelectionSetId, ToOffset, }; use crate::{settings::Settings, watch, workspace}; use anyhow::Result; @@ -16,7 +16,6 @@ use smol::Timer; use std::{ cmp::{self, Ordering}, fmt::Write, - mem, ops::Range, sync::Arc, time::Duration, @@ -90,7 +89,7 @@ pub struct BufferView { handle: WeakViewHandle, buffer: ModelHandle, display_map: ModelHandle, - selections: Vec, + selection_set_id: SelectionSetId, pending_selection: Option, scroll_position: Mutex, autoscroll_requested: Mutex, @@ -128,17 +127,22 @@ impl BufferView { }); ctx.observe(&display_map, Self::on_display_map_changed); - let buffer_ref = buffer.as_ref(ctx); + let (selection_set_id, ops) = buffer.update(ctx, |buffer, ctx| { + buffer.add_selection_set( + vec![Selection { + start: buffer.anchor_before(0).unwrap(), + end: buffer.anchor_before(0).unwrap(), + reversed: false, + goal_column: None, + }], + Some(ctx), + ) + }); Self { handle: ctx.handle().downgrade(), buffer, display_map, - selections: vec![Selection { - start: buffer_ref.anchor_before(0).unwrap(), - end: buffer_ref.anchor_before(0).unwrap(), - reversed: false, - goal_column: None, - }], + selection_set_id, pending_selection: None, scroll_position: Mutex::new(Vector2F::zero()), autoscroll_requested: Mutex::new(false), @@ -194,7 +198,7 @@ impl BufferView { let map = self.display_map.as_ref(app); let visible_lines = viewport_height / line_height; let first_cursor_top = self - .selections + .selections(app) .first() .unwrap() .head() @@ -202,7 +206,7 @@ impl BufferView { .unwrap() .row() as f32; let last_cursor_bottom = self - .selections + .selections(app) .last() .unwrap() .head() @@ -245,7 +249,7 @@ impl BufferView { let mut target_left = std::f32::INFINITY; let mut target_right = 0.0_f32; - for selection in &self.selections { + for selection in self.selections(app) { let head = selection.head().to_display_point(map, app).unwrap(); let start_column = head.column().saturating_sub(3); let end_column = cmp::min(map.line_len(head.row(), app).unwrap(), head.column() + 3); @@ -302,7 +306,7 @@ impl BufferView { }; if !add { - self.selections.clear(); + self.update_selections(Vec::new(), ctx); } self.pending_selection = Some(selection); @@ -333,9 +337,9 @@ impl BufferView { fn end_selection(&mut self, ctx: &mut ViewContext) { if let Some(selection) = self.pending_selection.take() { let ix = self.selection_insertion_index(&selection.start, ctx.app()); - self.selections.insert(ix, selection); - self.merge_selections(ctx.app()); - ctx.notify(); + let mut selections = self.selections(ctx.app()).to_vec(); + selections.insert(ix, selection); + self.update_selections(selections, ctx); } else { log::error!("end_selection dispatched with no pending selection"); } @@ -350,7 +354,6 @@ impl BufferView { where T: IntoIterator>, { - let buffer = self.buffer.as_ref(ctx); let map = self.display_map.as_ref(ctx); let mut selections = Vec::new(); for range in ranges { @@ -361,51 +364,50 @@ impl BufferView { goal_column: None, }); } - selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer).unwrap()); - self.selections = selections; - self.merge_selections(ctx.app()); - ctx.notify(); + self.update_selections(selections, ctx); Ok(()) } fn insert(&mut self, text: &String, ctx: &mut ViewContext) { - let buffer = self.buffer.as_ref(ctx); let mut offset_ranges = SmallVec::<[Range; 32]>::new(); - for selection in &self.selections { - let start = selection.start.to_offset(buffer).unwrap(); - let end = selection.end.to_offset(buffer).unwrap(); - offset_ranges.push(start..end); + { + let buffer = self.buffer.as_ref(ctx); + for selection in self.selections(ctx.app()) { + let start = selection.start.to_offset(buffer).unwrap(); + let end = selection.end.to_offset(buffer).unwrap(); + offset_ranges.push(start..end); + } } + 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)) { log::error!("error inserting text: {}", error); }; + let char_count = text.chars().count() as isize; + let mut delta = 0_isize; + new_selections = offset_ranges + .into_iter() + .map(|range| { + let start = range.start as isize; + let end = range.end as isize; + let anchor = buffer + .anchor_before((start + delta + char_count) as usize) + .unwrap(); + let deleted_count = end - start; + delta += char_count - deleted_count; + Selection { + start: anchor.clone(), + end: anchor, + reversed: false, + goal_column: None, + } + }) + .collect(); }); - let buffer = self.buffer.as_ref(ctx); - let char_count = text.chars().count() as isize; - let mut delta = 0_isize; - self.selections = offset_ranges - .into_iter() - .map(|range| { - let start = range.start as isize; - let end = range.end as isize; - let anchor = buffer - .anchor_before((start + delta + char_count) as usize) - .unwrap(); - let deleted_count = end - start; - delta += char_count - deleted_count; - Selection { - start: anchor.clone(), - end: anchor, - reversed: false, - goal_column: None, - } - }) - .collect(); - + self.update_selections(new_selections, ctx); self.pause_cursor_blinking(ctx); *self.autoscroll_requested.lock() = true; } @@ -419,22 +421,27 @@ impl BufferView { } pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext) { - let buffer = self.buffer.as_ref(ctx); - let map = self.display_map.as_ref(ctx); - for selection in &mut self.selections { - if selection.range(buffer).is_empty() { - let head = selection.head().to_display_point(map, ctx.app()).unwrap(); - let cursor = map - .anchor_before( - movement::left(map, head, ctx.app()).unwrap(), - Bias::Left, - ctx.app(), - ) - .unwrap(); - selection.set_head(&buffer, cursor); - selection.goal_column = None; + let mut selections = self.selections(ctx.app()).to_vec(); + { + let buffer = self.buffer.as_ref(ctx); + let map = self.display_map.as_ref(ctx); + for selection in &mut selections { + if selection.range(buffer).is_empty() { + let head = selection.head().to_display_point(map, ctx.app()).unwrap(); + let cursor = map + .anchor_before( + movement::left(map, head, ctx.app()).unwrap(), + Bias::Left, + ctx.app(), + ) + .unwrap(); + selection.set_head(&buffer, cursor); + selection.goal_column = None; + } } } + + self.update_selections(selections, ctx); self.changed_selections(ctx); self.insert(&String::new(), ctx); } @@ -450,10 +457,11 @@ impl BufferView { } pub fn move_left(&mut self, _: &(), ctx: &mut ViewContext) { + let mut selections = self.selections(ctx.app()).to_vec(); { let app = ctx.app(); - let map = self.display_map.as_ref(ctx); - for selection in &mut self.selections { + let map = self.display_map.as_ref(app); + for selection in &mut selections { let start = selection.start.to_display_point(map, app).unwrap(); let end = selection.end.to_display_point(map, app).unwrap(); @@ -470,14 +478,16 @@ impl BufferView { selection.goal_column = None; } } + self.update_selections(selections, ctx); self.changed_selections(ctx); } pub fn select_left(&mut self, _: &(), ctx: &mut ViewContext) { + let mut selections = self.selections(ctx.app()).to_vec(); { let buffer = self.buffer.as_ref(ctx); let map = self.display_map.as_ref(ctx); - for selection in &mut self.selections { + for selection in &mut selections { let head = selection.head().to_display_point(map, ctx.app()).unwrap(); let cursor = map .anchor_before( @@ -490,14 +500,16 @@ impl BufferView { selection.goal_column = None; } } + self.update_selections(selections, ctx); self.changed_selections(ctx); } pub fn move_right(&mut self, _: &(), ctx: &mut ViewContext) { + let mut selections = self.selections(ctx.app()).to_vec(); { let app = ctx.app(); let map = self.display_map.as_ref(app); - for selection in &mut self.selections { + for selection in &mut selections { let start = selection.start.to_display_point(map, app).unwrap(); let end = selection.end.to_display_point(map, app).unwrap(); @@ -514,15 +526,17 @@ impl BufferView { selection.goal_column = None; } } + self.update_selections(selections, ctx); self.changed_selections(ctx); } pub fn select_right(&mut self, _: &(), ctx: &mut ViewContext) { + let mut selections = self.selections(ctx.app()).to_vec(); { - let buffer = self.buffer.as_ref(ctx); let app = ctx.app(); + let buffer = self.buffer.as_ref(app); let map = self.display_map.as_ref(app); - for selection in &mut self.selections { + for selection in &mut selections { let head = selection.head().to_display_point(map, ctx.app()).unwrap(); let cursor = map .anchor_before(movement::right(map, head, app).unwrap(), Bias::Right, app) @@ -531,6 +545,7 @@ impl BufferView { selection.goal_column = None; } } + self.update_selections(selections, ctx); self.changed_selections(ctx); } @@ -538,23 +553,27 @@ impl BufferView { if self.single_line { ctx.propagate_action(); } else { - let app = ctx.app(); - let map = self.display_map.as_ref(app); - for selection in &mut self.selections { - let start = selection.start.to_display_point(map, app).unwrap(); - let end = selection.end.to_display_point(map, app).unwrap(); - if start != end { - selection.goal_column = None; - } + let mut selections = self.selections(ctx.app()).to_vec(); + { + let app = ctx.app(); + let map = self.display_map.as_ref(app); + for selection in &mut selections { + let start = selection.start.to_display_point(map, app).unwrap(); + let end = selection.end.to_display_point(map, app).unwrap(); + if start != end { + selection.goal_column = None; + } - let (start, goal_column) = - movement::up(map, start, selection.goal_column, app).unwrap(); - let cursor = map.anchor_before(start, Bias::Left, app).unwrap(); - selection.start = cursor.clone(); - selection.end = cursor; - selection.goal_column = goal_column; - selection.reversed = false; + let (start, goal_column) = + movement::up(map, start, selection.goal_column, app).unwrap(); + let cursor = map.anchor_before(start, Bias::Left, app).unwrap(); + selection.start = cursor.clone(); + selection.end = cursor; + selection.goal_column = goal_column; + selection.reversed = false; + } } + self.update_selections(selections, ctx); self.changed_selections(ctx); } } @@ -563,16 +582,20 @@ impl BufferView { if self.single_line { ctx.propagate_action(); } else { - let app = ctx.app(); - let buffer = self.buffer.as_ref(app); - let map = self.display_map.as_ref(app); - for selection in &mut self.selections { - let head = selection.head().to_display_point(map, app).unwrap(); - let (head, goal_column) = - movement::up(map, head, selection.goal_column, app).unwrap(); - selection.set_head(&buffer, map.anchor_before(head, Bias::Left, app).unwrap()); - selection.goal_column = goal_column; + let mut selections = self.selections(ctx.app()).to_vec(); + { + let app = ctx.app(); + let buffer = self.buffer.as_ref(app); + let map = self.display_map.as_ref(app); + for selection in &mut selections { + let head = selection.head().to_display_point(map, app).unwrap(); + let (head, goal_column) = + movement::up(map, head, selection.goal_column, app).unwrap(); + selection.set_head(&buffer, map.anchor_before(head, Bias::Left, app).unwrap()); + selection.goal_column = goal_column; + } } + self.update_selections(selections, ctx); self.changed_selections(ctx); } } @@ -581,23 +604,27 @@ impl BufferView { if self.single_line { ctx.propagate_action(); } else { - let app = ctx.app(); - let map = self.display_map.as_ref(app); - for selection in &mut self.selections { - let start = selection.start.to_display_point(map, app).unwrap(); - let end = selection.end.to_display_point(map, app).unwrap(); - if start != end { - selection.goal_column = None; - } + let mut selections = self.selections(ctx.app()).to_vec(); + { + let app = ctx.app(); + let map = self.display_map.as_ref(app); + for selection in &mut selections { + let start = selection.start.to_display_point(map, app).unwrap(); + let end = selection.end.to_display_point(map, app).unwrap(); + if start != end { + selection.goal_column = None; + } - let (start, goal_column) = - movement::down(map, end, selection.goal_column, app).unwrap(); - let cursor = map.anchor_before(start, Bias::Right, app).unwrap(); - selection.start = cursor.clone(); - selection.end = cursor; - selection.goal_column = goal_column; - selection.reversed = false; + let (start, goal_column) = + movement::down(map, end, selection.goal_column, app).unwrap(); + let cursor = map.anchor_before(start, Bias::Right, app).unwrap(); + selection.start = cursor.clone(); + selection.end = cursor; + selection.goal_column = goal_column; + selection.reversed = false; + } } + self.update_selections(selections, ctx); self.changed_selections(ctx); } } @@ -606,69 +633,39 @@ impl BufferView { if self.single_line { ctx.propagate_action(); } else { - let app = ctx.app(); - let buffer = self.buffer.as_ref(ctx); - let map = self.display_map.as_ref(ctx); - for selection in &mut self.selections { - let head = selection.head().to_display_point(map, app).unwrap(); - let (head, goal_column) = - movement::down(map, head, selection.goal_column, app).unwrap(); - selection.set_head(&buffer, map.anchor_before(head, Bias::Right, app).unwrap()); - selection.goal_column = goal_column; + let mut selections = self.selections(ctx.app()).to_vec(); + { + let app = ctx.app(); + let buffer = self.buffer.as_ref(app); + let map = self.display_map.as_ref(app); + for selection in &mut selections { + let head = selection.head().to_display_point(map, app).unwrap(); + let (head, goal_column) = + movement::down(map, head, selection.goal_column, app).unwrap(); + selection.set_head(&buffer, map.anchor_before(head, Bias::Right, app).unwrap()); + selection.goal_column = goal_column; + } } + self.update_selections(selections, ctx); self.changed_selections(ctx); } } pub fn changed_selections(&mut self, ctx: &mut ViewContext) { - self.merge_selections(ctx.app()); self.pause_cursor_blinking(ctx); *self.autoscroll_requested.lock() = true; ctx.notify(); } - fn merge_selections(&mut self, ctx: &AppContext) { - let buffer = self.buffer.as_ref(ctx); - let mut i = 1; - while i < self.selections.len() { - if self.selections[i - 1] - .end - .cmp(&self.selections[i].start, buffer) - .unwrap() - >= Ordering::Equal - { - let removed = self.selections.remove(i); - if removed - .start - .cmp(&self.selections[i - 1].start, buffer) - .unwrap() - < Ordering::Equal - { - self.selections[i - 1].start = removed.start; - } - if removed - .end - .cmp(&self.selections[i - 1].end, buffer) - .unwrap() - > Ordering::Equal - { - self.selections[i - 1].end = removed.end; - } - } else { - i += 1; - } - } - } - pub fn first_selection(&self, app: &AppContext) -> Range { - self.selections + self.selections(app) .first() .unwrap() .display_range(self.display_map.as_ref(app), app) } pub fn last_selection(&self, app: &AppContext) -> Range { - self.selections + self.selections(app) .last() .unwrap() .display_range(self.display_map.as_ref(app), app) @@ -691,7 +688,7 @@ impl BufferView { None } }); - self.selections[start_index..] + self.selections(app)[start_index..] .iter() .map(move |s| s.display_range(map, app)) .take_while(move |r| r.start <= range.end || r.end <= range.end) @@ -700,16 +697,12 @@ impl BufferView { fn selection_insertion_index(&self, start: &Anchor, app: &AppContext) -> usize { let buffer = self.buffer.as_ref(app); - - match self - .selections - .binary_search_by(|probe| probe.start.cmp(&start, buffer).unwrap()) - { + let selections = self.selections(app); + match selections.binary_search_by(|probe| probe.start.cmp(&start, buffer).unwrap()) { Ok(index) => index, Err(index) => { if index > 0 - && self.selections[index - 1].end.cmp(&start, buffer).unwrap() - == Ordering::Greater + && selections[index - 1].end.cmp(&start, buffer).unwrap() == Ordering::Greater { index - 1 } else { @@ -719,6 +712,21 @@ impl BufferView { } } + fn selections<'a>(&self, app: &'a AppContext) -> &'a [Selection] { + self.buffer + .as_ref(app) + .selections(self.selection_set_id) + .unwrap() + } + + fn update_selections<'a>(&self, selections: Vec, ctx: &mut ViewContext) { + let op = self.buffer.update(ctx, |buffer, ctx| { + buffer + .update_selection_set(self.selection_set_id, selections, Some(ctx)) + .unwrap() + }); + } + pub fn page_up(&mut self, _: &(), _: &mut ViewContext) { log::info!("BufferView::page_up"); } @@ -734,7 +742,7 @@ impl BufferView { let app = ctx.app(); let map = self.display_map.as_ref(app); - for selection in &self.selections { + for selection in self.selections(app) { let (start, end) = selection.display_range(map, app).sorted(); let buffer_start_row = start.to_buffer_point(map, Bias::Left, app).unwrap().row; @@ -766,7 +774,7 @@ impl BufferView { let map = self.display_map.as_ref(app); let buffer = self.buffer.as_ref(app); let ranges = self - .selections + .selections(app) .iter() .map(|s| { let (start, end) = s.display_range(map, app).sorted(); @@ -846,7 +854,7 @@ impl BufferView { self.display_map.update(ctx, |map, ctx| { let buffer = self.buffer.as_ref(ctx); let ranges = self - .selections + .selections(ctx.app()) .iter() .map(|s| s.range(buffer)) .collect::>(); @@ -1099,13 +1107,6 @@ impl BufferView { } } -struct Selection { - start: Anchor, - end: Anchor, - reversed: bool, - goal_column: Option, -} - pub enum Event { Activate, Edited, @@ -1194,60 +1195,6 @@ impl workspace::ItemView for BufferView { } } -impl Selection { - fn head(&self) -> &Anchor { - if self.reversed { - &self.start - } else { - &self.end - } - } - - fn set_head(&mut self, buffer: &Buffer, cursor: Anchor) { - if cursor.cmp(self.tail(), buffer).unwrap() < Ordering::Equal { - if !self.reversed { - mem::swap(&mut self.start, &mut self.end); - self.reversed = true; - } - self.start = cursor; - } else { - if self.reversed { - mem::swap(&mut self.start, &mut self.end); - self.reversed = false; - } - self.end = cursor; - } - } - - fn tail(&self) -> &Anchor { - if self.reversed { - &self.end - } else { - &self.start - } - } - - fn range(&self, buffer: &Buffer) -> Range { - let start = self.start.to_point(buffer).unwrap(); - let end = self.end.to_point(buffer).unwrap(); - if self.reversed { - end..start - } else { - start..end - } - } - - fn display_range(&self, map: &DisplayMap, app: &AppContext) -> Range { - let start = self.start.to_display_point(map, app).unwrap(); - let end = self.end.to_display_point(map, app).unwrap(); - if self.reversed { - end..start - } else { - start..end - } - } -} - #[cfg(test)] mod tests { use super::*; @@ -1492,12 +1439,12 @@ mod tests { view.update(&mut app, |view, ctx| { view.move_down(&(), ctx); assert_eq!( - view.selections(ctx.app()), + view.selection_ranges(ctx.app()), &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] ); view.move_right(&(), ctx); assert_eq!( - view.selections(ctx.app()), + view.selection_ranges(ctx.app()), &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)] ); Ok::<(), Error>(()) @@ -1543,7 +1490,7 @@ mod tests { } impl BufferView { - fn selections(&self, app: &AppContext) -> Vec> { + fn selection_ranges(&self, app: &AppContext) -> Vec> { self.selections_in_range(DisplayPoint::zero()..self.max_point(app), app) .collect::>() }