From b8e55426e8f8ae7d82da23eb42f154b95d649801 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Fri, 6 Nov 2026 00:58:03 +0800 Subject: [PATCH] fix(editor): open the launched file when the window restores its last tabs Starting OpenIDEA with a file opened LightEdit (or the file's project) and showed the tabs of the last session without the file. Restoring the saved tabs replaced the tab state, which counted as the user activating another tab, so the pending open of the launched file was dropped as stale. Restoring a session no longer counts as an activation: the launched file opens next to the restored tabs and becomes the active one. --- 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); }