Git actions v2 (#25197)
Closes #ISSUE Release Notes: - Rename `editor::RevertSelectedHunks` and `editor::RevertFile` to `git::Restore` and `git::RestoreFile` for consistency with git
This commit is contained in:
parent
e3836712d6
commit
d0f7dede79
12 changed files with 195 additions and 1688 deletions
|
@ -73,6 +73,7 @@ use futures::{
|
|||
};
|
||||
use fuzzy::StringMatchCandidate;
|
||||
|
||||
use ::git::Restore;
|
||||
use code_context_menus::{
|
||||
AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
|
||||
CompletionsMenu, ContextMenuOrigin,
|
||||
|
@ -7025,21 +7026,6 @@ impl Editor {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn revert_file(&mut self, _: &RevertFile, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let mut revert_changes = HashMap::default();
|
||||
let snapshot = self.snapshot(window, cx);
|
||||
for hunk in snapshot
|
||||
.hunks_for_ranges(Some(Point::zero()..snapshot.buffer_snapshot.max_point()).into_iter())
|
||||
{
|
||||
self.prepare_revert_change(&mut revert_changes, &hunk, cx);
|
||||
}
|
||||
if !revert_changes.is_empty() {
|
||||
self.transact(window, cx, |editor, window, cx| {
|
||||
editor.revert(revert_changes, window, cx);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let Some(project) = self.project.clone() else {
|
||||
return;
|
||||
|
@ -7048,27 +7034,62 @@ impl Editor {
|
|||
.detach_and_notify_err(window, cx);
|
||||
}
|
||||
|
||||
pub fn revert_selected_hunks(
|
||||
pub fn restore_file(
|
||||
&mut self,
|
||||
_: &RevertSelectedHunks,
|
||||
_: &::git::RestoreFile,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let selections = self.selections.all(cx).into_iter().map(|s| s.range());
|
||||
self.revert_hunks_in_ranges(selections, window, cx);
|
||||
let mut buffer_ids = HashSet::default();
|
||||
let snapshot = self.buffer().read(cx).snapshot(cx);
|
||||
for selection in self.selections.all::<usize>(cx) {
|
||||
buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
|
||||
}
|
||||
|
||||
let buffer = self.buffer().read(cx);
|
||||
let ranges = buffer_ids
|
||||
.into_iter()
|
||||
.flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.restore_hunks_in_ranges(ranges, window, cx);
|
||||
}
|
||||
|
||||
fn revert_hunks_in_ranges(
|
||||
pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let selections = self
|
||||
.selections
|
||||
.all(cx)
|
||||
.into_iter()
|
||||
.map(|s| s.range())
|
||||
.collect();
|
||||
self.restore_hunks_in_ranges(selections, window, cx);
|
||||
}
|
||||
|
||||
fn restore_hunks_in_ranges(
|
||||
&mut self,
|
||||
ranges: impl Iterator<Item = Range<Point>>,
|
||||
ranges: Vec<Range<Point>>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Editor>,
|
||||
) {
|
||||
let mut revert_changes = HashMap::default();
|
||||
let snapshot = self.snapshot(window, cx);
|
||||
for hunk in &snapshot.hunks_for_ranges(ranges) {
|
||||
self.prepare_revert_change(&mut revert_changes, &hunk, cx);
|
||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let Some(project) = &self.project else {
|
||||
return;
|
||||
};
|
||||
|
||||
let chunk_by = self
|
||||
.snapshot(window, cx)
|
||||
.hunks_for_ranges(ranges.into_iter())
|
||||
.into_iter()
|
||||
.chunk_by(|hunk| hunk.buffer_id);
|
||||
for (buffer_id, hunks) in &chunk_by {
|
||||
let hunks = hunks.collect::<Vec<_>>();
|
||||
for hunk in &hunks {
|
||||
self.prepare_restore_change(&mut revert_changes, hunk, cx);
|
||||
}
|
||||
Self::do_stage_or_unstage(project, false, buffer_id, hunks.into_iter(), &snapshot, cx);
|
||||
}
|
||||
drop(chunk_by);
|
||||
if !revert_changes.is_empty() {
|
||||
self.transact(window, cx, |editor, window, cx| {
|
||||
editor.revert(revert_changes, window, cx);
|
||||
|
@ -7098,7 +7119,7 @@ impl Editor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn prepare_revert_change(
|
||||
pub fn prepare_restore_change(
|
||||
&self,
|
||||
revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
|
||||
hunk: &MultiBufferDiffHunk,
|
||||
|
@ -12576,89 +12597,134 @@ impl Editor {
|
|||
|
||||
pub fn toggle_staged_selected_diff_hunks(
|
||||
&mut self,
|
||||
_: &ToggleStagedSelectedDiffHunks,
|
||||
_: &::git::ToggleStaged,
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
|
||||
self.stage_or_unstage_diff_hunks(&ranges, cx);
|
||||
let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
|
||||
self.stage_or_unstage_diff_hunks(stage, &ranges, cx);
|
||||
}
|
||||
|
||||
pub fn stage_and_next(
|
||||
&mut self,
|
||||
_: &::git::StageAndNext,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let head = self.selections.newest_anchor().head();
|
||||
self.stage_or_unstage_diff_hunks(true, &[head..head], cx);
|
||||
self.go_to_next_hunk(&Default::default(), window, cx);
|
||||
}
|
||||
|
||||
pub fn unstage_and_next(
|
||||
&mut self,
|
||||
_: &::git::UnstageAndNext,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let head = self.selections.newest_anchor().head();
|
||||
self.stage_or_unstage_diff_hunks(false, &[head..head], cx);
|
||||
self.go_to_next_hunk(&Default::default(), window, cx);
|
||||
}
|
||||
|
||||
pub fn stage_or_unstage_diff_hunks(
|
||||
&mut self,
|
||||
stage: bool,
|
||||
ranges: &[Range<Anchor>],
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let Some(project) = &self.project else {
|
||||
return;
|
||||
};
|
||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let stage = self.has_stageable_diff_hunks_in_ranges(ranges, &snapshot);
|
||||
|
||||
let chunk_by = self
|
||||
.diff_hunks_in_ranges(&ranges, &snapshot)
|
||||
.chunk_by(|hunk| hunk.buffer_id);
|
||||
for (buffer_id, hunks) in &chunk_by {
|
||||
let Some(buffer) = project.read(cx).buffer_for_id(buffer_id, cx) else {
|
||||
log::debug!("no buffer for id");
|
||||
continue;
|
||||
};
|
||||
let buffer = buffer.read(cx).snapshot();
|
||||
let Some((repo, path)) = project
|
||||
.read(cx)
|
||||
.repository_and_path_for_buffer_id(buffer_id, cx)
|
||||
else {
|
||||
log::debug!("no git repo for buffer id");
|
||||
continue;
|
||||
};
|
||||
let Some(diff) = snapshot.diff_for_buffer_id(buffer_id) else {
|
||||
log::debug!("no diff for buffer id");
|
||||
continue;
|
||||
};
|
||||
let Some(secondary_diff) = diff.secondary_diff() else {
|
||||
log::debug!("no secondary diff for buffer id");
|
||||
continue;
|
||||
};
|
||||
|
||||
let edits = diff.secondary_edits_for_stage_or_unstage(
|
||||
stage,
|
||||
hunks.map(|hunk| {
|
||||
(
|
||||
hunk.diff_base_byte_range.clone(),
|
||||
hunk.secondary_diff_base_byte_range.clone(),
|
||||
hunk.buffer_range.clone(),
|
||||
)
|
||||
}),
|
||||
&buffer,
|
||||
);
|
||||
|
||||
let index_base = secondary_diff.base_text().map_or_else(
|
||||
|| Rope::from(""),
|
||||
|snapshot| snapshot.text.as_rope().clone(),
|
||||
);
|
||||
let index_buffer = cx.new(|cx| {
|
||||
Buffer::local_normalized(index_base.clone(), text::LineEnding::default(), cx)
|
||||
});
|
||||
let new_index_text = index_buffer.update(cx, |index_buffer, cx| {
|
||||
index_buffer.edit(edits, None, cx);
|
||||
index_buffer.snapshot().as_rope().to_string()
|
||||
});
|
||||
let new_index_text = if new_index_text.is_empty()
|
||||
&& (diff.is_single_insertion
|
||||
|| buffer
|
||||
.file()
|
||||
.map_or(false, |file| file.disk_state() == DiskState::New))
|
||||
{
|
||||
log::debug!("removing from index");
|
||||
None
|
||||
} else {
|
||||
Some(new_index_text)
|
||||
};
|
||||
|
||||
let _ = repo.read(cx).set_index_text(&path, new_index_text);
|
||||
Self::do_stage_or_unstage(project, stage, buffer_id, hunks, &snapshot, cx);
|
||||
}
|
||||
}
|
||||
|
||||
fn do_stage_or_unstage(
|
||||
project: &Entity<Project>,
|
||||
stage: bool,
|
||||
buffer_id: BufferId,
|
||||
hunks: impl Iterator<Item = MultiBufferDiffHunk>,
|
||||
snapshot: &MultiBufferSnapshot,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let Some(buffer) = project.read(cx).buffer_for_id(buffer_id, cx) else {
|
||||
log::debug!("no buffer for id");
|
||||
return;
|
||||
};
|
||||
let buffer = buffer.read(cx).snapshot();
|
||||
let Some((repo, path)) = project
|
||||
.read(cx)
|
||||
.repository_and_path_for_buffer_id(buffer_id, cx)
|
||||
else {
|
||||
log::debug!("no git repo for buffer id");
|
||||
return;
|
||||
};
|
||||
let Some(diff) = snapshot.diff_for_buffer_id(buffer_id) else {
|
||||
log::debug!("no diff for buffer id");
|
||||
return;
|
||||
};
|
||||
let Some(secondary_diff) = diff.secondary_diff() else {
|
||||
log::debug!("no secondary diff for buffer id");
|
||||
return;
|
||||
};
|
||||
|
||||
let edits = diff.secondary_edits_for_stage_or_unstage(
|
||||
stage,
|
||||
hunks.filter_map(|hunk| {
|
||||
if stage && hunk.secondary_status == DiffHunkSecondaryStatus::None {
|
||||
return None;
|
||||
} else if !stage
|
||||
&& hunk.secondary_status == DiffHunkSecondaryStatus::HasSecondaryHunk
|
||||
{
|
||||
return None;
|
||||
}
|
||||
Some((
|
||||
hunk.diff_base_byte_range.clone(),
|
||||
hunk.secondary_diff_base_byte_range.clone(),
|
||||
hunk.buffer_range.clone(),
|
||||
))
|
||||
}),
|
||||
&buffer,
|
||||
);
|
||||
|
||||
let Some(index_base) = secondary_diff
|
||||
.base_text()
|
||||
.map(|snapshot| snapshot.text.as_rope().clone())
|
||||
else {
|
||||
log::debug!("no index base");
|
||||
return;
|
||||
};
|
||||
let index_buffer = cx.new(|cx| {
|
||||
Buffer::local_normalized(index_base.clone(), text::LineEnding::default(), cx)
|
||||
});
|
||||
let new_index_text = index_buffer.update(cx, |index_buffer, cx| {
|
||||
index_buffer.edit(edits, None, cx);
|
||||
index_buffer.snapshot().as_rope().to_string()
|
||||
});
|
||||
let new_index_text = if new_index_text.is_empty()
|
||||
&& (diff.is_single_insertion
|
||||
|| buffer
|
||||
.file()
|
||||
.map_or(false, |file| file.disk_state() == DiskState::New))
|
||||
{
|
||||
log::debug!("removing from index");
|
||||
None
|
||||
} else {
|
||||
Some(new_index_text)
|
||||
};
|
||||
|
||||
let _ = repo.read(cx).set_index_text(&path, new_index_text);
|
||||
}
|
||||
|
||||
pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
|
||||
let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
|
||||
self.buffer
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue