From 36c006828e403bc4ba6a41a6670509e336a5ad08 Mon Sep 17 00:00:00 2001 From: vipex <101529155+vipexv@users.noreply.github.com> Date: Tue, 21 Oct 2025 03:19:40 +0200 Subject: [PATCH] pane: Ignore max tabs on terminal pane (#40740) Closes #39901 I'm unsure as to which direction the team wants to go with this, but this is the behavior of VSCode which is what this feature is based off so i'm going with this. Changes: 1. Introduced a new argument to the `new` method on the Pane called `ignore_max_tabs` that forces the `max_tabs` to None if it's true. 2. Added a new test `test_bypass_max_tabs_limit`. Release Notes: - Fixed: `max_tabs` Setting affecting the terminal pane. --------- Co-authored-by: Joseph T. Lyons --- crates/debugger_ui/src/session/running.rs | 1 + crates/terminal_view/src/terminal_panel.rs | 51 ++++++++++++++++++++++ crates/workspace/src/pane.rs | 12 ++++- crates/workspace/src/workspace.rs | 2 + 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/crates/debugger_ui/src/session/running.rs b/crates/debugger_ui/src/session/running.rs index 8f25ee7fa4cf1210ff72b577765481e1ab109cc0..7340f2591623fcf8b61916fc3aea3337bcad3149 100644 --- a/crates/debugger_ui/src/session/running.rs +++ b/crates/debugger_ui/src/session/running.rs @@ -386,6 +386,7 @@ pub(crate) fn new_debugger_pane( Default::default(), None, NoAction.boxed_clone(), + true, window, cx, ); diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index cb80d58c13128fad19b647e060001e5cf63f052b..de66bb1ed64851a1101d434e3a7b54a8ae725cfb 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/crates/terminal_view/src/terminal_panel.rs @@ -1103,6 +1103,7 @@ pub fn new_terminal_pane( Default::default(), None, NewTerminal.boxed_clone(), + false, window, cx, ); @@ -1752,6 +1753,8 @@ impl Render for InlineAssistTabBarButton { #[cfg(test)] mod tests { + use std::num::NonZero; + use super::*; use gpui::{TestAppContext, UpdateGlobal as _}; use pretty_assertions::assert_eq; @@ -1808,6 +1811,46 @@ mod tests { .unwrap(); } + #[gpui::test] + async fn test_bypass_max_tabs_limit(cx: &mut TestAppContext) { + init_test(cx); + + let fs = FakeFs::new(cx.executor()); + let project = Project::test(fs, [], cx).await; + let workspace = cx.add_window(|window, cx| Workspace::test_new(project, window, cx)); + + let (window_handle, terminal_panel) = workspace + .update(cx, |workspace, window, cx| { + let window_handle = window.window_handle(); + let terminal_panel = cx.new(|cx| TerminalPanel::new(workspace, window, cx)); + (window_handle, terminal_panel) + }) + .unwrap(); + + set_max_tabs(cx, Some(3)); + + for _ in 0..5 { + let task = window_handle + .update(cx, |_, window, cx| { + terminal_panel.update(cx, |panel, cx| { + panel.add_terminal_shell(None, RevealStrategy::Always, window, cx) + }) + }) + .unwrap(); + task.await.unwrap(); + } + + cx.run_until_parked(); + + let item_count = + terminal_panel.read_with(cx, |panel, cx| panel.active_pane.read(cx).items_len()); + + assert_eq!( + item_count, 5, + "Terminal panel should bypass max_tabs limit and have all 5 terminals" + ); + } + // A complex Unix command won't be properly parsed by the Windows terminal hence omit the test there. #[cfg(unix)] #[gpui::test] @@ -1922,6 +1965,14 @@ mod tests { .unwrap(); } + fn set_max_tabs(cx: &mut TestAppContext, value: Option) { + cx.update_global(|store: &mut SettingsStore, cx| { + store.update_user_settings(cx, |settings| { + settings.workspace.max_tabs = value.map(|v| NonZero::new(v).unwrap()) + }); + }); + } + pub fn init_test(cx: &mut TestAppContext) { cx.update(|cx| { let store = SettingsStore::test(cx); diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 0784f30739be9ef6bf6c65f38e2f7e52c73390e8..3dcba4aa4ebc38bc7c0006c8402e38d4e12ac016 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -376,6 +376,7 @@ pub struct Pane { render_tab_bar: Rc) -> AnyElement>, show_tab_bar_buttons: bool, max_tabs: Option, + use_max_tabs: bool, _subscriptions: Vec, tab_bar_scroll_handle: ScrollHandle, /// This is set to true if a user scroll has occurred more recently than a system scroll @@ -473,10 +474,16 @@ impl Pane { next_timestamp: Arc, can_drop_predicate: Option bool + 'static>>, double_click_dispatch_action: Box, + use_max_tabs: bool, window: &mut Window, cx: &mut Context, ) -> Self { let focus_handle = cx.focus_handle(); + let max_tabs = if use_max_tabs { + WorkspaceSettings::get_global(cx).max_tabs + } else { + None + }; let subscriptions = vec![ cx.on_focus(&focus_handle, window, Pane::focus_in), @@ -498,7 +505,8 @@ impl Pane { zoomed: false, active_item_index: 0, preview_item_id: None, - max_tabs: WorkspaceSettings::get_global(cx).max_tabs, + max_tabs, + use_max_tabs, last_focus_handle_by_item: Default::default(), nav_history: NavHistory(Arc::new(Mutex::new(NavHistoryState { mode: NavigationMode::Normal, @@ -706,7 +714,7 @@ impl Pane { self.preview_item_id = None; } - if new_max_tabs != self.max_tabs { + if self.use_max_tabs && new_max_tabs != self.max_tabs { self.max_tabs = new_max_tabs; self.close_items_on_settings_change(window, cx); } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 53f416ae805e692db48b6676a3484e6f839feb99..3c8c94ce0e932dc6773c8f6c168c95563b60c879 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1331,6 +1331,7 @@ impl Workspace { pane_history_timestamp.clone(), None, NewFile.boxed_clone(), + true, window, cx, ); @@ -3235,6 +3236,7 @@ impl Workspace { self.pane_history_timestamp.clone(), None, NewFile.boxed_clone(), + true, window, cx, );