mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-08 08:08:16 -10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
418422547d |
No files matched your search
@@ -54,7 +54,7 @@ const { isJavaDebuggable, javaAttachConfig, javaLaunchConfig } = await import(".
|
||||
const app: RunConfig = {
|
||||
id: "application:a.Main",
|
||||
name: "Main",
|
||||
kind: "spring-boot",
|
||||
kind: "application",
|
||||
command: "java",
|
||||
args: ["-Xmx1g", "-cp", "${classpath}", "a.Main", "--port", "8081 x"],
|
||||
cwd: "api",
|
||||
@@ -93,6 +93,17 @@ describe("Java debugging (java-debug through jdtls)", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("debugs Spring Boot with coloured console output, as Run does", async () => {
|
||||
const boot = { ...app, kind: "spring-boot" };
|
||||
expect(JSON.parse((await javaLaunchConfig(boot, "/p")).extraJson!).vmArgs).toBe(
|
||||
"-Dspring.output.ansi.enabled=always -Xmx1g",
|
||||
);
|
||||
const own = { ...boot, args: ["-Dspring.output.ansi.enabled=never", ...app.args] };
|
||||
expect(JSON.parse((await javaLaunchConfig(own, "/p")).extraJson!).vmArgs).toBe(
|
||||
"-Dspring.output.ansi.enabled=never -Xmx1g",
|
||||
);
|
||||
});
|
||||
|
||||
it("passes the configuration's VM options to java-debug's vmArgs, before the main class", async () => {
|
||||
const args = [
|
||||
"-Ddemo.flag=on",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { executeAction } from "@/platform/actions";
|
||||
import { call, commands, IpcError, nextRequestId, type LaunchConfig, type RunConfig } from "@/platform/ipc";
|
||||
import {
|
||||
consoleVmArgs,
|
||||
formatCompileErrors,
|
||||
isJvmApplication,
|
||||
joinJavaArgs,
|
||||
@@ -117,7 +118,7 @@ export async function javaLaunchConfig(
|
||||
classPaths,
|
||||
modulePaths: info.modulePaths,
|
||||
javaExec: resolved.command,
|
||||
vmArguments: parsed.vmArgs,
|
||||
vmArguments: [...consoleVmArgs(rc), ...parsed.vmArgs],
|
||||
programArgs: parsed.programArgs,
|
||||
}),
|
||||
};
|
||||
@@ -139,7 +140,7 @@ export async function javaLaunchConfig(
|
||||
classPaths,
|
||||
modulePaths: info.modulePaths,
|
||||
javaExec: resolved.command === "java" ? undefined : resolved.command,
|
||||
vmArgs: joinJavaArgs(parsed.vmArgs),
|
||||
vmArgs: joinJavaArgs([...consoleVmArgs(rc), ...parsed.vmArgs]),
|
||||
args: joinJavaArgs(parsed.programArgs),
|
||||
// java-debug spawns the JVM itself: it must shorten a classpath too long for the OS the same way Run does.
|
||||
shortenCommandLine: info.shortenCommandLine ?? "none",
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useVirtualizer } from "@tanstack/react-virtual";
|
||||
import { copySelectionOnKeyDown } from "@/ui/selectableText";
|
||||
import { EmptyState, IconButton, showContextMenu, T, type MenuItem } from "@/ui";
|
||||
import { tx } from "@/platform/i18n";
|
||||
import { useWorkflowSettings } from "@/platform/workflowSettings";
|
||||
import { spanStyle } from "@/ui/ansi";
|
||||
import ansi from "@/ui/ansi.module.css";
|
||||
import { appendConsole, clearConsole, evaluate, isLive, useDebug, type DebugSession } from "../state";
|
||||
@@ -23,7 +24,14 @@ export function DebugServiceConsole({ sessionId }: { sessionId: number }) {
|
||||
export function DebugConsole({ session, interactive = true }: { session: DebugSession; interactive?: boolean }) {
|
||||
const lines = useDebug((s) => s.console[session.id]);
|
||||
const scroller = useRef<HTMLDivElement>(null);
|
||||
// Scroll to End: follows new output; scrolling up turns it off, back to the end turns it on.
|
||||
const [follow, setFollow] = useState(true);
|
||||
const stick = useRef(true);
|
||||
stick.current = follow;
|
||||
// Settings › Console › Use soft wraps is the default; the toggle overrides it for this console.
|
||||
const defaultWrap = useWorkflowSettings((s) => s.console.softWrap);
|
||||
const [wrapOverride, setWrapOverride] = useState<boolean | null>(null);
|
||||
const softWrap = wrapOverride ?? defaultWrap;
|
||||
const programmatic = useRef(false);
|
||||
const [input, setInput] = useState("");
|
||||
const history = useRef<string[]>(readHistory("console"));
|
||||
@@ -39,14 +47,21 @@ export function DebugConsole({ session, interactive = true }: { session: DebugSe
|
||||
getItemKey: (i) => lines?.[i]?.id ?? i,
|
||||
});
|
||||
|
||||
// Wrapping changes every row's height; the end is pinned again below.
|
||||
useLayoutEffect(() => virtualizer.measure?.(), [softWrap, virtualizer]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const el = scroller.current;
|
||||
if (!el || !stick.current || !lines?.length) return;
|
||||
programmatic.current = true;
|
||||
virtualizer.scrollToIndex(lines.length - 1, { align: "end" });
|
||||
el.scrollTop = el.scrollHeight;
|
||||
requestAnimationFrame(() => (programmatic.current = false));
|
||||
}, [lines, virtualizer]);
|
||||
// Rows measured after this frame grow the content: pin the end once more.
|
||||
requestAnimationFrame(() => {
|
||||
if (stick.current) el.scrollTop = el.scrollHeight;
|
||||
requestAnimationFrame(() => (programmatic.current = false));
|
||||
});
|
||||
}, [lines, virtualizer, follow, softWrap]);
|
||||
|
||||
const submit = async () => {
|
||||
const e = input.trim();
|
||||
@@ -101,11 +116,12 @@ export function DebugConsole({ session, interactive = true }: { session: DebugSe
|
||||
<div className={styles.console}>
|
||||
<div
|
||||
ref={scroller}
|
||||
className={clsx(styles.consoleOutput, ansi.palette)}
|
||||
className={clsx(styles.consoleOutput, ansi.palette, !softWrap && styles.noWrap)}
|
||||
onScroll={(e) => {
|
||||
if (programmatic.current) return;
|
||||
const el = e.currentTarget;
|
||||
stick.current = el.scrollHeight - el.scrollTop - el.clientHeight < 24;
|
||||
const atEnd = el.scrollHeight - el.scrollTop - el.clientHeight < 24;
|
||||
if (atEnd !== stick.current) setFollow(atEnd);
|
||||
}}
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
@@ -170,6 +186,22 @@ export function DebugConsole({ session, interactive = true }: { session: DebugSe
|
||||
{completion.popup}
|
||||
</>
|
||||
)}
|
||||
<IconButton
|
||||
icon="arrow-down"
|
||||
title="Scroll to End"
|
||||
size="small"
|
||||
iconSize={12}
|
||||
pressed={follow}
|
||||
onClick={() => setFollow((v) => !v)}
|
||||
/>
|
||||
<IconButton
|
||||
icon="soft-wrap"
|
||||
title="Soft-Wrap"
|
||||
size="small"
|
||||
iconSize={12}
|
||||
pressed={softWrap}
|
||||
onClick={() => setWrapOverride(!softWrap)}
|
||||
/>
|
||||
<IconButton
|
||||
icon="trash"
|
||||
title="Clear Console"
|
||||
|
||||
@@ -251,6 +251,12 @@
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
/* Soft-Wrap off: long lines scroll horizontally. */
|
||||
.noWrap {
|
||||
white-space: pre;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.out {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
||||
Reference in new issue
Block a user