Add pop stash command on Staches tab

This commit is contained in:
brunohgouveia 2021-04-09 23:33:04 +01:00 committed by Stephan Dilly
parent 1d90219df9
commit 79a38a70b9
10 changed files with 181 additions and 7 deletions

View file

@ -59,6 +59,7 @@
stashing_toggle_untracked: ( code: Char('u'), modifiers: ( bits: 0,),),
stashing_toggle_index: ( code: Char('m'), modifiers: ( bits: 0,),),
stash_apply: ( code: Char('a'), modifiers: ( bits: 0,),),
stash_open: ( code: Char('l'), modifiers: ( bits: 0,),),
stash_drop: ( code: Char('D'), modifiers: ( bits: 1,),),

View file

@ -51,7 +51,9 @@ pub use remotes::{
};
pub use reset::{reset_stage, reset_workdir};
pub use staging::{discard_lines, stage_lines};
pub use stash::{get_stashes, stash_apply, stash_drop, stash_save};
pub use stash::{
get_stashes, stash_apply, stash_drop, stash_pop, stash_save,
};
pub use state::{repo_state, RepoState};
pub use tags::{get_tags, CommitTags, Tags};
pub use utils::{

View file

@ -44,6 +44,19 @@ pub fn stash_drop(repo_path: &str, stash_id: CommitId) -> Result<()> {
Ok(())
}
///
pub fn stash_pop(repo_path: &str, stash_id: CommitId) -> Result<()> {
scope_time!("stash_pop");
let mut repo = repo(repo_path)?;
let index = get_stash_index(&mut repo, stash_id.into())?;
repo.stash_pop(index, None)?;
Ok(())
}
///
pub fn stash_apply(
repo_path: &str,
@ -122,7 +135,7 @@ mod tests {
debug_cmd_print, get_statuses, repo_init,
write_commit_file,
},
utils::repo_write_file,
utils::{repo_read_file, repo_write_file},
};
use std::{fs::File, io::Write, path::Path};
@ -286,4 +299,72 @@ mod tests {
assert!(res.is_ok());
}
#[test]
fn test_stash_pop_no_conflict() {
let (_td, repo) = repo_init().unwrap();
let root = repo.path().parent().unwrap();
let repo_path = root.as_os_str().to_str().unwrap();
write_commit_file(&repo, "test.txt", "test", "c1");
repo_write_file(&repo, "test.txt", "test2").unwrap();
let id =
stash_save(repo_path, Some("foo"), true, false).unwrap();
let res = stash_pop(repo_path, id);
assert!(res.is_ok());
assert_eq!(
repo_read_file(&repo, "test.txt").unwrap(),
"test2"
);
}
#[test]
fn test_stash_pop_conflict() {
let (_td, repo) = repo_init().unwrap();
let root = repo.path().parent().unwrap();
let repo_path = root.as_os_str().to_str().unwrap();
repo_write_file(&repo, "test.txt", "test").unwrap();
let id =
stash_save(repo_path, Some("foo"), true, false).unwrap();
repo_write_file(&repo, "test.txt", "test2").unwrap();
let res = stash_pop(repo_path, id);
assert!(res.is_err());
assert_eq!(
repo_read_file(&repo, "test.txt").unwrap(),
"test2"
);
}
#[test]
fn test_stash_pop_conflict_after_commit() {
let (_td, repo) = repo_init().unwrap();
let root = repo.path().parent().unwrap();
let repo_path = root.as_os_str().to_str().unwrap();
write_commit_file(&repo, "test.txt", "test", "c1");
repo_write_file(&repo, "test.txt", "test2").unwrap();
let id =
stash_save(repo_path, Some("foo"), true, false).unwrap();
repo_write_file(&repo, "test.txt", "test3").unwrap();
let res = stash_pop(repo_path, id);
assert!(res.is_err());
assert_eq!(
repo_read_file(&repo, "test.txt").unwrap(),
"test3"
);
}
}

View file

@ -187,6 +187,25 @@ pub(crate) fn repo_write_file(
Ok(())
}
#[cfg(test)]
pub(crate) fn repo_read_file(
repo: &Repository,
file: &str,
) -> Result<String> {
use std::io::Read;
let dir = work_dir(repo)?.join(file);
let file_path = dir.to_str().ok_or_else(|| {
Error::Generic(String::from("invalid file path"))
})?;
let mut file = File::open(file_path)?;
let mut buffer = Vec::new();
file.read_to_end(&mut buffer)?;
Ok(String::from_utf8(buffer)?)
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -494,8 +494,8 @@ impl App {
flags.insert(NeedsUpdate::ALL);
}
}
Action::StashDrop(s) => {
if StashList::drop(s) {
Action::StashDrop(_) | Action::StashPop(_) => {
if self.stashlist_tab.action_confirmed(&action) {
flags.insert(NeedsUpdate::ALL);
}
}

View file

@ -147,6 +147,10 @@ impl ResetComponent {
),
strings::confirm_msg_stashdrop(&self.key_config),
),
Action::StashPop(_) => (
strings::confirm_title_stashpop(&self.key_config),
strings::confirm_msg_stashpop(&self.key_config),
),
Action::ResetHunk(_, _) => (
strings::confirm_title_reset(&self.key_config),
strings::confirm_msg_resethunk(&self.key_config),

View file

@ -56,6 +56,7 @@ pub struct KeyConfig {
pub stashing_save: KeyEvent,
pub stashing_toggle_untracked: KeyEvent,
pub stashing_toggle_index: KeyEvent,
pub stash_apply: KeyEvent,
pub stash_open: KeyEvent,
pub stash_drop: KeyEvent,
pub cmd_bar_toggle: KeyEvent,
@ -112,6 +113,7 @@ impl Default for KeyConfig {
stashing_save: KeyEvent { code: KeyCode::Char('s'), modifiers: KeyModifiers::empty()},
stashing_toggle_untracked: KeyEvent { code: KeyCode::Char('u'), modifiers: KeyModifiers::empty()},
stashing_toggle_index: KeyEvent { code: KeyCode::Char('i'), modifiers: KeyModifiers::empty()},
stash_apply: KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::empty()},
stash_open: KeyEvent { code: KeyCode::Right, modifiers: KeyModifiers::empty()},
stash_drop: KeyEvent { code: KeyCode::Char('D'), modifiers: KeyModifiers::SHIFT},
cmd_bar_toggle: KeyEvent { code: KeyCode::Char('.'), modifiers: KeyModifiers::empty()},

View file

@ -29,6 +29,7 @@ pub enum Action {
ResetHunk(String, u64),
ResetLines(String, Vec<DiffLinePosition>),
StashDrop(CommitId),
StashPop(CommitId),
DeleteBranch(String),
ForcePush(String, bool),
PullMerge { incoming: usize, rebase: bool },

View file

@ -96,6 +96,11 @@ pub fn confirm_title_stashdrop(
) -> String {
"Drop".to_string()
}
pub fn confirm_title_stashpop(
_key_config: &SharedKeyConfig,
) -> String {
"Pop".to_string()
}
pub fn confirm_title_merge(
_key_config: &SharedKeyConfig,
rebase: bool,
@ -134,6 +139,10 @@ pub fn confirm_msg_stashdrop(
) -> String {
"confirm stash drop?".to_string()
}
pub fn confirm_msg_stashpop(_key_config: &SharedKeyConfig) -> String {
"The stash will be applied and then remove from the stash list. Confirm stash pop?"
.to_string()
}
pub fn confirm_msg_resethunk(
_key_config: &SharedKeyConfig,
) -> String {
@ -748,7 +757,7 @@ pub mod commands {
CommandText::new(
format!(
"Apply [{}]",
key_config.get_hint(key_config.enter),
key_config.get_hint(key_config.stash_apply),
),
"apply selected stash",
CMD_GROUP_STASHES,
@ -766,6 +775,18 @@ pub mod commands {
CMD_GROUP_STASHES,
)
}
pub fn stashlist_pop(
key_config: &SharedKeyConfig,
) -> CommandText {
CommandText::new(
format!(
"Pop [{}]",
key_config.get_hint(key_config.enter),
),
"pop selected stash",
CMD_GROUP_STASHES,
)
}
pub fn stashlist_inspect(
key_config: &SharedKeyConfig,
) -> CommandText {

View file

@ -83,6 +83,14 @@ impl StashList {
}
}
fn pop_stash(&mut self) {
if let Some(e) = self.list.selected_entry() {
self.queue.borrow_mut().push_back(
InternalEvent::ConfirmAction(Action::StashPop(e.id)),
);
}
}
fn inspect(&mut self) {
if let Some(e) = self.list.selected_entry() {
self.queue
@ -91,10 +99,38 @@ impl StashList {
}
}
///
pub fn drop(id: CommitId) -> bool {
/// Called when a pending stash action has been confirmed
pub fn action_confirmed(&self, action: &Action) -> bool {
match *action {
Action::StashDrop(id) => Self::drop(id),
Action::StashPop(id) => self.pop(id),
_ => false,
}
}
fn drop(id: CommitId) -> bool {
sync::stash_drop(CWD, id).is_ok()
}
fn pop(&self, id: CommitId) -> bool {
match sync::stash_pop(CWD, id) {
Ok(_) => {
self.queue
.borrow_mut()
.push_back(InternalEvent::TabSwitch);
true
}
Err(e) => {
self.queue.borrow_mut().push_back(
InternalEvent::ShowErrorMsg(format!(
"stash pop error:\n{}",
e,
)),
);
true
}
}
}
}
impl DrawableComponent for StashList {
@ -120,6 +156,11 @@ impl Component for StashList {
let selection_valid =
self.list.selected_entry().is_some();
out.push(CommandInfo::new(
strings::commands::stashlist_pop(&self.key_config),
selection_valid,
true,
));
out.push(CommandInfo::new(
strings::commands::stashlist_apply(&self.key_config),
selection_valid,
@ -150,6 +191,8 @@ impl Component for StashList {
if let Event::Key(k) = ev {
if k == self.key_config.enter {
self.pop_stash()
} else if k == self.key_config.stash_apply {
self.apply_stash()
} else if k == self.key_config.stash_drop {
self.drop_stash()