WIP: Start on pushing selection management down into Buffer
This commit is contained in:
parent
472ff1621f
commit
551c86f87a
3 changed files with 336 additions and 347 deletions
|
@ -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() {
|
||||||
let mut old_selections = selections.drain(..);
|
if selections[i - 1]
|
||||||
if let Some(mut prev_selection) = old_selections.next() {
|
.end
|
||||||
for selection in old_selections {
|
.cmp(&selections[i].start, self)
|
||||||
if prev_selection.end.cmp(&selection.start, self).unwrap() >= Ordering::Equal {
|
.unwrap()
|
||||||
if selection.end.cmp(&prev_selection.end, self).unwrap() > Ordering::Equal {
|
>= Ordering::Equal
|
||||||
prev_selection.end = selection.end;
|
{
|
||||||
}
|
let removed = selections.remove(i);
|
||||||
} else {
|
if removed.start.cmp(&selections[i - 1].start, self).unwrap() < Ordering::Equal {
|
||||||
new_selections.push(mem::replace(&mut prev_selection, selection));
|
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<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 {
|
} else {
|
||||||
selections.push(Selection {
|
i += 1;
|
||||||
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 {
|
||||||
|
|
75
zed/src/editor/buffer/selection.rs
Normal file
75
zed/src/editor/buffer/selection.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,51 +364,50 @@ 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 start = selection.start.to_offset(buffer).unwrap();
|
let buffer = self.buffer.as_ref(ctx);
|
||||||
let end = selection.end.to_offset(buffer).unwrap();
|
for selection in self.selections(ctx.app()) {
|
||||||
offset_ranges.push(start..end);
|
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| {
|
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 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);
|
self.update_selections(new_selections, 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.pause_cursor_blinking(ctx);
|
self.pause_cursor_blinking(ctx);
|
||||||
*self.autoscroll_requested.lock() = true;
|
*self.autoscroll_requested.lock() = true;
|
||||||
}
|
}
|
||||||
|
@ -419,22 +421,27 @@ impl BufferView {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
||||||
let buffer = self.buffer.as_ref(ctx);
|
let mut selections = self.selections(ctx.app()).to_vec();
|
||||||
let map = self.display_map.as_ref(ctx);
|
{
|
||||||
for selection in &mut self.selections {
|
let buffer = self.buffer.as_ref(ctx);
|
||||||
if selection.range(buffer).is_empty() {
|
let map = self.display_map.as_ref(ctx);
|
||||||
let head = selection.head().to_display_point(map, ctx.app()).unwrap();
|
for selection in &mut selections {
|
||||||
let cursor = map
|
if selection.range(buffer).is_empty() {
|
||||||
.anchor_before(
|
let head = selection.head().to_display_point(map, ctx.app()).unwrap();
|
||||||
movement::left(map, head, ctx.app()).unwrap(),
|
let cursor = map
|
||||||
Bias::Left,
|
.anchor_before(
|
||||||
ctx.app(),
|
movement::left(map, head, ctx.app()).unwrap(),
|
||||||
)
|
Bias::Left,
|
||||||
.unwrap();
|
ctx.app(),
|
||||||
selection.set_head(&buffer, cursor);
|
)
|
||||||
selection.goal_column = None;
|
.unwrap();
|
||||||
|
selection.set_head(&buffer, cursor);
|
||||||
|
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,23 +553,27 @@ impl BufferView {
|
||||||
if self.single_line {
|
if self.single_line {
|
||||||
ctx.propagate_action();
|
ctx.propagate_action();
|
||||||
} else {
|
} else {
|
||||||
let app = ctx.app();
|
let mut selections = self.selections(ctx.app()).to_vec();
|
||||||
let map = self.display_map.as_ref(app);
|
{
|
||||||
for selection in &mut self.selections {
|
let app = ctx.app();
|
||||||
let start = selection.start.to_display_point(map, app).unwrap();
|
let map = self.display_map.as_ref(app);
|
||||||
let end = selection.end.to_display_point(map, app).unwrap();
|
for selection in &mut selections {
|
||||||
if start != end {
|
let start = selection.start.to_display_point(map, app).unwrap();
|
||||||
selection.goal_column = None;
|
let end = selection.end.to_display_point(map, app).unwrap();
|
||||||
}
|
if start != end {
|
||||||
|
selection.goal_column = None;
|
||||||
|
}
|
||||||
|
|
||||||
let (start, goal_column) =
|
let (start, goal_column) =
|
||||||
movement::up(map, start, selection.goal_column, app).unwrap();
|
movement::up(map, start, selection.goal_column, app).unwrap();
|
||||||
let cursor = map.anchor_before(start, Bias::Left, app).unwrap();
|
let cursor = map.anchor_before(start, Bias::Left, app).unwrap();
|
||||||
selection.start = cursor.clone();
|
selection.start = cursor.clone();
|
||||||
selection.end = cursor;
|
selection.end = cursor;
|
||||||
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 app = ctx.app();
|
let mut selections = self.selections(ctx.app()).to_vec();
|
||||||
let buffer = self.buffer.as_ref(app);
|
{
|
||||||
let map = self.display_map.as_ref(app);
|
let app = ctx.app();
|
||||||
for selection in &mut self.selections {
|
let buffer = self.buffer.as_ref(app);
|
||||||
let head = selection.head().to_display_point(map, app).unwrap();
|
let map = self.display_map.as_ref(app);
|
||||||
let (head, goal_column) =
|
for selection in &mut selections {
|
||||||
movement::up(map, head, selection.goal_column, app).unwrap();
|
let head = selection.head().to_display_point(map, app).unwrap();
|
||||||
selection.set_head(&buffer, map.anchor_before(head, Bias::Left, app).unwrap());
|
let (head, goal_column) =
|
||||||
selection.goal_column = 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);
|
self.changed_selections(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -581,23 +604,27 @@ impl BufferView {
|
||||||
if self.single_line {
|
if self.single_line {
|
||||||
ctx.propagate_action();
|
ctx.propagate_action();
|
||||||
} else {
|
} else {
|
||||||
let app = ctx.app();
|
let mut selections = self.selections(ctx.app()).to_vec();
|
||||||
let map = self.display_map.as_ref(app);
|
{
|
||||||
for selection in &mut self.selections {
|
let app = ctx.app();
|
||||||
let start = selection.start.to_display_point(map, app).unwrap();
|
let map = self.display_map.as_ref(app);
|
||||||
let end = selection.end.to_display_point(map, app).unwrap();
|
for selection in &mut selections {
|
||||||
if start != end {
|
let start = selection.start.to_display_point(map, app).unwrap();
|
||||||
selection.goal_column = None;
|
let end = selection.end.to_display_point(map, app).unwrap();
|
||||||
}
|
if start != end {
|
||||||
|
selection.goal_column = None;
|
||||||
|
}
|
||||||
|
|
||||||
let (start, goal_column) =
|
let (start, goal_column) =
|
||||||
movement::down(map, end, selection.goal_column, app).unwrap();
|
movement::down(map, end, selection.goal_column, app).unwrap();
|
||||||
let cursor = map.anchor_before(start, Bias::Right, app).unwrap();
|
let cursor = map.anchor_before(start, Bias::Right, app).unwrap();
|
||||||
selection.start = cursor.clone();
|
selection.start = cursor.clone();
|
||||||
selection.end = cursor;
|
selection.end = cursor;
|
||||||
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 app = ctx.app();
|
let mut selections = self.selections(ctx.app()).to_vec();
|
||||||
let buffer = self.buffer.as_ref(ctx);
|
{
|
||||||
let map = self.display_map.as_ref(ctx);
|
let app = ctx.app();
|
||||||
for selection in &mut self.selections {
|
let buffer = self.buffer.as_ref(app);
|
||||||
let head = selection.head().to_display_point(map, app).unwrap();
|
let map = self.display_map.as_ref(app);
|
||||||
let (head, goal_column) =
|
for selection in &mut selections {
|
||||||
movement::down(map, head, selection.goal_column, app).unwrap();
|
let head = selection.head().to_display_point(map, app).unwrap();
|
||||||
selection.set_head(&buffer, map.anchor_before(head, Bias::Right, app).unwrap());
|
let (head, goal_column) =
|
||||||
selection.goal_column = 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);
|
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<_>>()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue