rmux-server 0.1.1

Tokio daemon and request dispatcher for the RMUX terminal multiplexer.
Documentation
use std::collections::{BTreeMap, BTreeSet};

use rmux_core::KeyCode;
use rmux_proto::types::OptionScopeSelector;
use rmux_proto::{PaneTarget, SessionName, Target, WindowTarget};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum ModeTreeKind {
    Tree,
    Buffer,
    Client,
    Customize,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum PreviewMode {
    Off,
    Big,
    Normal,
}

impl PreviewMode {
    pub(super) fn cycle(self) -> Self {
        match self {
            Self::Off => Self::Big,
            Self::Big => Self::Normal,
            Self::Normal => Self::Off,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum TreeDepth {
    Session,
    Window,
    Pane,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum SortOrder {
    Index,
    Name,
    Activity,
    Creation,
    Size,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum SearchDirection {
    Forward,
    Backward,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub(super) struct SearchState {
    pub(super) value: String,
    pub(super) direction: SearchDirection,
}

#[derive(Debug, Clone)]
pub(in crate::handler) struct ModeTreeClientState {
    pub(super) kind: ModeTreeKind,
    pub(super) session_name: SessionName,
    pub(super) host_pane: Option<PaneTarget>,
    pub(super) preview_mode: PreviewMode,
    pub(super) row_format: Option<String>,
    pub(super) filter_format: Option<String>,
    pub(super) filter_text: Option<String>,
    pub(super) key_format: String,
    pub(super) template: Option<String>,
    pub(super) search: Option<SearchState>,
    pub(super) tagged: BTreeSet<String>,
    pub(super) expanded: BTreeSet<String>,
    pub(super) selected_id: Option<String>,
    pub(super) scroll: usize,
    pub(super) preview_scroll: usize,
    pub(super) sort_order: Option<SortOrder>,
    pub(super) order_seq: Vec<SortOrder>,
    pub(super) reversed: bool,
    pub(super) tree_depth: TreeDepth,
    pub(super) show_all_group_members: bool,
    pub(super) auto_accept: bool,
    pub(in crate::handler) zoom_restore: Option<PaneTarget>,
    pub(super) last_list_rows: usize,
}

#[derive(Debug, Clone)]
pub(in crate::handler) struct ParsedModeTreeCommand {
    pub(super) kind: ModeTreeKind,
    pub(super) preview_mode: PreviewMode,
    pub(super) row_format: Option<String>,
    pub(super) filter_format: Option<String>,
    pub(super) key_format: Option<String>,
    pub(super) template: Option<String>,
    pub(super) sort_order: Option<SortOrder>,
    pub(super) reversed: bool,
    pub(super) tree_depth: TreeDepth,
    pub(super) show_all_group_members: bool,
    pub(super) auto_accept: bool,
    pub(super) zoom: bool,
}

#[derive(Debug, Clone)]
pub(super) struct ModeTreeBuild {
    pub(super) items: BTreeMap<String, ModeTreeItem>,
    pub(super) roots: Vec<String>,
    pub(super) order: Vec<String>,
    pub(super) visible: Vec<String>,
    pub(super) no_matches: bool,
}

#[derive(Debug, Clone)]
pub(super) struct ModeTreeItem {
    pub(super) id: String,
    pub(super) parent: Option<String>,
    pub(super) children: Vec<String>,
    pub(super) depth: usize,
    pub(super) line: String,
    pub(super) search_text: String,
    pub(super) preview: Vec<String>,
    pub(super) no_tag: bool,
    pub(super) action: ModeTreeAction,
}

#[derive(Debug, Clone)]
pub(super) enum ModeTreeAction {
    None,
    TreeTarget {
        session_name: SessionName,
        window_index: Option<u32>,
        pane_index: Option<u32>,
        pane_id: Option<u32>,
    },
    Buffer {
        name: String,
    },
    Client {
        pid: u32,
        control: bool,
    },
    CustomizeOption {
        scope: OptionScopeSelector,
        name: String,
    },
    CustomizeKey {
        table_name: String,
        key: KeyCode,
        key_string: String,
    },
}

impl ModeTreeKind {
    pub(super) fn command_name(self) -> &'static str {
        match self {
            Self::Tree => "choose-tree",
            Self::Buffer => "choose-buffer",
            Self::Client => "choose-client",
            Self::Customize => "customize-mode",
        }
    }

    pub(super) fn pane_mode_name(self) -> &'static str {
        match self {
            Self::Tree => "tree-mode",
            Self::Buffer => "buffer-mode",
            Self::Client => "client-mode",
            Self::Customize => "customize-mode",
        }
    }
}

impl ModeTreeAction {
    pub(super) fn target_string(&self) -> Option<String> {
        match self {
            Self::None => None,
            Self::TreeTarget {
                session_name,
                window_index,
                pane_index,
                pane_id,
            } => Some(match (window_index, pane_index) {
                (None, _) => format!("={session_name}:"),
                (Some(window_index), None) => format!("={session_name}:{window_index}."),
                (Some(window_index), Some(_)) => {
                    let pane_id = pane_id.unwrap_or_default();
                    format!("={session_name}:{window_index}.%{pane_id}")
                }
            }),
            Self::Buffer { name } => Some(name.clone()),
            Self::Client { pid, .. } => Some(pid.to_string()),
            Self::CustomizeOption { name, .. } => Some(name.clone()),
            Self::CustomizeKey {
                table_name,
                key_string,
                ..
            } => Some(format!("{table_name}:{key_string}")),
        }
    }

    pub(super) fn current_target(&self) -> Option<Target> {
        match self {
            Self::TreeTarget {
                session_name,
                window_index,
                pane_index,
                ..
            } => match (window_index, pane_index) {
                (None, _) => Some(Target::Session(session_name.clone())),
                (Some(window_index), None) => Some(Target::Window(WindowTarget::with_window(
                    session_name.clone(),
                    *window_index,
                ))),
                (Some(window_index), Some(pane_index)) => Some(Target::Pane(
                    PaneTarget::with_window(session_name.clone(), *window_index, *pane_index),
                )),
            },
            _ => None,
        }
    }
}

#[derive(Debug, Clone)]
pub(super) struct ClientSnapshot {
    pub(super) pid: u32,
    pub(super) session_name: Option<SessionName>,
    pub(super) label: String,
    pub(super) order: u64,
    pub(super) activity: i64,
    pub(super) width: u16,
    pub(super) height: u16,
}

#[derive(Debug, Clone)]
pub(super) enum ModeTreePromptCallback {
    Filter,
    Search(SearchDirection),
    Command,
    CustomizeSetOption {
        scope: OptionScopeSelector,
        name: String,
    },
    CustomizeSetKey {
        table_name: String,
        key: KeyCode,
    },
}

#[derive(Debug, Clone)]
pub(super) enum ModeTreeDeferredAction {
    DeleteBuffers,
    DetachClients,
    KillCurrentTreeSelection,
    KillTaggedTreeSelections,
}