Make rename highlights work across multibuffer excerpts

Co-authored-by: Antonio Scandurra <me@as-cii.com>
Co-authored-by: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Keith Simmons 2022-03-24 10:22:47 -07:00
parent ff4bdb3114
commit f6805eb802
9 changed files with 110 additions and 45 deletions

View file

@ -278,7 +278,8 @@ impl ProjectDiagnosticsEditor {
prev_excerpt_id = excerpt_id.clone(); prev_excerpt_id = excerpt_id.clone();
first_excerpt_id.get_or_insert_with(|| prev_excerpt_id.clone()); first_excerpt_id.get_or_insert_with(|| prev_excerpt_id.clone());
group_state.excerpts.push(excerpt_id.clone()); group_state.excerpts.push(excerpt_id.clone());
let header_position = (excerpt_id.clone(), language::Anchor::min()); let header_position =
(excerpt_id.clone(), language::Anchor::build_min());
if is_first_excerpt_for_group { if is_first_excerpt_for_group {
is_first_excerpt_for_group = false; is_first_excerpt_for_group = false;

View file

@ -2399,7 +2399,7 @@ impl Editor {
) -> Result<()> { ) -> Result<()> {
let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx)); let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx));
// If the code action's edits are all contained within this editor, then // If the project transaction's edits are all contained within this editor, then
// avoid opening a new editor to display them. // avoid opening a new editor to display them.
let mut entries = transaction.0.iter(); let mut entries = transaction.0.iter();
if let Some((buffer, transaction)) = entries.next() { if let Some((buffer, transaction)) = entries.next() {
@ -2521,7 +2521,6 @@ impl Editor {
} }
let buffer_id = cursor_position.buffer_id; let buffer_id = cursor_position.buffer_id;
let excerpt_id = cursor_position.excerpt_id.clone();
let style = this.style(cx); let style = this.style(cx);
let read_background = style.document_highlight_read_background; let read_background = style.document_highlight_read_background;
let write_background = style.document_highlight_write_background; let write_background = style.document_highlight_write_background;
@ -2533,17 +2532,33 @@ impl Editor {
return; return;
} }
let cursor_buffer_snapshot = cursor_buffer.read(cx);
let mut write_ranges = Vec::new(); let mut write_ranges = Vec::new();
let mut read_ranges = Vec::new(); let mut read_ranges = Vec::new();
for highlight in highlights { for highlight in highlights {
for (excerpt_id, excerpt_range) in
buffer.excerpts_for_buffer(&cursor_buffer, cx)
{
let start = highlight
.range
.start
.max(&excerpt_range.start, cursor_buffer_snapshot);
let end = highlight
.range
.end
.min(&excerpt_range.end, cursor_buffer_snapshot);
if start.cmp(&end, cursor_buffer_snapshot).unwrap().is_ge() {
continue;
}
let range = Anchor { let range = Anchor {
buffer_id, buffer_id,
excerpt_id: excerpt_id.clone(), excerpt_id: excerpt_id.clone(),
text_anchor: highlight.range.start, text_anchor: start,
}..Anchor { }..Anchor {
buffer_id, buffer_id,
excerpt_id: excerpt_id.clone(), excerpt_id,
text_anchor: highlight.range.end, text_anchor: end,
}; };
if highlight.kind == lsp::DocumentHighlightKind::WRITE { if highlight.kind == lsp::DocumentHighlightKind::WRITE {
write_ranges.push(range); write_ranges.push(range);
@ -2551,6 +2566,7 @@ impl Editor {
read_ranges.push(range); read_ranges.push(range);
} }
} }
}
this.highlight_background::<DocumentHighlightRead>( this.highlight_background::<DocumentHighlightRead>(
read_ranges, read_ranges,
@ -4413,7 +4429,6 @@ impl Editor {
.iter() .iter()
.map(|range| range.to_point(&snapshot)) .map(|range| range.to_point(&snapshot))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
dbg!(point_ranges);
this.highlight_text::<Rename>( this.highlight_text::<Rename>(
ranges, ranges,

View file

@ -211,7 +211,11 @@ impl MultiBuffer {
pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self { pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
let mut this = Self::new(buffer.read(cx).replica_id()); let mut this = Self::new(buffer.read(cx).replica_id());
this.singleton = true; this.singleton = true;
this.push_excerpts(buffer, [text::Anchor::min()..text::Anchor::max()], cx); this.push_excerpts(
buffer,
[text::Anchor::build_min()..text::Anchor::build_max()],
cx,
);
this.snapshot.borrow_mut().singleton = true; this.snapshot.borrow_mut().singleton = true;
this this
} }
@ -814,11 +818,30 @@ impl MultiBuffer {
cx.notify(); cx.notify();
} }
pub fn excerpt_ids_for_buffer(&self, buffer: &ModelHandle<Buffer>) -> Vec<ExcerptId> { pub fn excerpts_for_buffer(
self.buffers &self,
.borrow() buffer: &ModelHandle<Buffer>,
cx: &AppContext,
) -> Vec<(ExcerptId, Range<text::Anchor>)> {
let mut excerpts = Vec::new();
let snapshot = self.read(cx);
let buffers = self.buffers.borrow();
let mut cursor = snapshot.excerpts.cursor::<Option<&ExcerptId>>();
for excerpt_id in buffers
.get(&buffer.id()) .get(&buffer.id())
.map_or(Vec::new(), |state| state.excerpts.clone()) .map(|state| &state.excerpts)
.into_iter()
.flatten()
{
cursor.seek_forward(&Some(excerpt_id), Bias::Left, &());
if let Some(excerpt) = cursor.item() {
if excerpt.id == *excerpt_id {
excerpts.push((excerpt.id.clone(), excerpt.range.clone()));
}
}
}
excerpts
} }
pub fn excerpt_ids(&self) -> Vec<ExcerptId> { pub fn excerpt_ids(&self) -> Vec<ExcerptId> {
@ -3070,7 +3093,8 @@ mod tests {
); );
let snapshot = multibuffer.update(cx, |multibuffer, cx| { let snapshot = multibuffer.update(cx, |multibuffer, cx| {
let buffer_2_excerpt_id = multibuffer.excerpt_ids_for_buffer(&buffer_2)[0].clone(); let (buffer_2_excerpt_id, _) =
multibuffer.excerpts_for_buffer(&buffer_2, cx)[0].clone();
multibuffer.remove_excerpts(&[buffer_2_excerpt_id], cx); multibuffer.remove_excerpts(&[buffer_2_excerpt_id], cx);
multibuffer.snapshot(cx) multibuffer.snapshot(cx)
}); });

View file

@ -19,7 +19,7 @@ impl Anchor {
Self { Self {
buffer_id: None, buffer_id: None,
excerpt_id: ExcerptId::min(), excerpt_id: ExcerptId::min(),
text_anchor: text::Anchor::min(), text_anchor: text::Anchor::build_min(),
} }
} }
@ -27,7 +27,7 @@ impl Anchor {
Self { Self {
buffer_id: None, buffer_id: None,
excerpt_id: ExcerptId::max(), excerpt_id: ExcerptId::max(),
text_anchor: text::Anchor::max(), text_anchor: text::Anchor::build_max(),
} }
} }

View file

@ -0,0 +1,9 @@
fn test(complicated: i32, test: i32) {
complicated;
test;
// 1
// 2
// 3
complicated;
test;
}

View file

@ -187,10 +187,10 @@ impl DiagnosticEntry<Anchor> {
impl Default for Summary { impl Default for Summary {
fn default() -> Self { fn default() -> Self {
Self { Self {
start: Anchor::min(), start: Anchor::build_min(),
end: Anchor::max(), end: Anchor::build_max(),
min_start: Anchor::max(), min_start: Anchor::build_max(),
max_end: Anchor::min(), max_end: Anchor::build_min(),
count: 0, count: 0,
} }
} }

View file

@ -789,7 +789,7 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
for buffer in &buffers { for buffer in &buffers {
let buffer = buffer.read(cx).snapshot(); let buffer = buffer.read(cx).snapshot();
let actual_remote_selections = buffer let actual_remote_selections = buffer
.remote_selections_in_range(Anchor::min()..Anchor::max()) .remote_selections_in_range(Anchor::build_min()..Anchor::build_max())
.map(|(replica_id, selections)| (replica_id, selections.collect::<Vec<_>>())) .map(|(replica_id, selections)| (replica_id, selections.collect::<Vec<_>>()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let expected_remote_selections = active_selections let expected_remote_selections = active_selections

View file

@ -12,7 +12,7 @@ pub struct Anchor {
} }
impl Anchor { impl Anchor {
pub fn min() -> Self { pub fn build_min() -> Self {
Self { Self {
timestamp: clock::Local::MIN, timestamp: clock::Local::MIN,
offset: usize::MIN, offset: usize::MIN,
@ -20,7 +20,7 @@ impl Anchor {
} }
} }
pub fn max() -> Self { pub fn build_max() -> Self {
Self { Self {
timestamp: clock::Local::MAX, timestamp: clock::Local::MAX,
offset: usize::MAX, offset: usize::MAX,
@ -42,6 +42,22 @@ impl Anchor {
.then_with(|| self.bias.cmp(&other.bias))) .then_with(|| self.bias.cmp(&other.bias)))
} }
pub fn min(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
if self.cmp(other, buffer).unwrap().is_le() {
self.clone()
} else {
other.clone()
}
}
pub fn max(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
if self.cmp(other, buffer).unwrap().is_ge() {
self.clone()
} else {
other.clone()
}
}
pub fn bias(&self, bias: Bias, buffer: &BufferSnapshot) -> Anchor { pub fn bias(&self, bias: Bias, buffer: &BufferSnapshot) -> Anchor {
if bias == Bias::Left { if bias == Bias::Left {
self.bias_left(buffer) self.bias_left(buffer)

View file

@ -1318,8 +1318,8 @@ impl Buffer {
let mut futures = Vec::new(); let mut futures = Vec::new();
for anchor in anchors { for anchor in anchors {
if !self.version.observed(anchor.timestamp) if !self.version.observed(anchor.timestamp)
&& *anchor != Anchor::max() && *anchor != Anchor::build_max()
&& *anchor != Anchor::min() && *anchor != Anchor::build_min()
{ {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.edit_id_resolvers self.edit_id_resolvers
@ -1638,9 +1638,9 @@ impl BufferSnapshot {
let mut position = D::default(); let mut position = D::default();
anchors.map(move |anchor| { anchors.map(move |anchor| {
if *anchor == Anchor::min() { if *anchor == Anchor::build_min() {
return D::default(); return D::default();
} else if *anchor == Anchor::max() { } else if *anchor == Anchor::build_max() {
return D::from_text_summary(&self.visible_text.summary()); return D::from_text_summary(&self.visible_text.summary());
} }
@ -1680,9 +1680,9 @@ impl BufferSnapshot {
where where
D: TextDimension, D: TextDimension,
{ {
if *anchor == Anchor::min() { if *anchor == Anchor::build_min() {
D::default() D::default()
} else if *anchor == Anchor::max() { } else if *anchor == Anchor::build_max() {
D::from_text_summary(&self.visible_text.summary()) D::from_text_summary(&self.visible_text.summary())
} else { } else {
let anchor_key = InsertionFragmentKey { let anchor_key = InsertionFragmentKey {
@ -1718,9 +1718,9 @@ impl BufferSnapshot {
} }
fn fragment_id_for_anchor(&self, anchor: &Anchor) -> &Locator { fn fragment_id_for_anchor(&self, anchor: &Anchor) -> &Locator {
if *anchor == Anchor::min() { if *anchor == Anchor::build_min() {
&locator::MIN &locator::MIN
} else if *anchor == Anchor::max() { } else if *anchor == Anchor::build_max() {
&locator::MAX &locator::MAX
} else { } else {
let anchor_key = InsertionFragmentKey { let anchor_key = InsertionFragmentKey {
@ -1758,9 +1758,9 @@ impl BufferSnapshot {
pub fn anchor_at<T: ToOffset>(&self, position: T, bias: Bias) -> Anchor { pub fn anchor_at<T: ToOffset>(&self, position: T, bias: Bias) -> Anchor {
let offset = position.to_offset(self); let offset = position.to_offset(self);
if bias == Bias::Left && offset == 0 { if bias == Bias::Left && offset == 0 {
Anchor::min() Anchor::build_min()
} else if bias == Bias::Right && offset == self.len() { } else if bias == Bias::Right && offset == self.len() {
Anchor::max() Anchor::build_max()
} else { } else {
let mut fragment_cursor = self.fragments.cursor::<usize>(); let mut fragment_cursor = self.fragments.cursor::<usize>();
fragment_cursor.seek(&offset, bias, &None); fragment_cursor.seek(&offset, bias, &None);
@ -1775,8 +1775,8 @@ impl BufferSnapshot {
} }
pub fn can_resolve(&self, anchor: &Anchor) -> bool { pub fn can_resolve(&self, anchor: &Anchor) -> bool {
*anchor == Anchor::min() *anchor == Anchor::build_min()
|| *anchor == Anchor::max() || *anchor == Anchor::build_max()
|| self.version.observed(anchor.timestamp) || self.version.observed(anchor.timestamp)
} }
@ -1799,7 +1799,7 @@ impl BufferSnapshot {
where where
D: TextDimension + Ord, D: TextDimension + Ord,
{ {
self.edits_since_in_range(since, Anchor::min()..Anchor::max()) self.edits_since_in_range(since, Anchor::build_min()..Anchor::build_max())
} }
pub fn edited_ranges_for_transaction<'a, D>( pub fn edited_ranges_for_transaction<'a, D>(