Get selections rendering again when local selections are owned by Editor
This commit is contained in:
parent
4dd0752e80
commit
1e7184ea07
7 changed files with 169 additions and 118 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1531,6 +1531,7 @@ dependencies = [
|
||||||
"ctor",
|
"ctor",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"itertools",
|
||||||
"language",
|
"language",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
|
|
|
@ -28,6 +28,7 @@ util = { path = "../util" }
|
||||||
workspace = { path = "../workspace" }
|
workspace = { path = "../workspace" }
|
||||||
aho-corasick = "0.7"
|
aho-corasick = "0.7"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
itertools = "0.10"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
parking_lot = "0.11"
|
parking_lot = "0.11"
|
||||||
|
|
|
@ -3006,61 +3006,90 @@ impl Editor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_selections_in_range<'a, D>(
|
pub fn visible_selections<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
range: Range<DisplayPoint>,
|
display_rows: Range<u32>,
|
||||||
cx: &'a mut MutableAppContext,
|
cx: &'a mut MutableAppContext,
|
||||||
) -> HashMap<ReplicaId, Vec<Selection<D>>>
|
) -> HashMap<ReplicaId, Vec<Selection<DisplayPoint>>> {
|
||||||
where
|
|
||||||
D: TextDimension + Ord + Sub<D, Output = D>,
|
|
||||||
{
|
|
||||||
let mut result = HashMap::new();
|
|
||||||
|
|
||||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
let buffer = &display_map.buffer_snapshot;
|
let buffer = &display_map.buffer_snapshot;
|
||||||
let range = range.start.to_offset(&display_map, Bias::Left)
|
|
||||||
..range.end.to_offset(&display_map, Bias::Left);
|
|
||||||
|
|
||||||
let anchor_range = buffer.anchor_before(range.start)..buffer.anchor_after(range.end);
|
let start = if display_rows.start == 0 {
|
||||||
|
Anchor::min()
|
||||||
|
} else {
|
||||||
|
buffer.anchor_before(
|
||||||
|
DisplayPoint::new(display_rows.start, 0).to_offset(&display_map, Bias::Left),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let end = if display_rows.end > display_map.max_point().row() {
|
||||||
|
Anchor::max()
|
||||||
|
} else {
|
||||||
|
buffer.anchor_before(
|
||||||
|
DisplayPoint::new(display_rows.end, 0).to_offset(&display_map, Bias::Right),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
dbg!(&start, &end);
|
||||||
|
dbg!(&self.selections);
|
||||||
|
|
||||||
let start_ix = match self
|
let start_ix = match self
|
||||||
.selections
|
.selections
|
||||||
.binary_search_by(|probe| probe.end.cmp(&anchor_range.start, &buffer).unwrap())
|
.binary_search_by(|probe| probe.end.cmp(&start, &buffer).unwrap())
|
||||||
{
|
{
|
||||||
Ok(ix) | Err(ix) => ix,
|
Ok(ix) | Err(ix) => ix,
|
||||||
};
|
};
|
||||||
let end_ix = match self
|
let end_ix = match self
|
||||||
.selections
|
.selections
|
||||||
.binary_search_by(|probe| probe.start.cmp(&anchor_range.end, &buffer).unwrap())
|
.binary_search_by(|probe| probe.start.cmp(&end, &buffer).unwrap())
|
||||||
{
|
{
|
||||||
Ok(ix) | Err(ix) => ix,
|
Ok(ix) => ix + 1,
|
||||||
|
Err(ix) => ix,
|
||||||
};
|
};
|
||||||
|
|
||||||
let selections = &self.selections[start_ix..end_ix];
|
dbg!(start_ix, end_ix);
|
||||||
let mut summaries = buffer
|
|
||||||
.summaries_for_anchors::<D, _>(selections.iter().flat_map(|s| [&s.start, &s.end]))
|
fn display_selection(
|
||||||
.into_iter();
|
selection: &Selection<Anchor>,
|
||||||
|
display_map: &DisplaySnapshot,
|
||||||
|
) -> Selection<DisplayPoint> {
|
||||||
|
Selection {
|
||||||
|
id: selection.id,
|
||||||
|
start: selection.start.to_display_point(&display_map),
|
||||||
|
end: selection.end.to_display_point(&display_map),
|
||||||
|
reversed: selection.reversed,
|
||||||
|
goal: selection.goal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut result = HashMap::new();
|
||||||
|
|
||||||
result.insert(
|
result.insert(
|
||||||
self.replica_id(cx),
|
self.replica_id(cx),
|
||||||
selections
|
self.selections[start_ix..end_ix]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| Selection {
|
.chain(
|
||||||
id: s.id,
|
self.pending_selection
|
||||||
start: summaries.next().unwrap(),
|
.as_ref()
|
||||||
end: summaries.next().unwrap(),
|
.map(|pending| &pending.selection),
|
||||||
reversed: s.reversed,
|
)
|
||||||
goal: s.goal,
|
.map(|s| display_selection(s, &display_map))
|
||||||
})
|
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (replica_id, selections) in display_map
|
for (replica_id, selections) in display_map
|
||||||
.buffer_snapshot
|
.buffer_snapshot
|
||||||
.remote_selections_in_range(range)
|
.remote_selections_in_range(start..end)
|
||||||
{
|
{
|
||||||
result.insert(replica_id, selections.collect());
|
result.insert(
|
||||||
|
replica_id,
|
||||||
|
selections
|
||||||
|
.map(|s| display_selection(&s, &display_map))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbg!(&result);
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3137,6 +3166,31 @@ impl Editor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_selections<
|
||||||
|
'a,
|
||||||
|
D: TextDimension + Ord + Sub<D, Output = D>,
|
||||||
|
I: 'a + Iterator<Item = &'a Selection<Anchor>>,
|
||||||
|
>(
|
||||||
|
&self,
|
||||||
|
selections: I,
|
||||||
|
buffer: &MultiBufferSnapshot,
|
||||||
|
) -> impl 'a + Iterator<Item = Selection<D>> {
|
||||||
|
use itertools::Itertools as _;
|
||||||
|
|
||||||
|
let (to_map, to_summarize) = selections.tee();
|
||||||
|
let mut summaries = buffer
|
||||||
|
.summaries_for_anchors::<D, _>(to_summarize.flat_map(|s| [&s.start, &s.end]))
|
||||||
|
.into_iter();
|
||||||
|
|
||||||
|
to_map.map(move |s| Selection {
|
||||||
|
id: s.id,
|
||||||
|
start: summaries.next().unwrap(),
|
||||||
|
end: summaries.next().unwrap(),
|
||||||
|
reversed: s.reversed,
|
||||||
|
goal: s.goal,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn selection_count<'a>(&self) -> usize {
|
fn selection_count<'a>(&self) -> usize {
|
||||||
let mut count = self.selections.len();
|
let mut count = self.selections.len();
|
||||||
if self.pending_selection.is_some() {
|
if self.pending_selection.is_some() {
|
||||||
|
@ -3729,8 +3783,6 @@ pub fn diagnostic_style(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use language::LanguageConfig;
|
use language::LanguageConfig;
|
||||||
use text::Point;
|
use text::Point;
|
||||||
|
@ -3786,6 +3838,7 @@ mod tests {
|
||||||
view.update_selection(DisplayPoint::new(0, 0), 0, Vector2F::zero(), cx);
|
view.update_selection(DisplayPoint::new(0, 0), 0, Vector2F::zero(), cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
eprintln!(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor.update(cx, |view, cx| view.selection_ranges(cx)),
|
editor.update(cx, |view, cx| view.selection_ranges(cx)),
|
||||||
[
|
[
|
||||||
|
@ -3984,6 +4037,8 @@ mod tests {
|
||||||
});
|
});
|
||||||
|
|
||||||
view.update(cx, |view, cx| {
|
view.update(cx, |view, cx| {
|
||||||
|
dbg!(&view.selections);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
view.selection_ranges(cx),
|
view.selection_ranges(cx),
|
||||||
&[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
|
&[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
|
||||||
|
@ -5691,16 +5746,16 @@ mod tests {
|
||||||
|
|
||||||
impl Editor {
|
impl Editor {
|
||||||
fn selection_ranges(&self, cx: &mut MutableAppContext) -> Vec<Range<DisplayPoint>> {
|
fn selection_ranges(&self, cx: &mut MutableAppContext) -> Vec<Range<DisplayPoint>> {
|
||||||
let snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
self.visible_selections(0..self.max_point(cx).row() + 1, cx)
|
||||||
self.selections
|
.get(&self.replica_id(cx))
|
||||||
.iter()
|
.unwrap()
|
||||||
|
.into_iter()
|
||||||
.map(|s| {
|
.map(|s| {
|
||||||
let mut range =
|
|
||||||
s.start.to_display_point(&snapshot)..s.end.to_display_point(&snapshot);
|
|
||||||
if s.reversed {
|
if s.reversed {
|
||||||
mem::swap(&mut range.start, &mut range.end);
|
s.end..s.start
|
||||||
|
} else {
|
||||||
|
s.start..s.end
|
||||||
}
|
}
|
||||||
range
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -733,37 +733,28 @@ impl Element for EditorElement {
|
||||||
let scroll_top = scroll_position.y() * line_height;
|
let scroll_top = scroll_position.y() * line_height;
|
||||||
let end_row = ((scroll_top + size.y()) / line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen
|
let end_row = ((scroll_top + size.y()) / line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen
|
||||||
|
|
||||||
let selections = HashMap::new();
|
let mut active_rows = BTreeMap::new();
|
||||||
let active_rows = BTreeMap::new();
|
|
||||||
let mut highlighted_row = None;
|
let mut highlighted_row = None;
|
||||||
self.update_view(cx.app, |view, cx| {
|
let selections = self.update_view(cx.app, |view, cx| {
|
||||||
highlighted_row = view.highlighted_row();
|
highlighted_row = view.highlighted_row();
|
||||||
|
let selections = view.visible_selections(start_row..end_row, cx);
|
||||||
// TODO: Get this working with editors owning their own selections
|
for (replica_id, selections) in &selections {
|
||||||
|
if *replica_id == view.replica_id(cx) {
|
||||||
// for selection_set_id in view.active_selection_sets(cx).collect::<Vec<_>>() {
|
for selection in selections {
|
||||||
// let replica_selections = view.intersecting_selections(
|
let is_empty = selection.start == selection.end;
|
||||||
// selection_set_id,
|
let selection_start = snapshot.prev_row_boundary(selection.start).0;
|
||||||
// DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
|
let selection_end = snapshot.next_row_boundary(selection.end).0;
|
||||||
// cx,
|
for row in cmp::max(selection_start.row(), start_row)
|
||||||
// );
|
..=cmp::min(selection_end.row(), end_row)
|
||||||
// for selection in &replica_selections {
|
{
|
||||||
// if selection_set_id == view.selection_set_id {
|
let contains_non_empty_selection =
|
||||||
// let is_empty = selection.start == selection.end;
|
active_rows.entry(row).or_insert(!is_empty);
|
||||||
// let selection_start = snapshot.prev_row_boundary(selection.start).0;
|
*contains_non_empty_selection |= !is_empty;
|
||||||
// let selection_end = snapshot.next_row_boundary(selection.end).0;
|
}
|
||||||
// for row in cmp::max(selection_start.row(), start_row)
|
}
|
||||||
// ..=cmp::min(selection_end.row(), end_row)
|
}
|
||||||
// {
|
}
|
||||||
// let contains_non_empty_selection =
|
selections
|
||||||
// active_rows.entry(row).or_insert(!is_empty);
|
|
||||||
// *contains_non_empty_selection |= !is_empty;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// selections.insert(selection_set_id.replica_id, replica_selections);
|
|
||||||
// }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let line_number_layouts = self.layout_rows(start_row..end_row, &active_rows, &snapshot, cx);
|
let line_number_layouts = self.layout_rows(start_row..end_row, &active_rows, &snapshot, cx);
|
||||||
|
|
|
@ -7,8 +7,8 @@ use clock::ReplicaId;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use gpui::{AppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task};
|
use gpui::{AppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task};
|
||||||
use language::{
|
use language::{
|
||||||
Buffer, BufferChunks, BufferSnapshot, Chunk, DiagnosticEntry, Event, File, Language, Selection,
|
Buffer, BufferChunks, BufferSnapshot, Chunk, DiagnosticEntry, Event, File, FromAnchor,
|
||||||
ToOffset as _, ToPoint as _, TransactionId,
|
Language, Selection, ToOffset as _, ToPoint as _, TransactionId,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefCell},
|
cell::{Ref, RefCell},
|
||||||
|
@ -805,19 +805,18 @@ impl MultiBufferSnapshot {
|
||||||
let mut summaries = Vec::new();
|
let mut summaries = Vec::new();
|
||||||
while let Some(anchor) = anchors.peek() {
|
while let Some(anchor) = anchors.peek() {
|
||||||
let excerpt_id = &anchor.excerpt_id;
|
let excerpt_id = &anchor.excerpt_id;
|
||||||
cursor.seek(&Some(excerpt_id), Bias::Left, &());
|
let excerpt_anchors = std::iter::from_fn(|| {
|
||||||
if let Some(excerpt) = cursor.item() {
|
let anchor = anchors.peek()?;
|
||||||
let excerpt_exists = excerpt.id == *excerpt_id;
|
if anchor.excerpt_id == *excerpt_id {
|
||||||
let excerpt_anchors = std::iter::from_fn(|| {
|
Some(&anchors.next().unwrap().text_anchor)
|
||||||
let anchor = anchors.peek()?;
|
} else {
|
||||||
if anchor.excerpt_id == *excerpt_id {
|
None
|
||||||
Some(&anchors.next().unwrap().text_anchor)
|
}
|
||||||
} else {
|
});
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if excerpt_exists {
|
cursor.seek_forward(&Some(excerpt_id), Bias::Left, &());
|
||||||
|
if let Some(excerpt) = cursor.item() {
|
||||||
|
if excerpt.id == *excerpt_id {
|
||||||
let mut excerpt_start = D::from_text_summary(&cursor.start().text);
|
let mut excerpt_start = D::from_text_summary(&cursor.start().text);
|
||||||
excerpt_start.add_summary(&excerpt.header_summary(), &());
|
excerpt_start.add_summary(&excerpt.header_summary(), &());
|
||||||
let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
|
let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
|
||||||
|
@ -834,12 +833,12 @@ impl MultiBufferSnapshot {
|
||||||
excerpt_start
|
excerpt_start
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} else {
|
continue;
|
||||||
excerpt_anchors.for_each(drop);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let summary = D::from_text_summary(&cursor.start().text);
|
||||||
|
summaries.extend(excerpt_anchors.map(|_| summary.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
summaries
|
summaries
|
||||||
|
@ -935,17 +934,34 @@ impl MultiBufferSnapshot {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remote_selections_in_range<'a, I, O>(
|
pub fn remote_selections_in_range<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
range: Range<I>,
|
range: Range<Anchor>,
|
||||||
) -> impl 'a + Iterator<Item = (ReplicaId, impl 'a + Iterator<Item = Selection<O>>)>
|
) -> impl 'a + Iterator<Item = (ReplicaId, impl 'a + Iterator<Item = Selection<Anchor>>)> {
|
||||||
where
|
// TODO
|
||||||
I: ToOffset,
|
let excerpt_id = self.excerpts.first().unwrap().id.clone();
|
||||||
O: TextDimension,
|
|
||||||
{
|
|
||||||
self.as_singleton()
|
self.as_singleton()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.remote_selections_in_range(range.start.to_offset(self)..range.end.to_offset(self))
|
.remote_selections_in_range(range.start.text_anchor..range.end.text_anchor)
|
||||||
|
.map(move |(replica_id, selections)| {
|
||||||
|
let excerpt_id = excerpt_id.clone();
|
||||||
|
(
|
||||||
|
replica_id,
|
||||||
|
selections.map(move |s| Selection {
|
||||||
|
id: s.id,
|
||||||
|
start: Anchor {
|
||||||
|
excerpt_id: excerpt_id.clone(),
|
||||||
|
text_anchor: s.start.clone(),
|
||||||
|
},
|
||||||
|
end: Anchor {
|
||||||
|
excerpt_id: excerpt_id.clone(),
|
||||||
|
text_anchor: s.end.clone(),
|
||||||
|
},
|
||||||
|
reversed: s.reversed,
|
||||||
|
goal: s.goal,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,15 +31,16 @@ impl Anchor {
|
||||||
pub fn cmp<'a>(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Result<Ordering> {
|
pub fn cmp<'a>(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Result<Ordering> {
|
||||||
let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id);
|
let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id);
|
||||||
if excerpt_id_cmp.is_eq() {
|
if excerpt_id_cmp.is_eq() {
|
||||||
if self.excerpt_id == ExcerptId::max() {
|
if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() {
|
||||||
return Ok(Ordering::Equal);
|
Ok(Ordering::Equal)
|
||||||
|
} else {
|
||||||
|
self.text_anchor.cmp(
|
||||||
|
&other.text_anchor,
|
||||||
|
snapshot
|
||||||
|
.buffer_snapshot_for_excerpt(&self.excerpt_id)
|
||||||
|
.ok_or_else(|| anyhow!("excerpt {:?} not found", self.excerpt_id))?,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
self.text_anchor.cmp(
|
|
||||||
&other.text_anchor,
|
|
||||||
snapshot
|
|
||||||
.buffer_snapshot_for_excerpt(&self.excerpt_id)
|
|
||||||
.ok_or_else(|| anyhow!("excerpt {:?} not found", self.excerpt_id))?,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
return Ok(excerpt_id_cmp);
|
return Ok(excerpt_id_cmp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1648,15 +1648,11 @@ impl BufferSnapshot {
|
||||||
.min_by_key(|(open_range, close_range)| close_range.end - open_range.start)
|
.min_by_key(|(open_range, close_range)| close_range.end - open_range.start)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remote_selections_in_range<'a, I, O>(
|
pub fn remote_selections_in_range<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
range: Range<I>,
|
range: Range<Anchor>,
|
||||||
) -> impl 'a + Iterator<Item = (ReplicaId, impl 'a + Iterator<Item = Selection<O>>)>
|
) -> impl 'a + Iterator<Item = (ReplicaId, impl 'a + Iterator<Item = &'a Selection<Anchor>>)>
|
||||||
where
|
|
||||||
I: ToOffset,
|
|
||||||
O: TextDimension,
|
|
||||||
{
|
{
|
||||||
let range = self.anchor_before(range.start)..self.anchor_after(range.end);
|
|
||||||
self.remote_selections
|
self.remote_selections
|
||||||
.iter()
|
.iter()
|
||||||
.map(move |(replica_id, selections)| {
|
.map(move |(replica_id, selections)| {
|
||||||
|
@ -1671,17 +1667,7 @@ impl BufferSnapshot {
|
||||||
Ok(ix) | Err(ix) => ix,
|
Ok(ix) | Err(ix) => ix,
|
||||||
};
|
};
|
||||||
|
|
||||||
let selections = &selections[start_ix..end_ix];
|
(*replica_id, selections[start_ix..end_ix].iter())
|
||||||
let mut summaries =
|
|
||||||
self.summaries_for_anchors(selections.iter().flat_map(|s| [&s.start, &s.end]));
|
|
||||||
let resolved = selections.iter().map(move |s| Selection {
|
|
||||||
id: s.id,
|
|
||||||
start: summaries.next().unwrap(),
|
|
||||||
end: summaries.next().unwrap(),
|
|
||||||
reversed: s.reversed,
|
|
||||||
goal: s.goal,
|
|
||||||
});
|
|
||||||
(*replica_id, resolved)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue