Skip to content

Commit 79a38a7

Browse files
brunogouveiaStephan Dilly
authored and
Stephan Dilly
committed
Add pop stash command on Staches tab
1 parent 1d90219 commit 79a38a7

File tree

10 files changed

+181
-7
lines changed

10 files changed

+181
-7
lines changed

Diff for: assets/vim_style_key_config.ron

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
stashing_toggle_untracked: ( code: Char('u'), modifiers: ( bits: 0,),),
6060
stashing_toggle_index: ( code: Char('m'), modifiers: ( bits: 0,),),
6161

62+
stash_apply: ( code: Char('a'), modifiers: ( bits: 0,),),
6263
stash_open: ( code: Char('l'), modifiers: ( bits: 0,),),
6364
stash_drop: ( code: Char('D'), modifiers: ( bits: 1,),),
6465

Diff for: asyncgit/src/sync/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ pub use remotes::{
5151
};
5252
pub use reset::{reset_stage, reset_workdir};
5353
pub use staging::{discard_lines, stage_lines};
54-
pub use stash::{get_stashes, stash_apply, stash_drop, stash_save};
54+
pub use stash::{
55+
get_stashes, stash_apply, stash_drop, stash_pop, stash_save,
56+
};
5557
pub use state::{repo_state, RepoState};
5658
pub use tags::{get_tags, CommitTags, Tags};
5759
pub use utils::{

Diff for: asyncgit/src/sync/stash.rs

+82-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ pub fn stash_drop(repo_path: &str, stash_id: CommitId) -> Result<()> {
4444
Ok(())
4545
}
4646

47+
///
48+
pub fn stash_pop(repo_path: &str, stash_id: CommitId) -> Result<()> {
49+
scope_time!("stash_pop");
50+
51+
let mut repo = repo(repo_path)?;
52+
53+
let index = get_stash_index(&mut repo, stash_id.into())?;
54+
55+
repo.stash_pop(index, None)?;
56+
57+
Ok(())
58+
}
59+
4760
///
4861
pub fn stash_apply(
4962
repo_path: &str,
@@ -122,7 +135,7 @@ mod tests {
122135
debug_cmd_print, get_statuses, repo_init,
123136
write_commit_file,
124137
},
125-
utils::repo_write_file,
138+
utils::{repo_read_file, repo_write_file},
126139
};
127140
use std::{fs::File, io::Write, path::Path};
128141

@@ -286,4 +299,72 @@ mod tests {
286299

287300
assert!(res.is_ok());
288301
}
302+
303+
#[test]
304+
fn test_stash_pop_no_conflict() {
305+
let (_td, repo) = repo_init().unwrap();
306+
let root = repo.path().parent().unwrap();
307+
let repo_path = root.as_os_str().to_str().unwrap();
308+
309+
write_commit_file(&repo, "test.txt", "test", "c1");
310+
311+
repo_write_file(&repo, "test.txt", "test2").unwrap();
312+
313+
let id =
314+
stash_save(repo_path, Some("foo"), true, false).unwrap();
315+
316+
let res = stash_pop(repo_path, id);
317+
318+
assert!(res.is_ok());
319+
assert_eq!(
320+
repo_read_file(&repo, "test.txt").unwrap(),
321+
"test2"
322+
);
323+
}
324+
325+
#[test]
326+
fn test_stash_pop_conflict() {
327+
let (_td, repo) = repo_init().unwrap();
328+
let root = repo.path().parent().unwrap();
329+
let repo_path = root.as_os_str().to_str().unwrap();
330+
331+
repo_write_file(&repo, "test.txt", "test").unwrap();
332+
333+
let id =
334+
stash_save(repo_path, Some("foo"), true, false).unwrap();
335+
336+
repo_write_file(&repo, "test.txt", "test2").unwrap();
337+
338+
let res = stash_pop(repo_path, id);
339+
340+
assert!(res.is_err());
341+
assert_eq!(
342+
repo_read_file(&repo, "test.txt").unwrap(),
343+
"test2"
344+
);
345+
}
346+
347+
#[test]
348+
fn test_stash_pop_conflict_after_commit() {
349+
let (_td, repo) = repo_init().unwrap();
350+
let root = repo.path().parent().unwrap();
351+
let repo_path = root.as_os_str().to_str().unwrap();
352+
353+
write_commit_file(&repo, "test.txt", "test", "c1");
354+
355+
repo_write_file(&repo, "test.txt", "test2").unwrap();
356+
357+
let id =
358+
stash_save(repo_path, Some("foo"), true, false).unwrap();
359+
360+
repo_write_file(&repo, "test.txt", "test3").unwrap();
361+
362+
let res = stash_pop(repo_path, id);
363+
364+
assert!(res.is_err());
365+
assert_eq!(
366+
repo_read_file(&repo, "test.txt").unwrap(),
367+
"test3"
368+
);
369+
}
289370
}

Diff for: asyncgit/src/sync/utils.rs

+19
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,25 @@ pub(crate) fn repo_write_file(
187187
Ok(())
188188
}
189189

190+
#[cfg(test)]
191+
pub(crate) fn repo_read_file(
192+
repo: &Repository,
193+
file: &str,
194+
) -> Result<String> {
195+
use std::io::Read;
196+
197+
let dir = work_dir(repo)?.join(file);
198+
let file_path = dir.to_str().ok_or_else(|| {
199+
Error::Generic(String::from("invalid file path"))
200+
})?;
201+
202+
let mut file = File::open(file_path)?;
203+
let mut buffer = Vec::new();
204+
file.read_to_end(&mut buffer)?;
205+
206+
Ok(String::from_utf8(buffer)?)
207+
}
208+
190209
#[cfg(test)]
191210
mod tests {
192211
use super::*;

Diff for: src/app.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -494,8 +494,8 @@ impl App {
494494
flags.insert(NeedsUpdate::ALL);
495495
}
496496
}
497-
Action::StashDrop(s) => {
498-
if StashList::drop(s) {
497+
Action::StashDrop(_) | Action::StashPop(_) => {
498+
if self.stashlist_tab.action_confirmed(&action) {
499499
flags.insert(NeedsUpdate::ALL);
500500
}
501501
}

Diff for: src/components/reset.rs

+4
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ impl ResetComponent {
147147
),
148148
strings::confirm_msg_stashdrop(&self.key_config),
149149
),
150+
Action::StashPop(_) => (
151+
strings::confirm_title_stashpop(&self.key_config),
152+
strings::confirm_msg_stashpop(&self.key_config),
153+
),
150154
Action::ResetHunk(_, _) => (
151155
strings::confirm_title_reset(&self.key_config),
152156
strings::confirm_msg_resethunk(&self.key_config),

Diff for: src/keys.rs

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ pub struct KeyConfig {
5656
pub stashing_save: KeyEvent,
5757
pub stashing_toggle_untracked: KeyEvent,
5858
pub stashing_toggle_index: KeyEvent,
59+
pub stash_apply: KeyEvent,
5960
pub stash_open: KeyEvent,
6061
pub stash_drop: KeyEvent,
6162
pub cmd_bar_toggle: KeyEvent,
@@ -112,6 +113,7 @@ impl Default for KeyConfig {
112113
stashing_save: KeyEvent { code: KeyCode::Char('s'), modifiers: KeyModifiers::empty()},
113114
stashing_toggle_untracked: KeyEvent { code: KeyCode::Char('u'), modifiers: KeyModifiers::empty()},
114115
stashing_toggle_index: KeyEvent { code: KeyCode::Char('i'), modifiers: KeyModifiers::empty()},
116+
stash_apply: KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::empty()},
115117
stash_open: KeyEvent { code: KeyCode::Right, modifiers: KeyModifiers::empty()},
116118
stash_drop: KeyEvent { code: KeyCode::Char('D'), modifiers: KeyModifiers::SHIFT},
117119
cmd_bar_toggle: KeyEvent { code: KeyCode::Char('.'), modifiers: KeyModifiers::empty()},

Diff for: src/queue.rs

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub enum Action {
2929
ResetHunk(String, u64),
3030
ResetLines(String, Vec<DiffLinePosition>),
3131
StashDrop(CommitId),
32+
StashPop(CommitId),
3233
DeleteBranch(String),
3334
ForcePush(String, bool),
3435
PullMerge { incoming: usize, rebase: bool },

Diff for: src/strings.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ pub fn confirm_title_stashdrop(
9696
) -> String {
9797
"Drop".to_string()
9898
}
99+
pub fn confirm_title_stashpop(
100+
_key_config: &SharedKeyConfig,
101+
) -> String {
102+
"Pop".to_string()
103+
}
99104
pub fn confirm_title_merge(
100105
_key_config: &SharedKeyConfig,
101106
rebase: bool,
@@ -134,6 +139,10 @@ pub fn confirm_msg_stashdrop(
134139
) -> String {
135140
"confirm stash drop?".to_string()
136141
}
142+
pub fn confirm_msg_stashpop(_key_config: &SharedKeyConfig) -> String {
143+
"The stash will be applied and then remove from the stash list. Confirm stash pop?"
144+
.to_string()
145+
}
137146
pub fn confirm_msg_resethunk(
138147
_key_config: &SharedKeyConfig,
139148
) -> String {
@@ -748,7 +757,7 @@ pub mod commands {
748757
CommandText::new(
749758
format!(
750759
"Apply [{}]",
751-
key_config.get_hint(key_config.enter),
760+
key_config.get_hint(key_config.stash_apply),
752761
),
753762
"apply selected stash",
754763
CMD_GROUP_STASHES,
@@ -766,6 +775,18 @@ pub mod commands {
766775
CMD_GROUP_STASHES,
767776
)
768777
}
778+
pub fn stashlist_pop(
779+
key_config: &SharedKeyConfig,
780+
) -> CommandText {
781+
CommandText::new(
782+
format!(
783+
"Pop [{}]",
784+
key_config.get_hint(key_config.enter),
785+
),
786+
"pop selected stash",
787+
CMD_GROUP_STASHES,
788+
)
789+
}
769790
pub fn stashlist_inspect(
770791
key_config: &SharedKeyConfig,
771792
) -> CommandText {

Diff for: src/tabs/stashlist.rs

+45-2
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ impl StashList {
8383
}
8484
}
8585

86+
fn pop_stash(&mut self) {
87+
if let Some(e) = self.list.selected_entry() {
88+
self.queue.borrow_mut().push_back(
89+
InternalEvent::ConfirmAction(Action::StashPop(e.id)),
90+
);
91+
}
92+
}
93+
8694
fn inspect(&mut self) {
8795
if let Some(e) = self.list.selected_entry() {
8896
self.queue
@@ -91,10 +99,38 @@ impl StashList {
9199
}
92100
}
93101

94-
///
95-
pub fn drop(id: CommitId) -> bool {
102+
/// Called when a pending stash action has been confirmed
103+
pub fn action_confirmed(&self, action: &Action) -> bool {
104+
match *action {
105+
Action::StashDrop(id) => Self::drop(id),
106+
Action::StashPop(id) => self.pop(id),
107+
_ => false,
108+
}
109+
}
110+
111+
fn drop(id: CommitId) -> bool {
96112
sync::stash_drop(CWD, id).is_ok()
97113
}
114+
115+
fn pop(&self, id: CommitId) -> bool {
116+
match sync::stash_pop(CWD, id) {
117+
Ok(_) => {
118+
self.queue
119+
.borrow_mut()
120+
.push_back(InternalEvent::TabSwitch);
121+
true
122+
}
123+
Err(e) => {
124+
self.queue.borrow_mut().push_back(
125+
InternalEvent::ShowErrorMsg(format!(
126+
"stash pop error:\n{}",
127+
e,
128+
)),
129+
);
130+
true
131+
}
132+
}
133+
}
98134
}
99135

100136
impl DrawableComponent for StashList {
@@ -120,6 +156,11 @@ impl Component for StashList {
120156

121157
let selection_valid =
122158
self.list.selected_entry().is_some();
159+
out.push(CommandInfo::new(
160+
strings::commands::stashlist_pop(&self.key_config),
161+
selection_valid,
162+
true,
163+
));
123164
out.push(CommandInfo::new(
124165
strings::commands::stashlist_apply(&self.key_config),
125166
selection_valid,
@@ -150,6 +191,8 @@ impl Component for StashList {
150191

151192
if let Event::Key(k) = ev {
152193
if k == self.key_config.enter {
194+
self.pop_stash()
195+
} else if k == self.key_config.stash_apply {
153196
self.apply_stash()
154197
} else if k == self.key_config.stash_drop {
155198
self.drop_stash()

0 commit comments

Comments
 (0)