use crate::pane::PaneId;
use crate::tab::TabId;
use crate::tmux::{PrefixKey, PrefixState, TmuxPaneId, TmuxSession, TmuxSync};
#[cfg_attr(not(feature = "mux"), allow(dead_code))]
pub(crate) trait TmuxTransport {
fn drain(
&self,
) -> (
Vec<par_term_emu_core_rust::tmux_control::TmuxNotification>,
bool,
);
fn send_command(&self, command: &str) -> std::io::Result<Vec<String>>;
fn send_command_no_wait(&self, command: &str) -> std::io::Result<()> {
self.send_command(command).map(|_| ())
}
fn daemon_health_event(&self) -> Option<String> {
None
}
}
#[cfg(feature = "mux")]
pub(crate) struct PendingMuxPaste {
pub(crate) pane: TmuxPaneId,
pub(crate) chunks: std::collections::VecDeque<Vec<u8>>,
pub(crate) delay: std::time::Duration,
pub(crate) next_due: std::time::Instant,
}
pub(crate) struct TmuxState {
pub(crate) tmux_session: Option<TmuxSession>,
pub(crate) transport: Option<Box<dyn TmuxTransport>>,
pub(crate) tmux_sync: TmuxSync,
pub(crate) tmux_session_name: Option<String>,
pub(crate) tmux_gateway_tab_id: Option<TabId>,
pub(crate) tmux_prefix_key: Option<PrefixKey>,
pub(crate) tmux_prefix_state: PrefixState,
#[cfg_attr(not(feature = "mux"), allow(dead_code))]
pub(crate) mux_focused_pane: Option<TmuxPaneId>,
pub(crate) mux_session_id: Option<u64>,
#[cfg_attr(not(feature = "mux"), allow(dead_code))]
pub(crate) mux_screen_seeds: std::collections::HashMap<TmuxPaneId, Vec<u8>>,
#[cfg_attr(not(feature = "mux"), allow(dead_code))]
pub(crate) mux_pane_titles: std::collections::HashMap<TmuxPaneId, (String, bool)>,
#[cfg(feature = "mux")]
pub(crate) agent_roster: super::notifications::agent_roster::AgentRoster,
#[cfg(feature = "mux")]
pub(crate) mux_attach_pending: Option<super::notifications::mux::MuxAttachPending>,
pub(crate) mux_restore_placeholder_tab: Option<TabId>,
#[cfg(feature = "mux")]
pub(crate) pending_mux_paste: std::cell::RefCell<Option<PendingMuxPaste>>,
pub(crate) tmux_pane_owners: std::collections::HashMap<TmuxPaneId, (TabId, PaneId)>,
}
impl TmuxState {
pub(crate) fn new(tmux_prefix_key: Option<PrefixKey>) -> Self {
Self {
tmux_session: None,
transport: None,
tmux_sync: TmuxSync::new(),
tmux_session_name: None,
tmux_gateway_tab_id: None,
tmux_prefix_key,
tmux_prefix_state: PrefixState::new(),
mux_focused_pane: None,
mux_session_id: None,
mux_screen_seeds: std::collections::HashMap::new(),
mux_pane_titles: std::collections::HashMap::new(),
#[cfg(feature = "mux")]
agent_roster: super::notifications::agent_roster::AgentRoster::new(),
#[cfg(feature = "mux")]
mux_attach_pending: None,
mux_restore_placeholder_tab: None,
#[cfg(feature = "mux")]
pending_mux_paste: std::cell::RefCell::new(None),
tmux_pane_owners: std::collections::HashMap::new(),
}
}
pub(crate) fn persisted_session_names(&self) -> (Option<String>, Option<String>) {
match (&self.tmux_session_name, self.transport.is_some()) {
(Some(name), true) => {
if !self.tmux_sync.has_windows() {
return (None, None);
}
(None, Some(name.clone()))
}
(name, false) => (name.clone(), None),
(None, true) => (None, None),
}
}
pub(crate) fn set_tab_pane_mappings(
&mut self,
tab_id: TabId,
mappings: &std::collections::HashMap<TmuxPaneId, PaneId>,
) {
self.tmux_pane_owners
.retain(|_, (owner, _)| *owner != tab_id);
self.tmux_pane_owners.extend(
mappings
.iter()
.map(|(&tmux, &native)| (tmux, (tab_id, native))),
);
}
pub(crate) fn tmux_pane_owner(&self, tmux_id: TmuxPaneId) -> Option<(TabId, PaneId)> {
self.tmux_pane_owners.get(&tmux_id).copied()
}
pub(crate) fn tmux_pane_in_tab(&self, tab_id: TabId, native_id: PaneId) -> Option<TmuxPaneId> {
self.tmux_pane_owners
.iter()
.find(|(_, (owner, pane))| *owner == tab_id && *pane == native_id)
.map(|(&tmux, _)| tmux)
}
pub(crate) fn tab_tmux_pane_ids(&self, tab_id: TabId) -> std::collections::HashSet<TmuxPaneId> {
self.tmux_pane_owners
.iter()
.filter(|(_, (owner, _))| *owner == tab_id)
.map(|(&tmux, _)| tmux)
.collect()
}
pub(crate) fn tab_mappings(
&self,
tab_id: TabId,
) -> std::collections::HashMap<TmuxPaneId, PaneId> {
self.tmux_pane_owners
.iter()
.filter(|(_, (owner, _))| *owner == tab_id)
.map(|(&tmux, &(_, native))| (tmux, native))
.collect()
}
pub(crate) fn remove_tmux_pane_mapping(&mut self, tmux_id: TmuxPaneId) {
self.tmux_pane_owners.remove(&tmux_id);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_gateway_session_name_persists_as_tmux() {
let mut state = TmuxState::new(None);
assert_eq!(state.persisted_session_names(), (None, None));
state.tmux_session_name = Some("work".to_string());
assert_eq!(
state.persisted_session_names(),
(Some("work".to_string()), None)
);
}
}