use crate::core::{Effect, Msg};
use crate::services::git::GitService;
use std::sync::Arc;
pub struct EffectExecutor {
git_service: Arc<GitService>,
repo_path: String,
}
impl EffectExecutor {
pub fn new(git_service: Arc<GitService>, repo_path: String) -> Self {
Self { git_service, repo_path }
}
pub async fn execute(&self, effect: Effect) -> Option<Msg> {
tracing::debug!("Executing effect: {:?}", effect);
match effect {
Effect::None => None,
Effect::Batch(effects) => {
for e in effects {
if let Some(msg) = Box::pin(self.execute(e)).await {
return Some(msg);
}
}
None
}
Effect::GitStage { path } => {
let path_str = path.to_string_lossy().to_string();
match self.git_service.stage_file(&self.repo_path, &path_str) {
Ok(()) => Some(Msg::StageSuccess { path: path_str }),
Err(e) => Some(Msg::StageFailed {
path: path_str,
error: e.to_string()
}),
}
}
Effect::GitUnstage { path } => {
let path_str = path.to_string_lossy().to_string();
match self.git_service.unstage_file(&self.repo_path, &path_str) {
Ok(()) => Some(Msg::StageSuccess { path: path_str }),
Err(e) => Some(Msg::StageFailed {
path: path_str,
error: e.to_string()
}),
}
}
Effect::GitStageAll => {
None
}
Effect::GitUnstageAll => {
None
}
Effect::GitCommit { message, amend, author_name, author_email } => {
match self.git_service.commit(
&self.repo_path,
&message,
amend,
author_name.as_deref(),
author_email.as_deref(),
) {
Ok(()) => {
let hash = self.git_service.last_commit_info(&self.repo_path)
.map(|info| info.hash)
.unwrap_or_else(|_| "unknown".to_string());
Some(Msg::CommitSuccess { hash })
}
Err(e) => Some(Msg::CommitFailed { error: e.to_string() }),
}
}
Effect::GitPush { force_with_lease } => {
match self.git_service.push(&self.repo_path, force_with_lease) {
Ok(()) => Some(Msg::SetFeedback {
message: Some("Pushed successfully".to_string())
}),
Err(e) => Some(Msg::SetError {
error: Some(e.to_string()),
guidance: None
}),
}
}
Effect::GitPull { rebase: _ } => {
None
}
Effect::GitFetch => {
None
}
Effect::GitCheckout { branch } => {
match self.git_service.checkout_branch(&self.repo_path, &branch) {
Ok(()) => Some(Msg::SetFeedback {
message: Some(format!("Checked out {}", branch))
}),
Err(e) => Some(Msg::SetError {
error: Some(e.to_string()),
guidance: None
}),
}
}
Effect::GitCreateBranch { name, start_point: _ } => {
match self.git_service.create_branch(&self.repo_path, &name) {
Ok(()) => Some(Msg::SetFeedback {
message: Some(format!("Created branch {}", name))
}),
Err(e) => Some(Msg::SetError {
error: Some(e.to_string()),
guidance: None
}),
}
}
Effect::GitDeleteBranch { name: _, force: _ } => {
None
}
Effect::GitRebaseStart { base: _, use_root: _, todo_content: _ } => {
None
}
Effect::GitRebaseContinue { message: _, author_name: _, author_email: _ } => {
None
}
Effect::GitRebaseAbort => {
None
}
Effect::GitRebaseSkip => {
None
}
Effect::GitCherryPick { hash: _ } => None,
Effect::GitRevert { hash: _ } => None,
Effect::GitReset { target: _, mode: _ } => None,
Effect::GitStash { message } => {
let msg = message.unwrap_or_default();
match self.git_service.stash_push(&self.repo_path, &msg) {
Ok(()) => Some(Msg::SetFeedback {
message: Some("Stashed changes".to_string())
}),
Err(e) => Some(Msg::SetError {
error: Some(e.to_string()),
guidance: None
}),
}
}
Effect::GitStashPop { index } => {
let stash_ref = format!("stash@{{{}}}", index);
match self.git_service.stash_apply(&self.repo_path, &stash_ref, true) {
Ok(()) => Some(Msg::SetFeedback {
message: Some("Applied stash".to_string())
}),
Err(e) => Some(Msg::SetError {
error: Some(e.to_string()),
guidance: None
}),
}
}
Effect::GitStashDrop { stash_ref } => {
match self.git_service.stash_drop(&self.repo_path, &stash_ref) {
Ok(()) => Some(Msg::SetFeedback {
message: Some("Dropped stash".to_string())
}),
Err(e) => Some(Msg::SetError {
error: Some(e.to_string()),
guidance: None
}),
}
}
Effect::RefreshStatus | Effect::RefreshLog | Effect::RefreshBranches |
Effect::RefreshStashes | Effect::RefreshAll => {
None
}
Effect::ComputeDiff { path, staged } => {
let path_str = path.to_string_lossy().to_string();
match self.git_service.diff(&self.repo_path, &path_str, staged, 3) {
Ok(content) => Some(Msg::DiffComputed {
path: path_str,
content,
truncated: false
}),
Err(_) => None,
}
}
Effect::OpenInEditor { path: _ } => None,
Effect::SaveConfig { key, value } => {
if key == "theme" {
let _ = crate::config::persist_theme(&value);
}
None
}
Effect::ExecuteCustomCommand { name: _, command: _ } => None,
}
}
}