Skip to main content

gitkraft_gui/features/staging/
update.rs

1//! Update logic for staging-related messages.
2
3use iced::Task;
4
5use crate::message::Message;
6use crate::state::GitKraft;
7
8use super::commands;
9
10/// Handle all staging-related messages, returning a [`Task`] for any follow-up
11/// async work.
12pub fn update(state: &mut GitKraft, message: Message) -> Task<Message> {
13    match message {
14        Message::StageFile(path) => {
15            state.active_tab_mut().context_menu = None;
16            with_repo!(state, format!("Staging '{path}'…"), |repo_path| {
17                commands::stage_file(repo_path, path)
18            })
19        }
20
21        Message::UnstageFile(path) => {
22            state.active_tab_mut().context_menu = None;
23            with_repo!(state, format!("Unstaging '{path}'…"), |repo_path| {
24                commands::unstage_file(repo_path, path)
25            })
26        }
27
28        Message::StageAll => {
29            state.active_tab_mut().context_menu = None;
30            with_repo!(state, "Staging all files…".into(), |repo_path| {
31                commands::stage_all(repo_path)
32            })
33        }
34
35        Message::UnstageAll => {
36            state.active_tab_mut().context_menu = None;
37            with_repo!(state, "Unstaging all files…".into(), |repo_path| {
38                commands::unstage_all(repo_path)
39            })
40        }
41
42        Message::DiscardFile(path) => {
43            state.active_tab_mut().context_menu = None;
44            state.active_tab_mut().pending_discard = None;
45            with_repo!(state, format!("Discarding '{path}'…"), |repo_path| {
46                commands::discard_file(repo_path, path)
47            })
48        }
49
50        Message::ConfirmDiscard(path) => {
51            with_repo!(
52                state,
53                format!("Discarding changes in '{path}'…"),
54                |repo_path| {
55                    state.active_tab_mut().pending_discard = None;
56                    commands::discard_file(repo_path, path)
57                }
58            )
59        }
60
61        Message::CancelDiscard => {
62            let tab = state.active_tab_mut();
63            tab.pending_discard = None;
64            tab.status_message = None;
65            Task::none()
66        }
67
68        Message::StagingUpdated(result) => {
69            let tab = state.active_tab_mut();
70            match result {
71                Ok(payload) => {
72                    tab.unstaged_changes = payload.unstaged;
73                    tab.staged_changes = payload.staged;
74                    tab.status_message = Some("Staging area updated.".into());
75                }
76                Err(e) => {
77                    tab.error_message = Some(format!("Staging operation failed: {e}"));
78                    tab.status_message = None;
79                }
80            }
81            Task::none()
82        }
83
84        Message::ToggleSelectUnstaged(path) => {
85            let tab = state.active_tab_mut();
86            if tab.selected_unstaged.contains(&path) {
87                tab.selected_unstaged.remove(&path);
88            } else {
89                tab.selected_unstaged.insert(path);
90            }
91            Task::none()
92        }
93
94        Message::ToggleSelectStaged(path) => {
95            let tab = state.active_tab_mut();
96            if tab.selected_staged.contains(&path) {
97                tab.selected_staged.remove(&path);
98            } else {
99                tab.selected_staged.insert(path);
100            }
101            Task::none()
102        }
103
104        Message::StageSelected => {
105            let paths: Vec<String> = state
106                .active_tab()
107                .selected_unstaged
108                .iter()
109                .cloned()
110                .collect();
111            if paths.is_empty() {
112                return Task::none();
113            }
114            state.active_tab_mut().selected_unstaged.clear();
115            state.active_tab_mut().context_menu = None;
116            with_repo!(
117                state,
118                format!("Staging {} file(s)…", paths.len()),
119                |repo_path| commands::stage_files(repo_path, paths)
120            )
121        }
122
123        Message::UnstageSelected => {
124            let paths: Vec<String> = state.active_tab().selected_staged.iter().cloned().collect();
125            if paths.is_empty() {
126                return Task::none();
127            }
128            state.active_tab_mut().selected_staged.clear();
129            state.active_tab_mut().context_menu = None;
130            with_repo!(
131                state,
132                format!("Unstaging {} file(s)…", paths.len()),
133                |repo_path| commands::unstage_files(repo_path, paths)
134            )
135        }
136
137        Message::DiscardSelected => {
138            let unstaged_paths: Vec<String> = state
139                .active_tab()
140                .selected_unstaged
141                .iter()
142                .cloned()
143                .collect();
144            let staged_paths: Vec<String> =
145                state.active_tab().selected_staged.iter().cloned().collect();
146
147            if unstaged_paths.is_empty() && staged_paths.is_empty() {
148                return Task::none();
149            }
150
151            let total = unstaged_paths.len() + staged_paths.len();
152            state.active_tab_mut().selected_unstaged.clear();
153            state.active_tab_mut().selected_staged.clear();
154            state.active_tab_mut().context_menu = None;
155            with_repo!(
156                state,
157                format!("Discarding {} file(s)…", total),
158                |repo_path| commands::discard_all_selected(repo_path, unstaged_paths, staged_paths)
159            )
160        }
161
162        Message::DiscardStagedFile(path) => {
163            state.active_tab_mut().context_menu = None;
164            with_repo!(state, format!("Discarding '{path}'…"), |repo_path| {
165                commands::discard_staged_file(repo_path, path)
166            })
167        }
168
169        _ => Task::none(),
170    }
171}