diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-08-15 15:09:53 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-15 15:09:53 +0300 |
| commit | 15539d3dec40bcc40e6f4bb0eaa4f073ad26b74f (patch) | |
| tree | 2ff7cf0353d3c3228f32d5d7756b45ba2486edb2 /src/server | |
| parent | b660cad80450147610091e0e5758faa6276e5983 (diff) | |
feat: make headless terminal size configurable (#2829)
refs #2828
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/headless.rs | 47 |
1 files changed, 37 insertions, 10 deletions
diff --git a/src/server/headless.rs b/src/server/headless.rs index ac1e7db2..354b0008 100644 --- a/src/server/headless.rs +++ b/src/server/headless.rs @@ -252,10 +252,6 @@ fn dirty_patch_intersects_hyperlinks( // Constants // --------------------------------------------------------------------------- -/// Default shared runtime size (columns, rows) when no clients are attached. -const MIN_COLS: u16 = 80; -const MIN_ROWS: u16 = 24; - /// Timeout for in-flight API requests during shutdown. #[allow(dead_code)] const SHUTDOWN_API_TIMEOUT: Duration = Duration::from_secs(5); @@ -326,8 +322,10 @@ pub struct HeadlessServer { deferred_alt_screen_reads: Vec<api::ApiRequestMessage>, /// Monotonic activity counter used to pick the most recently active client. next_activity_stamp: u64, - /// Shared pane runtime size derived from the foreground client, - /// or MIN_COLS × MIN_ROWS when no clients are connected. + /// Configured virtual terminal size used when no clients are connected. + headless_size: (u16, u16), + /// Shared pane runtime size derived from the foreground client, or the + /// configured headless size when no clients are connected. effective_size: (u16, u16), /// Flag set when shutdown is initiated. shutting_down: bool, @@ -495,6 +493,7 @@ impl HeadlessServer { spawn_windows_client_accept_thread(listener, should_quit.clone(), server_event_tx.clone()); let server_keybindings = app_keybindings(&app); + let headless_size = app.state.headless_size; let (server_config_diagnostic, server_config_diagnostic_without_keybindings) = server_config_diagnostic_summaries(config_diagnostics); #[cfg(not(unix))] @@ -521,7 +520,8 @@ impl HeadlessServer { pending_alt_screen_reads: Vec::new(), deferred_alt_screen_reads: Vec::new(), next_activity_stamp: 1, - effective_size: (MIN_COLS, MIN_ROWS), + headless_size, + effective_size: headless_size, shutting_down: false, handoff_in_progress: false, #[cfg(unix)] @@ -1139,6 +1139,14 @@ impl HeadlessServer { } } + fn sync_headless_view_geometry(&mut self) { + crate::ui::compute_view_without_resizing_panes( + &mut self.app.state, + &self.app.terminal_runtimes, + Rect::new(0, 0, self.headless_size.0, self.headless_size.1), + ); + } + fn sync_foreground_client_state(&mut self) { self.app.direct_graphics_available = self.direct_graphics_available(); self.app.pixel_mouse_available = self.foreground_client_id.is_some_and(|id| { @@ -1150,9 +1158,10 @@ impl HeadlessServer { self.retire_all_direct_graphics(); } let Some(client_id) = self.foreground_client_id else { - self.effective_size = (MIN_COLS, MIN_ROWS); + self.effective_size = self.headless_size; self.app.state.outer_terminal_focus = None; self.app.state.host_cell_size = crate::kitty_graphics::HostCellSize::default(); + self.sync_headless_view_geometry(); let server_keybindings = self.server_keybindings.clone(); apply_keybindings(&mut self.app, &server_keybindings); self.sync_visible_server_config_diagnostic(false); @@ -1160,9 +1169,10 @@ impl HeadlessServer { }; let Some(client) = self.clients.get(&client_id) else { self.foreground_client_id = None; - self.effective_size = (MIN_COLS, MIN_ROWS); + self.effective_size = self.headless_size; self.app.state.outer_terminal_focus = None; self.app.state.host_cell_size = crate::kitty_graphics::HostCellSize::default(); + self.sync_headless_view_geometry(); let server_keybindings = self.server_keybindings.clone(); apply_keybindings(&mut self.app, &server_keybindings); self.sync_visible_server_config_diagnostic(false); @@ -1507,6 +1517,7 @@ impl HeadlessServer { let report = self.app.apply_config_from_disk(notify_success); self.app.take_config_reloaded_from_disk(); self.server_keybindings = app_keybindings(&self.app); + self.headless_size = self.app.state.headless_size; let (server_config_diagnostic, server_config_diagnostic_without_keybindings) = server_config_diagnostic_summaries(&report.diagnostics); self.server_config_diagnostic = server_config_diagnostic; @@ -5306,6 +5317,7 @@ mod tests { #[cfg(windows)] spawn_windows_client_accept_thread(listener, should_quit.clone(), server_event_tx.clone()); let server_keybindings = app_keybindings(&app); + let headless_size = app.state.headless_size; HeadlessServer { app, @@ -5329,7 +5341,8 @@ mod tests { pending_alt_screen_reads: Vec::new(), deferred_alt_screen_reads: Vec::new(), next_activity_stamp: 1, - effective_size: (MIN_COLS, MIN_ROWS), + headless_size, + effective_size: headless_size, shutting_down: false, handoff_in_progress: false, #[cfg(unix)] @@ -5380,6 +5393,20 @@ mod tests { } } + #[test] + fn default_headless_size_is_effective_without_clients() { + let server = test_headless_server(); + + assert_eq!( + server.headless_size, + ( + crate::config::DEFAULT_HEADLESS_COLS, + crate::config::DEFAULT_HEADLESS_ROWS + ) + ); + assert_eq!(server.effective_size, server.headless_size); + } + #[tokio::test] async fn headless_api_reads_latest_title_without_spinner_event_flooding() { let event_hub = api::EventHub::default(); |
