diff --git a/src/features/run/java.test.ts b/src/features/run/java.test.ts index 3aae4705c..586f3f8cb 100644 --- a/src/features/run/java.test.ts +++ b/src/features/run/java.test.ts @@ -252,6 +252,21 @@ describe("java command lines", () => { ).toEqual(["--module-path", "/m/x.jar"]); }); + it("colours a Spring Boot console unless the configuration sets the property", () => { + const boot = (args: string[]) => ({ + ...applicationConfig({ className: "a.Main" }, "src/main/java/a/Main.java"), + kind: "spring-boot" as const, + args, + }); + expect(resolveJavaCommand(boot(["-Xmx1g", "a.Main"]), info).args[0]).toBe("-Dspring.output.ansi.enabled=always"); + expect(resolveJavaCommand(boot(["-Dspring.output.ansi.enabled=never", "a.Main"]), info).args).toEqual([ + "-Dspring.output.ansi.enabled=never", + "a.Main", + ]); + const plain = applicationConfig({ className: "a.Main" }, "src/main/java/a/Main.java"); + expect(resolveJavaCommand(plain, info).args).not.toContain("-Dspring.output.ansi.enabled=always"); + }); + it("joins arguments for java-debug and reads JDWP's port", () => { expect(joinJavaArgs(["a", "b c", 'q"'])).toBe('a "b c" "q\\""'); expect(jdwpListeningPort("Listening for transport dt_socket at address: 50123")).toBe(50123); diff --git a/src/platform/javaLaunch.ts b/src/platform/javaLaunch.ts index 91d9cf6d5..75c57eefb 100644 --- a/src/platform/javaLaunch.ts +++ b/src/platform/javaLaunch.ts @@ -71,10 +71,21 @@ export function parseJavaArgs(args: readonly string[]): JavaCommandLine { return { vmArgs, mainClass: null, programArgs: [], classpath, explicitClasspath }; } +/** + * VM options a launch adds for the console, as IDEA's Spring Boot configurations do: the + * console renders ANSI colours, but Spring only detects a terminal, and the process runs on pipes. + * Kept out when the configuration sets the property itself. + */ +export function consoleVmArgs(config: Pick): string[] { + if (config.kind !== "spring-boot") return []; + const own = parseJavaArgs(config.args).vmArgs.some((a) => a.startsWith("-Dspring.output.ansi.enabled=")); + return own ? [] : ["-Dspring.output.ansi.enabled=always"]; +} + /** The configuration with its placeholders and launcher resolved. */ export function resolveJavaCommand(config: RunConfig, info: JavaLaunchInfo): RunConfig { const cp = info.classPaths.join(info.pathListSeparator); - const args: string[] = []; + const args: string[] = [...consoleVmArgs(config)]; if (info.modulePaths.length && !config.args.some((a) => a === "-p" || a === "--module-path")) args.push("--module-path", info.modulePaths.join(info.pathListSeparator)); args.push(...config.args.map((a) => (a === CLASSPATH || a === TEST_CLASSPATH ? cp : a)));