rmux-server 0.1.1

Tokio daemon and request dispatcher for the RMUX terminal multiplexer.
Documentation
use std::io;

#[path = "handler_pane/attached_input.rs"]
mod pane_attached_input;
#[path = "handler_pane/attached_key_dispatch.rs"]
mod pane_attached_key_dispatch;
#[path = "handler_pane/display_panes.rs"]
mod pane_display_panes;
#[path = "handler_pane/inspection.rs"]
mod pane_inspection;
#[path = "handler_pane/io_encoding.rs"]
mod pane_io_encoding;
#[path = "handler_pane/key_bindings.rs"]
mod pane_key_bindings;
#[path = "handler_pane/layout.rs"]
mod pane_layout;
#[path = "handler_pane/lifecycle.rs"]
mod pane_lifecycle;
#[path = "handler_pane/management.rs"]
mod pane_management;
#[path = "handler_pane/prompt_input.rs"]
mod pane_prompt_input;
#[path = "handler_pane/selection.rs"]
mod pane_selection;
#[path = "handler_pane/send_keys.rs"]
mod pane_send_keys;
#[path = "handler_pane/snapshot.rs"]
mod pane_snapshot;

pub(super) use pane_attached_input::retain_partial_attached_control_input;
pub(super) use pane_inspection::{
    attached_status_message_for_error, command_output_from_lines, display_message_context,
    display_time,
};
pub(super) use pane_io_encoding::write_bracketed_pane_payload;
use pane_io_encoding::{
    encode_key_for_target, encode_mouse_for_target, encode_tokens_for_target,
    expand_send_key_tokens, prepare_pane_input_write, write_bytes_to_target,
};
pub(super) use pane_prompt_input::decode_prompt_input_event;
pub(in crate::handler) use pane_snapshot::PaneSnapshotRevisionRegistry;

use rmux_proto::{PaneTarget, RmuxError, Target};

use super::RequestHandler;
use crate::pane_terminals::{session_not_found, HandlerState};

struct AttachedKeyDispatch {
    attach_pid: u32,
    requester_pid: u32,
    current_target: Option<Target>,
    mouse_target: Option<Target>,
    key: rmux_core::KeyCode,
    attached_live_input: bool,
}

fn io_other(error: impl std::fmt::Display) -> io::Error {
    io::Error::other(error.to_string())
}

fn active_pane_target_for_session(
    state: &HandlerState,
    session_name: &rmux_proto::SessionName,
) -> Option<PaneTarget> {
    let session = state.sessions.session(session_name)?;
    let window_index = session.active_window_index();
    let window = session.window_at(window_index)?;
    let pane = window.active_pane()?;
    Some(PaneTarget::with_window(
        session_name.clone(),
        window_index,
        pane.index(),
    ))
}

pub(super) fn resolve_input_target(
    state: &HandlerState,
    explicit: Option<&PaneTarget>,
    attached_session: Option<&rmux_proto::SessionName>,
) -> Result<PaneTarget, RmuxError> {
    if let Some(target) = explicit {
        return Ok(target.clone());
    }
    if let Some(session_name) = attached_session {
        return active_pane_target_for_session(state, session_name)
            .ok_or_else(|| session_not_found(session_name));
    }
    state
        .sessions
        .iter()
        .map(|(session_name, _)| session_name)
        .min_by(|left, right| left.as_str().cmp(right.as_str()))
        .and_then(|session_name| active_pane_target_for_session(state, session_name))
        .ok_or_else(|| RmuxError::Server("no active pane is available".to_owned()))
}