diff --git a/screenshots/after-cmd-n-again.png b/screenshots/after-cmd-n-again.png new file mode 100644 index 00000000000..1168c72feb3 Binary files /dev/null and b/screenshots/after-cmd-n-again.png differ diff --git a/screenshots/after-cmd-n.png b/screenshots/after-cmd-n.png new file mode 100644 index 00000000000..6770e93a0f1 Binary files /dev/null and b/screenshots/after-cmd-n.png differ diff --git a/screenshots/after-reload.png b/screenshots/after-reload.png new file mode 100644 index 00000000000..6021f5cf110 Binary files /dev/null and b/screenshots/after-reload.png differ diff --git a/screenshots/after-session-select.png b/screenshots/after-session-select.png new file mode 100644 index 00000000000..46ac6fc04aa Binary files /dev/null and b/screenshots/after-session-select.png differ diff --git a/screenshots/after-toggle-closed.png b/screenshots/after-toggle-closed.png new file mode 100644 index 00000000000..1168c72feb3 Binary files /dev/null and b/screenshots/after-toggle-closed.png differ diff --git a/screenshots/after-workspace-click.png b/screenshots/after-workspace-click.png new file mode 100644 index 00000000000..5e9f698f150 Binary files /dev/null and b/screenshots/after-workspace-click.png differ diff --git a/screenshots/before-reload-open.png b/screenshots/before-reload-open.png new file mode 100644 index 00000000000..6770e93a0f1 Binary files /dev/null and b/screenshots/before-reload-open.png differ diff --git a/screenshots/before-session-select.png b/screenshots/before-session-select.png new file mode 100644 index 00000000000..040e198c230 Binary files /dev/null and b/screenshots/before-session-select.png differ diff --git a/screenshots/initial-state.png b/screenshots/initial-state.png new file mode 100644 index 00000000000..3818b5ec933 Binary files /dev/null and b/screenshots/initial-state.png differ diff --git a/src/vs/sessions/SINGLE_PANE_SCENARIOS.md b/src/vs/sessions/SINGLE_PANE_SCENARIOS.md index 3ca9f28f38b..8c1a0e8423b 100644 --- a/src/vs/sessions/SINGLE_PANE_SCENARIOS.md +++ b/src/vs/sessions/SINGLE_PANE_SCENARIOS.md @@ -112,13 +112,13 @@ The **auto-managed** tabs (the pinned Changes tab and the default File tab) are ## 5. Detail panel content (driven by the active tab) -`DetailPanelController` maps the active editor tab to the detail content, **reveal-on-activate**: +The single-pane layout controller (`SinglePaneDesktopSessionLayoutController`) maps the active editor tab to the detail content. By default the detail panel is **closed** for a created session (Editor-only); it is opened via **Toggle Details** (or restored per-session), and while visible its container follows the active tab (the one exception is restoring the detail after a transient browser-tab hide): | Active tab | Detail panel | |-----------|--------------| -| **Changes** | Branch Changes file list + Checks — revealed when the Changes tab activates | -| **File** (Explorer) | Files/Explorer tree — revealed when a File tab activates | -| **Browser** | **Hidden** (transiently) while the Browser tab is active | +| **Changes** | Branch Changes file list + Checks — shown (Changes container) while the detail is visible | +| **File** (Explorer) | Files/Explorer tree — shown (Files container) while the detail is visible | +| **Browser** | **Hidden** (transiently) while the Browser tab is active; restored when switching back | Rules: - **Reveal on activate, respect after.** Switching to a Changes/File tab reveals the detail with the @@ -229,9 +229,9 @@ No side pane at all — the detail panel and managed tabs are not shown; the cha | Docked layout, hide/show editor, detail width, sash-reveal sync, grid | `browser/workbench.ts` | | Docked panel overlay + resize sash | `browser/dockedAuxiliaryBarController.ts` | | Editor tab bar kept visible when content hidden; sash-reveal trigger | `browser/parts/editorPart.ts` | -| Active tab → detail container mapping (reveal-on-activate, browser transient) | `contrib/changes/browser/detailPanelController.ts` | -| Managed Changes + File tabs (suppressed opens) | `contrib/changes/browser/changesTabController.ts` | +| Active tab → detail container mapping (browser transient) | `contrib/layout/browser/singlePaneDesktopSessionLayoutController.ts` | +| Managed Changes + File tabs (suppressed opens) | `contrib/layout/browser/singlePaneDesktopSessionLayoutController.ts` | | Startup controller selection | `contrib/layout/browser/sessions.layout.contribution.ts` | -| New-session level-triggered editor hide (R1/R2) | `contrib/layout/browser/singlePaneDesktopSessionLayoutController.ts` | +| New-session transition-triggered editor hide (R1) | `contrib/layout/browser/singlePaneDesktopSessionLayoutController.ts` | | Hide Editor chevron, Maximize, add-tab actions | `contrib/editor/browser/editor.contribution.ts`, `contrib/editor/browser/addTabActions.ts` | -| Detail (aux bar) toggle | `browser/layoutActions.ts` | +| Toggle Details command + editor-title item | `contrib/layout/browser/singlePaneDesktopSessionLayoutController.ts` | diff --git a/src/vs/sessions/contrib/editor/browser/editor.contribution.ts b/src/vs/sessions/contrib/editor/browser/editor.contribution.ts index 8963bc3d38f..31ef41d57c1 100644 --- a/src/vs/sessions/contrib/editor/browser/editor.contribution.ts +++ b/src/vs/sessions/contrib/editor/browser/editor.contribution.ts @@ -50,9 +50,7 @@ const editorTitleActionsWhen = ContextKeyExpr.and( IsAuxiliaryWindowContext.toNegated(), IsTopRightEditorGroupContext); const singlePaneEditorTitleMaximizeOrder = 1000000; -const singlePaneEditorTitleAuxiliaryBarOrder = 1000001; const singlePaneEditorTitleHideEditorOrder = 999999; -void singlePaneEditorTitleAuxiliaryBarOrder; class SinglePaneAddTabContribution extends Disposable implements IWorkbenchContribution { diff --git a/src/vs/sessions/contrib/layout/browser/baseSessionLayoutController.ts b/src/vs/sessions/contrib/layout/browser/baseSessionLayoutController.ts index 8d0bfa99699..5456c3c3fe7 100644 --- a/src/vs/sessions/contrib/layout/browser/baseSessionLayoutController.ts +++ b/src/vs/sessions/contrib/layout/browser/baseSessionLayoutController.ts @@ -18,7 +18,6 @@ import { Categories } from '../../../../platform/action/common/actionCommonCateg import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { ContextKeyExpr, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; -import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; import { ILifecycleService } from '../../../../workbench/services/lifecycle/common/lifecycle.js'; import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js'; @@ -143,7 +142,6 @@ export abstract class BaseLayoutController extends Disposable { @ISessionChangesService protected readonly _sessionChangesService: ISessionChangesService, @IChangesViewService protected readonly _changesViewService: IChangesViewService, @IViewDescriptorService protected readonly _viewDescriptorService: IViewDescriptorService, - @ICommandService protected readonly _commandService: ICommandService, @IContextKeyService protected readonly _contextKeyService: IContextKeyService, @IInstantiationService protected readonly _instantiationService: IInstantiationService, @ILifecycleService protected readonly _lifecycleService: ILifecycleService, diff --git a/src/vs/sessions/contrib/layout/browser/desktopSessionLayoutController.md b/src/vs/sessions/contrib/layout/browser/desktopSessionLayoutController.md index 8dfa7e21452..f173e7b6dd2 100644 --- a/src/vs/sessions/contrib/layout/browser/desktopSessionLayoutController.md +++ b/src/vs/sessions/contrib/layout/browser/desktopSessionLayoutController.md @@ -124,15 +124,18 @@ menu item, keybinding, and command-palette entry are inert. #### D11 — Single-pane new-session views are Files-only In single-pane detail-panel mode only, while a new (uncreated) workspace session view is active, the editor content is hidden by default so the editor tab bar and Files detail panel remain without showing -editor content. The hide is driven by the **session and active editor**, not by the editor's visibility: -`_registerSinglePaneNewSessionRules` hides the editor part whenever this is a new-session view whose active -editor is not real content (the managed empty tab or none), and leaves it alone once a real file/browser -editor is active. It deliberately does **not** react to the editor becoming visible, so an explicit reveal -sticks — opening a file reveals the editor before the file becomes the active editor (Task 4), and toggling -the detail panel off reveals the empty editor so the side pane does not vanish (Task 2). Spurious width-based -reveals are blocked at the source via `setSuppressDockedEditorRevealSync(true)` while the view has no real -content. The shared D3b/D9b new-session side-pane visibility state is unchanged: once the user hides the -side pane for a new session, it stays hidden for later new sessions. +editor content. The hide is **transition-triggered**: `_registerNewSessionRules` (a no-op base hook +overridden by `SinglePaneDesktopSessionLayoutController`) hides the editor part when it **just became +visible**, or when the new-session view was **just entered** with the editor already visible (an +inherited-visible editor from the previous session), and only while the active editor is not real content +(the managed empty tab or none). It leaves the editor alone once a real file/browser editor is active. +Switching to a managed tab (e.g. the Files placeholder) while the editor is **already** visible does not +hide it — only a visibility transition or entering the view does. An explicit reveal sticks — opening a +file reveals the editor before the file becomes the active editor (Task 4), and toggling the detail panel +off reveals the empty editor so the side pane does not vanish (Task 2); entering the view always resets to +editor-closed, so a stale cross-session explicit reveal cannot carry over. A momentary width-based reveal +(e.g. a sash drag) is re-hidden by the same rule. The shared D3b/D9b new-session side-pane visibility state +is unchanged: once the user hides the side pane for a new session, it stays hidden for later new sessions. ### Scenario: a cramped (small) window On a small window there isn't room for the sessions sidebar, the editor, and the side pane all at once. @@ -256,13 +259,14 @@ and hands control back once the user reopens the sessions sidebar manually. collapsing an already editor-only state) just captures the resulting state, so an explicit aux-bar hide — including one whose editor-only state is restored when the pane re-opens — is never turned into a collapse. -- **Single-pane new-session rule [D11]** — `LayoutController` exposes - `_registerSinglePaneNewSessionRules` as a no-op hook. `SinglePaneDesktopSessionLayoutController` - overrides it with an `autorun` over the active session, multi-session state, and editor maximized - state; on entering an uncreated workspace session that is not a quick chat, it hides `EDITOR_PART` under - `suppressEditorPartAutoVisibility()` and remembers that session resource. The autorun does not read - editor visibility as an observable, so later editor reveals do not retrigger the hide. D3b continues to - open the Files container unless the shared new-session side-pane state says it is hidden. +- **Single-pane new-session rule [D11]** — `LayoutController` exposes `_registerNewSessionRules` as a + no-op hook. `SinglePaneDesktopSessionLayoutController` overrides it with an `autorun` over the active + session, multi-session state, editor maximized state, the active editor, and **the editor-part + visibility**; on an uncreated workspace session that is not a quick chat, it hides `EDITOR_PART` (under + `suppressEditorPartAutoVisibility()`) when the editor just became visible or the view was just entered + with the editor visible, tracking the previous editor-visible / in-new-session-view values across runs so + a mere active-editor change (e.g. switching to the Files placeholder) does not retrigger the hide. D3b + continues to open the Files container unless the shared new-session side-pane state says it is hidden. - **Responsive sidebar [D7]** — `_registerResponsiveSidebar` derives `spaceConstrained = enabled && small && editor visible && aux-bar visible && !multipleSessionsVisible` from the experimental setting `sessions.layout.autoCollapseSessionsSidebar` (`observableConfigValue`, default `product.quality !== diff --git a/src/vs/sessions/contrib/layout/test/browser/layoutControllerTestUtils.ts b/src/vs/sessions/contrib/layout/test/browser/layoutControllerTestUtils.ts index 4e4ff00052d..1b79287324f 100644 --- a/src/vs/sessions/contrib/layout/test/browser/layoutControllerTestUtils.ts +++ b/src/vs/sessions/contrib/layout/test/browser/layoutControllerTestUtils.ts @@ -10,7 +10,6 @@ import { constObservable, ISettableObservable, observableValue } from '../../../ import { URI } from '../../../../../base/common/uri.js'; import { isEqual } from '../../../../../base/common/resources.js'; import { mock } from '../../../../../base/test/common/mock.js'; -import { ICommandEvent, ICommandService } from '../../../../../platform/commands/common/commands.js'; import { Codicon } from '../../../../../base/common/codicons.js'; import { TestConfigurationService } from '../../../../../platform/configuration/test/common/testConfigurationService.js'; import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; @@ -161,7 +160,6 @@ export interface ITestLayoutHarness { onDidChangeEditorMaximized: Emitter; onDidActiveEditorChange: Emitter; onWillOpenEditor: Emitter; - onDidExecuteCommand: Emitter; onDidCloseEditor: Emitter<{ editor: EditorInput }>; onDidEditorsChange: Emitter; onDidLayoutMainContainer: Emitter; @@ -238,7 +236,6 @@ export function createTestHarness(store: DisposableStore, options: ICreateOption onDidChangeEditorMaximized: store.add(new Emitter()), onDidActiveEditorChange: store.add(new Emitter()), onWillOpenEditor: store.add(new Emitter()), - onDidExecuteCommand: store.add(new Emitter()), onDidCloseEditor: store.add(new Emitter<{ editor: EditorInput }>()), onDidEditorsChange: store.add(new Emitter()), onDidLayoutMainContainer: store.add(new Emitter()), @@ -307,9 +304,6 @@ export function createTestHarness(store: DisposableStore, options: ICreateOption instaService.stub(IChangesViewService, new class extends mock() { override setChangesetId(): void { } }); - instaService.stub(ICommandService, new class extends mock() { - override readonly onDidExecuteCommand = harness.onDidExecuteCommand.event; - }); instaService.stub(ILifecycleService, new class extends mock() { // Resolves only when a test opts in via `activateAux`, so the single-pane // managed-tab / detail-panel behaviour is not spun up otherwise.