use super::super::*;
use super::support::*;
#[test]
fn autocomplete_tab_accepts_when_visible() {
let mut state = MissionControlState {
prompt_editor: crate::tui::state::PromptEditor::new("/n", 2),
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
..Default::default()
};
state.recompute_autocomplete(&autocomplete_candidates());
assert!(state.autocomplete_visible());
assert!(matches!(
handle_key_with_candidates(key(KeyCode::Tab), &mut state),
InputAction::None
));
assert_eq!(state.prompt_plain_text(), "/new");
assert!(state.is_prompt_focused());
}
#[test]
fn autocomplete_enter_accepts_when_visible_without_submitting() {
let mut state = MissionControlState {
prompt_editor: crate::tui::state::PromptEditor::new("/n", 2),
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
..Default::default()
};
state.recompute_autocomplete(&autocomplete_candidates());
assert!(state.autocomplete_visible());
assert!(matches!(
handle_key_with_candidates(key(KeyCode::Enter), &mut state),
InputAction::None
));
assert_eq!(state.prompt_plain_text(), "/new");
assert!(state.is_prompt_focused());
}
#[test]
fn autocomplete_arrows_navigate_when_visible_and_move_cursor_when_hidden() {
let mut state = MissionControlState {
prompt_editor: crate::tui::state::PromptEditor::new("/q", 2),
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
..Default::default()
};
state.recompute_autocomplete(&autocomplete_candidates());
assert!(matches!(
handle_key_with_candidates(key(KeyCode::Down), &mut state),
InputAction::None
));
assert_eq!(state.autocomplete.as_ref().unwrap().selected, 0);
assert_eq!(state.prompt_cursor(), 2);
assert!(matches!(
handle_key_with_candidates(key(KeyCode::Up), &mut state),
InputAction::None
));
assert_eq!(state.autocomplete.as_ref().unwrap().selected, 0);
state.hide_autocomplete();
state.set_prompt_text("a\nb", "a\nb".len());
assert!(matches!(
handle_key(key(KeyCode::Up), &mut state),
InputAction::None
));
assert!(state.prompt_cursor() < state.prompt_plain_text().len());
}
#[test]
fn autocomplete_esc_dismisses_before_focus_and_help_behavior() {
let mut state = MissionControlState {
prompt_editor: crate::tui::state::PromptEditor::new("/n", 2),
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
show_help: true,
..Default::default()
};
state.recompute_autocomplete(&autocomplete_candidates());
assert!(matches!(
handle_key_with_candidates(key(KeyCode::Esc), &mut state),
InputAction::None
));
assert!(!state.autocomplete_visible());
assert!(state.show_help);
assert!(state.is_prompt_focused());
state.focus_activity_tree();
assert!(matches!(
handle_key(key(KeyCode::Esc), &mut state),
InputAction::None
));
assert!(state.is_prompt_focused());
assert!(!state.show_help);
}
#[test]
fn autocomplete_recomputes_and_hides_after_prompt_edits() {
let mut state = MissionControlState {
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
..Default::default()
};
assert!(matches!(
handle_key_with_candidates(key(KeyCode::Char('/')), &mut state),
InputAction::None
));
assert!(state.autocomplete_visible());
assert!(matches!(
handle_key_with_candidates(key(KeyCode::Char('n')), &mut state),
InputAction::None
));
assert_eq!(
state.autocomplete.as_ref().unwrap().candidates[0].name,
"new"
);
assert!(matches!(
handle_key_with_candidates(key(KeyCode::Backspace), &mut state),
InputAction::None
));
assert!(state.autocomplete_visible());
assert!(matches!(
handle_key_with_candidates(key(KeyCode::Backspace), &mut state),
InputAction::None
));
assert!(state.autocomplete.is_none());
}
#[test]
fn file_autocomplete_tab_accepts_active_at_token_anywhere_without_toggling_focus() {
let candidates = vec![AutocompleteCandidate::file_tag("src/tui/input/mod.rs")];
let mut state = MissionControlState {
prompt_editor: crate::tui::state::PromptEditor::new("check @tuiinp", "check @tuiinp".len()),
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
..Default::default()
};
state.recompute_autocomplete(&candidates);
assert!(state.autocomplete_visible());
assert!(matches!(
handle_key_with_viewport(key(KeyCode::Tab), &mut state, None, &candidates),
InputAction::None
));
assert_eq!(state.prompt_plain_text(), "check @src/tui/input/mod.rs ");
assert!(state.is_prompt_focused());
}
#[test]
fn skill_autocomplete_accepts_active_dollar_token_anywhere_without_submitting() {
let candidates = vec![AutocompleteCandidate::skill_tag_with_argument_hint(
"rust-dev",
Some("path to review"),
)];
let mut state = MissionControlState {
prompt_editor: crate::tui::state::PromptEditor::new(
"please use $rust",
"please use $rust".len(),
),
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
..Default::default()
};
state.recompute_autocomplete(&candidates);
assert!(state.autocomplete_visible());
assert!(matches!(
handle_key_with_viewport(key(KeyCode::Enter), &mut state, None, &candidates),
InputAction::None
));
assert_eq!(state.prompt_plain_text(), "please use $rust-dev ");
assert!(state.is_prompt_focused());
}
#[test]
fn autocomplete_uses_visible_offsets_around_collapsed_paste_atoms() {
let payload = "one\ntwo\n$rust";
let candidates = vec![AutocompleteCandidate::skill_tag("rust-dev")];
let mut state = MissionControlState {
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
..Default::default()
};
state.prompt_editor.insert_paste(payload, 1, 80);
state.recompute_autocomplete(&candidates);
assert!(!state.autocomplete_visible());
state.prompt_editor.insert_paste(" $ru", 1, 80);
state.recompute_autocomplete(&candidates);
let autocomplete = state.autocomplete.as_ref().expect("skill suggestions");
let label = "[Pasted #1 ยท 3 lines]";
assert_eq!(autocomplete.token_start, label.len() + 1);
assert_eq!(
autocomplete.token_end,
state.prompt_editor.visible_text().len()
);
assert!(matches!(
handle_key_with_viewport(key(KeyCode::Enter), &mut state, None, &candidates),
InputAction::None
));
assert_eq!(
state.prompt_editor.visible_text(),
format!("{label} $rust-dev ")
);
assert_eq!(state.prompt_plain_text(), "one\ntwo\n$rust $rust-dev ");
}
#[test]
fn submitted_skill_tags_remain_literal_prompt_text() {
let mut state = MissionControlState {
prompt_editor: crate::tui::state::PromptEditor::new(
"please use $rust-dev",
"please use $rust-dev".len(),
),
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
..Default::default()
};
match handle_key_with_viewport(key(KeyCode::Enter), &mut state, None, &[]) {
InputAction::Submit(prompt) => assert_eq!(prompt, "please use $rust-dev"),
other => panic!("expected submit, got {other:?}"),
}
assert!(state.autocomplete.is_none());
}