Add stash apply action
This commit is contained in:
parent
4a11d9d4c6
commit
775425e8c7
10 changed files with 180 additions and 6 deletions
|
@ -424,6 +424,14 @@ impl GitRepository for FakeGitRepository {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
fn stash_apply(
|
||||
&self,
|
||||
_index: Option<usize>,
|
||||
_env: Arc<HashMap<String, String>>,
|
||||
) -> BoxFuture<'_, Result<()>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn stash_drop(
|
||||
&self,
|
||||
_index: Option<usize>,
|
||||
|
|
|
@ -60,6 +60,8 @@ actions!(
|
|||
StashAll,
|
||||
/// Pops the most recent stash.
|
||||
StashPop,
|
||||
/// Apply the most recent stash.
|
||||
StashApply,
|
||||
/// Restores all tracked files to their last committed state.
|
||||
RestoreTrackedFiles,
|
||||
/// Moves all untracked files to trash.
|
||||
|
|
|
@ -408,6 +408,12 @@ pub trait GitRepository: Send + Sync {
|
|||
env: Arc<HashMap<String, String>>,
|
||||
) -> BoxFuture<'_, Result<()>>;
|
||||
|
||||
fn stash_apply(
|
||||
&self,
|
||||
index: Option<usize>,
|
||||
env: Arc<HashMap<String, String>>,
|
||||
) -> BoxFuture<'_, Result<()>>;
|
||||
|
||||
fn stash_drop(
|
||||
&self,
|
||||
index: Option<usize>,
|
||||
|
@ -1289,6 +1295,35 @@ impl GitRepository for RealGitRepository {
|
|||
.boxed()
|
||||
}
|
||||
|
||||
fn stash_apply(
|
||||
&self,
|
||||
index: Option<usize>,
|
||||
env: Arc<HashMap<String, String>>,
|
||||
) -> BoxFuture<'_, Result<()>> {
|
||||
let working_directory = self.working_directory();
|
||||
self.executor
|
||||
.spawn(async move {
|
||||
let mut cmd = new_smol_command("git");
|
||||
let mut args = vec!["stash".to_string(), "apply".to_string()];
|
||||
if let Some(index) = index {
|
||||
args.push(format!("stash@{{{}}}", index));
|
||||
}
|
||||
cmd.current_dir(&working_directory?)
|
||||
.envs(env.iter())
|
||||
.args(args);
|
||||
|
||||
let output = cmd.output().await?;
|
||||
|
||||
anyhow::ensure!(
|
||||
output.status.success(),
|
||||
"Failed to apply stash:\n{}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
Ok(())
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn stash_drop(
|
||||
&self,
|
||||
index: Option<usize>,
|
||||
|
|
|
@ -28,8 +28,8 @@ use git::stash::GitStash;
|
|||
use git::status::StageStatus;
|
||||
use git::{Amend, Signoff, ToggleStaged, repository::RepoPath, status::FileStatus};
|
||||
use git::{
|
||||
ExpandCommitEditor, RestoreTrackedFiles, StageAll, StashAll, StashPop, TrashUntrackedFiles,
|
||||
UnstageAll,
|
||||
ExpandCommitEditor, RestoreTrackedFiles, StageAll, StashAll, StashApply, StashPop,
|
||||
TrashUntrackedFiles, UnstageAll,
|
||||
};
|
||||
use gpui::{
|
||||
Action, Animation, AnimationExt as _, AsyncApp, AsyncWindowContext, Axis, ClickEvent, Corner,
|
||||
|
@ -1442,6 +1442,29 @@ impl GitPanel {
|
|||
.detach();
|
||||
}
|
||||
|
||||
pub fn stash_apply(&mut self, _: &StashApply, _window: &mut Window, cx: &mut Context<Self>) {
|
||||
let Some(active_repository) = self.active_repository.clone() else {
|
||||
return;
|
||||
};
|
||||
|
||||
cx.spawn({
|
||||
async move |this, cx| {
|
||||
let stash_task = active_repository
|
||||
.update(cx, |repo, cx| repo.stash_apply(None, cx))?
|
||||
.await;
|
||||
this.update(cx, |this, cx| {
|
||||
stash_task
|
||||
.map_err(|e| {
|
||||
this.show_error_toast("stash apply", e, cx);
|
||||
})
|
||||
.ok();
|
||||
cx.notify();
|
||||
})
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
pub fn stash_all(&mut self, _: &StashAll, _window: &mut Window, cx: &mut Context<Self>) {
|
||||
let Some(active_repository) = self.active_repository.clone() else {
|
||||
return;
|
||||
|
|
|
@ -135,6 +135,14 @@ pub fn init(cx: &mut App) {
|
|||
panel.stash_pop(action, window, cx);
|
||||
});
|
||||
});
|
||||
workspace.register_action(|workspace, action: &git::StashApply, window, cx| {
|
||||
let Some(panel) = workspace.panel::<git_panel::GitPanel>(cx) else {
|
||||
return;
|
||||
};
|
||||
panel.update(cx, |panel, cx| {
|
||||
panel.stash_apply(action, window, cx);
|
||||
});
|
||||
});
|
||||
workspace.register_action(|workspace, action: &git::StageAll, window, cx| {
|
||||
let Some(panel) = workspace.panel::<git_panel::GitPanel>(cx) else {
|
||||
return;
|
||||
|
|
|
@ -253,6 +253,22 @@ impl StashListDelegate {
|
|||
});
|
||||
cx.emit(DismissEvent);
|
||||
}
|
||||
|
||||
fn apply_stash(&self, stash_index: usize, window: &mut Window, cx: &mut Context<Picker<Self>>) {
|
||||
let Some(repo) = self.repo.clone() else {
|
||||
return;
|
||||
};
|
||||
|
||||
cx.spawn(async move |_, cx| {
|
||||
repo.update(cx, |repo, cx| repo.stash_apply(Some(stash_index), cx))?
|
||||
.await?;
|
||||
Ok(())
|
||||
})
|
||||
.detach_and_prompt_err("Failed to apply stash", window, cx, |e, _, _| {
|
||||
Some(e.to_string())
|
||||
});
|
||||
cx.emit(DismissEvent);
|
||||
}
|
||||
}
|
||||
|
||||
impl PickerDelegate for StashListDelegate {
|
||||
|
@ -356,12 +372,16 @@ impl PickerDelegate for StashListDelegate {
|
|||
})
|
||||
}
|
||||
|
||||
fn confirm(&mut self, _: bool, window: &mut Window, cx: &mut Context<Picker<Self>>) {
|
||||
fn confirm(&mut self, secondary: bool, window: &mut Window, cx: &mut Context<Picker<Self>>) {
|
||||
let Some(entry_match) = self.matches.get(self.selected_index()) else {
|
||||
return;
|
||||
};
|
||||
let stash_index = entry_match.entry.index;
|
||||
if secondary {
|
||||
self.pop_stash(stash_index, window, cx);
|
||||
} else {
|
||||
self.apply_stash(stash_index, window, cx);
|
||||
}
|
||||
}
|
||||
|
||||
fn dismissed(&mut self, _: &mut Window, cx: &mut Context<Picker<Self>>) {
|
||||
|
@ -486,7 +506,7 @@ impl PickerDelegate for StashListDelegate {
|
|||
}),
|
||||
)
|
||||
.child(
|
||||
Button::new("pop-stash", "Pop")
|
||||
Button::new("apply-stash", "Apply")
|
||||
.key_binding(
|
||||
KeyBinding::for_action_in(
|
||||
&menu::Confirm,
|
||||
|
@ -499,6 +519,21 @@ impl PickerDelegate for StashListDelegate {
|
|||
.on_click(|_, window, cx| {
|
||||
window.dispatch_action(menu::Confirm.boxed_clone(), cx)
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
Button::new("pop-stash", "Pop")
|
||||
.key_binding(
|
||||
KeyBinding::for_action_in(
|
||||
&menu::SecondaryConfirm,
|
||||
&focus_handle,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
.map(|kb| kb.size(rems_from_px(12.))),
|
||||
)
|
||||
.on_click(|_, window, cx| {
|
||||
window.dispatch_action(menu::SecondaryConfirm.boxed_clone(), cx)
|
||||
}),
|
||||
),
|
||||
)
|
||||
.into_any(),
|
||||
|
|
|
@ -427,6 +427,7 @@ impl GitStore {
|
|||
client.add_entity_request_handler(Self::handle_unstage);
|
||||
client.add_entity_request_handler(Self::handle_stash);
|
||||
client.add_entity_request_handler(Self::handle_stash_pop);
|
||||
client.add_entity_request_handler(Self::handle_stash_apply);
|
||||
client.add_entity_request_handler(Self::handle_stash_drop);
|
||||
client.add_entity_request_handler(Self::handle_commit);
|
||||
client.add_entity_request_handler(Self::handle_reset);
|
||||
|
@ -1792,6 +1793,24 @@ impl GitStore {
|
|||
Ok(proto::Ack {})
|
||||
}
|
||||
|
||||
async fn handle_stash_apply(
|
||||
this: Entity<Self>,
|
||||
envelope: TypedEnvelope<proto::StashApply>,
|
||||
mut cx: AsyncApp,
|
||||
) -> Result<proto::Ack> {
|
||||
let repository_id = RepositoryId::from_proto(envelope.payload.repository_id);
|
||||
let repository_handle = Self::repository_for_request(&this, repository_id, &mut cx)?;
|
||||
let stash_index = envelope.payload.stash_index.map(|i| i as usize);
|
||||
|
||||
repository_handle
|
||||
.update(&mut cx, |repository_handle, cx| {
|
||||
repository_handle.stash_apply(stash_index, cx)
|
||||
})?
|
||||
.await?;
|
||||
|
||||
Ok(proto::Ack {})
|
||||
}
|
||||
|
||||
async fn handle_stash_drop(
|
||||
this: Entity<Self>,
|
||||
envelope: TypedEnvelope<proto::StashDrop>,
|
||||
|
@ -3791,6 +3810,40 @@ impl Repository {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn stash_apply(
|
||||
&mut self,
|
||||
index: Option<usize>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<anyhow::Result<()>> {
|
||||
let id = self.id;
|
||||
cx.spawn(async move |this, cx| {
|
||||
this.update(cx, |this, _| {
|
||||
this.send_job(None, move |git_repo, _cx| async move {
|
||||
match git_repo {
|
||||
RepositoryState::Local {
|
||||
backend,
|
||||
environment,
|
||||
..
|
||||
} => backend.stash_apply(index, environment).await,
|
||||
RepositoryState::Remote { project_id, client } => {
|
||||
client
|
||||
.request(proto::StashApply {
|
||||
project_id: project_id.0,
|
||||
repository_id: id.to_proto(),
|
||||
stash_index: index.map(|i| i as u64),
|
||||
})
|
||||
.await
|
||||
.context("sending stash apply request")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
})
|
||||
})?
|
||||
.await??;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn stash_drop(
|
||||
&mut self,
|
||||
index: Option<usize>,
|
||||
|
|
|
@ -318,6 +318,12 @@ message StashPop {
|
|||
optional uint64 stash_index = 3;
|
||||
}
|
||||
|
||||
message StashApply {
|
||||
uint64 project_id = 1;
|
||||
uint64 repository_id = 2;
|
||||
optional uint64 stash_index = 3;
|
||||
}
|
||||
|
||||
message StashDrop {
|
||||
uint64 project_id = 1;
|
||||
uint64 repository_id = 2;
|
||||
|
|
|
@ -397,7 +397,8 @@ message Envelope {
|
|||
|
||||
LspQuery lsp_query = 365;
|
||||
LspQueryResponse lsp_query_response = 366;
|
||||
StashDrop stash_drop = 367; // current max
|
||||
StashDrop stash_drop = 367;
|
||||
StashApply stash_apply = 368; // current max
|
||||
}
|
||||
|
||||
reserved 87 to 88;
|
||||
|
|
|
@ -257,6 +257,7 @@ messages!(
|
|||
(Unstage, Background),
|
||||
(Stash, Background),
|
||||
(StashPop, Background),
|
||||
(StashApply, Background),
|
||||
(StashDrop, Background),
|
||||
(UpdateBuffer, Foreground),
|
||||
(UpdateBufferFile, Foreground),
|
||||
|
@ -418,6 +419,7 @@ request_messages!(
|
|||
(Unstage, Ack),
|
||||
(Stash, Ack),
|
||||
(StashPop, Ack),
|
||||
(StashApply, Ack),
|
||||
(StashDrop, Ack),
|
||||
(UpdateBuffer, Ack),
|
||||
(UpdateParticipantLocation, Ack),
|
||||
|
@ -572,6 +574,7 @@ entity_messages!(
|
|||
Unstage,
|
||||
Stash,
|
||||
StashPop,
|
||||
StashApply,
|
||||
StashDrop,
|
||||
UpdateBuffer,
|
||||
UpdateBufferFile,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue