rmux-server 0.9.0

Tokio daemon and request dispatcher for the RMUX terminal multiplexer.
Documentation
use rmux_core::WindowId;
use rmux_proto::{SessionId, SessionName, WindowTarget};

use super::{HandlerState, WindowLinkSlot};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct WindowLinkOccurrenceId(u64);

impl WindowLinkOccurrenceId {
    pub(crate) const fn as_u64(self) -> u64 {
        self.0
    }

    #[cfg(test)]
    pub(crate) const fn new_for_test(value: u64) -> Self {
        Self(value)
    }
}

impl HandlerState {
    pub(crate) fn ensure_live_window_link_occurrences(&mut self) {
        let slots = self
            .sessions
            .iter()
            .flat_map(|(session_name, session)| {
                session
                    .windows()
                    .keys()
                    .copied()
                    .map(move |window_index| (session_name.clone(), window_index))
            })
            .collect::<Vec<_>>();
        for (session_name, window_index) in slots {
            let slot = self.canonical_window_link_slot_by_index(&session_name, window_index);
            let _ = self.ensure_window_link_occurrence(&slot);
        }
    }

    pub(crate) fn window_link_occurrence_id(
        &self,
        session_name: &SessionName,
        window_index: u32,
    ) -> Option<WindowLinkOccurrenceId> {
        let slot = self.canonical_window_link_slot_by_index(session_name, window_index);
        self.window_link_occurrences.get(&slot).copied()
    }

    pub(crate) fn window_link_occurrence_target(
        &self,
        occurrence_id: WindowLinkOccurrenceId,
        preferred_session_id: SessionId,
        window_id: WindowId,
    ) -> Option<WindowTarget> {
        self.sessions
            .iter()
            .flat_map(|(session_name, session)| {
                session
                    .windows()
                    .iter()
                    .filter(move |(window_index, window)| {
                        window.id() == window_id
                            && self.window_link_occurrence_id(session_name, **window_index)
                                == Some(occurrence_id)
                    })
                    .map(move |(window_index, _)| {
                        (
                            session.id(),
                            WindowTarget::with_window(session_name.clone(), *window_index),
                        )
                    })
            })
            .min_by_key(|(session_id, target)| {
                (
                    *session_id != preferred_session_id,
                    std::cmp::Reverse(*session_id),
                    target.window_index(),
                )
            })
            .map(|(_, target)| target)
    }

    pub(in crate::pane_terminals) fn set_window_link_occurrence_id(
        &mut self,
        session_name: &SessionName,
        window_index: u32,
        occurrence_id: WindowLinkOccurrenceId,
    ) {
        let slot = self.canonical_window_link_slot_by_index(session_name, window_index);
        let _ = self.window_link_occurrences.insert(slot, occurrence_id);
    }

    fn allocate_window_link_occurrence_id(&mut self) -> WindowLinkOccurrenceId {
        loop {
            let occurrence_id = WindowLinkOccurrenceId(self.next_window_link_occurrence_id);
            self.next_window_link_occurrence_id =
                self.next_window_link_occurrence_id.wrapping_add(1);
            if !self
                .window_link_occurrences
                .values()
                .any(|candidate| *candidate == occurrence_id)
            {
                return occurrence_id;
            }
        }
    }

    pub(super) fn ensure_window_link_occurrence(
        &mut self,
        slot: &WindowLinkSlot,
    ) -> WindowLinkOccurrenceId {
        if let Some(occurrence_id) = self.window_link_occurrences.get(slot).copied() {
            return occurrence_id;
        }
        let occurrence_id = self.allocate_window_link_occurrence_id();
        let _ = self
            .window_link_occurrences
            .insert(slot.clone(), occurrence_id);
        occurrence_id
    }

    pub(super) fn renew_window_link_occurrence(&mut self, slot: WindowLinkSlot) {
        let occurrence_id = self.allocate_window_link_occurrence_id();
        let _ = self.window_link_occurrences.insert(slot, occurrence_id);
    }
}