use crossterm::event::{KeyCode, KeyEvent};
use crate::tui::action::{EditTarget, FetchReq};
use crate::tui::panes::PaneOutcome;
#[derive(Default)]
pub struct DiffState {
pub b: String,
}
impl DiffState {
pub fn handle_key(&mut self, key: KeyEvent, domain: Option<&str>) -> Option<PaneOutcome> {
match key.code {
KeyCode::Char('e') | KeyCode::Char('i') => {
Some(PaneOutcome::EditField(EditTarget::DiffB))
}
KeyCode::Enter if !self.b.is_empty() => domain.map(|a| {
PaneOutcome::Fetch(FetchReq::Diff {
a: a.to_string(),
b: self.b.clone(),
})
}),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crossterm::event::KeyModifiers;
fn press(code: KeyCode) -> KeyEvent {
KeyEvent::new(code, KeyModifiers::NONE)
}
#[test]
fn e_returns_edit_field_diffb() {
let mut state = DiffState::default();
let outcome = state.handle_key(press(KeyCode::Char('e')), None);
assert!(
matches!(outcome, Some(PaneOutcome::EditField(EditTarget::DiffB))),
"expected EditField(DiffB), got {outcome:?}",
);
}
#[test]
fn i_returns_edit_field_diffb() {
let mut state = DiffState::default();
let outcome = state.handle_key(press(KeyCode::Char('i')), None);
assert!(
matches!(outcome, Some(PaneOutcome::EditField(EditTarget::DiffB))),
"expected EditField(DiffB), got {outcome:?}",
);
}
#[test]
fn esc_returns_none() {
let mut state = DiffState::default();
assert!(
state.handle_key(press(KeyCode::Esc), None).is_none(),
"Esc must not be swallowed",
);
}
#[test]
fn unowned_keys_return_none() {
let mut state = DiffState::default();
assert!(state.handle_key(press(KeyCode::Tab), None).is_none());
assert!(state.handle_key(press(KeyCode::Char('j')), None).is_none());
assert!(state.handle_key(press(KeyCode::Char('d')), None).is_none());
assert!(state.handle_key(press(KeyCode::Enter), None).is_none());
}
#[test]
fn enter_with_b_set_and_domain_recompares() {
let mut state = DiffState { b: "b.com".into() };
let out = state.handle_key(press(KeyCode::Enter), Some("a.com"));
assert!(
matches!(out, Some(PaneOutcome::Fetch(FetchReq::Diff { ref a, ref b })) if a == "a.com" && b == "b.com"),
"Enter with B set + domain should re-run the diff, got {out:?}",
);
}
#[test]
fn enter_with_empty_b_falls_through() {
let mut state = DiffState::default();
assert!(
state
.handle_key(press(KeyCode::Enter), Some("a.com"))
.is_none(),
"Enter with no B set must fall through (not swallowed)",
);
}
}