WIP: Start on pushing selection management down into Buffer

This commit is contained in:
Antonio Scandurra 2021-04-09 18:45:13 +02:00
parent 472ff1621f
commit 551c86f87a
3 changed files with 336 additions and 347 deletions

View file

@ -1,11 +1,13 @@
mod anchor; mod anchor;
mod point; mod point;
mod selection;
mod text; mod text;
pub use anchor::*; pub use anchor::*;
use futures_core::future::LocalBoxFuture; use futures_core::future::LocalBoxFuture;
pub use point::*; pub use point::*;
use seahash::SeaHasher; use seahash::SeaHasher;
pub use selection::*;
pub use text::*; pub use text::*;
use crate::{ use crate::{
@ -23,7 +25,6 @@ use std::{
cmp::{self, Ordering}, cmp::{self, Ordering},
hash::BuildHasher, hash::BuildHasher,
iter::{self, Iterator}, iter::{self, Iterator},
mem,
ops::{AddAssign, Range}, ops::{AddAssign, Range},
path::PathBuf, path::PathBuf,
str, str,
@ -33,9 +34,6 @@ use std::{
const UNDO_GROUP_INTERVAL: Duration = Duration::from_millis(300); const UNDO_GROUP_INTERVAL: Duration = Duration::from_millis(300);
pub type SelectionSetId = time::Lamport;
pub type SelectionsVersion = usize;
#[derive(Clone, Default)] #[derive(Clone, Default)]
struct DeterministicState; 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)] #[derive(Clone, Default, Debug)]
struct UndoMap(HashMap<time::Local, Vec<UndoOperation>>); struct UndoMap(HashMap<time::Local, Vec<UndoOperation>>);
@ -679,45 +670,46 @@ impl Buffer {
(old_ranges, new_text, operations) (old_ranges, new_text, operations)
} }
pub fn add_selection_set<I>(&mut self, ranges: I) -> Result<(SelectionSetId, Operation)> pub fn add_selection_set(
where &mut self,
I: IntoIterator<Item = Range<Point>>, selections: Vec<Selection>,
{ ctx: Option<&mut ModelContext<Self>>,
let selections = self.selections_from_ranges(ranges)?; ) -> (SelectionSetId, Operation) {
let lamport_timestamp = self.lamport_clock.tick(); let lamport_timestamp = self.lamport_clock.tick();
self.selections self.selections
.insert(lamport_timestamp, selections.clone()); .insert(lamport_timestamp, selections.clone());
self.selections_last_update += 1; self.selections_last_update += 1;
Ok(( if let Some(ctx) = ctx {
ctx.notify();
}
(
lamport_timestamp, lamport_timestamp,
Operation::UpdateSelections { Operation::UpdateSelections {
set_id: lamport_timestamp, set_id: lamport_timestamp,
selections: Some(selections), selections: Some(selections),
lamport_timestamp, lamport_timestamp,
}, },
)) )
} }
pub fn replace_selection_set<I>( pub fn update_selection_set(
&mut self, &mut self,
set_id: SelectionSetId, set_id: SelectionSetId,
ranges: I, mut selections: Vec<Selection>,
) -> Result<Operation> ctx: Option<&mut ModelContext<Self>>,
where ) -> Result<Operation> {
I: IntoIterator<Item = Range<Point>>,
{
self.selections
.remove(&set_id)
.ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?;
let mut selections = self.selections_from_ranges(ranges)?;
self.merge_selections(&mut selections); self.merge_selections(&mut selections);
self.selections.insert(set_id, selections.clone()); self.selections.insert(set_id, selections.clone());
let lamport_timestamp = self.lamport_clock.tick(); let lamport_timestamp = self.lamport_clock.tick();
self.selections_last_update += 1; self.selections_last_update += 1;
if let Some(ctx) = ctx {
ctx.notify();
}
Ok(Operation::UpdateSelections { Ok(Operation::UpdateSelections {
set_id, set_id,
selections: Some(selections), selections: Some(selections),
@ -725,12 +717,21 @@ impl Buffer {
}) })
} }
pub fn remove_selection_set(&mut self, set_id: SelectionSetId) -> Result<Operation> { pub fn remove_selection_set(
&mut self,
set_id: SelectionSetId,
ctx: Option<&mut ModelContext<Self>>,
) -> Result<Operation> {
self.selections self.selections
.remove(&set_id) .remove(&set_id)
.ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?; .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?;
let lamport_timestamp = self.lamport_clock.tick(); let lamport_timestamp = self.lamport_clock.tick();
self.selections_last_update += 1; self.selections_last_update += 1;
if let Some(ctx) = ctx {
ctx.notify();
}
Ok(Operation::UpdateSelections { Ok(Operation::UpdateSelections {
set_id, set_id,
selections: None, 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>( pub fn selection_ranges<'a>(
&'a self, &'a self,
set_id: SelectionSetId, set_id: SelectionSetId,
) -> Result<impl Iterator<Item = Range<Point>> + 'a> { ) -> Result<impl Iterator<Item = Range<Point>> + 'a> {
let selections = self Ok(self.selections(set_id)?.iter().map(move |selection| {
.selections
.get(&set_id)
.ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?;
Ok(selections.iter().map(move |selection| {
let start = selection.start.to_point(self).unwrap(); let start = selection.start.to_point(self).unwrap();
let end = selection.end.to_point(self).unwrap(); let end = selection.end.to_point(self).unwrap();
if selection.reversed { if selection.reversed {
@ -770,49 +774,25 @@ impl Buffer {
} }
fn merge_selections(&mut self, selections: &mut Vec<Selection>) { fn merge_selections(&mut self, selections: &mut Vec<Selection>) {
let mut new_selections = Vec::with_capacity(selections.len()); let mut i = 1;
while i < selections.len() {
if selections[i - 1]
.end
.cmp(&selections[i].start, self)
.unwrap()
>= Ordering::Equal
{ {
let mut old_selections = selections.drain(..); let removed = selections.remove(i);
if let Some(mut prev_selection) = old_selections.next() { if removed.start.cmp(&selections[i - 1].start, self).unwrap() < Ordering::Equal {
for selection in old_selections { selections[i - 1].start = removed.start;
if prev_selection.end.cmp(&selection.start, self).unwrap() >= Ordering::Equal { }
if selection.end.cmp(&prev_selection.end, self).unwrap() > Ordering::Equal { if removed.end.cmp(&selections[i - 1].end, self).unwrap() > Ordering::Equal {
prev_selection.end = selection.end; selections[i - 1].end = removed.end;
} }
} else { } else {
new_selections.push(mem::replace(&mut prev_selection, selection)); i += 1;
} }
} }
new_selections.push(prev_selection);
}
}
*selections = new_selections;
}
fn selections_from_ranges<I>(&self, ranges: I) -> Result<Vec<Selection>>
where
I: IntoIterator<Item = Range<Point>>,
{
let mut ranges = ranges.into_iter().collect::<Vec<_>>();
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,
});
}
}
Ok(selections)
} }
pub fn apply_ops<I: IntoIterator<Item = Operation>>( pub fn apply_ops<I: IntoIterator<Item = Operation>>(
@ -1927,48 +1907,6 @@ impl<'a, F: Fn(&FragmentSummary) -> bool> Iterator for Edits<'a, F> {
// collector.into_inner().changes // collector.into_inner().changes
// } // }
impl Selection {
pub fn head(&self) -> &Anchor {
if self.reversed {
&self.start
} else {
&self.end
}
}
pub fn set_head<S>(&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<Anchor> {
self.start.clone()..self.end.clone()
}
}
#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Debug)] #[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Debug)]
struct FragmentId(Arc<[u16]>); struct FragmentId(Arc<[u16]>);
@ -3049,7 +2987,7 @@ mod tests {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let set_id = replica_selection_sets.choose(rng); let set_id = replica_selection_sets.choose(rng);
if set_id.is_some() && rng.gen_bool(1.0 / 6.0) { 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); operations.push(op);
} else { } else {
let mut ranges = Vec::new(); let mut ranges = Vec::new();
@ -3060,11 +2998,12 @@ mod tests {
let end_point = self.point_for_offset(end).unwrap(); let end_point = self.point_for_offset(end).unwrap();
ranges.push(start_point..end_point); 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) { 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 { } else {
self.replace_selection_set(*set_id.unwrap(), ranges) self.update_selection_set(*set_id.unwrap(), new_selections, None)
.unwrap() .unwrap()
}; };
operations.push(op); operations.push(op);
@ -3082,6 +3021,34 @@ mod tests {
} }
ops ops
} }
fn selections_from_ranges<I>(&self, ranges: I) -> Result<Vec<Selection>>
where
I: IntoIterator<Item = Range<Point>>,
{
let mut ranges = ranges.into_iter().collect::<Vec<_>>();
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 { impl Operation {

View file

@ -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<u32>,
}
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<Point> {
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<DisplayPoint> {
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
}
}
}

View file

@ -1,6 +1,6 @@
use super::{ use super::{
buffer, movement, Anchor, Bias, Buffer, BufferElement, DisplayMap, DisplayPoint, Point, buffer, movement, Anchor, Bias, Buffer, BufferElement, DisplayMap, DisplayPoint, Point,
ToOffset, ToPoint, Selection, SelectionSetId, ToOffset,
}; };
use crate::{settings::Settings, watch, workspace}; use crate::{settings::Settings, watch, workspace};
use anyhow::Result; use anyhow::Result;
@ -16,7 +16,6 @@ use smol::Timer;
use std::{ use std::{
cmp::{self, Ordering}, cmp::{self, Ordering},
fmt::Write, fmt::Write,
mem,
ops::Range, ops::Range,
sync::Arc, sync::Arc,
time::Duration, time::Duration,
@ -90,7 +89,7 @@ pub struct BufferView {
handle: WeakViewHandle<Self>, handle: WeakViewHandle<Self>,
buffer: ModelHandle<Buffer>, buffer: ModelHandle<Buffer>,
display_map: ModelHandle<DisplayMap>, display_map: ModelHandle<DisplayMap>,
selections: Vec<Selection>, selection_set_id: SelectionSetId,
pending_selection: Option<Selection>, pending_selection: Option<Selection>,
scroll_position: Mutex<Vector2F>, scroll_position: Mutex<Vector2F>,
autoscroll_requested: Mutex<bool>, autoscroll_requested: Mutex<bool>,
@ -128,17 +127,22 @@ impl BufferView {
}); });
ctx.observe(&display_map, Self::on_display_map_changed); 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 { Self {
handle: ctx.handle().downgrade(), handle: ctx.handle().downgrade(),
buffer, buffer,
display_map, display_map,
selections: vec![Selection { selection_set_id,
start: buffer_ref.anchor_before(0).unwrap(),
end: buffer_ref.anchor_before(0).unwrap(),
reversed: false,
goal_column: None,
}],
pending_selection: None, pending_selection: None,
scroll_position: Mutex::new(Vector2F::zero()), scroll_position: Mutex::new(Vector2F::zero()),
autoscroll_requested: Mutex::new(false), autoscroll_requested: Mutex::new(false),
@ -194,7 +198,7 @@ impl BufferView {
let map = self.display_map.as_ref(app); let map = self.display_map.as_ref(app);
let visible_lines = viewport_height / line_height; let visible_lines = viewport_height / line_height;
let first_cursor_top = self let first_cursor_top = self
.selections .selections(app)
.first() .first()
.unwrap() .unwrap()
.head() .head()
@ -202,7 +206,7 @@ impl BufferView {
.unwrap() .unwrap()
.row() as f32; .row() as f32;
let last_cursor_bottom = self let last_cursor_bottom = self
.selections .selections(app)
.last() .last()
.unwrap() .unwrap()
.head() .head()
@ -245,7 +249,7 @@ impl BufferView {
let mut target_left = std::f32::INFINITY; let mut target_left = std::f32::INFINITY;
let mut target_right = 0.0_f32; 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 head = selection.head().to_display_point(map, app).unwrap();
let start_column = head.column().saturating_sub(3); let start_column = head.column().saturating_sub(3);
let end_column = cmp::min(map.line_len(head.row(), app).unwrap(), head.column() + 3); let end_column = cmp::min(map.line_len(head.row(), app).unwrap(), head.column() + 3);
@ -302,7 +306,7 @@ impl BufferView {
}; };
if !add { if !add {
self.selections.clear(); self.update_selections(Vec::new(), ctx);
} }
self.pending_selection = Some(selection); self.pending_selection = Some(selection);
@ -333,9 +337,9 @@ impl BufferView {
fn end_selection(&mut self, ctx: &mut ViewContext<Self>) { fn end_selection(&mut self, ctx: &mut ViewContext<Self>) {
if let Some(selection) = self.pending_selection.take() { if let Some(selection) = self.pending_selection.take() {
let ix = self.selection_insertion_index(&selection.start, ctx.app()); let ix = self.selection_insertion_index(&selection.start, ctx.app());
self.selections.insert(ix, selection); let mut selections = self.selections(ctx.app()).to_vec();
self.merge_selections(ctx.app()); selections.insert(ix, selection);
ctx.notify(); self.update_selections(selections, ctx);
} else { } else {
log::error!("end_selection dispatched with no pending selection"); log::error!("end_selection dispatched with no pending selection");
} }
@ -350,7 +354,6 @@ impl BufferView {
where where
T: IntoIterator<Item = &'a Range<DisplayPoint>>, T: IntoIterator<Item = &'a Range<DisplayPoint>>,
{ {
let buffer = self.buffer.as_ref(ctx);
let map = self.display_map.as_ref(ctx); let map = self.display_map.as_ref(ctx);
let mut selections = Vec::new(); let mut selections = Vec::new();
for range in ranges { for range in ranges {
@ -361,33 +364,30 @@ impl BufferView {
goal_column: None, goal_column: None,
}); });
} }
selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer).unwrap()); self.update_selections(selections, ctx);
self.selections = selections;
self.merge_selections(ctx.app());
ctx.notify();
Ok(()) Ok(())
} }
fn insert(&mut self, text: &String, ctx: &mut ViewContext<Self>) { fn insert(&mut self, text: &String, ctx: &mut ViewContext<Self>) {
let buffer = self.buffer.as_ref(ctx);
let mut offset_ranges = SmallVec::<[Range<usize>; 32]>::new(); let mut offset_ranges = SmallVec::<[Range<usize>; 32]>::new();
for selection in &self.selections { {
let buffer = self.buffer.as_ref(ctx);
for selection in self.selections(ctx.app()) {
let start = selection.start.to_offset(buffer).unwrap(); let start = selection.start.to_offset(buffer).unwrap();
let end = selection.end.to_offset(buffer).unwrap(); let end = selection.end.to_offset(buffer).unwrap();
offset_ranges.push(start..end); offset_ranges.push(start..end);
} }
}
let mut new_selections = Vec::new();
self.buffer.update(ctx, |buffer, ctx| { self.buffer.update(ctx, |buffer, ctx| {
if let Err(error) = buffer.edit(offset_ranges.iter().cloned(), text.as_str(), Some(ctx)) if let Err(error) = buffer.edit(offset_ranges.iter().cloned(), text.as_str(), Some(ctx))
{ {
log::error!("error inserting text: {}", error); log::error!("error inserting text: {}", error);
}; };
});
let buffer = self.buffer.as_ref(ctx);
let char_count = text.chars().count() as isize; let char_count = text.chars().count() as isize;
let mut delta = 0_isize; let mut delta = 0_isize;
self.selections = offset_ranges new_selections = offset_ranges
.into_iter() .into_iter()
.map(|range| { .map(|range| {
let start = range.start as isize; let start = range.start as isize;
@ -405,7 +405,9 @@ impl BufferView {
} }
}) })
.collect(); .collect();
});
self.update_selections(new_selections, ctx);
self.pause_cursor_blinking(ctx); self.pause_cursor_blinking(ctx);
*self.autoscroll_requested.lock() = true; *self.autoscroll_requested.lock() = true;
} }
@ -419,9 +421,11 @@ impl BufferView {
} }
pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext<Self>) { pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
let mut selections = self.selections(ctx.app()).to_vec();
{
let buffer = self.buffer.as_ref(ctx); let buffer = self.buffer.as_ref(ctx);
let map = self.display_map.as_ref(ctx); let map = self.display_map.as_ref(ctx);
for selection in &mut self.selections { for selection in &mut selections {
if selection.range(buffer).is_empty() { if selection.range(buffer).is_empty() {
let head = selection.head().to_display_point(map, ctx.app()).unwrap(); let head = selection.head().to_display_point(map, ctx.app()).unwrap();
let cursor = map let cursor = map
@ -435,6 +439,9 @@ impl BufferView {
selection.goal_column = None; selection.goal_column = None;
} }
} }
}
self.update_selections(selections, ctx);
self.changed_selections(ctx); self.changed_selections(ctx);
self.insert(&String::new(), ctx); self.insert(&String::new(), ctx);
} }
@ -450,10 +457,11 @@ impl BufferView {
} }
pub fn move_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) { pub fn move_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
let mut selections = self.selections(ctx.app()).to_vec();
{ {
let app = ctx.app(); let app = ctx.app();
let map = self.display_map.as_ref(ctx); 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 start = selection.start.to_display_point(map, app).unwrap();
let end = selection.end.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; selection.goal_column = None;
} }
} }
self.update_selections(selections, ctx);
self.changed_selections(ctx); self.changed_selections(ctx);
} }
pub fn select_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) { pub fn select_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
let mut selections = self.selections(ctx.app()).to_vec();
{ {
let buffer = self.buffer.as_ref(ctx); let buffer = self.buffer.as_ref(ctx);
let map = self.display_map.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 head = selection.head().to_display_point(map, ctx.app()).unwrap();
let cursor = map let cursor = map
.anchor_before( .anchor_before(
@ -490,14 +500,16 @@ impl BufferView {
selection.goal_column = None; selection.goal_column = None;
} }
} }
self.update_selections(selections, ctx);
self.changed_selections(ctx); self.changed_selections(ctx);
} }
pub fn move_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) { pub fn move_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
let mut selections = self.selections(ctx.app()).to_vec();
{ {
let app = ctx.app(); let app = ctx.app();
let map = self.display_map.as_ref(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 start = selection.start.to_display_point(map, app).unwrap();
let end = selection.end.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; selection.goal_column = None;
} }
} }
self.update_selections(selections, ctx);
self.changed_selections(ctx); self.changed_selections(ctx);
} }
pub fn select_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) { pub fn select_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
let mut selections = self.selections(ctx.app()).to_vec();
{ {
let buffer = self.buffer.as_ref(ctx);
let app = ctx.app(); let app = ctx.app();
let buffer = self.buffer.as_ref(app);
let map = self.display_map.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 head = selection.head().to_display_point(map, ctx.app()).unwrap();
let cursor = map let cursor = map
.anchor_before(movement::right(map, head, app).unwrap(), Bias::Right, app) .anchor_before(movement::right(map, head, app).unwrap(), Bias::Right, app)
@ -531,6 +545,7 @@ impl BufferView {
selection.goal_column = None; selection.goal_column = None;
} }
} }
self.update_selections(selections, ctx);
self.changed_selections(ctx); self.changed_selections(ctx);
} }
@ -538,9 +553,11 @@ impl BufferView {
if self.single_line { if self.single_line {
ctx.propagate_action(); ctx.propagate_action();
} else { } else {
let mut selections = self.selections(ctx.app()).to_vec();
{
let app = ctx.app(); let app = ctx.app();
let map = self.display_map.as_ref(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 start = selection.start.to_display_point(map, app).unwrap();
let end = selection.end.to_display_point(map, app).unwrap(); let end = selection.end.to_display_point(map, app).unwrap();
if start != end { if start != end {
@ -555,6 +572,8 @@ impl BufferView {
selection.goal_column = goal_column; selection.goal_column = goal_column;
selection.reversed = false; selection.reversed = false;
} }
}
self.update_selections(selections, ctx);
self.changed_selections(ctx); self.changed_selections(ctx);
} }
} }
@ -563,16 +582,20 @@ impl BufferView {
if self.single_line { if self.single_line {
ctx.propagate_action(); ctx.propagate_action();
} else { } else {
let mut selections = self.selections(ctx.app()).to_vec();
{
let app = ctx.app(); let app = ctx.app();
let buffer = self.buffer.as_ref(app); let buffer = self.buffer.as_ref(app);
let map = self.display_map.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, app).unwrap(); let head = selection.head().to_display_point(map, app).unwrap();
let (head, goal_column) = let (head, goal_column) =
movement::up(map, head, selection.goal_column, app).unwrap(); movement::up(map, head, selection.goal_column, app).unwrap();
selection.set_head(&buffer, map.anchor_before(head, Bias::Left, app).unwrap()); selection.set_head(&buffer, map.anchor_before(head, Bias::Left, app).unwrap());
selection.goal_column = goal_column; selection.goal_column = goal_column;
} }
}
self.update_selections(selections, ctx);
self.changed_selections(ctx); self.changed_selections(ctx);
} }
} }
@ -581,9 +604,11 @@ impl BufferView {
if self.single_line { if self.single_line {
ctx.propagate_action(); ctx.propagate_action();
} else { } else {
let mut selections = self.selections(ctx.app()).to_vec();
{
let app = ctx.app(); let app = ctx.app();
let map = self.display_map.as_ref(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 start = selection.start.to_display_point(map, app).unwrap();
let end = selection.end.to_display_point(map, app).unwrap(); let end = selection.end.to_display_point(map, app).unwrap();
if start != end { if start != end {
@ -598,6 +623,8 @@ impl BufferView {
selection.goal_column = goal_column; selection.goal_column = goal_column;
selection.reversed = false; selection.reversed = false;
} }
}
self.update_selections(selections, ctx);
self.changed_selections(ctx); self.changed_selections(ctx);
} }
} }
@ -606,69 +633,39 @@ impl BufferView {
if self.single_line { if self.single_line {
ctx.propagate_action(); ctx.propagate_action();
} else { } else {
let mut selections = self.selections(ctx.app()).to_vec();
{
let app = ctx.app(); let app = ctx.app();
let buffer = self.buffer.as_ref(ctx); let buffer = self.buffer.as_ref(app);
let map = self.display_map.as_ref(ctx); 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, app).unwrap(); let head = selection.head().to_display_point(map, app).unwrap();
let (head, goal_column) = let (head, goal_column) =
movement::down(map, head, selection.goal_column, app).unwrap(); movement::down(map, head, selection.goal_column, app).unwrap();
selection.set_head(&buffer, map.anchor_before(head, Bias::Right, app).unwrap()); selection.set_head(&buffer, map.anchor_before(head, Bias::Right, app).unwrap());
selection.goal_column = goal_column; selection.goal_column = goal_column;
} }
}
self.update_selections(selections, ctx);
self.changed_selections(ctx); self.changed_selections(ctx);
} }
} }
pub fn changed_selections(&mut self, ctx: &mut ViewContext<Self>) { pub fn changed_selections(&mut self, ctx: &mut ViewContext<Self>) {
self.merge_selections(ctx.app());
self.pause_cursor_blinking(ctx); self.pause_cursor_blinking(ctx);
*self.autoscroll_requested.lock() = true; *self.autoscroll_requested.lock() = true;
ctx.notify(); 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<DisplayPoint> { pub fn first_selection(&self, app: &AppContext) -> Range<DisplayPoint> {
self.selections self.selections(app)
.first() .first()
.unwrap() .unwrap()
.display_range(self.display_map.as_ref(app), app) .display_range(self.display_map.as_ref(app), app)
} }
pub fn last_selection(&self, app: &AppContext) -> Range<DisplayPoint> { pub fn last_selection(&self, app: &AppContext) -> Range<DisplayPoint> {
self.selections self.selections(app)
.last() .last()
.unwrap() .unwrap()
.display_range(self.display_map.as_ref(app), app) .display_range(self.display_map.as_ref(app), app)
@ -691,7 +688,7 @@ impl BufferView {
None None
} }
}); });
self.selections[start_index..] self.selections(app)[start_index..]
.iter() .iter()
.map(move |s| s.display_range(map, app)) .map(move |s| s.display_range(map, app))
.take_while(move |r| r.start <= range.end || r.end <= range.end) .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 { fn selection_insertion_index(&self, start: &Anchor, app: &AppContext) -> usize {
let buffer = self.buffer.as_ref(app); let buffer = self.buffer.as_ref(app);
let selections = self.selections(app);
match self match selections.binary_search_by(|probe| probe.start.cmp(&start, buffer).unwrap()) {
.selections
.binary_search_by(|probe| probe.start.cmp(&start, buffer).unwrap())
{
Ok(index) => index, Ok(index) => index,
Err(index) => { Err(index) => {
if index > 0 if index > 0
&& self.selections[index - 1].end.cmp(&start, buffer).unwrap() && selections[index - 1].end.cmp(&start, buffer).unwrap() == Ordering::Greater
== Ordering::Greater
{ {
index - 1 index - 1
} else { } 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<Selection>, ctx: &mut ViewContext<Self>) {
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<Self>) { pub fn page_up(&mut self, _: &(), _: &mut ViewContext<Self>) {
log::info!("BufferView::page_up"); log::info!("BufferView::page_up");
} }
@ -734,7 +742,7 @@ impl BufferView {
let app = ctx.app(); let app = ctx.app();
let map = self.display_map.as_ref(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 (start, end) = selection.display_range(map, app).sorted();
let buffer_start_row = start.to_buffer_point(map, Bias::Left, app).unwrap().row; 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 map = self.display_map.as_ref(app);
let buffer = self.buffer.as_ref(app); let buffer = self.buffer.as_ref(app);
let ranges = self let ranges = self
.selections .selections(app)
.iter() .iter()
.map(|s| { .map(|s| {
let (start, end) = s.display_range(map, app).sorted(); let (start, end) = s.display_range(map, app).sorted();
@ -846,7 +854,7 @@ impl BufferView {
self.display_map.update(ctx, |map, ctx| { self.display_map.update(ctx, |map, ctx| {
let buffer = self.buffer.as_ref(ctx); let buffer = self.buffer.as_ref(ctx);
let ranges = self let ranges = self
.selections .selections(ctx.app())
.iter() .iter()
.map(|s| s.range(buffer)) .map(|s| s.range(buffer))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -1099,13 +1107,6 @@ impl BufferView {
} }
} }
struct Selection {
start: Anchor,
end: Anchor,
reversed: bool,
goal_column: Option<u32>,
}
pub enum Event { pub enum Event {
Activate, Activate,
Edited, 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<Point> {
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<DisplayPoint> {
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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -1492,12 +1439,12 @@ mod tests {
view.update(&mut app, |view, ctx| { view.update(&mut app, |view, ctx| {
view.move_down(&(), ctx); view.move_down(&(), ctx);
assert_eq!( assert_eq!(
view.selections(ctx.app()), view.selection_ranges(ctx.app()),
&[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
); );
view.move_right(&(), ctx); view.move_right(&(), ctx);
assert_eq!( assert_eq!(
view.selections(ctx.app()), view.selection_ranges(ctx.app()),
&[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)] &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)]
); );
Ok::<(), Error>(()) Ok::<(), Error>(())
@ -1543,7 +1490,7 @@ mod tests {
} }
impl BufferView { impl BufferView {
fn selections(&self, app: &AppContext) -> Vec<Range<DisplayPoint>> { fn selection_ranges(&self, app: &AppContext) -> Vec<Range<DisplayPoint>> {
self.selections_in_range(DisplayPoint::zero()..self.max_point(app), app) self.selections_in_range(DisplayPoint::zero()..self.max_point(app), app)
.collect::<Vec<_>>() .collect::<Vec<_>>()
} }