mod activity_state;
mod constructors;
mod initial_text;
mod manager;
mod manager_nav;
mod pane_accessors;
mod pane_ops;
mod profile_state;
mod profile_tracking;
mod refresh_task;
mod scripting_state;
mod session_logging;
mod setup;
mod tmux_state;
pub(crate) use activity_state::TabActivityMonitor;
pub(crate) use profile_state::TabProfileState;
pub(crate) use scripting_state::TabScriptingState;
pub(crate) use tmux_state::TabTmuxState;
use crate::pane::PaneManager;
use crate::session_logger::SharedSessionLogger;
use crate::terminal::TerminalManager;
pub use manager::TabManager;
pub(crate) use setup::{
apply_login_shell_flag, build_shell_env, configure_terminal_from_config, get_shell_command,
};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use tokio::runtime::Runtime;
use tokio::sync::RwLock;
use tokio::task::JoinHandle;
pub use par_term_config::TabId;
pub struct Tab {
pub(crate) id: TabId,
pub(crate) terminal: Arc<RwLock<TerminalManager>>,
pub(crate) pane_manager: Option<PaneManager>,
pub(crate) title: String,
pub(crate) refresh_task: Option<JoinHandle<()>>,
pub(in crate::tab) working_directory: Option<String>,
pub(crate) custom_color: Option<[u8; 3]>,
pub(crate) has_default_title: bool,
pub(crate) user_named: bool,
pub(crate) activity: TabActivityMonitor,
pub(crate) session_logger: SharedSessionLogger,
pub(crate) tmux: TabTmuxState,
pub(crate) detected_hostname: Option<String>,
pub(in crate::tab) detected_cwd: Option<String>,
pub(crate) custom_icon: Option<String>,
pub(crate) profile: TabProfileState,
pub(crate) scripting: TabScriptingState,
pub(crate) was_alt_screen: bool,
pub(in crate::tab) is_active: Arc<AtomicBool>,
pub(crate) shutdown_fast: bool,
pub(crate) is_hidden: bool,
pub(crate) cached_modify_other_keys_mode: AtomicU8,
pub(crate) cached_application_cursor: AtomicBool,
pub(crate) cached_alt_screen_active: AtomicBool,
pub(crate) cached_has_tmux_child: AtomicBool,
}
impl Tab {
pub(crate) fn read_or_cached_modes(&self) -> (u8, bool, bool) {
if let Ok(term) = self.terminal.try_read() {
let m = term.modify_other_keys_mode();
let a = term.application_cursor();
let s = term.is_alt_screen_active();
self.cached_modify_other_keys_mode
.store(m, Ordering::Relaxed);
self.cached_application_cursor.store(a, Ordering::Relaxed);
self.cached_alt_screen_active.store(s, Ordering::Relaxed);
(m, a, s)
} else {
(
self.cached_modify_other_keys_mode.load(Ordering::Relaxed),
self.cached_application_cursor.load(Ordering::Relaxed),
self.cached_alt_screen_active.load(Ordering::Relaxed),
)
}
}
}
pub(super) struct TabInitParams {
pub(super) id: TabId,
pub(super) title: String,
pub(super) has_default_title: bool,
pub(super) user_named: bool,
pub(super) working_directory: Option<String>,
pub(super) runtime: Option<Arc<Runtime>>,
}
impl Drop for Tab {
fn drop(&mut self) {
if self.shutdown_fast {
log::info!("Fast-dropping tab {} (cleanup handled externally)", self.id);
return;
}
log::info!("Dropping tab {}", self.id);
if let Some(ref mut logger) = *self.session_logger.lock() {
match logger.stop() {
Ok(path) => {
log::info!("Session log saved to: {:?}", path);
}
Err(e) => {
log::warn!("Failed to stop session logging: {}", e);
}
}
}
self.stop_refresh_task();
if let Ok(mut term) = self.terminal.try_write()
&& term.is_running()
{
log::info!("Killing terminal for tab {}", self.id);
let _ = term.kill();
}
}
}
impl Tab {
#[inline]
pub(crate) fn try_with_terminal<R>(&self, f: impl FnOnce(&TerminalManager) -> R) -> Option<R> {
self.terminal.try_read().ok().map(|guard| f(&guard))
}
#[inline]
pub(crate) fn try_with_terminal_mut<R>(
&self,
f: impl FnOnce(&mut TerminalManager) -> R,
) -> Option<R> {
self.terminal
.try_write()
.ok()
.map(|mut guard| f(&mut guard))
}
}