Fix bugs with applying hunks from branch buffers (#18721)
Release Notes: - N/A --------- Co-authored-by: Marshall <marshall@zed.dev>
This commit is contained in:
parent
3c91184726
commit
b0a16a7601
4 changed files with 128 additions and 61 deletions
|
@ -18,6 +18,7 @@ use crate::{
|
|||
};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use async_watch as watch;
|
||||
use clock::Lamport;
|
||||
pub use clock::ReplicaId;
|
||||
use futures::channel::oneshot;
|
||||
use gpui::{
|
||||
|
@ -90,7 +91,7 @@ enum BufferDiffBase {
|
|||
PastBufferVersion {
|
||||
buffer: Model<Buffer>,
|
||||
rope: Rope,
|
||||
operations_to_ignore: Vec<clock::Lamport>,
|
||||
merged_operations: Vec<Lamport>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -802,7 +803,7 @@ impl Buffer {
|
|||
diff_base: Some(BufferDiffBase::PastBufferVersion {
|
||||
buffer: this.clone(),
|
||||
rope: self.as_rope().clone(),
|
||||
operations_to_ignore: Vec::new(),
|
||||
merged_operations: Default::default(),
|
||||
}),
|
||||
language: self.language.clone(),
|
||||
has_conflict: self.has_conflict,
|
||||
|
@ -834,34 +835,32 @@ impl Buffer {
|
|||
return;
|
||||
};
|
||||
|
||||
base_buffer.update(cx, |base_buffer, cx| {
|
||||
let edits = self
|
||||
.edits_since::<usize>(&base_buffer.version)
|
||||
.filter_map(|edit| {
|
||||
if range
|
||||
.as_ref()
|
||||
.map_or(true, |range| range.overlaps(&edit.new))
|
||||
{
|
||||
Some((edit.old, self.text_for_range(edit.new).collect::<String>()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let mut edits = Vec::new();
|
||||
for edit in self.edits_since::<usize>(&base_buffer.read(cx).version()) {
|
||||
if let Some(range) = &range {
|
||||
if range.start > edit.new.end || edit.new.start > range.end {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
edits.push((
|
||||
edit.old.clone(),
|
||||
self.text_for_range(edit.new.clone()).collect::<String>(),
|
||||
));
|
||||
}
|
||||
|
||||
let operation = base_buffer.edit(edits, None, cx);
|
||||
let operation = base_buffer.update(cx, |base_buffer, cx| {
|
||||
cx.emit(BufferEvent::DiffBaseChanged);
|
||||
base_buffer.edit(edits, None, cx)
|
||||
});
|
||||
|
||||
// Prevent this operation from being reapplied to the branch.
|
||||
if let Some(operation) = operation {
|
||||
if let Some(BufferDiffBase::PastBufferVersion {
|
||||
operations_to_ignore,
|
||||
..
|
||||
merged_operations, ..
|
||||
}) = &mut self.diff_base
|
||||
{
|
||||
operations_to_ignore.extend(operation);
|
||||
merged_operations.push(operation);
|
||||
}
|
||||
|
||||
cx.emit(BufferEvent::DiffBaseChanged);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn on_base_buffer_event(
|
||||
|
@ -870,31 +869,34 @@ impl Buffer {
|
|||
event: &BufferEvent,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
if let BufferEvent::Operation { operation, .. } = event {
|
||||
if let Some(BufferDiffBase::PastBufferVersion {
|
||||
operations_to_ignore,
|
||||
..
|
||||
}) = &mut self.diff_base
|
||||
{
|
||||
let mut is_ignored = false;
|
||||
if let Operation::Buffer(text::Operation::Edit(buffer_operation)) = &operation {
|
||||
operations_to_ignore.retain(|operation_to_ignore| {
|
||||
match buffer_operation.timestamp.cmp(&operation_to_ignore) {
|
||||
Ordering::Less => true,
|
||||
Ordering::Equal => {
|
||||
is_ignored = true;
|
||||
false
|
||||
}
|
||||
Ordering::Greater => false,
|
||||
}
|
||||
});
|
||||
}
|
||||
if !is_ignored {
|
||||
self.apply_ops([operation.clone()], cx);
|
||||
self.diff_base_version += 1;
|
||||
}
|
||||
let BufferEvent::Operation { operation, .. } = event else {
|
||||
return;
|
||||
};
|
||||
let Some(BufferDiffBase::PastBufferVersion {
|
||||
merged_operations, ..
|
||||
}) = &mut self.diff_base
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut operation_to_undo = None;
|
||||
if let Operation::Buffer(text::Operation::Edit(operation)) = &operation {
|
||||
if let Ok(ix) = merged_operations.binary_search(&operation.timestamp) {
|
||||
merged_operations.remove(ix);
|
||||
operation_to_undo = Some(operation.timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
self.apply_ops([operation.clone()], cx);
|
||||
|
||||
if let Some(timestamp) = operation_to_undo {
|
||||
let operation = self
|
||||
.text
|
||||
.undo_operations([(timestamp, u32::MAX)].into_iter().collect());
|
||||
self.send_operation(Operation::Buffer(operation), true, cx);
|
||||
}
|
||||
|
||||
self.diff_base_version += 1;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue