use crate::tab::Pane; use crate::{os_input_output::ServerOsApi, panes::PaneId, ClientId}; use std::collections::{BTreeMap, HashMap, HashSet}; #[derive(Clone)] pub struct ActivePanes { active_panes: HashMap, shadow_clients: HashSet, last_panes: HashMap, os_api: Box, } impl std::fmt::Debug for ActivePanes { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self.active_panes) } } impl ActivePanes { pub fn new(os_api: &Box) -> Self { let os_api = os_api.clone(); ActivePanes { active_panes: HashMap::new(), shadow_clients: HashSet::new(), last_panes: HashMap::new(), os_api, } } pub fn is_shadow_client(&self, client_id: &ClientId) -> bool { self.shadow_clients.contains(client_id) } pub fn iter_shadow_clients(&self) -> impl Iterator { self.shadow_clients.iter() } pub fn has_shadow_focus_on(&self, client_id: ClientId, pane_id: PaneId) -> bool { self.shadow_clients.contains(&client_id) && self.active_panes.get(&client_id) == Some(&pane_id) } pub fn get(&self, client_id: &ClientId) -> Option<&PaneId> { self.active_panes.get(client_id) } pub fn get_last(&self, client_id: &ClientId) -> Option<&PaneId> { self.last_panes.get(client_id) } pub fn insert( &mut self, client_id: ClientId, pane_id: PaneId, panes: &mut BTreeMap>, ) { self.shadow_clients.remove(&client_id); let previously_focused = self.active_panes.get(&client_id).copied(); self.unfocus_pane_for_client(client_id, panes); self.active_panes.insert(client_id, pane_id); self.focus_pane(pane_id, panes); // Both the pane losing focus and the pane gaining it may need to be // repainted in full; see Pane::refresh_for_focus_change. for id in previously_focused.into_iter().chain(std::iter::once(pane_id)) { if let Some(pane) = panes.get_mut(&id) { pane.refresh_for_focus_change(); } } } pub fn insert_silent(&mut self, client_id: ClientId, pane_id: PaneId) { self.active_panes.insert(client_id, pane_id); self.shadow_clients.insert(client_id); } pub fn remove_silent(&mut self, client_id: &ClientId) -> Option { self.shadow_clients.remove(client_id); self.active_panes.remove(client_id) } pub fn set_last_pane(&mut self, client_id: ClientId, pane_id: PaneId) { self.last_panes.insert(client_id, pane_id); } pub fn clear(&mut self, panes: &mut BTreeMap>) { for pane_id in self.active_panes.values() { self.unfocus_pane(*pane_id, panes); } self.active_panes.clear(); self.shadow_clients.clear(); } pub fn is_empty(&self) -> bool { self.active_panes.is_empty() } pub fn iter(&self) -> impl Iterator { self.active_panes.iter() } pub fn values(&self) -> impl Iterator { self.active_panes.values() } pub fn remove( &mut self, client_id: &ClientId, panes: &mut BTreeMap>, ) -> Option { if let Some(pane_id_to_unfocus) = self.active_panes.get(&client_id) { self.unfocus_pane(*pane_id_to_unfocus, panes); } self.shadow_clients.remove(client_id); self.active_panes.remove(client_id) } pub fn unfocus_all_panes(&self, panes: &mut BTreeMap>) { for (_client_id, pane_id) in &self.active_panes { self.unfocus_pane(*pane_id, panes); } } pub fn focus_all_panes(&self, panes: &mut BTreeMap>) { for (_client_id, pane_id) in &self.active_panes { self.focus_pane(*pane_id, panes); } } pub fn clone_active_panes(&self) -> HashMap { self.active_panes.clone() } pub fn contains_key(&self, client_id: &ClientId) -> bool { self.active_panes.contains_key(client_id) } fn unfocus_pane_for_client( &self, client_id: ClientId, panes: &mut BTreeMap>, ) { if let Some(pane_id_to_unfocus) = self.active_panes.get(&client_id) { self.unfocus_pane(*pane_id_to_unfocus, panes); } } fn unfocus_pane(&self, pane_id: PaneId, panes: &mut BTreeMap>) { if let PaneId::Terminal(terminal_id) = pane_id { if let Some(focus_event) = panes.get(&pane_id).and_then(|p| p.unfocus_event()) { let _ = self .os_api .write_to_tty_stdin(terminal_id, focus_event.as_bytes()); } } } fn focus_pane(&self, pane_id: PaneId, panes: &mut BTreeMap>) { if let PaneId::Terminal(terminal_id) = pane_id { if let Some(focus_event) = panes.get(&pane_id).and_then(|p| p.focus_event()) { let _ = self .os_api .write_to_tty_stdin(terminal_id, focus_event.as_bytes()); } } } pub fn pane_id_is_focused(&self, pane_id: &PaneId) -> bool { self.active_panes .values() .find(|p_id| **p_id == *pane_id) .is_some() } }