use crate::app::{Action, AppState};
use crate::commands::{
Command, ApplyStashCommand, CheckoutBranchCommand, MergeBranchCommand,
PopStashCommand, RebaseBranchCommand, StageFilesCommand, UnstageFilesCommand,
PushCommand, CherryPickCommand, RevertCommand, ResetCommand,
ListMergedBranchesCommand, PruneMergedBranchesCommand, RemotePruneCommand, ShowRemoteUrlCommand, SetRemoteSshCommand, LogBriefCommand, LogStatsCommand,
PullCommand, PullRebaseCommand, PullMergeCommand, FetchAllPruneCommand, OpenInEditorCommand, CheckMergeStatusCommand, AutoFetchCommand,
StageHunkCommand, UnstageHunkCommand, StageLinesCommand, UnstageLinesCommand,
PrListCommand, PrCheckoutCommand, PrOpenCommand, CreateBranchCommand,
CreateStashCommand, DeleteStashCommand, RebaseSaveAndRunCommand,
RebaseContinueCommand, RebaseSkipCommand, RebaseAbortCommand,
RebaseResolveConflictsCommand, RebaseAbortFromConflictCommand,
RebaseContinueInterruptedCommand, RebaseAbortInterruptedCommand,
};
use crate::commands::custom::CustomCommand;
use crate::git::parsers::diff;
use super::helpers;
pub fn action_to_command(state: &AppState, action: &Action) -> Option<Box<dyn Command>> {
match action {
Action::StageSelectedFile => {
helpers::create_stage_command(state, true)
}
Action::UnstageSelectedFile => {
helpers::create_stage_command(state, false)
}
Action::StageAllFiles => {
let paths: Vec<String> = state
.status_entries
.iter()
.filter(|e| e.unstaged || (!e.staged && !e.unstaged)) .map(|e| e.path.clone())
.collect();
if paths.is_empty() {
None
} else {
Some(Box::new(StageFilesCommand { paths }))
}
}
Action::UnstageAllFiles => {
let paths: Vec<String> = state
.status_entries
.iter()
.filter(|e| e.staged)
.map(|e| e.path.clone())
.collect();
if paths.is_empty() {
None
} else {
Some(Box::new(UnstageFilesCommand { paths }))
}
}
Action::CommitSubmit => {
helpers::create_commit_command(state, state.amend_mode)
}
Action::AmendCommit => {
None
}
Action::Push => {
Some(Box::new(PushCommand {
force_with_lease: !state.push_ff_only_enforce,
}))
}
Action::ForcePushAfterAmend => {
Some(Box::new(PushCommand {
force_with_lease: true,
}))
}
Action::CherryPickSelected => {
let hash = state
.commits
.get(state.commit_selected)
.map(|c| c.hash.clone());
hash.map(|h| Box::new(CherryPickCommand { hash: h }) as Box<dyn Command>)
}
Action::RevertSelected => {
let hash = state
.commits
.get(state.commit_selected)
.map(|c| c.hash.clone());
hash.map(|h| Box::new(RevertCommand { hash: h }) as Box<dyn Command>)
}
Action::CheckAutoFetch => Some(Box::new(AutoFetchCommand {
remote: state.auto_fetch_remote.clone(),
})),
Action::ShowPrHelper => Some(Box::new(PrListCommand {
remote: state.auto_fetch_remote.clone(),
})),
Action::CheckoutPr(pr) => Some(Box::new(PrCheckoutCommand {
remote: state.auto_fetch_remote.clone(),
pr: pr.clone(),
})),
Action::OpenPrInBrowser(pr) => Some(Box::new(PrOpenCommand {
remote: state.auto_fetch_remote.clone(),
pr: pr.clone(),
})),
Action::ResetSoft => Some(Box::new(ResetCommand {
mode: "--soft",
target: "HEAD~1".to_string(),
})),
Action::ResetMixed => Some(Box::new(ResetCommand {
mode: "--mixed",
target: "HEAD~1".to_string(),
})),
Action::ResetHard => Some(Box::new(ResetCommand {
mode: "--hard",
target: "HEAD~1".to_string(),
})),
Action::ListMergedBranches => Some(Box::new(ListMergedBranchesCommand {
base: state.merge_base_branch.clone(),
})),
Action::PruneMergedBranches => Some(Box::new(PruneMergedBranchesCommand {
base: state.merge_base_branch.clone(),
})),
Action::RemotePrune(remote) => Some(Box::new(RemotePruneCommand {
remote: remote.clone(),
})),
Action::ShowRemoteUrl(remote) => Some(Box::new(ShowRemoteUrlCommand {
remote: remote.clone(),
})),
Action::SetRemoteSsh(remote) => Some(Box::new(SetRemoteSshCommand {
remote: remote.clone(),
})),
Action::ShowLogBrief => Some(Box::new(LogBriefCommand { limit: 5 })),
Action::ShowLogStats => Some(Box::new(LogStatsCommand { limit: 5 })),
Action::Pull => Some(Box::new(PullCommand {
ff_only: state.pull_ff_only,
timeout_secs: state.pull_timeout_secs,
})),
Action::PullRebase => Some(Box::new(PullRebaseCommand {
autostash: state.pull_autostash,
timeout_secs: state.rebase_timeout_secs,
})),
Action::PullMerge => Some(Box::new(PullMergeCommand {
timeout_secs: state.pull_timeout_secs,
})),
Action::FetchAllPrune => Some(Box::new(FetchAllPruneCommand)),
Action::OpenInEditor => {
if state.status_selected_path.is_empty() {
None
} else {
Some(Box::new(OpenInEditorCommand {
path: state.status_selected_path.clone(),
line: None,
}))
}
}
Action::OpenConflictInEditor(path) => {
Some(Box::new(OpenInEditorCommand {
path: path.clone(),
line: None,
}))
}
Action::CheckMergeStatus => Some(Box::new(CheckMergeStatusCommand {
base: state.merge_base_branch.clone(),
})),
Action::ShowMergeBasePicker
| Action::HideMergeBasePicker
| Action::MergeBaseUp
| Action::MergeBaseDown
| Action::TogglePushFFOnly => None,
Action::ApplyMergeBase(name) => Some(Box::new(CheckMergeStatusCommand { base: name.clone() })),
Action::StageCurrentHunk => {
let parsed = diff::parse_diff(&state.last_diff).ok()?;
let file = parsed.files.first()?;
let idx = state.hunk_selected.min(file.hunks.len().saturating_sub(1));
Some(Box::new(StageHunkCommand {
hunk_index: idx,
parsed,
path: state.last_diff_path.clone(),
raw_diff: state.last_diff.clone(),
}))
}
Action::UnstageCurrentHunk => {
let parsed = diff::parse_diff(&state.last_diff).ok()?;
let file = parsed.files.first()?;
let idx = state.hunk_selected.min(file.hunks.len().saturating_sub(1));
Some(Box::new(UnstageHunkCommand {
hunk_index: idx,
parsed,
path: state.last_diff_path.clone(),
raw_diff: state.last_diff.clone(),
}))
}
Action::StageSelectedLines => {
if state.selected_lines.is_empty() {
None
} else {
Some(Box::new(StageLinesCommand {
raw_diff: state.last_diff.clone(),
path: state.last_diff_path.clone(),
selected_lines: state.selected_lines.clone(),
}))
}
}
Action::UnstageSelectedLines => {
if state.selected_lines.is_empty() {
None
} else {
Some(Box::new(UnstageLinesCommand {
raw_diff: state.last_diff.clone(),
path: state.last_diff_path.clone(),
selected_lines: state.selected_lines.clone(),
}))
}
}
Action::CheckoutBranch(branch_name) => {
Some(Box::new(CheckoutBranchCommand { branch_name: branch_name.clone() }))
}
Action::MergeBranch(branch_name) => {
Some(Box::new(MergeBranchCommand { branch_name: branch_name.clone() }))
}
Action::RebaseBranch(branch_name) => {
Some(Box::new(RebaseBranchCommand { branch_name: branch_name.clone() }))
}
Action::ApplyStash(stash_name) => {
Some(Box::new(ApplyStashCommand { name: stash_name.clone() }))
}
Action::PopStash(stash_name) => {
Some(Box::new(PopStashCommand { name: stash_name.clone() }))
}
Action::DeleteStash(stash_name) => {
Some(Box::new(DeleteStashCommand { name: stash_name.clone() }))
}
Action::BranchSubmit => {
Some(Box::new(CreateBranchCommand {
branch_name: state.branch_name_input.clone(),
}))
}
Action::StashSubmit => {
Some(Box::new(CreateStashCommand {
message: state.stash_message_input.clone(),
}))
}
Action::ExecuteCustomCommand(name) => {
if let Some(command) = state.custom_commands.get(name.as_str()) {
Some(Box::new(CustomCommand {
name: name.clone(),
command: command.clone(),
}))
} else {
None
}
}
Action::RebaseSaveAndRun => {
Some(Box::new(RebaseSaveAndRunCommand))
}
Action::RebaseContinue => {
Some(Box::new(RebaseContinueCommand))
}
Action::RebaseSkip => {
Some(Box::new(RebaseSkipCommand))
}
Action::RebaseAbort => {
Some(Box::new(RebaseAbortCommand))
}
Action::RebaseResolveConflicts => {
Some(Box::new(RebaseResolveConflictsCommand))
}
Action::RebaseAbortFromConflict => {
Some(Box::new(RebaseAbortFromConflictCommand))
}
Action::RebaseContinueInterrupted => {
Some(Box::new(RebaseContinueInterruptedCommand))
}
Action::RebaseAbortInterrupted => {
Some(Box::new(RebaseAbortInterruptedCommand))
}
_ => None,
}
}