yuru-tui 0.2.3

Terminal user interface for Yuru
Documentation
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers};

use crate::api::{BindingAction, KeyBinding};
use crate::keys::{classify_key, KeyDecision};
use crate::run::is_actionable_key_event;
use crate::state::TuiAction;

#[test]
fn expected_key_accepts_with_key_name() {
    let decision = classify_key(
        KeyEvent::new(KeyCode::Char('y'), KeyModifiers::CONTROL),
        10,
        &["ctrl-y".to_string()],
        &[],
    );

    assert_eq!(decision, KeyDecision::Accept(Some("ctrl-y".to_string())));
}

#[test]
fn enter_accepts_without_expected_key_name() {
    let decision = classify_key(
        KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE),
        10,
        &[],
        &[],
    );

    assert_eq!(decision, KeyDecision::Accept(None));
}

#[test]
fn key_release_events_are_ignored() {
    assert!(is_actionable_key_event(&KeyEvent::new(
        KeyCode::Enter,
        KeyModifiers::NONE,
    )));
    assert!(!is_actionable_key_event(&KeyEvent::new_with_kind(
        KeyCode::Enter,
        KeyModifiers::NONE,
        KeyEventKind::Release,
    )));
}

#[test]
fn bind_key_can_abort() {
    let decision = classify_key(
        KeyEvent::new(KeyCode::Char('x'), KeyModifiers::CONTROL),
        10,
        &[],
        &[KeyBinding {
            key: "ctrl-x".to_string(),
            action: BindingAction::Abort,
        }],
    );

    assert_eq!(decision, KeyDecision::Abort);
}

#[test]
fn shifted_navigation_keys_scroll_preview() {
    let decision = classify_key(
        KeyEvent::new(KeyCode::Down, KeyModifiers::SHIFT),
        10,
        &[],
        &[],
    );
    assert_eq!(decision, KeyDecision::Action(TuiAction::PreviewDown));

    let decision = classify_key(
        KeyEvent::new(KeyCode::PageUp, KeyModifiers::SHIFT),
        10,
        &[],
        &[],
    );
    assert_eq!(decision, KeyDecision::Action(TuiAction::PreviewPageUp(10)));
}

#[test]
fn bind_key_can_scroll_preview() {
    let decision = classify_key(
        KeyEvent::new(KeyCode::Char('j'), KeyModifiers::CONTROL),
        10,
        &[],
        &[KeyBinding {
            key: "ctrl-j".to_string(),
            action: BindingAction::PreviewDown,
        }],
    );

    assert_eq!(decision, KeyDecision::Action(TuiAction::PreviewDown));
}

#[test]
fn bind_key_can_scroll_preview_to_edges() {
    let decision = classify_key(
        KeyEvent::new(KeyCode::End, KeyModifiers::NONE),
        10,
        &[],
        &[KeyBinding {
            key: "end".to_string(),
            action: BindingAction::PreviewBottom,
        }],
    );

    assert_eq!(decision, KeyDecision::Action(TuiAction::PreviewBottom));
}

#[test]
fn bind_key_can_drive_basic_navigation_actions() {
    let decision = classify_key(
        KeyEvent::new(KeyCode::Char('j'), KeyModifiers::CONTROL),
        10,
        &[],
        &[KeyBinding {
            key: "ctrl-j".to_string(),
            action: BindingAction::MoveSelectionDown,
        }],
    );
    assert_eq!(decision, KeyDecision::Action(TuiAction::MoveSelectionDown));

    let decision = classify_key(
        KeyEvent::new(KeyCode::Char('a'), KeyModifiers::CONTROL),
        10,
        &[],
        &[KeyBinding {
            key: "ctrl-a".to_string(),
            action: BindingAction::MoveCursorStart,
        }],
    );
    assert_eq!(decision, KeyDecision::Action(TuiAction::MoveCursorStart));
}

#[test]
fn readline_keys_map_to_editing_actions() {
    let cases = [
        (
            KeyEvent::new(KeyCode::Char('b'), KeyModifiers::CONTROL),
            TuiAction::MoveCursorLeft,
        ),
        (
            KeyEvent::new(KeyCode::Char('f'), KeyModifiers::CONTROL),
            TuiAction::MoveCursorRight,
        ),
        (
            KeyEvent::new(KeyCode::Char('k'), KeyModifiers::CONTROL),
            TuiAction::DeleteToEnd,
        ),
        (
            KeyEvent::new(KeyCode::Char('w'), KeyModifiers::CONTROL),
            TuiAction::DeleteWord,
        ),
        (
            KeyEvent::new(KeyCode::Left, KeyModifiers::ALT),
            TuiAction::MoveCursorWordLeft,
        ),
        (
            KeyEvent::new(KeyCode::Right, KeyModifiers::ALT),
            TuiAction::MoveCursorWordRight,
        ),
        (
            KeyEvent::new(KeyCode::Char('h'), KeyModifiers::CONTROL),
            TuiAction::Backspace,
        ),
        (
            KeyEvent::new(KeyCode::Char('d'), KeyModifiers::CONTROL),
            TuiAction::DeleteOrExit,
        ),
    ];

    for (key, action) in cases {
        assert_eq!(classify_key(key, 10, &[], &[]), KeyDecision::Action(action));
    }
}