aboutsummaryrefslogtreecommitdiff
path: root/src/app/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/mod.rs')
-rw-r--r--src/app/mod.rs55
1 files changed, 53 insertions, 2 deletions
diff --git a/src/app/mod.rs b/src/app/mod.rs
index 15f352af..cca530ce 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -22,6 +22,7 @@ mod runtime;
mod runtime_mutations;
mod session;
pub mod state;
+mod tab_bar_status;
mod terminal_targets;
mod terminal_titles;
mod theme_sync;
@@ -139,6 +140,10 @@ pub struct App {
pub(crate) session_save_deadline: Option<Instant>,
pub(crate) session_save_thread: Option<std::thread::JoinHandle<()>>,
pub(crate) detached_custom_command_children: Vec<std::process::Child>,
+ tab_bar_status_generation: u64,
+ tab_bar_datetimes: Vec<tab_bar_status::TabBarDatetimeRuntime>,
+ tab_bar_commands: Vec<tab_bar_status::TabBarCommandRuntime>,
+ next_tab_bar_datetime_refresh: Option<Instant>,
pub(crate) persist_pane_history: bool,
pub(crate) last_render_at: Option<Instant>,
pub(crate) input_leases: input::InputLeaseTable,
@@ -642,6 +647,8 @@ impl App {
show_agent_labels_on_pane_borders: config.ui.show_agent_labels_on_pane_borders,
hide_tab_bar_when_single_tab: config.ui.hide_tab_bar_when_single_tab,
tab_bar_position: config.ui.tab_bar_position,
+ tab_bar_right: Vec::new(),
+ tab_bar_right_separator: String::new(),
pane_history_persistence: config.experimental.pane_history,
reveal_hidden_cursor_for_cjk_ime: config.experimental.reveal_hidden_cursor_for_cjk_ime,
cjk_ime_agent_filter_configured: !config.experimental.cjk_ime_agents.is_empty(),
@@ -723,7 +730,7 @@ impl App {
.and_then(|ws| ws.focused_pane_id().map(|pane_id| (idx, pane_id)))
});
- Self {
+ let mut app = Self {
config_diagnostic_deadline: None,
toast_deadline: None,
copy_feedback_deadline: None,
@@ -762,6 +769,10 @@ impl App {
session_save_deadline: None,
session_save_thread: None,
detached_custom_command_children: Vec::new(),
+ tab_bar_status_generation: 0,
+ tab_bar_datetimes: Vec::new(),
+ tab_bar_commands: Vec::new(),
+ next_tab_bar_datetime_refresh: None,
selection_autoscroll_deadline: None,
selection_highlight_clear_deadline: None,
persist_pane_history: config.experimental.pane_history,
@@ -781,7 +792,9 @@ impl App {
local_input_source_switch: true,
config_reloaded_from_disk: false,
prefix_input_source: Box::new(crate::platform::RealPrefixInputSource::default()),
- }
+ };
+ app.configure_tab_bar_status(&config.ui.tab_bar_right, &config.ui.tab_bar_right_separator);
+ app
}
#[cfg(unix)]
@@ -1421,6 +1434,9 @@ impl App {
diagnostics.push(format!("{diagnostic}; keeping previous [ui] settings"));
} else {
diagnostics.extend(config.ui.sound.diagnostics());
+ diagnostics.extend(crate::config::tab_bar_right_diagnostics(
+ &config.ui.tab_bar_right,
+ ));
self.state.default_sidebar_width = config.ui.sidebar_width;
if self.state.sidebar_width_source == state::SidebarWidthSource::ConfigDefault {
@@ -1460,6 +1476,10 @@ impl App {
config.ui.show_agent_labels_on_pane_borders;
self.state.hide_tab_bar_when_single_tab = config.ui.hide_tab_bar_when_single_tab;
self.state.tab_bar_position = config.ui.tab_bar_position;
+ self.configure_tab_bar_status(
+ &config.ui.tab_bar_right,
+ &config.ui.tab_bar_right_separator,
+ );
self.state.agent_panel_sort =
agent_panel_sort_from_config(config.ui.agent_panel_sort);
self.state.status_indicators = config.ui.status_indicators;
@@ -2332,6 +2352,37 @@ mod tests {
}
#[test]
+ fn tab_bar_command_events_render_only_when_visible_output_changes() {
+ if !crate::platform::status_commands_supported() {
+ return;
+ }
+
+ let mut app = test_app();
+ app.configure_tab_bar_status(
+ &[crate::config::TabBarRightEntryConfig::Command {
+ command: "status".into(),
+ interval_seconds: 5,
+ timeout_seconds: 2,
+ }],
+ " ",
+ );
+ let generation = app.tab_bar_status_generation;
+ let event = |generation, output: Option<&str>| AppEvent::TabBarCommandFinished {
+ generation,
+ segment_index: 0,
+ result: Ok(output.map(str::to_string)),
+ };
+
+ assert!(!app.handle_internal_event_with_prefix_sync(event(generation, None)));
+ assert!(app.handle_internal_event_with_prefix_sync(event(generation, Some("ready"))));
+ assert!(!app.handle_internal_event_with_prefix_sync(event(generation, Some("ready"))));
+ assert!(!app.handle_internal_event_with_prefix_sync(event(
+ generation.wrapping_add(1),
+ Some("stale"),
+ )));
+ }
+
+ #[test]
fn git_status_event_clears_in_flight_refresh() {
let mut app = test_app();
app.git_refresh_in_flight = true;