feat(run): reuse the configuration of a main class run from its context (#783)

Running or debugging a main class from the editor, gutter or Project view now selects an existing saved Application or Spring Boot configuration of the same main class and module, keeping its VM options, environment and profiles, instead of creating a temporary one.

Co-authored-by: ntbang0901 <121003585+ntbang0901@users.noreply.github.com>
This commit is contained in:
ntbang0901
2026-11-02 14:57:15 +08:00
committed by GitHub
parent 47f68862c8
commit a8e12ff7c4
2 changed files with 30 additions and 1 deletions
+19
View File
@@ -395,6 +395,25 @@ describe("temporary configurations", () => {
expect(useRun.getState().temporary).toEqual([]);
});
it("reuse a configuration of the same main class and module, whatever its id", () => {
const own = (module: string) =>
cfg({
id: `user:${module}`,
kind: "spring-boot",
name: `Mine ${module}`,
args: ["-Xmx1g", "-cp", "${classpath}", "a.Main"],
module,
detected: false,
});
useRun.setState({ configs: [own("other"), own("app")] });
expect(adoptTemporary(applicationConfig({ className: "a.Main" }, "app/src/main/java/a/Main.java")).name).toBe(
"Mine app",
);
expect(useRun.getState().temporary).toEqual([]);
const fresh = adoptTemporary(applicationConfig({ className: "a.Other" }, "app/src/main/java/a/Other.java"));
expect(useRun.getState().temporary).toEqual([fresh.id]);
});
it("offer Save in the chooser while selected", async () => {
const app = adoptTemporary(applicationConfig({ className: "a.Main" }, "src/main/java/a/Main.java"));
const { configs, temporary } = useRun.getState();
+11 -1
View File
@@ -256,6 +256,13 @@ function persistTemporary() {
);
}
/** IDEA's `isConfigurationFromContext` for an Application: the same main class of the same module. */
function sameApplication(a: RunConfig, b: RunConfig): boolean {
if (!isJvmApplication(a) || !isJvmApplication(b)) return false;
const main = parseJavaArgs(a.args).mainClass;
return main !== null && main === parseJavaArgs(b.args).mainClass && (a.module ?? a.cwd) === (b.module ?? b.cwd);
}
/**
* Selects the configuration for a gutter / context run: a saved or detected
* configuration with the same id is reused, otherwise `config` becomes a
@@ -263,7 +270,10 @@ function persistTemporary() {
*/
export function adoptTemporary(config: RunConfig): RunConfig {
const state = useRun.getState();
const existing = state.configs.find((c) => c.id === config.id);
// IDEA's `findExistingConfiguration`: a configuration the user keeps for this context wins.
const existing =
state.configs.find((c) => c.id === config.id) ??
state.configs.find((c) => !state.temporary.includes(c.id) && sameApplication(c, config));
if (existing && !state.temporary.includes(config.id)) {
selectConfig(existing.id);
return existing;