use crate::error::XorcistError;
use crate::jj::{fetch_diff_file, fetch_graph_log, parse_diff_summary};
use super::{App, CommandResult, DiffState, ModalState, PendingAction, View};
impl App {
pub fn refresh_log(&mut self) -> Result<(), XorcistError> {
self.graph_log = fetch_graph_log(&self.runner, self.log_limit)?;
let count = self.commit_count();
if count > 0 && self.selected >= count {
self.selected = count - 1;
}
Ok(())
}
pub(super) fn handle_command_result(&mut self, result: Result<CommandResult, XorcistError>) {
match result {
Ok(cmd_result) => {
self.last_command_result = Some(cmd_result);
}
Err(e) => {
self.last_command_result = Some(CommandResult {
success: false,
message: e.to_string(),
});
}
}
}
fn handle_command_result_and_refresh_log(
&mut self,
result: Result<CommandResult, XorcistError>,
) -> Result<(), XorcistError> {
self.handle_command_result(result);
self.refresh_log()
}
pub fn show_abandon_confirm(&mut self) {
if let Some(change_id) = self.selected_change_id() {
let description = self.selected_description().unwrap_or_default();
self.modal = ModalState::Confirm(PendingAction::Abandon {
change_id: change_id.to_string(),
description,
});
}
}
pub fn show_squash_confirm(&mut self) {
if let Some(change_id) = self.selected_change_id() {
let description = self.selected_description().unwrap_or_default();
self.modal = ModalState::Confirm(PendingAction::Squash {
change_id: change_id.to_string(),
description,
});
}
}
fn selected_description(&self) -> Option<String> {
let line_idx = self.selected_line_index()?;
self.graph_log.lines[line_idx].description.clone()
}
pub fn show_push_confirm(&mut self) {
self.modal = ModalState::Confirm(PendingAction::GitPush);
}
pub fn show_undo_confirm(&mut self) {
self.modal = ModalState::Confirm(PendingAction::Undo);
}
pub fn confirm_action(&mut self) -> Result<(), XorcistError> {
let action = match std::mem::take(&mut self.modal) {
ModalState::Confirm(action) => action,
ModalState::None => return Ok(()),
};
match action {
PendingAction::Abandon { change_id, .. } => {
let result = self.runner.execute_abandon(&change_id);
self.handle_command_result_and_refresh_log(result)?;
}
PendingAction::Squash { change_id, .. } => {
let result = self.runner.execute_squash(&change_id);
self.handle_command_result_and_refresh_log(result)?;
}
PendingAction::GitPush => {
let result = self.runner.execute_git_push();
self.handle_command_result_and_refresh_log(result)?;
}
PendingAction::Undo => {
let result = self.runner.execute_undo();
self.handle_command_result_and_refresh_log(result)?;
}
}
Ok(())
}
pub fn execute_git_fetch(&mut self) -> Result<(), XorcistError> {
let result = self.runner.execute_git_fetch();
self.handle_command_result_and_refresh_log(result)?;
Ok(())
}
pub fn execute_new(&mut self) -> Result<(), XorcistError> {
let Some(change_id) = self.selected_change_id() else {
return Ok(());
};
let change_id = change_id.to_string();
let result = self.runner.execute_new(&change_id);
self.handle_command_result_and_refresh_log(result)?;
Ok(())
}
pub fn execute_new_with_message(&mut self, message: &str) -> Result<(), XorcistError> {
let Some(change_id) = self.selected_change_id() else {
return Ok(());
};
let change_id = change_id.to_string();
let result = if message.is_empty() {
self.runner.execute_new(&change_id)
} else {
self.runner.execute_new_with_message(&change_id, message)
};
self.handle_command_result_and_refresh_log(result)?;
Ok(())
}
pub fn execute_edit(&mut self) -> Result<(), XorcistError> {
let Some(change_id) = self.selected_change_id() else {
return Ok(());
};
let change_id = change_id.to_string();
let result = self.runner.execute_edit(&change_id);
self.handle_command_result_and_refresh_log(result)?;
Ok(())
}
pub fn execute_describe(&mut self, message: &str) -> Result<(), XorcistError> {
let Some(change_id) = self.selected_change_id() else {
return Ok(());
};
let change_id = change_id.to_string();
let result = self.runner.execute_describe(&change_id, message);
self.handle_command_result_and_refresh_log(result)?;
Ok(())
}
pub fn execute_bookmark_set(&mut self, name: &str) -> Result<(), XorcistError> {
if name.is_empty() {
self.last_command_result = Some(CommandResult {
success: false,
message: "Bookmark name cannot be empty".to_string(),
});
return Ok(());
}
let Some(change_id) = self.selected_change_id() else {
return Ok(());
};
let change_id = change_id.to_string();
let result = self.runner.execute_bookmark_set(name, &change_id);
self.handle_command_result_and_refresh_log(result)?;
Ok(())
}
pub fn execute_rebase(&mut self, destination: &str) -> Result<(), XorcistError> {
let destination = destination.trim();
if destination.is_empty() {
self.last_command_result = Some(CommandResult {
success: false,
message: "Destination cannot be empty".to_string(),
});
return Ok(());
}
let Some(change_id) = self.selected_change_id() else {
return Ok(());
};
let change_id = change_id.to_string();
let result = self.runner.execute_rebase(&change_id, destination);
self.handle_command_result_and_refresh_log(result)?;
Ok(())
}
pub fn open_diff_view(&mut self) -> Result<(), XorcistError> {
let Some(detail) = &self.detail_state else {
return Ok(());
};
let change_id = detail.show_output.change_id.clone();
let summary_output =
self.runner
.run_capture(&["diff", "-r", &change_id, "--color=never", "--summary"])?;
let files = parse_diff_summary(&summary_output);
self.diff_state = DiffState::new(change_id, files);
if !self.diff_state.files.is_empty() {
self.refresh_diff_text()?;
}
self.view = View::Diff;
Ok(())
}
pub fn refresh_diff_text(&mut self) -> Result<(), XorcistError> {
let Some(file) = self.diff_state.selected_file() else {
self.diff_state.diff_lines = Vec::new();
return Ok(());
};
let path = file.path.clone();
let output = fetch_diff_file(&self.runner, &self.diff_state.change_id, &path)?;
self.diff_state.diff_lines = output.lines().map(|s| s.to_string()).collect();
self.diff_state.diff_scroll = 0; self.diff_state.diff_h_scroll = 0; Ok(())
}
}