1use std::collections::HashMap;
2
3use crate::contexts::Context;
4use crate::layout::Node;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum MultiplexerKind {
8 Tmux,
9 Zellij,
10}
11
12impl MultiplexerKind {
13 const ALL: &[(&str, MultiplexerKind)] = &[
14 ("tmux", MultiplexerKind::Tmux),
15 ("zellij", MultiplexerKind::Zellij),
16 ];
17
18 pub fn parse(raw: &str) -> Option<MultiplexerKind> {
19 Self::ALL
20 .iter()
21 .find(|(name, _)| *name == raw)
22 .map(|(_, kind)| *kind)
23 }
24
25 pub fn names() -> String {
26 Self::ALL
27 .iter()
28 .map(|(name, _)| *name)
29 .collect::<Vec<_>>()
30 .join(", ")
31 }
32}
33
34#[derive(Debug, thiserror::Error)]
35#[error("{0}")]
36pub struct MultiplexerError(pub String);
37
38pub(crate) fn env_var(key: &str) -> Option<String> {
41 #[cfg(test)]
42 if let Some(value) = crate::testutil::get_env(key) {
43 return Some(value);
44 }
45 std::env::var(key).ok()
46}
47
48pub(crate) fn env_truthy(key: &str) -> bool {
50 env_var(key).is_some_and(|value| !value.is_empty())
51}
52
53pub trait Multiplexer: Send + Sync {
54 fn can_open_in_place(&self) -> bool;
56
57 fn exists(&self, ctx: &Context) -> bool;
59
60 fn is_current(&self, ctx: &Context) -> bool;
62
63 fn create(
67 &self,
68 ctx: &Context,
69 values: Option<&HashMap<String, String>>,
70 ) -> Result<(), MultiplexerError>;
71
72 fn open(
79 &self,
80 ctx: &Context,
81 values: Option<&HashMap<String, String>>,
82 ) -> Result<(), MultiplexerError>;
83
84 fn kill(&self, ctx: &Context) -> Result<(), MultiplexerError>;
86}
87
88pub fn get_multiplexer(kind: MultiplexerKind, layout: Node) -> std::sync::Arc<dyn Multiplexer> {
89 match kind {
90 MultiplexerKind::Tmux => {
91 std::sync::Arc::new(crate::multiplexers::tmux::TmuxMultiplexer::new(layout))
92 }
93 MultiplexerKind::Zellij => {
94 std::sync::Arc::new(crate::multiplexers::zellij::ZellijMultiplexer::new(layout))
95 }
96 }
97}