magi-code 0.77.1

Repository-aware CLI coding agent for terminal work
Documentation
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());
}