rmux-server 0.10.0

Tokio daemon and request dispatcher for the RMUX terminal multiplexer.
Documentation
use super::*;

fn ctrl_semicolon_keystroke() -> rmux_proto::AttachedKeystroke {
    rmux_proto::AttachedKeystroke::new(b";".to_vec()).with_windows_console_key(
        rmux_proto::AttachedWindowsConsoleKey::new(0xba, 0x27, b';' as u16, 0x0008, 1),
    )
}

async fn dispatch_ctrl_semicolon(
    handler: &RequestHandler,
    requester_pid: u32,
    pending_input: &mut Vec<u8>,
) -> bool {
    handler
        .handle_attached_keystroke_input(requester_pid, pending_input, &ctrl_semicolon_keystroke())
        .await
        .expect("Ctrl+; attached input succeeds")
}

#[tokio::test]
async fn repeated_ctrl_semicolon_dispatches_each_root_binding() {
    let handler = RequestHandler::new();
    let alpha = session_name("alpha");
    let requester_pid = std::process::id();

    create_send_keys_test_session(&handler, &alpha).await;
    let (control_tx, _control_rx) = mpsc::unbounded_channel();
    let _attach_id = handler
        .register_attach(requester_pid, alpha.clone(), control_tx)
        .await;
    let rebound = handler
        .handle(Request::BindKey(Box::new(BindKeyRequest {
            table_name: "root".to_owned(),
            key: "C-;".to_owned(),
            note: Some("repeated-windows-ctrl-semicolon-root".to_owned()),
            repeat: false,
            command: Some(vec![
                "send-keys".to_owned(),
                "-l".to_owned(),
                "R".to_owned(),
            ]),
        })))
        .await;
    assert!(matches!(rebound, Response::BindKey(_)));

    let capture =
        RawPaneInputProbe::start(&handler, &alpha, "repeat-windows-c-semicolon-root", 3).await;
    let mut pending_input = Vec::new();
    for _ in 0..3 {
        assert!(!dispatch_ctrl_semicolon(&handler, requester_pid, &mut pending_input).await);
        assert!(pending_input.is_empty());
    }

    capture.finish(&handler, &alpha).await;
    capture.assert_contents(&handler, b"RRR").await;
}

#[tokio::test]
async fn repeated_ctrl_semicolon_preserves_prefix_table_semantics() {
    let handler = RequestHandler::new();
    let alpha = session_name("alpha");
    let requester_pid = std::process::id();

    create_send_keys_test_session(&handler, &alpha).await;
    let set_prefix = handler
        .handle(Request::SetOption(SetOptionRequest {
            scope: ScopeSelector::Global,
            option: OptionName::Prefix,
            value: "C-;".to_owned(),
            mode: SetOptionMode::Replace,
        }))
        .await;
    assert!(matches!(set_prefix, Response::SetOption(_)));
    let rebound = handler
        .handle(Request::BindKey(Box::new(BindKeyRequest {
            table_name: "prefix".to_owned(),
            key: "C-;".to_owned(),
            note: Some("repeated-windows-ctrl-semicolon-prefix".to_owned()),
            repeat: false,
            command: Some(vec![
                "send-keys".to_owned(),
                "-l".to_owned(),
                "P".to_owned(),
            ]),
        })))
        .await;
    assert!(matches!(rebound, Response::BindKey(_)));
    let (control_tx, _control_rx) = mpsc::unbounded_channel();
    let _attach_id = handler
        .register_attach(requester_pid, alpha.clone(), control_tx)
        .await;

    let capture =
        RawPaneInputProbe::start(&handler, &alpha, "repeat-windows-c-semicolon-prefix", 1).await;
    let mut pending_input = Vec::new();
    assert!(!dispatch_ctrl_semicolon(&handler, requester_pid, &mut pending_input).await);
    assert!(!dispatch_ctrl_semicolon(&handler, requester_pid, &mut pending_input).await);
    assert!(pending_input.is_empty());

    capture.finish(&handler, &alpha).await;
    capture.assert_contents(&handler, b"P").await;
}

#[tokio::test]
async fn repeated_unbound_ctrl_semicolon_forwards_each_original_byte() {
    let handler = RequestHandler::new();
    let alpha = session_name("alpha");
    let requester_pid = std::process::id();

    create_send_keys_test_session(&handler, &alpha).await;
    let (control_tx, _control_rx) = mpsc::unbounded_channel();
    let _attach_id = handler
        .register_attach(requester_pid, alpha.clone(), control_tx)
        .await;
    let capture =
        RawPaneInputProbe::start(&handler, &alpha, "repeat-windows-c-semicolon-forward", 3).await;

    let mut pending_input = Vec::new();
    for _ in 0..3 {
        assert!(dispatch_ctrl_semicolon(&handler, requester_pid, &mut pending_input).await);
        assert!(pending_input.is_empty());
    }

    capture.finish(&handler, &alpha).await;
    capture.assert_contents(&handler, b";;;").await;
}