Add editor::RevertSelectedHunks
to revert git diff hunks in the editor (#9068)
https://github.com/zed-industries/zed/assets/2690773/653b5658-e3f3-4aee-9a9d-0f2153b4141b Release Notes: - Added `editor::RevertSelectedHunks` (`cmd-alt-z` by default) for reverting git hunks from the editor
This commit is contained in:
parent
6a7a3b257a
commit
347178039c
13 changed files with 1003 additions and 72 deletions
|
@ -1,6 +1,6 @@
|
|||
use std::{iter, ops::Range};
|
||||
use sum_tree::SumTree;
|
||||
use text::{Anchor, BufferSnapshot, OffsetRangeExt, Point};
|
||||
use text::{Anchor, BufferId, BufferSnapshot, OffsetRangeExt, Point};
|
||||
|
||||
pub use git2 as libgit;
|
||||
use libgit::{DiffLineType as GitDiffLineType, DiffOptions as GitOptions, Patch as GitPatch};
|
||||
|
@ -12,17 +12,53 @@ pub enum DiffHunkStatus {
|
|||
Removed,
|
||||
}
|
||||
|
||||
/// A diff hunk, representing a range of consequent lines in a singleton buffer, associated with a generic range.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct DiffHunk<T> {
|
||||
pub buffer_range: Range<T>,
|
||||
/// E.g. a range in multibuffer, that has an excerpt added, singleton buffer for which has this diff hunk.
|
||||
/// Consider a singleton buffer with 10 lines, all of them are modified — so a corresponding diff hunk would have a range 0..10.
|
||||
/// And a multibuffer with the excerpt of lines 2-6 from the singleton buffer.
|
||||
/// If the multibuffer is searched for diff hunks, the associated range would be multibuffer rows, corresponding to rows 2..6 from the singleton buffer.
|
||||
/// But the hunk range would be 0..10, same for any other excerpts from the same singleton buffer.
|
||||
pub associated_range: Range<T>,
|
||||
/// Singleton buffer ID this hunk belongs to.
|
||||
pub buffer_id: BufferId,
|
||||
/// A consequent range of lines in the singleton buffer, that were changed and produced this diff hunk.
|
||||
pub buffer_range: Range<Anchor>,
|
||||
/// Original singleton buffer text before the change, that was instead of the `buffer_range`.
|
||||
pub diff_base_byte_range: Range<usize>,
|
||||
}
|
||||
|
||||
impl<T> DiffHunk<T> {
|
||||
fn buffer_range_empty(&self) -> bool {
|
||||
if self.buffer_range.start == self.buffer_range.end {
|
||||
return true;
|
||||
}
|
||||
|
||||
// buffer diff hunks are per line, so if we arrive to the same line with different bias, it's the same hunk
|
||||
let Anchor {
|
||||
timestamp: timestamp_start,
|
||||
offset: offset_start,
|
||||
buffer_id: buffer_id_start,
|
||||
bias: _,
|
||||
} = self.buffer_range.start;
|
||||
let Anchor {
|
||||
timestamp: timestamp_end,
|
||||
offset: offset_end,
|
||||
buffer_id: buffer_id_end,
|
||||
bias: _,
|
||||
} = self.buffer_range.end;
|
||||
timestamp_start == timestamp_end
|
||||
&& offset_start == offset_end
|
||||
&& buffer_id_start == buffer_id_end
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffHunk<u32> {
|
||||
pub fn status(&self) -> DiffHunkStatus {
|
||||
if self.diff_base_byte_range.is_empty() {
|
||||
DiffHunkStatus::Added
|
||||
} else if self.buffer_range.is_empty() {
|
||||
} else if self.buffer_range_empty() {
|
||||
DiffHunkStatus::Removed
|
||||
} else {
|
||||
DiffHunkStatus::Modified
|
||||
|
@ -35,7 +71,7 @@ impl sum_tree::Item for DiffHunk<Anchor> {
|
|||
|
||||
fn summary(&self) -> Self::Summary {
|
||||
DiffHunkSummary {
|
||||
buffer_range: self.buffer_range.clone(),
|
||||
buffer_range: self.associated_range.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +93,7 @@ impl sum_tree::Summary for DiffHunkSummary {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BufferDiff {
|
||||
last_buffer_version: Option<clock::Global>,
|
||||
tree: SumTree<DiffHunk<Anchor>>,
|
||||
|
@ -103,8 +139,11 @@ impl BufferDiff {
|
|||
})
|
||||
.flat_map(move |hunk| {
|
||||
[
|
||||
(&hunk.buffer_range.start, hunk.diff_base_byte_range.start),
|
||||
(&hunk.buffer_range.end, hunk.diff_base_byte_range.end),
|
||||
(
|
||||
&hunk.associated_range.start,
|
||||
hunk.diff_base_byte_range.start,
|
||||
),
|
||||
(&hunk.associated_range.end, hunk.diff_base_byte_range.end),
|
||||
]
|
||||
.into_iter()
|
||||
});
|
||||
|
@ -112,17 +151,17 @@ impl BufferDiff {
|
|||
let mut summaries = buffer.summaries_for_anchors_with_payload::<Point, _, _>(anchor_iter);
|
||||
iter::from_fn(move || {
|
||||
let (start_point, start_base) = summaries.next()?;
|
||||
let (end_point, end_base) = summaries.next()?;
|
||||
let (mut end_point, end_base) = summaries.next()?;
|
||||
|
||||
let end_row = if end_point.column > 0 {
|
||||
end_point.row + 1
|
||||
} else {
|
||||
end_point.row
|
||||
};
|
||||
if end_point.column > 0 {
|
||||
end_point.row += 1;
|
||||
}
|
||||
|
||||
Some(DiffHunk {
|
||||
buffer_range: start_point.row..end_row,
|
||||
associated_range: start_point.row..end_point.row,
|
||||
diff_base_byte_range: start_base..end_base,
|
||||
buffer_range: buffer.anchor_before(start_point)..buffer.anchor_after(end_point),
|
||||
buffer_id: buffer.remote_id(),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -142,7 +181,7 @@ impl BufferDiff {
|
|||
cursor.prev(buffer);
|
||||
|
||||
let hunk = cursor.item()?;
|
||||
let range = hunk.buffer_range.to_point(buffer);
|
||||
let range = hunk.associated_range.to_point(buffer);
|
||||
let end_row = if range.end.column > 0 {
|
||||
range.end.row + 1
|
||||
} else {
|
||||
|
@ -150,8 +189,10 @@ impl BufferDiff {
|
|||
};
|
||||
|
||||
Some(DiffHunk {
|
||||
buffer_range: range.start.row..end_row,
|
||||
associated_range: range.start.row..end_row,
|
||||
diff_base_byte_range: hunk.diff_base_byte_range.clone(),
|
||||
buffer_range: hunk.buffer_range.clone(),
|
||||
buffer_id: hunk.buffer_id,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -269,8 +310,10 @@ impl BufferDiff {
|
|||
let end = Point::new(buffer_row_range.end, 0);
|
||||
let buffer_range = buffer.anchor_before(start)..buffer.anchor_before(end);
|
||||
DiffHunk {
|
||||
associated_range: buffer_range.clone(),
|
||||
buffer_range,
|
||||
diff_base_byte_range,
|
||||
buffer_id: buffer.remote_id(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -289,12 +332,12 @@ pub fn assert_hunks<Iter>(
|
|||
let actual_hunks = diff_hunks
|
||||
.map(|hunk| {
|
||||
(
|
||||
hunk.buffer_range.clone(),
|
||||
hunk.associated_range.clone(),
|
||||
&diff_base[hunk.diff_base_byte_range],
|
||||
buffer
|
||||
.text_for_range(
|
||||
Point::new(hunk.buffer_range.start, 0)
|
||||
..Point::new(hunk.buffer_range.end, 0),
|
||||
Point::new(hunk.associated_range.start, 0)
|
||||
..Point::new(hunk.associated_range.end, 0),
|
||||
)
|
||||
.collect::<String>(),
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue