From f68d8f499a25d3089b787b4046d3744d91caa308 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Fri, 6 Nov 2026 00:58:18 +0800 Subject: [PATCH] fix(editor): open the launched file when the window restores its last tabs (#1594) Starting OpenIDEA with a file showed the last session's tabs without the file: restoring the saved tabs counted as the user activating another tab, so the pending open of the launched file was dropped as superseded. Restoring a session no longer counts as an activation; the launched file opens next to the restored tabs and becomes active (also for a file opened with its project at startup). --- src/editor/core/controller.test.ts | 18 ++++++++++++++++++ src/editor/core/controller.ts | 10 +++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/editor/core/controller.test.ts b/src/editor/core/controller.test.ts index 09cb1b05..5724c122 100644 --- a/src/editor/core/controller.test.ts +++ b/src/editor/core/controller.test.ts @@ -262,6 +262,24 @@ describe("EditorController", () => { useProject.setState({ lightEdit: false }); }); + it("opens a file requested while the LightEdit session is being restored", async () => { + ctrl = new EditorController(createMemoryBackend({ "/x/a.txt": "a", "/y/b.md": "b", "/z/launch.lua": "l" })); + ctrl.start(); + useProject.setState({ lightEdit: true }); + await ctrl.openFile("/x/a.txt", { focus: false }); + await ctrl.openFile("/y/b.md", { focus: false }); + useProject.setState({ lightEdit: false }); + // A launch with a file path: LightEdit starts and the file opens before the old tabs are back. + useProject.setState({ lightEdit: true }); + await ctrl.openFile("/z/launch.lua", { focus: false }); + expect(openFilePaths(useTabs.getState())).toEqual(["/x/a.txt", "/y/b.md", "/z/launch.lua"]); + const s = useTabs.getState(); + const active = s.panes[s.activePane]!; + expect(active.tabs.find((t) => t.id === active.active)?.input.path).toBe("/z/launch.lua"); + await ctrl.closeEverything(); + useProject.setState({ lightEdit: false }); + }); + it("closes a tab by its input key", async () => { ctrl = new EditorController(createMemoryBackend()); ctrl.start(); diff --git a/src/editor/core/controller.ts b/src/editor/core/controller.ts index 6faa65f5..a883e509 100644 --- a/src/editor/core/controller.ts +++ b/src/editor/core/controller.ts @@ -237,6 +237,8 @@ export class EditorController implements SlotHost { private selectionRequests = new Map(); private activationGeneration = 0; private admitting = false; + /** Tabs restored from a saved session: not a user's activation, so a pending open still activates its tab. */ + private restoring = false; private closeRequests = 0; private projectTransition: Promise = Promise.resolve(); @@ -269,6 +271,7 @@ export class EditorController implements SlotHost { prevTabs = s; if ( !this.admitting && + !this.restoring && (s.activePane !== prev.activePane || s.panes[s.activePane]?.active !== prev.panes[prev.activePane]?.active) ) ++this.activationGeneration; @@ -486,7 +489,12 @@ export class EditorController implements SlotHost { pane.tabs = pane.tabs.map((tab) => (documentLifecycle(tab.input, kinds) ? { ...tab, preview: false } : tab)); this.restoredViews = new Map(Object.entries(session.files)); this.restoredTabs = new Set(Object.values(state.panes).flatMap((p) => p.tabs.map((t) => t.id))); - useTabs.setState(state, true); + this.restoring = true; + try { + useTabs.setState(state, true); + } finally { + this.restoring = false; + } for (const pane of Object.values(state.panes)) if (pane.active) void this.ensureSlot(pane.active); }