feat(run): Add VM options to Java run configurations (#206)

Adds Application and Spring Boot run configuration types with main class, VM options, program arguments, classpath and active profiles. Maven passes them through spring-boot.run.jvmArguments / profiles / argLine; Gradle through an init script.

Fixes #187

Claude-Session: https://claude.ai/code/session_01Dq6jQQn8ZhRfkkyj3PRutA
Цей коміт міститься в:
l0ng-ai authored and GitHub committed 2026-10-29 11:39:20 +08:00
1 джерело ed7b0f88ef
коміт 8ebeaa2663
15 files changed
+690 -8

No files matched your search

+2
Переглянути файл
@@ -515,6 +515,8 @@ export const commands = {
runCloseStdin: (id: RunId) => typedError<null, IdeError>(__TAURI_INVOKE("run_close_stdin", { id })),
/** Terminal size of a run started with "Emulate terminal in output console". */
runResize: (id: RunId, cols: number, rows: number) => typedError<null, IdeError>(__TAURI_INVOKE("run_resize", { id, cols, rows })),
/** Writes the Gradle init script adding `jvm_args` to the JVMs the build forks; returns its path. */
runGradleJvmArgsScript: (jvmArgs: string[]) => typedError<string, IdeError>(__TAURI_INVOKE("run_gradle_jvm_args_script", { jvmArgs })),
/**
* Results from the JUnit XML reports (Surefire, Failsafe, Gradle) of the module at
* `module` (relative to the project root) written since `since_ms` (Unix epoch, ms).
+17
Переглянути файл
@@ -75,6 +75,23 @@ describe("Java debugging (java-debug through jdtls)", () => {
});
});
it("passes the configuration's VM options to java-debug's vmArgs, before the main class", async () => {
const args = [
"-Ddemo.flag=on",
"--add-opens",
"java.base/java.lang=ALL-UNNAMED",
"-Dname=a b",
"-cp",
"${classpath}",
];
const l = await javaLaunchConfig({ ...app, args: [...args, "a.App", "--spring.profiles.active=dev"] }, "/p");
expect(JSON.parse(l.extraJson!)).toMatchObject({
mainClass: "a.App",
vmArgs: '-Ddemo.flag=on --add-opens java.base/java.lang=ALL-UNNAMED "-Dname=a b"',
args: "--spring.profiles.active=dev",
});
});
it("lets java-debug shorten a classpath too long for the OS, as Run does", async () => {
for (const how of ["jarmanifest", "argfile"]) {
shortenCommandLine = how;
+1 -1
Переглянути файл
@@ -648,7 +648,7 @@ function TypeField({
spellCheck={false}
value={value}
placeholder={tx(field.placeholder)}
rows={4}
rows={field.rows ?? 4}
onChange={(e) => onChange(e.target.value)}
/>
);
+12 -4
Переглянути файл
@@ -258,8 +258,11 @@ export function validateConfig(config: RunConfig, all: readonly RunConfig[] = []
export const hasErrors = (e: ConfigErrors) => Object.keys(e).length > 0;
/** Splits a command line into arguments: whitespace, '…' and "…" quoting, backslash escapes. */
export function parseArgs(input: string): string[] {
/**
* Splits a command line into arguments: whitespace, '…' and "…" quoting, backslash escapes.
* `windowsPaths`: a backslash only escapes a quote, so `C:\dir\app.jar` stays as typed.
*/
export function parseArgs(input: string, windowsPaths = false): string[] {
const out: string[] = [];
let cur = "";
let has = false;
@@ -268,13 +271,18 @@ export function parseArgs(input: string): string[] {
const ch = input[i]!;
if (quote) {
if (ch === quote) quote = null;
else if (ch === "\\" && quote === '"' && i + 1 < input.length && '"\\$`'.includes(input[i + 1]!))
else if (
ch === "\\" &&
quote === '"' &&
i + 1 < input.length &&
(windowsPaths ? '"' : '"\\$`').includes(input[i + 1]!)
)
cur += input[++i];
else cur += ch;
} else if (ch === "'" || ch === '"') {
quote = ch;
has = true;
} else if (ch === "\\" && i + 1 < input.length) {
} else if (ch === "\\" && i + 1 < input.length && (!windowsPaths || "\"'".includes(input[i + 1]!))) {
cur += input[++i];
has = true;
} else if (/\s/.test(ch)) {
+249
Переглянути файл
@@ -0,0 +1,249 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { RunConfig } from "@/platform/ipc";
const scripts: string[][] = [];
vi.mock("@/platform/ipc", async (orig) => {
const real = await orig<typeof import("@/platform/ipc")>();
return {
...real,
commands: {
...real.commands,
runGradleJvmArgsScript: (jvmArgs: string[]) => {
scripts.push(jvmArgs);
return Promise.resolve({ status: "ok", data: "/tmp/openidea-gradle/jvm-args-1.init.gradle" });
},
},
};
});
const { parseJavaArgs, joinJavaArgs } = await import("@/platform/javaLaunch");
const { parseArgs } = await import("./configs");
const { jdwpLaunch } = await import("./javaDebug");
const { applicationType, gradleJvmArgs, joinPropertyArgs, springBootType } = await import("./jvmTypes");
const { formParams, newConfigOfType, registerBuiltinTypes, typeFor, withParams } = await import("./types");
const REPORTER_VM = "-Ddemo.flag=on --add-opens java.base/java.lang=ALL-UNNAMED";
const cfg = (over: Partial<RunConfig>): RunConfig => ({
id: "c",
name: "c",
kind: "spring-boot",
command: "java",
args: [],
cwd: null,
env: {},
detected: false,
isTest: false,
debugAdapter: "java-debug",
...over,
});
let dispose: () => void;
beforeEach(() => {
dispose = registerBuiltinTypes();
scripts.length = 0;
});
afterEach(() => dispose());
describe("Application / Spring Boot command line", () => {
it.each([
["application", applicationType],
["spring-boot", springBootType],
] as const)("%s puts VM options before the main class and program arguments after it", (_, type) => {
const line = type.commandLine({
mainClass: "com.example.Application",
vmOptions: REPORTER_VM,
programArgs: "--server.port=8081 'two words'",
classpath: "${classpath}",
});
expect(line).toEqual({
command: "java",
args: [
"-Ddemo.flag=on",
"--add-opens",
"java.base/java.lang=ALL-UNNAMED",
"-cp",
"${classpath}",
"com.example.Application",
"--server.port=8081",
"two words",
],
});
const parsed = parseJavaArgs(line!.args);
expect(parsed.vmArgs).toEqual(["-Ddemo.flag=on", "--add-opens", "java.base/java.lang=ALL-UNNAMED"]);
expect(parsed.mainClass).toBe("com.example.Application");
expect(parsed.programArgs).toEqual(["--server.port=8081", "two words"]);
});
it("reads VM options over several lines and with quoted spaces", () => {
const line = applicationType.commandLine({
mainClass: "a.Main",
vmOptions: '-Xmx1g\n-Dapp.name="My App"\n -Dempty=""',
});
expect(line!.args.slice(0, 3)).toEqual(["-Xmx1g", "-Dapp.name=My App", "-Dempty="]);
expect(joinJavaArgs(parseJavaArgs(line!.args).vmArgs)).toBe('-Xmx1g "-Dapp.name=My App" -Dempty=');
});
it("keeps Windows paths as typed on Windows", () => {
expect(parseArgs(String.raw`-javaagent:C:\tools\agent.jar "-Dlog=C:\Program Files\x.log"`, true)).toEqual([
String.raw`-javaagent:C:\tools\agent.jar`,
String.raw`-Dlog=C:\Program Files\x.log`,
]);
expect(parseArgs(String.raw`-Dq=\"x\" "a \"b\""`, true)).toEqual(['-Dq="x"', 'a "b"']);
// Elsewhere a backslash still escapes.
expect(parseArgs(String.raw`a\ b`)).toEqual(["a b"]);
});
it("passes Spring Boot's active profiles before the program arguments", () => {
const line = springBootType.commandLine({ mainClass: "a.App", activeProfiles: "dev,local", programArgs: "--x" });
expect(line!.args).toEqual(["-cp", "${classpath}", "a.App", "--spring.profiles.active=dev,local", "--x"]);
// Application has no profiles field.
expect(applicationType.commandLine({ mainClass: "a.App", activeProfiles: "dev" })!.args).toEqual([
"-cp",
"${classpath}",
"a.App",
]);
});
it("uses the test classpath when chosen", () => {
expect(applicationType.commandLine({ mainClass: "a.T", classpath: "${testClasspath}" })!.args).toEqual([
"-cp",
"${testClasspath}",
"a.T",
]);
});
});
describe("configurations saved or detected as a raw command line", () => {
it("opens a detected Spring Boot configuration in the form", () => {
const detected = cfg({ args: ["-cp", "${classpath}", "com.example.DemoApplication"], detected: true });
expect(formParams(detected)).toEqual({
mainClass: "com.example.DemoApplication",
vmOptions: "",
programArgs: "",
classpath: "${classpath}",
});
});
it("splits an older configuration's arguments into VM options, main class, profiles and program arguments", () => {
const old = cfg({
args: ["-Xmx1g", "-Dname=a b", "-cp", "${classpath}", "a.App", "--spring.profiles.active=dev", "x y"],
});
const params = formParams(old);
expect(params).toEqual({
mainClass: "a.App",
vmOptions: "-Xmx1g '-Dname=a b'",
programArgs: "'x y'",
classpath: "${classpath}",
activeProfiles: "dev",
});
// Editing VM options keeps the rest of the command line.
const next = withParams(old, { ...params!, vmOptions: REPORTER_VM });
expect(next.args).toEqual([
"-Ddemo.flag=on",
"--add-opens",
"java.base/java.lang=ALL-UNNAMED",
"-cp",
"${classpath}",
"a.App",
"--spring.profiles.active=dev",
"x y",
]);
expect(next.params).toMatchObject({ vmOptions: REPORTER_VM });
});
it("keeps an explicit classpath and edits other command lines as a command", () => {
expect(formParams(cfg({ kind: "application", args: ["-cp", "lib/*", "a.Main"] }))).toMatchObject({
classpath: "lib/*",
});
expect(formParams(cfg({ command: "./run.sh", args: ["a.Main"] }))).toBeNull();
expect(formParams(cfg({ args: ["a.Main"] }))).toBeNull();
});
it("prefers the stored params", () => {
const c = cfg({
params: { mainClass: "a.App", vmOptions: "-Xss2m" },
args: ["-Xss2m", "-cp", "${classpath}", "a.App"],
});
expect(formParams(c)).toEqual({ mainClass: "a.App", vmOptions: "-Xss2m" });
});
});
describe("templates", () => {
it("applies the template's VM options to a new configuration", () => {
const template = cfg({ id: "template:spring-boot", params: { classpath: "${classpath}", vmOptions: "-Xmx512m" } });
const c = newConfigOfType(springBootType, [], template);
expect(c.kind).toBe("spring-boot");
expect(c.debugAdapter).toBe("java-debug");
expect(c.params).toMatchObject({ vmOptions: "-Xmx512m" });
expect(c.args).toEqual(["-Xmx512m", "-cp", "${classpath}"]);
});
});
describe("Maven / Gradle: VM options of the forked JVM", () => {
const maven = () => typeFor("maven")!;
const gradle = () => typeFor("gradle")!;
it("passes spring-boot:run's VM options and profiles to the application, not to Maven", () => {
const line = maven().commandLine({
tasks: "spring-boot:run",
vmOptions: REPORTER_VM + " '-Dname=a b'",
activeProfiles: "dev",
});
expect(line!.args).toEqual([
"spring-boot:run",
`-Dspring-boot.run.jvmArguments=-Ddemo.flag=on --add-opens java.base/java.lang=ALL-UNNAMED "-Dname=a b"`,
"-Dspring-boot.run.profiles=dev",
]);
// Debugging adds the JDWP agent to the same property.
const debug = jdwpLaunch(cfg({ kind: "maven", command: "mvn", args: line!.args }));
expect(debug!.args[1]).toMatch(/^-Dspring-boot\.run\.jvmArguments=-Ddemo\.flag=on .* -agentlib:jdwp=/);
});
it("passes test goals' VM options to Surefire and nothing for other goals", () => {
expect(maven().commandLine({ tasks: "test", vmOptions: "-Xmx1g" })!.args).toEqual(["test", "-DargLine=-Xmx1g"]);
expect(maven().commandLine({ tasks: "package", vmOptions: "-Xmx1g" })!.args).toEqual(["package"]);
const vm = maven().fields.find((f) => f.key === "vmOptions")!;
expect(vm.visible!({ tasks: "clean spring-boot:run" })).toBe(true);
expect(vm.visible!({ tasks: "package" })).toBe(false);
});
it("quotes property values the plugins split", () => {
expect(joinPropertyArgs(["-Xmx1g", "-Dp=C:\\Program Files\\x", 'say "hi"', ""])).toBe(
`-Xmx1g "-Dp=C:\\Program Files\\x" 'say "hi"' ""`,
);
});
it("hands Gradle's VM options to an init script for the forked JVMs", async () => {
const params = { tasks: "bootRun", vmOptions: REPORTER_VM, activeProfiles: "dev", wrapper: "true" };
expect(gradleJvmArgs(params)).toEqual([
"-Ddemo.flag=on",
"--add-opens",
"java.base/java.lang=ALL-UNNAMED",
"-Dspring.profiles.active=dev",
]);
expect(gradleJvmArgs({ tasks: "build", vmOptions: "-Xmx1g" })).toEqual([]);
const c = withParams(cfg({ kind: "gradle" }), params);
// Gradle's own command line is unchanged.
expect(c.args).toEqual(["bootRun"]);
const launched = await gradle().prepareLaunch!(c);
expect(scripts).toEqual([gradleJvmArgs(params)]);
expect(launched.args).toEqual(["--init-script", "/tmp/openidea-gradle/jvm-args-1.init.gradle", "bootRun"]);
// Debugging keeps them: `--debug-jvm` is added before the launch is prepared.
const debug = await gradle().prepareLaunch!(jdwpLaunch(c)!);
expect(debug.args).toEqual([
"--init-script",
"/tmp/openidea-gradle/jvm-args-1.init.gradle",
"bootRun",
"--debug-jvm",
]);
});
it("leaves Gradle configurations without VM options alone", async () => {
const c = withParams(cfg({ kind: "gradle" }), { tasks: "bootRun" });
expect(await gradle().prepareLaunch!(c)).toBe(c);
expect(scripts).toEqual([]);
const remote = withParams(cfg({ kind: "gradle", target: "ssh-1" }), { tasks: "bootRun", vmOptions: "-Xmx1g" });
await expect(gradle().prepareLaunch!(remote)).rejects.toThrow(/run targets/);
});
});
+206
Переглянути файл
@@ -0,0 +1,206 @@
/**
* JVM run configuration types: Application and Spring Boot
* (`java [VM options] -cp ${classpath} <main class> [program arguments]`), and the
* VM options Maven / Gradle configurations hand to the JVM the build forks
* (`spring-boot:run`, tests, `bootRun`) rather than to the build tool's own JVM.
*/
import { call, commands, type RunConfig } from "@/platform/ipc";
import { CLASSPATH, parseJavaArgs, TEST_CLASSPATH } from "@/platform/javaLaunch";
import type { RunConfigTypeContribution, RunConfigTypeField } from "@/workbench/contributions";
import { formatArgs, parseArgs } from "./configs";
export const isWindows = () => typeof navigator !== "undefined" && /win/i.test(navigator.platform);
/** VM options / program arguments as typed; on Windows a backslash is a path separator. */
export const splitJvmArgs = (text: string | undefined, windows = isWindows()) => parseArgs(text ?? "", windows);
export const PROFILES_ARG = "--spring.profiles.active=";
const VM_OPTIONS_PLACEHOLDER = "e.g. -Xmx1g -Dkey=value --add-opens java.base/java.lang=ALL-UNNAMED";
const vmOptionsField = (hint?: string, visible?: RunConfigTypeField["visible"]): RunConfigTypeField => ({
key: "vmOptions",
label: "VM options",
control: "textarea",
rows: 2,
mono: true,
placeholder: VM_OPTIONS_PLACEHOLDER,
...(hint ? { hint } : {}),
...(visible ? { visible } : {}),
});
const profilesField = (hint: string, visible?: RunConfigTypeField["visible"]): RunConfigTypeField => ({
key: "activeProfiles",
label: "Active profiles",
mono: true,
placeholder: "e.g. dev,local",
hint,
...(visible ? { visible } : {}),
});
const isJava = (command: string) => /^java(\.exe)?$/i.test(command.replace(/\\/g, "/").split("/").pop() ?? "");
/** Main classes of the JVM configurations, offered while typing. */
function mainClasses(configs: readonly RunConfig[]): string[] {
const out = new Set<string>();
for (const c of configs) {
if (c.kind !== "application" && c.kind !== "spring-boot") continue;
const main = c.params?.mainClass || parseJavaArgs(c.args).mainClass;
if (main) out.add(main);
}
return [...out];
}
function jvmApplicationType(spring: boolean): RunConfigTypeContribution {
return {
id: spring ? "spring-boot" : "application",
label: spring ? "Spring Boot" : "Application",
icon: spring ? "spring-boot" : "class",
description: spring ? "Run a Spring Boot application" : "Run a Java main class",
defaults: { classpath: CLASSPATH },
debugAdapter: "java-debug",
fields: [
{
key: "mainClass",
label: "Main class",
mono: true,
required: true,
placeholder: "e.g. com.example.Application",
suggestions: mainClasses,
},
vmOptionsField(),
{ key: "programArgs", label: "Program arguments", mono: true },
...(spring ? [profilesField("Comma separated; passed as --spring.profiles.active")] : []),
{
key: "classpath",
label: "Classpath",
control: "select",
options: [
{ value: CLASSPATH, label: "Runtime classpath of the module" },
{ value: TEST_CLASSPATH, label: "Test classpath of the module" },
],
},
],
commandLine(p) {
const main = p.mainClass?.trim() ?? "";
const profiles = spring ? (p.activeProfiles?.trim() ?? "") : "";
return {
command: "java",
args: [
...splitJvmArgs(p.vmOptions),
"-cp",
p.classpath || CLASSPATH,
...(main ? [main] : []),
...(profiles ? [PROFILES_ARG + profiles] : []),
...splitJvmArgs(p.programArgs),
],
};
},
// Configurations detected or saved before these fields existed: `java [vm] -cp <cp> Main [args]`.
paramsFrom(c) {
if (!isJava(c.command)) return null;
const parsed = parseJavaArgs(c.args);
const classpath =
parsed.classpath === "runtime"
? CLASSPATH
: parsed.classpath === "test"
? TEST_CLASSPATH
: parsed.explicitClasspath;
if (!parsed.mainClass || classpath === null) return null;
let rest = parsed.programArgs;
let activeProfiles = "";
if (spring && rest[0]?.startsWith(PROFILES_ARG)) {
activeProfiles = rest[0].slice(PROFILES_ARG.length);
rest = rest.slice(1);
}
return {
mainClass: parsed.mainClass,
vmOptions: formatArgs(parsed.vmArgs),
programArgs: formatArgs(rest),
classpath,
...(activeProfiles ? { activeProfiles } : {}),
};
},
};
}
export const applicationType = jvmApplicationType(false);
export const springBootType = jvmApplicationType(true);
/**
* One value for a Maven property holding JVM arguments (`spring-boot.run.jvmArguments`,
* `argLine`): the plugins split it on whitespace, honouring "…" and '…'.
*/
export function joinPropertyArgs(args: readonly string[]): string {
return args
.map((a) => {
if (a && !/[\s"']/.test(a)) return a;
return a.includes('"') ? `'${a}'` : `"${a}"`;
})
.join(" ");
}
const words = (tasks: string | undefined) => (tasks ?? "").split(/\s+/).filter(Boolean);
const isSpringBootRun = (goal: string) =>
goal === "spring-boot:run" || /:spring-boot-maven-plugin:[^:]*:run$/.test(goal);
const isMavenTestGoal = (goal: string) =>
/^(test|verify|integration-test|surefire:test|failsafe:integration-test)$/.test(goal);
const isBootRun = (task: string) => /(^|:)bootRun$/.test(task);
const isGradleJvmTask = (task: string) => /(^|:)(test|bootRun|run|integrationTest|check)$/.test(task);
/** What a build tool configuration does with VM options and Spring Boot profiles. */
export interface ForkedJvm {
fields: readonly RunConfigTypeField[];
/** Arguments appended to the build tool's command line. */
args(params: Readonly<Record<string, string>>): string[];
prepareLaunch?(config: RunConfig): Promise<RunConfig>;
}
export const mavenForkedJvm: ForkedJvm = {
fields: [
vmOptionsField("Passed to the JVM that spring-boot:run or the tests start, not to Maven", (p) =>
words(p.tasks).some((g) => isSpringBootRun(g) || isMavenTestGoal(g)),
),
profilesField("Comma separated; passed as -Dspring-boot.run.profiles", (p) => words(p.tasks).some(isSpringBootRun)),
],
args(p) {
const goals = words(p.tasks);
const vm = splitJvmArgs(p.vmOptions);
const out: string[] = [];
if (goals.some(isSpringBootRun)) {
if (vm.length) out.push(`-Dspring-boot.run.jvmArguments=${joinPropertyArgs(vm)}`);
const profiles = p.activeProfiles?.trim();
if (profiles) out.push(`-Dspring-boot.run.profiles=${profiles}`);
} else if (vm.length && goals.some(isMavenTestGoal)) {
out.push(`-DargLine=${joinPropertyArgs(vm)}`);
}
return out;
},
};
/** VM options (and profiles, as `-Dspring.profiles.active`) of a Gradle configuration's forked JVMs. */
export function gradleJvmArgs(p: Readonly<Record<string, string>>): string[] {
const tasks = words(p.tasks);
if (!tasks.some(isGradleJvmTask)) return [];
const profiles = tasks.some(isBootRun) ? p.activeProfiles?.trim() : "";
return [...splitJvmArgs(p.vmOptions), ...(profiles ? [`-Dspring.profiles.active=${profiles}`] : [])];
}
export const gradleForkedJvm: ForkedJvm = {
fields: [
vmOptionsField("Passed to the JVMs the tasks start (bootRun, run, test), not to Gradle", (p) =>
words(p.tasks).some(isGradleJvmTask),
),
profilesField("Comma separated; passed as -Dspring.profiles.active", (p) => words(p.tasks).some(isBootRun)),
],
// Gradle has no command-line switch for them: an init script adds them to the JavaExec / Test tasks.
args: () => [],
async prepareLaunch(config) {
const jvmArgs = gradleJvmArgs(config.params ?? {});
if (!jvmArgs.length) return config;
if (config.target) throw new Error("VM options of Gradle configurations are not applied on run targets");
const script = await call(commands.runGradleJvmArgsScript(jvmArgs));
return { ...config, args: ["--init-script", script, ...config.args] };
},
};
+17 -3
Переглянути файл
@@ -1,6 +1,6 @@
/**
* Built-in run configuration types (Shell Script, Program, npm, Gradle, Maven,
* Compound) and the helpers that turn a type's params into the launched
* Application, Spring Boot, Compound) and the helpers that turn a type's params into the launched
* command line. Other features contribute types with `registerRunConfigType`.
*/
import type { RunConfig } from "@/platform/ipc";
@@ -11,11 +11,18 @@ import {
type RunConfigTypeContribution,
} from "@/workbench/contributions";
import { formatArgs, parseArgs, uid, uniqueName } from "./configs";
import {
applicationType,
gradleForkedJvm,
isWindows,
mavenForkedJvm,
springBootType,
type ForkedJvm,
} from "./jvmTypes";
import { tx } from "@/platform/i18n";
export const COMPOUND = "compound";
const isWindows = () => typeof navigator !== "undefined" && /win/i.test(navigator.platform);
const on = (v: string | undefined) => v === "true";
const baseName = (p: string) => p.replace(/\\/g, "/").split("/").pop() ?? p;
const dirOf = (cwd: string | null | undefined) => cwd ?? "";
@@ -213,6 +220,7 @@ function buildToolType(
icon: string,
tasks: { label: string; description: string },
wrapper: { unix: string; windows: string; plain: string; label: string; byDefault: boolean },
jvm: ForkedJvm,
): RunConfigTypeContribution {
return {
id,
@@ -231,13 +239,15 @@ function buildToolType(
suggestions: (configs) => argsOf(configs, id, 0),
},
{ key: "arguments", label: "Arguments", mono: true },
...jvm.fields,
{ key: "wrapper", label: wrapper.label, control: "checkbox" },
],
commandLine: (p) => ({
command: wrapperCommand(wrapper.unix, wrapper.windows, wrapper.plain, on(p.wrapper)),
args: [...parseArgs(p.tasks ?? ""), ...parseArgs(p.arguments ?? "")],
args: [...parseArgs(p.tasks ?? ""), ...parseArgs(p.arguments ?? ""), ...jvm.args(p)],
cwd: p.projectDir?.trim() || null,
}),
...(jvm.prepareLaunch ? { prepareLaunch: jvm.prepareLaunch } : {}),
paramsFrom(c) {
const name = baseName(c.command);
const usesWrapper = name === wrapper.unix || name === wrapper.windows;
@@ -264,6 +274,7 @@ const gradle = buildToolType(
label: "Use the Gradle wrapper",
byDefault: true,
},
gradleForkedJvm,
);
const maven = buildToolType(
@@ -278,6 +289,7 @@ const maven = buildToolType(
label: "Use the Maven wrapper",
byDefault: false,
},
mavenForkedJvm,
);
const compound: RunConfigTypeContribution = {
@@ -296,6 +308,8 @@ export const BUILTIN_TYPES: readonly RunConfigTypeContribution[] = [
gradle,
maven,
godot,
applicationType,
springBootType,
compound,
];
+17
Переглянути файл
@@ -2828,6 +2828,23 @@
"Executable": "可执行文件",
"Path or command on PATH": "路径或 PATH 中的命令",
"Program arguments": "程序实参",
"VM options": "VM 选项",
"e.g. -Xmx1g -Dkey=value --add-opens java.base/java.lang=ALL-UNNAMED": "例如 -Xmx1g -Dkey=value --add-opens java.base/java.lang=ALL-UNNAMED",
"Main class": "主类",
"e.g. com.example.Application": "例如 com.example.Application",
"Active profiles": "活动配置文件",
"e.g. dev,local": "例如 dev,local",
"Comma separated; passed as --spring.profiles.active": "以逗号分隔;作为 --spring.profiles.active 传递",
"Comma separated; passed as -Dspring-boot.run.profiles": "以逗号分隔;作为 -Dspring-boot.run.profiles 传递",
"Comma separated; passed as -Dspring.profiles.active": "以逗号分隔;作为 -Dspring.profiles.active 传递",
"Classpath": "类路径",
"Runtime classpath of the module": "模块的运行时类路径",
"Test classpath of the module": "模块的测试类路径",
"Run a Java main class": "运行 Java 主类",
"Run a Spring Boot application": "运行 Spring Boot 应用程序",
"Spring Boot": "Spring Boot",
"Passed to the JVM that spring-boot:run or the tests start, not to Maven": "传给 spring-boot:run 或测试启动的 JVM,而不是 Maven 本身",
"Passed to the JVMs the tasks start (bootRun, run, test), not to Gradle": "传给任务启动的 JVM(bootRun、run、test),而不是 Gradle 本身",
"Run a package.json script": "运行 package.json 脚本",
"package.json directory": "package.json 目录",
"Tasks": "任务",
+2
Переглянути файл
@@ -886,6 +886,8 @@ export interface RunConfigTypeField {
*/
control?: "text" | "textarea" | "select" | "checkbox" | "output";
mono?: boolean;
/** Visible lines of a `textarea` (default 4). */
rows?: number;
placeholder?: string;
options?: ReadonlyArray<{ value: string; label: string }>;
/** Values offered while typing (e.g. the scripts of detected configurations). */