store buffer and display_map model handles on selections collection

This commit is contained in:
Keith Simmons 2022-05-12 15:55:18 -07:00
parent db0a9114c2
commit de9dc27980
14 changed files with 373 additions and 393 deletions

View File

@ -5499,11 +5499,11 @@ mod tests {
Some((worktree_id, "2.txt").into())
);
assert_eq!(
editor_b2.read_with(cx_b, |editor, cx| editor.selected_ranges(cx)),
editor_b2.read_with(cx_b, |editor, cx| editor.selections.selected_ranges(cx)),
vec![2..3]
);
assert_eq!(
editor_b1.read_with(cx_b, |editor, cx| editor.selected_ranges(cx)),
editor_b1.read_with(cx_b, |editor, cx| editor.selections.selected_ranges(cx)),
vec![0..1]
);
@ -5546,7 +5546,7 @@ mod tests {
});
editor_b1
.condition(cx_b, |editor, cx| {
editor.selected_ranges(cx) == vec![1..1, 2..2]
editor.selections.selected_ranges(cx) == vec![1..1, 2..2]
})
.await;
@ -5560,7 +5560,9 @@ mod tests {
editor.set_scroll_position(vec2f(0., 100.), cx);
});
editor_b1
.condition(cx_b, |editor, cx| editor.selected_ranges(cx) == vec![3..3])
.condition(cx_b, |editor, cx| {
editor.selections.selected_ranges(cx) == vec![3..3]
})
.await;
// After unfollowing, client B stops receiving updates from client A.

View File

@ -419,9 +419,7 @@ impl ProjectDiagnosticsEditor {
groups = self.path_states.get(path_ix)?.diagnostic_groups.as_slice();
new_excerpt_ids_by_selection_id =
editor.change_selections(Some(Autoscroll::Fit), cx, |s| s.refresh());
selections = editor
.selections
.interleaved::<usize>(&editor.buffer().read(cx).read(cx));
selections = editor.selections.interleaved::<usize>(cx);
}
// If any selection has lost its position, move it to start of the next primary diagnostic.
@ -899,7 +897,7 @@ mod tests {
// Cursor is at the first diagnostic
view.editor.update(cx, |editor, cx| {
assert_eq!(
editor.selected_display_ranges(cx),
editor.selections.selected_display_ranges(cx),
[DisplayPoint::new(12, 6)..DisplayPoint::new(12, 6)]
);
});
@ -1000,7 +998,7 @@ mod tests {
// Cursor keeps its position.
view.editor.update(cx, |editor, cx| {
assert_eq!(
editor.selected_display_ranges(cx),
editor.selections.selected_display_ranges(cx),
[DisplayPoint::new(19, 6)..DisplayPoint::new(19, 6)]
);
});

View File

@ -58,7 +58,7 @@ impl DiagnosticIndicator {
fn update(&mut self, editor: ViewHandle<Editor>, cx: &mut ViewContext<Self>) {
let editor = editor.read(cx);
let buffer = editor.buffer().read(cx);
let cursor_position = editor.selections.newest::<usize>(&buffer.read(cx)).head();
let cursor_position = editor.selections.newest::<usize>(cx).head();
let new_diagnostic = buffer
.read(cx)
.diagnostics_in_range::<_, usize>(cursor_position..cursor_position, false)

File diff suppressed because it is too large Load Diff

View File

@ -959,7 +959,7 @@ impl Element for EditorElement {
if view.show_local_selections {
let local_selections = view
.selections
.interleaved_in_range(start_anchor..end_anchor, &display_map.buffer_snapshot);
.interleaved_in_range(start_anchor..end_anchor, cx);
for selection in &local_selections {
let is_empty = selection.start == selection.end;
let selection_start = snapshot.prev_line_boundary(selection.start).1;
@ -1043,7 +1043,7 @@ impl Element for EditorElement {
let newest_selection_head = view
.selections
.newest::<usize>(&snapshot.buffer_snapshot)
.newest::<usize>(cx)
.head()
.to_display_point(&snapshot);

View File

@ -252,13 +252,13 @@ fn deserialize_selection(
impl Item for Editor {
fn navigate(&mut self, data: Box<dyn std::any::Any>, cx: &mut ViewContext<Self>) -> bool {
if let Ok(data) = data.downcast::<NavigationData>() {
let newest_selection = self.selections.newest::<Point>(cx);
let buffer = self.buffer.read(cx).read(cx);
let offset = if buffer.can_resolve(&data.cursor_anchor) {
data.cursor_anchor.to_point(&buffer)
} else {
buffer.clip_point(data.cursor_position, Bias::Left)
};
let newest_selection = self.selections.newest::<Point>(&buffer);
let scroll_top_anchor = if buffer.can_resolve(&data.scroll_top_anchor) {
data.scroll_top_anchor
@ -465,7 +465,7 @@ impl CursorPosition {
self.selected_count = 0;
let mut last_selection: Option<Selection<usize>> = None;
for selection in editor.selections.interleaved::<usize>(&buffer) {
for selection in editor.selections.interleaved::<usize>(cx) {
self.selected_count += selection.end - selection.start;
if last_selection
.as_ref()

View File

@ -5,7 +5,7 @@ use std::{
};
use collections::HashMap;
use gpui::{ModelHandle, MutableAppContext};
use gpui::{AppContext, ModelHandle, MutableAppContext};
use itertools::Itertools;
use language::{rope::TextDimension, Bias, Point, Selection, SelectionGoal, ToPoint};
use util::post_inc;
@ -22,14 +22,18 @@ pub struct PendingSelection {
}
pub struct SelectionsCollection {
display_map: ModelHandle<DisplayMap>,
buffer: ModelHandle<MultiBuffer>,
pub next_selection_id: usize,
disjoint: Arc<[Selection<Anchor>]>,
pending: Option<PendingSelection>,
}
impl SelectionsCollection {
pub fn new() -> Self {
pub fn new(display_map: ModelHandle<DisplayMap>, buffer: ModelHandle<MultiBuffer>) -> Self {
Self {
display_map,
buffer,
next_selection_id: 1,
disjoint: Arc::from([]),
pending: Some(PendingSelection {
@ -45,6 +49,14 @@ impl SelectionsCollection {
}
}
fn display_map(&self, cx: &mut MutableAppContext) -> DisplaySnapshot {
self.display_map.update(cx, |map, cx| map.snapshot(cx))
}
fn buffer(&self, cx: &AppContext) -> MultiBufferSnapshot {
self.buffer.read(cx).snapshot(cx)
}
pub fn count<'a>(&self) -> usize {
let mut count = self.disjoint.len();
if self.pending.is_some() {
@ -65,25 +77,26 @@ impl SelectionsCollection {
pub fn pending<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
snapshot: &MultiBufferSnapshot,
cx: &AppContext,
) -> Option<Selection<D>> {
self.pending_anchor()
.as_ref()
.map(|pending| pending.map(|p| p.summary::<D>(&snapshot)))
.map(|pending| pending.map(|p| p.summary::<D>(&self.buffer(cx))))
}
pub fn pending_mode(&self) -> Option<SelectMode> {
self.pending.as_ref().map(|pending| pending.mode.clone())
}
pub fn interleaved<'a, D>(&self, buffer: &MultiBufferSnapshot) -> Vec<Selection<D>>
pub fn interleaved<'a, D>(&self, cx: &AppContext) -> Vec<Selection<D>>
where
D: 'a + TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug,
{
let disjoint_anchors = &self.disjoint;
let mut disjoint = resolve_multiple::<D, _>(disjoint_anchors.iter(), &buffer).peekable();
let mut disjoint =
resolve_multiple::<D, _>(disjoint_anchors.iter(), &self.buffer(cx)).peekable();
let mut pending_opt = self.pending::<D>(&buffer);
let mut pending_opt = self.pending::<D>(cx);
iter::from_fn(move || {
if let Some(pending) = pending_opt.as_mut() {
@ -114,8 +127,9 @@ impl SelectionsCollection {
pub fn interleaved_in_range<'a>(
&self,
range: Range<Anchor>,
buffer: &MultiBufferSnapshot,
cx: &AppContext,
) -> Vec<Selection<Point>> {
let buffer = self.buffer(cx);
let start_ix = match self
.disjoint
.binary_search_by(|probe| probe.end.cmp(&range.start, &buffer))
@ -162,9 +176,9 @@ impl SelectionsCollection {
pub fn newest<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
snapshot: &MultiBufferSnapshot,
cx: &AppContext,
) -> Selection<D> {
resolve(self.newest_anchor(), snapshot)
resolve(self.newest_anchor(), &self.buffer(cx))
}
pub fn oldest_anchor(&self) -> &Selection<Anchor> {
@ -177,36 +191,65 @@ impl SelectionsCollection {
pub fn oldest<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
snapshot: &MultiBufferSnapshot,
cx: &AppContext,
) -> Selection<D> {
resolve(self.oldest_anchor(), snapshot)
resolve(self.oldest_anchor(), &self.buffer(cx))
}
pub fn first<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
snapshot: &MultiBufferSnapshot,
cx: &AppContext,
) -> Selection<D> {
self.interleaved(&snapshot).first().unwrap().clone()
self.interleaved(cx).first().unwrap().clone()
}
pub fn last<D: TextDimension + Ord + Sub<D, Output = D>>(
&self,
snapshot: &MultiBufferSnapshot,
cx: &AppContext,
) -> Selection<D> {
self.interleaved(&snapshot).last().unwrap().clone()
self.interleaved(cx).last().unwrap().clone()
}
#[cfg(any(test, feature = "test-support"))]
pub fn selected_ranges<D: TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug>(
&self,
cx: &AppContext,
) -> Vec<Range<D>> {
self.interleaved::<D>(cx)
.iter()
.map(|s| {
if s.reversed {
s.end.clone()..s.start.clone()
} else {
s.start.clone()..s.end.clone()
}
})
.collect()
}
#[cfg(any(test, feature = "test-support"))]
pub fn selected_display_ranges(&self, cx: &mut MutableAppContext) -> Vec<Range<DisplayPoint>> {
let display_map = self.display_map(cx);
self.disjoint_anchors()
.iter()
.chain(self.pending_anchor().as_ref())
.map(|s| {
if s.reversed {
s.end.to_display_point(&display_map)..s.start.to_display_point(&display_map)
} else {
s.start.to_display_point(&display_map)..s.end.to_display_point(&display_map)
}
})
.collect()
}
pub(crate) fn change_with<R>(
&mut self,
display_map: ModelHandle<DisplayMap>,
buffer: ModelHandle<MultiBuffer>,
cx: &mut MutableAppContext,
change: impl FnOnce(&mut MutableSelectionsCollection) -> R,
) -> R {
let mut mutable_collection = MutableSelectionsCollection {
collection: self,
display_map,
buffer,
cx,
};
@ -221,12 +264,18 @@ impl SelectionsCollection {
pub struct MutableSelectionsCollection<'a> {
collection: &'a mut SelectionsCollection,
buffer: ModelHandle<MultiBuffer>,
display_map: ModelHandle<DisplayMap>,
cx: &'a mut MutableAppContext,
}
impl<'a> MutableSelectionsCollection<'a> {
fn display_map(&mut self) -> DisplaySnapshot {
self.collection.display_map(self.cx)
}
fn buffer(&mut self) -> MultiBufferSnapshot {
self.collection.buffer(self.cx)
}
pub fn clear_disjoint(&mut self) {
self.collection.disjoint = Arc::from([]);
}
@ -303,19 +352,11 @@ impl<'a> MutableSelectionsCollection<'a> {
pub fn insert_range<T>(&mut self, range: Range<T>)
where
T: 'a
+ ToOffset
+ ToPoint
+ TextDimension
+ Ord
+ Sub<T, Output = T>
+ std::marker::Copy
+ std::fmt::Debug,
T: 'a + ToOffset + ToPoint + TextDimension + Ord + Sub<T, Output = T> + std::marker::Copy,
{
let buffer = self.buffer.read(self.cx).snapshot(self.cx);
let mut selections = self.interleaved(&buffer);
let mut start = range.start.to_offset(&buffer);
let mut end = range.end.to_offset(&buffer);
let mut selections = self.interleaved(self.cx);
let mut start = range.start.to_offset(&self.buffer());
let mut end = range.end.to_offset(&self.buffer());
let reversed = if start > end {
mem::swap(&mut start, &mut end);
true
@ -440,7 +481,7 @@ impl<'a> MutableSelectionsCollection<'a> {
where
T: IntoIterator<Item = Range<DisplayPoint>>,
{
let display_map = self.display_map.update(self.cx, |map, cx| map.snapshot(cx));
let display_map = self.display_map();
let selections = ranges
.into_iter()
.map(|range| {
@ -468,9 +509,9 @@ impl<'a> MutableSelectionsCollection<'a> {
&mut self,
mut move_selection: impl FnMut(&DisplaySnapshot, &mut Selection<DisplayPoint>),
) {
let display_map = self.display_map.update(self.cx, |map, cx| map.snapshot(cx));
let display_map = self.display_map();
let selections = self
.interleaved::<Point>(&display_map.buffer_snapshot)
.interleaved::<Point>(self.cx)
.into_iter()
.map(|selection| {
let mut selection = selection.map(|point| point.to_display_point(&display_map));
@ -514,7 +555,7 @@ impl<'a> MutableSelectionsCollection<'a> {
&mut self,
mut find_replacement_cursors: impl FnMut(&DisplaySnapshot) -> Vec<DisplayPoint>,
) {
let display_map = self.display_map.update(self.cx, |map, cx| map.snapshot(cx));
let display_map = self.display_map();
let new_selections = find_replacement_cursors(&display_map)
.into_iter()
.map(|cursor| {

View File

@ -54,5 +54,5 @@ pub fn assert_text_with_selections(
let (unmarked_text, text_ranges) = marked_text_ranges(marked_text);
assert_eq!(editor.text(cx), unmarked_text);
assert_eq!(editor.selected_ranges(cx), text_ranges);
assert_eq!(editor.selections.selected_ranges(cx), text_ranges);
}

View File

@ -43,7 +43,7 @@ impl GoToLine {
let buffer = editor.buffer().read(cx).read(cx);
(
Some(scroll_position),
editor.selections.newest(&buffer).head(),
editor.selections.newest(cx).head(),
buffer.max_point(),
)
});

View File

@ -172,7 +172,7 @@ impl PickerDelegate for OutlineView {
let editor = self.active_editor.read(cx);
let buffer = editor.buffer().read(cx).read(cx);
let cursor_offset = editor.selections.newest::<usize>(&buffer).head();
let cursor_offset = editor.selections.newest::<usize>(cx).head();
selected_index = self
.outline
.items

View File

@ -225,10 +225,7 @@ impl BufferSearchBar {
let display_map = editor
.update(cx, |editor, cx| editor.snapshot(cx))
.display_snapshot;
let selection = editor
.read(cx)
.selections
.newest::<usize>(&display_map.buffer_snapshot);
let selection = editor.read(cx).selections.newest::<usize>(cx);
let mut text: String;
if selection.start == selection.end {
@ -732,7 +729,9 @@ mod tests {
assert_eq!(search_bar.active_match_index, Some(0));
search_bar.select_next_match(&SelectNextMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
);
});
@ -743,7 +742,9 @@ mod tests {
search_bar.update(cx, |search_bar, cx| {
search_bar.select_next_match(&SelectNextMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13)]
);
});
@ -754,7 +755,9 @@ mod tests {
search_bar.update(cx, |search_bar, cx| {
search_bar.select_next_match(&SelectNextMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)]
);
});
@ -765,7 +768,9 @@ mod tests {
search_bar.update(cx, |search_bar, cx| {
search_bar.select_next_match(&SelectNextMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
);
});
@ -776,7 +781,9 @@ mod tests {
search_bar.update(cx, |search_bar, cx| {
search_bar.select_prev_match(&SelectPrevMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)]
);
});
@ -787,7 +794,9 @@ mod tests {
search_bar.update(cx, |search_bar, cx| {
search_bar.select_prev_match(&SelectPrevMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13)]
);
});
@ -798,7 +807,9 @@ mod tests {
search_bar.update(cx, |search_bar, cx| {
search_bar.select_prev_match(&SelectPrevMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
);
});
@ -817,7 +828,9 @@ mod tests {
assert_eq!(search_bar.active_match_index, Some(1));
search_bar.select_prev_match(&SelectPrevMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
);
});
@ -836,7 +849,9 @@ mod tests {
assert_eq!(search_bar.active_match_index, Some(1));
search_bar.select_next_match(&SelectNextMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13)]
);
});
@ -855,7 +870,9 @@ mod tests {
assert_eq!(search_bar.active_match_index, Some(2));
search_bar.select_prev_match(&SelectPrevMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)]
);
});
@ -874,7 +891,9 @@ mod tests {
assert_eq!(search_bar.active_match_index, Some(2));
search_bar.select_next_match(&SelectNextMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
);
});
@ -893,7 +912,9 @@ mod tests {
assert_eq!(search_bar.active_match_index, Some(0));
search_bar.select_prev_match(&SelectPrevMatch, cx);
assert_eq!(
editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)]
);
});

View File

@ -891,7 +891,7 @@ mod tests {
assert_eq!(
search_view
.results_editor
.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
.update(cx, |editor, cx| editor.selections.selected_display_ranges(cx)),
[DisplayPoint::new(2, 32)..DisplayPoint::new(2, 35)]
);
@ -901,9 +901,9 @@ mod tests {
search_view.update(cx, |search_view, cx| {
assert_eq!(search_view.active_match_index, Some(1));
assert_eq!(
search_view
.results_editor
.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
search_view.results_editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(2, 37)..DisplayPoint::new(2, 40)]
);
search_view.select_match(Direction::Next, cx);
@ -912,9 +912,9 @@ mod tests {
search_view.update(cx, |search_view, cx| {
assert_eq!(search_view.active_match_index, Some(2));
assert_eq!(
search_view
.results_editor
.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
search_view.results_editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 9)]
);
search_view.select_match(Direction::Next, cx);
@ -923,9 +923,9 @@ mod tests {
search_view.update(cx, |search_view, cx| {
assert_eq!(search_view.active_match_index, Some(0));
assert_eq!(
search_view
.results_editor
.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
search_view.results_editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(2, 32)..DisplayPoint::new(2, 35)]
);
search_view.select_match(Direction::Prev, cx);
@ -934,9 +934,9 @@ mod tests {
search_view.update(cx, |search_view, cx| {
assert_eq!(search_view.active_match_index, Some(2));
assert_eq!(
search_view
.results_editor
.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
search_view.results_editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 9)]
);
search_view.select_match(Direction::Prev, cx);
@ -945,9 +945,9 @@ mod tests {
search_view.update(cx, |search_view, cx| {
assert_eq!(search_view.active_match_index, Some(1));
assert_eq!(
search_view
.results_editor
.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
search_view.results_editor.update(cx, |editor, cx| editor
.selections
.selected_display_ranges(cx)),
[DisplayPoint::new(2, 37)..DisplayPoint::new(2, 40)]
);
});

View File

@ -200,7 +200,7 @@ impl<'a> VimTestContext<'a> {
self.editor.read_with(self.cx, |editor, cx| {
let (empty_selections, non_empty_selections): (Vec<_>, Vec<_>) = editor
.selections
.interleaved::<usize>(&editor.buffer().read(cx).read(cx))
.interleaved::<usize>(cx)
.into_iter()
.partition_map(|selection| {
if selection.is_empty() {

View File

@ -1180,7 +1180,7 @@ mod tests {
let editor = item.downcast::<Editor>().unwrap();
let (selections, scroll_position) = editor.update(cx, |editor, cx| {
(
editor.selected_display_ranges(cx),
editor.selections.selected_display_ranges(cx),
editor.scroll_position(cx),
)
});