use crate::app::Action;
#[derive(Debug, Clone, PartialEq)]
#[allow(dead_code)]
pub enum ErrorType {
UncommittedChanges,
MergeConflict,
AuthenticationFailed,
RemoteConnectionFailed,
BranchNotFound,
CommitNotFound,
RebaseInProgress,
MergeInProgress,
StashNotFound,
InvalidOperation,
Unknown,
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct ErrorAction {
pub key: String,
pub label: String,
pub action: Option<Action>,
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct ErrorGuidance {
pub error_type: ErrorType,
pub message: String,
pub suggestions: Vec<String>,
pub next_actions: Vec<ErrorAction>,
}
impl ErrorGuidance {
pub fn from_error(error_msg: &str) -> Self {
let error_lower = error_msg.to_lowercase();
let error_type = if error_lower.contains("uncommitted changes")
|| error_lower.contains("local changes would be overwritten") {
ErrorType::UncommittedChanges
} else if error_lower.contains("merge conflict")
|| error_lower.contains("conflicts") {
ErrorType::MergeConflict
} else if error_lower.contains("authentication")
|| error_lower.contains("permission denied") {
ErrorType::AuthenticationFailed
} else if error_lower.contains("could not resolve host")
|| error_lower.contains("connection refused")
|| error_lower.contains("network") {
ErrorType::RemoteConnectionFailed
} else if error_lower.contains("branch") && error_lower.contains("not found") {
ErrorType::BranchNotFound
} else if error_lower.contains("commit") && error_lower.contains("not found") {
ErrorType::CommitNotFound
} else if error_lower.contains("rebase") && error_lower.contains("in progress") {
ErrorType::RebaseInProgress
} else if error_lower.contains("merge") && error_lower.contains("in progress") {
ErrorType::MergeInProgress
} else if error_lower.contains("stash") && error_lower.contains("not found") {
ErrorType::StashNotFound
} else {
ErrorType::Unknown
};
let (suggestions, next_actions) = match error_type {
ErrorType::UncommittedChanges => (
vec![
"You have uncommitted changes that would be overwritten".to_string(),
"Commit your changes first, or stash them to save for later".to_string(),
],
vec![
ErrorAction {
key: "c".to_string(),
label: "Commit changes".to_string(),
action: Some(Action::StartCommit),
},
ErrorAction {
key: "u".to_string(),
label: "Unstage changes".to_string(),
action: Some(Action::UnstageAllFiles),
},
],
),
ErrorType::MergeConflict => (
vec![
"Merge conflicts detected in your files".to_string(),
"Resolve conflicts manually or use guided resolution".to_string(),
],
vec![
ErrorAction {
key: "g".to_string(),
label: "Open guided resolution".to_string(),
action: Some(Action::ShowConflictsGuided),
},
ErrorAction {
key: "o".to_string(),
label: "Open conflicts in editor".to_string(),
action: None, },
],
),
ErrorType::AuthenticationFailed => (
vec![
"Authentication failed with remote repository".to_string(),
"Check your credentials or SSH keys".to_string(),
],
vec![],
),
ErrorType::RemoteConnectionFailed => (
vec![
"Cannot connect to remote repository".to_string(),
"Check your internet connection and remote URL".to_string(),
],
vec![],
),
ErrorType::BranchNotFound => (
vec![
"Branch not found".to_string(),
"Check branch name or fetch from remote".to_string(),
],
vec![
ErrorAction {
key: "f".to_string(),
label: "Check auto-fetch".to_string(),
action: Some(Action::CheckAutoFetch),
},
],
),
ErrorType::CommitNotFound => (
vec![
"Commit not found".to_string(),
"Check commit hash or fetch from remote".to_string(),
],
vec![],
),
ErrorType::RebaseInProgress => (
vec![
"A rebase is already in progress".to_string(),
"Continue, abort, or skip the current rebase step".to_string(),
],
vec![
ErrorAction {
key: "rc".to_string(),
label: "Continue rebase".to_string(),
action: Some(Action::RebaseContinue),
},
ErrorAction {
key: "ra".to_string(),
label: "Abort rebase".to_string(),
action: Some(Action::RebaseAbort),
},
],
),
ErrorType::MergeInProgress => (
vec![
"A merge is already in progress".to_string(),
"Resolve conflicts and commit, or abort the merge".to_string(),
],
vec![],
),
ErrorType::StashNotFound => (
vec![
"Stash not found".to_string(),
"Check stash name or list available stashes".to_string(),
],
vec![],
),
ErrorType::InvalidOperation | ErrorType::Unknown => (
vec![
"An error occurred".to_string(),
"Check the error message above for details".to_string(),
],
vec![],
),
};
Self {
error_type,
message: error_msg.to_string(),
suggestions,
next_actions,
}
}
pub fn format_display(&self) -> String {
let mut lines = vec![self.message.clone()];
lines.push(String::new());
if !self.suggestions.is_empty() {
lines.push("Suggestions:".to_string());
for suggestion in &self.suggestions {
lines.push(format!(" • {}", suggestion));
}
}
if !self.next_actions.is_empty() {
lines.push(String::new());
lines.push("Quick actions:".to_string());
for action in &self.next_actions {
lines.push(format!(" [{}] {}", action.key, action.label));
}
}
lines.join("\n")
}
}