Skip to main content

gitkraft_gui/features/stash/
commands.rs

1//! Async command helpers for stash operations.
2//!
3//! Stash operations in `gitkraft_core` require `&mut Repository`, so each
4//! command opens its own mutable repository handle inside the blocking task.
5
6use std::path::PathBuf;
7
8use iced::Task;
9
10use crate::message::Message;
11
12/// Save the current working state as a new stash entry, then return the
13/// refreshed stash list.
14pub fn stash_save(path: PathBuf, stash_message: Option<String>) -> Task<Message> {
15    git_task!(
16        Message::StashUpdated,
17        (|| {
18            let mut repo = open_repo!(&path);
19            let msg_ref = stash_message.as_deref();
20            gitkraft_core::features::stash::stash_save(&mut repo, msg_ref)
21                .map_err(|e| e.to_string())?;
22            refresh_stash_list(&path)
23        })()
24    )
25}
26
27/// Pop (apply + drop) a stash entry by index, then return the refreshed stash
28/// list.
29pub fn stash_pop(path: PathBuf, index: usize) -> Task<Message> {
30    git_task!(
31        Message::StashUpdated,
32        (|| {
33            let mut repo = open_repo!(&path);
34            gitkraft_core::features::stash::stash_pop(&mut repo, index)
35                .map_err(|e| e.to_string())?;
36            refresh_stash_list(&path)
37        })()
38    )
39}
40
41/// Drop (delete without applying) a stash entry by index, then return the
42/// refreshed stash list.
43pub fn stash_drop(path: PathBuf, index: usize) -> Task<Message> {
44    git_task!(
45        Message::StashUpdated,
46        (|| {
47            let mut repo = open_repo!(&path);
48            gitkraft_core::features::stash::stash_drop(&mut repo, index)
49                .map_err(|e| e.to_string())?;
50            refresh_stash_list(&path)
51        })()
52    )
53}
54
55/// Load the diff for a stash entry.
56pub fn load_stash_diff(path: PathBuf, index: usize) -> Task<Message> {
57    git_task!(
58        Message::StashDiffLoaded,
59        (|| {
60            let mut repo = open_repo!(&path);
61            // Get the stash commit OID
62            let mut stash_oid = None;
63            repo.stash_foreach(|i, _msg, oid| {
64                if i == index {
65                    stash_oid = Some(oid.to_string());
66                    false // stop iterating
67                } else {
68                    true
69                }
70            })
71            .map_err(|e| e.to_string())?;
72
73            let oid = stash_oid.ok_or_else(|| format!("stash@{{{index}}} not found"))?;
74            let repo = open_repo!(&path); // reopen as immutable
75            gitkraft_core::features::diff::get_commit_diff(&repo, &oid).map_err(|e| e.to_string())
76        })()
77    )
78}
79
80/// Apply a stash entry (like pop but keeps it in the stash list).
81pub fn stash_apply(path: PathBuf, index: usize) -> Task<Message> {
82    git_task!(
83        Message::StashUpdated,
84        (|| {
85            let mut repo = open_repo!(&path);
86            repo.stash_apply(index, None).map_err(|e| e.to_string())?;
87            refresh_stash_list(&path)
88        })()
89    )
90}
91
92// ── Helper ────────────────────────────────────────────────────────────────────
93
94/// Re-read the stash list so the caller can update the UI in one shot.
95fn refresh_stash_list(path: &std::path::Path) -> Result<Vec<gitkraft_core::StashEntry>, String> {
96    let mut repo = open_repo!(path);
97    gitkraft_core::features::stash::list_stashes(&mut repo).map_err(|e| e.to_string())
98}