From 207be3c771d281baae6e5fa0fb74be9a056e97a2 Mon Sep 17 00:00:00 2001 From: Can Celik Date: Tue, 1 Sep 2026 15:48:22 +0300 Subject: refactor: render the shell in the client (#3487) * feat: add opt-in client-rendered shell * feat: add client-owned shell mouse controls * feat: complete client-owned shell chrome * feat: add client-owned shell settings and notifications * feat: run client shell custom commands * feat: render popup terminals in client shell * feat: add client-owned scrollback and copy mode * fix: preserve client worktree trust defaults * feat: render startup diagnostics in client shell * feat: render onboarding in client shell * feat: render product announcements in client shell * feat: render release notes in client shell * feat: render mobile switcher in client shell * feat: render kitty graphics in client shell * fix: preserve client shell lifecycle coherence * refactor: route client shell commands through endpoint connections * refactor: make the client-rendered shell the default * refactor: remove monolithic launch mode * refactor: complete client-rendered shell cutover * perf: retain client pane surface updates * perf: scale retained pane surface updates * perf: remove remote pane input latency * test: make client shell checks platform-independent * fix: prevent client timer starvation * test: fix client shell platform gates * test: accept retained surfaces in cross-area checks * test: make client mode assertions platform-neutral * fix: badge only outdated integrations --- src/app/creation.rs | 145 +++------------------------------------------------- 1 file changed, 8 insertions(+), 137 deletions(-) (limited to 'src/app/creation.rs') diff --git a/src/app/creation.rs b/src/app/creation.rs index d531e733..fbe61902 100644 --- a/src/app/creation.rs +++ b/src/app/creation.rs @@ -1,13 +1,10 @@ use std::path::PathBuf; -use crate::api::schema::{EventData, EventEnvelope, EventKind}; -#[cfg(test)] -use tracing::error; - use super::{ api_helpers::{pane_agent_status, tab_attention_priority}, App, Mode, }; +use crate::api::schema::{EventData, EventEnvelope, EventKind}; use crate::{config::NewTerminalCwdConfig, workspace::Workspace}; pub(crate) fn resolve_new_terminal_cwd( @@ -81,6 +78,13 @@ impl App { resolve_new_terminal_cwd(&self.state.new_terminal_cwd, follow_cwd) } + pub(crate) fn resolved_new_workspace_cwd_from(&self, ws_idx: usize) -> PathBuf { + let follow_cwd = self + .focused_pane_cwd_in_workspace(ws_idx) + .or_else(|| self.seed_cwd_from_workspace(ws_idx)); + self.resolve_new_terminal_cwd(follow_cwd) + } + pub(super) fn workspace_creation_source(&self) -> Option { if self.state.mode == Mode::Navigate && self.state.workspaces.get(self.state.selected).is_some() @@ -96,128 +100,6 @@ impl App { }) } - pub(super) fn begin_tui_workspace_create(&mut self, request_id: &'static str) { - if self.state.prompt_new_workspace_name { - let follow_cwd = self.workspace_creation_source().and_then(|ws_idx| { - self.focused_pane_cwd_in_workspace(ws_idx) - .or_else(|| self.seed_cwd_from_workspace(ws_idx)) - }); - let cwd = self.resolve_new_terminal_cwd(follow_cwd); - super::input::open_new_workspace_dialog(&mut self.state, cwd); - return; - } - - self.runtime_workspace_create( - request_id, - crate::api::schema::WorkspaceCreateParams { - cwd: None, - focus: true, - label: None, - env: Default::default(), - }, - ); - self.state.mode = if self.state.active.is_some() { - Mode::Terminal - } else { - Mode::Navigate - }; - } - - /// Create a workspace with a real PTY (needs event_tx). - #[cfg(test)] - pub(crate) fn create_workspace(&mut self) { - let follow_cwd = self.workspace_creation_source().and_then(|ws_idx| { - self.focused_pane_cwd_in_workspace(ws_idx) - .or_else(|| self.seed_cwd_from_workspace(ws_idx)) - }); - let initial_cwd = self.resolve_new_terminal_cwd(follow_cwd); - if let Err(e) = self.create_workspace_with_events(initial_cwd, true) { - error!(err = %e, "failed to create workspace"); - self.state.mode = Mode::Navigate; - } - } - - #[cfg(test)] - pub(crate) fn create_tab(&mut self) { - let custom_name = self.state.requested_new_tab_name.take(); - let active_before = self.state.active; - let follow_cwd = self.state.active.and_then(|ws_idx| { - self.focused_pane_cwd_in_workspace(ws_idx) - .or_else(|| self.seed_cwd_from_workspace(ws_idx)) - }); - let initial_cwd = self.resolve_new_terminal_cwd(follow_cwd); - match self.create_tab_with_options(initial_cwd, true) { - Ok(created_idx) => { - let created_workspace = active_before.is_none(); - let ws_idx = if created_workspace { - Some(created_idx) - } else { - self.state.active - }; - let tab_idx = if created_workspace { 0 } else { created_idx }; - if let Some(name) = custom_name { - if let Some(ws) = - ws_idx.and_then(|ws_idx| self.state.workspaces.get_mut(ws_idx)) - { - if let Some(tab) = ws.tabs.get_mut(tab_idx) { - tab.set_custom_name(name); - } - self.schedule_session_save(); - } - } - if let Some(ws_idx) = ws_idx { - if created_workspace { - self.emit_workspace_open_events(ws_idx); - } else { - self.emit_tab_created_events(ws_idx, tab_idx); - } - } - } - Err(e) => { - error!(err = %e, "failed to create tab"); - } - } - } - - #[cfg(test)] - pub(super) fn create_tab_with_options( - &mut self, - initial_cwd: PathBuf, - focus: bool, - ) -> std::io::Result { - let Some(ws_idx) = self.state.active else { - return self.create_workspace_with_options(initial_cwd, focus); - }; - let (rows, cols) = self.state.estimate_pane_size(); - let ws = &mut self.state.workspaces[ws_idx]; - let (idx, terminal, runtime) = ws.create_tab( - rows, - cols, - initial_cwd, - self.state.pane_scrollback_limit_bytes, - self.state.host_terminal_theme, - self.state.host_terminal_appearance, - crate::pane::PaneShellConfig::new(&self.state.default_shell, self.state.shell_mode), - Vec::new(), - )?; - let root_pane = ws.tabs[idx].root_pane; - self.terminal_runtimes.insert(terminal.id.clone(), runtime); - self.state.terminals.insert(terminal.id.clone(), terminal); - self.state.remove_alias_shadowed_by_new_pane(root_pane); - if focus { - self.state.switch_workspace_tab(ws_idx, idx); - self.state.mode = Mode::Terminal; - } - let workspace_id = self.state.workspaces[ws_idx].id.clone(); - let tab_id = self - .public_tab_id(ws_idx, idx) - .unwrap_or_else(|| crate::workspace::public_tab_id_for_number(&workspace_id, idx + 1)); - let root_pane = self.state.workspaces[ws_idx].tabs[idx].root_pane.raw(); - crate::logging::tab_created(&workspace_id, &tab_id, root_pane); - self.schedule_session_save(); - Ok(idx) - } - pub(crate) fn create_workspace_with_options( &mut self, initial_cwd: PathBuf, @@ -226,17 +108,6 @@ impl App { self.create_workspace_with_launch_env(initial_cwd, focus, Vec::new()) } - #[cfg(test)] - pub(crate) fn create_workspace_with_events( - &mut self, - initial_cwd: PathBuf, - focus: bool, - ) -> std::io::Result<()> { - let ws_idx = self.create_workspace_with_options(initial_cwd, focus)?; - self.emit_workspace_open_events(ws_idx); - Ok(()) - } - pub(crate) fn create_workspace_with_launch_env( &mut self, initial_cwd: PathBuf, -- cgit v1.2.3