use crate::app::{AppState, state::DiffMode};
use super::ComponentManager;
use tracing::{debug, warn};
pub fn sync_status_selection(mgr: &ComponentManager, state: &mut AppState) {
let max_idx = state.status_entries.len().saturating_sub(1);
let selected = state.status_selected.min(max_idx);
state.status_selected = selected;
let Some(entry) = state.status_entries.get(selected) else {
state.last_diff.clear();
state.last_diff_path.clear();
state.last_status_error = None;
debug!("No status entry selected, cleared diff");
return;
};
state.status_selected_path = entry.path.clone();
let current_diff_mode_is_staged = matches!(state.diff_mode, DiffMode::Staged);
let should_show_staged_diff = determine_diff_mode(entry, current_diff_mode_is_staged);
let mut diff_result = mgr.git_service.diff(
&state.repo_path,
&state.status_selected_path,
should_show_staged_diff,
state.diff_context,
);
let final_diff_mode = if should_fallback_to_staged_diff(&diff_result, should_show_staged_diff, entry) {
state.diff_mode = DiffMode::Staged;
debug!(path = %state.status_selected_path, "Working diff empty, falling back to staged diff");
diff_result = mgr.git_service.diff(
&state.repo_path,
&state.status_selected_path,
true, state.diff_context,
);
true
} else {
should_show_staged_diff
};
update_diff_state(state, diff_result, final_diff_mode);
}
fn determine_diff_mode(entry: &crate::git::parsers::status::StatusEntry, current_mode_is_staged: bool) -> bool {
if entry.unstaged {
false
} else if entry.staged {
true
} else {
current_mode_is_staged
}
}
fn should_fallback_to_staged_diff(
diff_result: &Result<String, crate::errors::GitError>,
currently_showing_staged: bool,
entry: &crate::git::parsers::status::StatusEntry,
) -> bool {
!currently_showing_staged
&& diff_result.as_ref().map(|d| d.is_empty()).unwrap_or(false)
&& entry.staged
}
fn update_diff_state(
state: &mut AppState,
diff_result: Result<String, crate::errors::GitError>,
is_staged: bool,
) {
match diff_result {
Ok(diff) => {
state.last_diff = diff;
state.last_diff_path = state.status_selected_path.clone();
state.detail_scroll = 0;
state.load_full_diff = false;
state.last_diff_truncated = false;
state.last_diff_total = state.last_diff.lines().count();
state.last_status_error = None;
debug!(
path = %state.status_selected_path,
staged = is_staged,
lines = state.last_diff_total,
"Diff refreshed successfully"
);
}
Err(e) => {
state.last_diff.clear();
let error_msg = format!(
"Failed to load {} diff for '{}': {}. \
Check file permissions and Git repository state.",
if is_staged { "staged" } else { "working" },
state.status_selected_path,
e
);
state.last_status_error = Some(error_msg.clone());
warn!(
error = %e,
path = %state.status_selected_path,
staged = is_staged,
operation = "diff_refresh",
"Diff refresh failed - file may be deleted or repository corrupted"
);
}
}
}