Skip to main content

gitkraft_gui/
message.rs

1//! Unified message type for the entire GitKraft GUI application.
2//!
3//! Every user interaction, async result callback, and internal event is
4//! represented as a variant of [`Message`]. The top-level `update` function
5//! pattern-matches on these and delegates to the appropriate feature handler.
6
7use std::path::PathBuf;
8
9use gitkraft_core::{
10    BranchInfo, CommitInfo, DiffFileEntry, DiffInfo, GraphRow, RemoteInfo, RepoInfo, StashEntry,
11};
12
13// ── Payload types ─────────────────────────────────────────────────────────────
14
15/// Payload returned after successfully opening / refreshing a repository.
16/// Bundles every piece of state the UI needs so we can update in one shot.
17#[derive(Debug, Clone)]
18pub struct RepoPayload {
19    pub info: RepoInfo,
20    pub branches: Vec<BranchInfo>,
21    pub commits: Vec<CommitInfo>,
22    pub graph_rows: Vec<GraphRow>,
23    pub unstaged: Vec<DiffInfo>,
24    pub staged: Vec<DiffInfo>,
25    pub stashes: Vec<StashEntry>,
26    pub remotes: Vec<RemoteInfo>,
27}
28
29/// Payload returned after a staging operation (stage / unstage / discard).
30#[derive(Debug, Clone)]
31pub struct StagingPayload {
32    pub unstaged: Vec<DiffInfo>,
33    pub staged: Vec<DiffInfo>,
34}
35
36/// Payload returned by a lazy-load page request.
37#[derive(Debug, Clone)]
38pub struct CommitPage {
39    pub commits: Vec<gitkraft_core::CommitInfo>,
40    pub graph_rows: Vec<gitkraft_core::GraphRow>,
41}
42
43// ── Message enum ──────────────────────────────────────────────────────────────
44
45#[derive(Debug, Clone)]
46pub enum Message {
47    // ── Tabs ──────────────────────────────────────────────────────────────
48    /// User clicked a tab in the tab bar.
49    SwitchTab(usize),
50    /// User clicked the "+" button to open a new empty tab.
51    NewTab,
52    /// User clicked the close (×) button on a tab.
53    CloseTab(usize),
54
55    // ── Repository ────────────────────────────────────────────────────────
56    /// User clicked "Open Repository" — launch the folder picker.
57    OpenRepo,
58    /// User clicked "Init Repository" — launch the folder picker for init.
59    InitRepo,
60    /// Folder picker returned a path (or was cancelled → `None`).
61    RepoSelected(Option<PathBuf>),
62    /// Folder picker returned a path for init (or was cancelled → `None`).
63    RepoInitSelected(Option<PathBuf>),
64    /// Async repo-open completed.
65    RepoOpened(Result<RepoPayload, String>),
66    /// User requested a full refresh of the current repo.
67    RefreshRepo,
68    /// Async refresh completed.
69    RepoRefreshed(Result<RepoPayload, String>),
70
71    // ── Branches ──────────────────────────────────────────────────────────
72    /// User clicked a branch name → checkout that branch.
73    CheckoutBranch(String),
74    /// Async checkout completed.
75    BranchCheckedOut(Result<(), String>),
76    /// User submitted the new-branch form.
77    CreateBranch,
78    /// User is typing a new branch name.
79    NewBranchNameChanged(String),
80    /// Async branch creation completed.
81    BranchCreated(Result<(), String>),
82    /// User clicked the delete button next to a branch.
83    DeleteBranch(String),
84    /// Async branch deletion completed.
85    BranchDeleted(Result<(), String>),
86    /// Toggle visibility of the new-branch inline form.
87    ToggleBranchCreate,
88    /// Collapse or expand the Local branches section.
89    ToggleLocalBranches,
90    /// Collapse or expand the Remote branches section.
91    ToggleRemoteBranches,
92
93    // ── Commits ───────────────────────────────────────────────────────────
94    /// User clicked a commit row in the log.
95    SelectCommit(usize),
96    /// Async commit file-list load completed (lightweight — no diff content).
97    CommitFileListLoaded(Result<Vec<DiffFileEntry>, String>),
98    /// Async single-file diff load completed.
99    SingleFileDiffLoaded(Result<DiffInfo, String>),
100    /// The commit log scrollable was scrolled.
101    /// Carries `(absolute_y, relative_y)` — absolute for virtual-window
102    /// positioning, relative (0.0 = top, 1.0 = bottom) for load-more trigger.
103    CommitLogScrolled(f32, f32),
104    /// The diff viewer scrollable was scrolled — carries `absolute_y`.
105    DiffViewScrolled(f32),
106    /// A lazy-loaded page of additional commits was fetched from the background.
107    MoreCommitsLoaded(Result<CommitPage, String>),
108
109    // ── Staging ───────────────────────────────────────────────────────────
110    /// Stage a single file by its path.
111    StageFile(String),
112    /// Unstage a single file by its path.
113    UnstageFile(String),
114    /// Stage all unstaged files.
115    StageAll,
116    /// Unstage all staged files.
117    UnstageAll,
118    /// Discard working-directory changes for a file.
119    DiscardFile(String),
120    /// User confirmed the discard for a file.
121    ConfirmDiscard(String),
122    /// User cancelled a pending discard.
123    CancelDiscard,
124    /// Async staging operation completed.
125    StagingUpdated(Result<StagingPayload, String>),
126
127    // ── Commit creation ───────────────────────────────────────────────────
128    /// User is typing in the commit-message input.
129    CommitMessageChanged(String),
130    /// User clicked "Commit".
131    CreateCommit,
132    /// Async commit creation completed.
133    CommitCreated(Result<(), String>),
134
135    // ── Stash ─────────────────────────────────────────────────────────────
136    /// Save the current working state as a stash.
137    StashSave,
138    /// Pop (apply + drop) a stash by index.
139    StashPop(usize),
140    /// Drop (delete) a stash by index without applying.
141    StashDrop(usize),
142    /// Async stash operation completed.
143    StashUpdated(Result<Vec<StashEntry>, String>),
144    /// User is typing in the stash-message input.
145    StashMessageChanged(String),
146
147    // ── Remotes ───────────────────────────────────────────────────────────
148    /// Fetch from the first configured remote.
149    Fetch,
150    /// Async fetch completed.
151    FetchCompleted(Result<(), String>),
152
153    // ── UI ────────────────────────────────────────────────────────────────
154    /// User clicked a file in the commit-diff file list (by index into `commit_files`).
155    SelectDiffByIndex(usize),
156    /// User clicked a file in the staging area to view its diff.
157    SelectDiff(DiffInfo),
158    /// Dismiss the current error banner.
159    DismissError,
160    /// Zoom in (increase UI scale).
161    ZoomIn,
162    /// Zoom out (decrease UI scale).
163    ZoomOut,
164    /// Reset zoom to 100%.
165    ZoomReset,
166    /// Toggle the left sidebar.
167    ToggleSidebar,
168    /// Close the current repository and return to the welcome screen.
169    CloseRepo,
170
171    // ── Pane resize ───────────────────────────────────────────────────────
172    /// User pressed the mouse button on a vertical divider to start dragging.
173    PaneDragStart(crate::state::DragTarget, f32),
174    /// User pressed the mouse button on the horizontal staging divider.
175    PaneDragStartH(crate::state::DragTargetH, f32),
176    /// Mouse moved during a drag — `(x, y)` in window coordinates.
177    PaneDragMove(f32, f32),
178    /// Mouse button released — stop dragging.
179    PaneDragEnd,
180    // ── Async persistence results ─────────────────────────────────────
181    /// Background `record_repo_opened` + `load_settings` completed.
182    /// Carries the refreshed recent-repos list (or an error string).
183    RepoRecorded(Result<Vec<gitkraft_core::RepoHistoryEntry>, String>),
184    /// Background `load_settings` completed (e.g. after closing a repo).
185    SettingsLoaded(Result<Vec<gitkraft_core::RepoHistoryEntry>, String>),
186    /// Background `save_theme` completed (fire-and-forget, errors logged).
187    ThemeSaved(Result<(), String>),
188    /// Background layout save completed (fire-and-forget, errors logged).
189    LayoutSaved(Result<(), String>),
190    /// Layout loaded from persisted settings on startup.
191    LayoutLoaded(Result<Option<gitkraft_core::LayoutSettings>, String>),
192    /// Background session save completed (fire-and-forget).
193    SessionSaved(Result<(), String>),
194    /// Async restore of a specific tab (by index) completed on startup.
195    RepoRestoredAt(usize, Result<RepoPayload, String>),
196
197    // ── Context menus ─────────────────────────────────────────────────────────────
198    /// User right-clicked a local branch.
199    /// Payload: (branch_name, index_in_local_list, is_current_branch).
200    OpenBranchContextMenu(String, usize, bool),
201
202    /// User right-clicked a remote branch.
203    OpenRemoteBranchContextMenu(String),
204
205    /// Checkout a remote branch (creates local tracking branch).
206    CheckoutRemoteBranch(String),
207
208    /// Delete a remote branch.
209    DeleteRemoteBranch(String),
210    /// User right-clicked a commit row.
211    OpenCommitContextMenu(usize),
212
213    /// Dismiss the context menu without taking an action.
214    CloseContextMenu,
215
216    // ── Branch actions ────────────────────────────────────────────────────────────
217    /// Push the named branch to its default remote.
218    PushBranch(String),
219
220    /// Pull the current branch from its remote, rebasing local commits on top.
221    PullBranch(String),
222
223    /// Rebase the current HEAD onto `target` (a branch name or OID string).
224    RebaseOnto(String),
225
226    /// Begin an inline rename: record the branch being renamed and pre-fill input.
227    BeginRenameBranch(String),
228
229    /// User is typing in the rename input.
230    RenameBranchInputChanged(String),
231
232    /// User confirmed the rename.
233    ConfirmRenameBranch,
234
235    /// User cancelled the rename.
236    CancelRename,
237
238    /// Merge a named branch into the current HEAD branch.
239    MergeBranch(String),
240
241    /// Begin an inline tag-creation form at the given commit OID.
242    /// The bool indicates whether this is an annotated tag (true) or lightweight (false).
243    BeginCreateTag(String, bool),
244
245    /// User is typing in the tag name input.
246    TagNameChanged(String),
247
248    /// User is typing in the annotated tag message input.
249    TagMessageChanged(String),
250
251    /// User confirmed tag creation.
252    ConfirmCreateTag,
253
254    /// User cancelled tag creation.
255    CancelCreateTag,
256
257    // ── Commit actions ────────────────────────────────────────────────────────────
258    /// Checkout a specific commit in detached HEAD mode.
259    CheckoutCommitDetached(String),
260
261    /// Rebase the current branch on top of a specific commit.
262    RebaseOntoCommit(String),
263
264    /// Revert a specific commit (creates a revert commit).
265    RevertCommit(String),
266
267    /// git reset --soft `oid` — move HEAD, keep staged + working changes.
268    ResetSoft(String),
269    /// git reset --mixed `oid` — move HEAD and unstage; keep working directory.
270    ResetMixed(String),
271    /// git reset --hard `oid` — move HEAD and discard all uncommitted changes.
272    ResetHard(String),
273
274    // ── Shared ───────────────────────────────────────────────────────────────────
275    /// Copy a string to the system clipboard.
276    CopyText(String),
277
278    /// Generic result for any git operation that produces a full repo refresh.
279    /// The operation itself is responsible for a descriptive error string.
280    GitOperationResult(Result<RepoPayload, String>),
281
282    /// User selected a different theme from the picker (by index into
283    /// `gitkraft_core::THEME_NAMES`).
284    ThemeChanged(usize),
285    /// User clicked a recent repository entry on the welcome screen.
286    OpenRecentRepo(PathBuf),
287    /// No-op (used for disabled buttons, etc.).
288    Noop,
289}