mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-13 04:34:21 -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 = {
|
const app: RunConfig = {
|
||||||
id: "application:a.Main",
|
id: "application:a.Main",
|
||||||
name: "Main",
|
name: "Main",
|
||||||
kind: "spring-boot",
|
kind: "application",
|
||||||
command: "java",
|
command: "java",
|
||||||
args: ["-Xmx1g", "-cp", "${classpath}", "a.Main", "--port", "8081 x"],
|
args: ["-Xmx1g", "-cp", "${classpath}", "a.Main", "--port", "8081 x"],
|
||||||
cwd: "api",
|
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 () => {
|
it("passes the configuration's VM options to java-debug's vmArgs, before the main class", async () => {
|
||||||
const args = [
|
const args = [
|
||||||
"-Ddemo.flag=on",
|
"-Ddemo.flag=on",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
import { executeAction } from "@/platform/actions";
|
import { executeAction } from "@/platform/actions";
|
||||||
import { call, commands, IpcError, nextRequestId, type LaunchConfig, type RunConfig } from "@/platform/ipc";
|
import { call, commands, IpcError, nextRequestId, type LaunchConfig, type RunConfig } from "@/platform/ipc";
|
||||||
import {
|
import {
|
||||||
|
consoleVmArgs,
|
||||||
formatCompileErrors,
|
formatCompileErrors,
|
||||||
isJvmApplication,
|
isJvmApplication,
|
||||||
joinJavaArgs,
|
joinJavaArgs,
|
||||||
@@ -117,7 +118,7 @@ export async function javaLaunchConfig(
|
|||||||
classPaths,
|
classPaths,
|
||||||
modulePaths: info.modulePaths,
|
modulePaths: info.modulePaths,
|
||||||
javaExec: resolved.command,
|
javaExec: resolved.command,
|
||||||
vmArguments: parsed.vmArgs,
|
vmArguments: [...consoleVmArgs(rc), ...parsed.vmArgs],
|
||||||
programArgs: parsed.programArgs,
|
programArgs: parsed.programArgs,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
@@ -139,7 +140,7 @@ export async function javaLaunchConfig(
|
|||||||
classPaths,
|
classPaths,
|
||||||
modulePaths: info.modulePaths,
|
modulePaths: info.modulePaths,
|
||||||
javaExec: resolved.command === "java" ? undefined : resolved.command,
|
javaExec: resolved.command === "java" ? undefined : resolved.command,
|
||||||
vmArgs: joinJavaArgs(parsed.vmArgs),
|
vmArgs: joinJavaArgs([...consoleVmArgs(rc), ...parsed.vmArgs]),
|
||||||
args: joinJavaArgs(parsed.programArgs),
|
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.
|
// 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",
|
shortenCommandLine: info.shortenCommandLine ?? "none",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useVirtualizer } from "@tanstack/react-virtual";
|
|||||||
import { copySelectionOnKeyDown } from "@/ui/selectableText";
|
import { copySelectionOnKeyDown } from "@/ui/selectableText";
|
||||||
import { EmptyState, IconButton, showContextMenu, T, type MenuItem } from "@/ui";
|
import { EmptyState, IconButton, showContextMenu, T, type MenuItem } from "@/ui";
|
||||||
import { tx } from "@/platform/i18n";
|
import { tx } from "@/platform/i18n";
|
||||||
|
import { useWorkflowSettings } from "@/platform/workflowSettings";
|
||||||
import { spanStyle } from "@/ui/ansi";
|
import { spanStyle } from "@/ui/ansi";
|
||||||
import ansi from "@/ui/ansi.module.css";
|
import ansi from "@/ui/ansi.module.css";
|
||||||
import { appendConsole, clearConsole, evaluate, isLive, useDebug, type DebugSession } from "../state";
|
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 }) {
|
export function DebugConsole({ session, interactive = true }: { session: DebugSession; interactive?: boolean }) {
|
||||||
const lines = useDebug((s) => s.console[session.id]);
|
const lines = useDebug((s) => s.console[session.id]);
|
||||||
const scroller = useRef<HTMLDivElement>(null);
|
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);
|
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 programmatic = useRef(false);
|
||||||
const [input, setInput] = useState("");
|
const [input, setInput] = useState("");
|
||||||
const history = useRef<string[]>(readHistory("console"));
|
const history = useRef<string[]>(readHistory("console"));
|
||||||
@@ -39,14 +47,21 @@ export function DebugConsole({ session, interactive = true }: { session: DebugSe
|
|||||||
getItemKey: (i) => lines?.[i]?.id ?? i,
|
getItemKey: (i) => lines?.[i]?.id ?? i,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Wrapping changes every row's height; the end is pinned again below.
|
||||||
|
useLayoutEffect(() => virtualizer.measure?.(), [softWrap, virtualizer]);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const el = scroller.current;
|
const el = scroller.current;
|
||||||
if (!el || !stick.current || !lines?.length) return;
|
if (!el || !stick.current || !lines?.length) return;
|
||||||
programmatic.current = true;
|
programmatic.current = true;
|
||||||
virtualizer.scrollToIndex(lines.length - 1, { align: "end" });
|
virtualizer.scrollToIndex(lines.length - 1, { align: "end" });
|
||||||
el.scrollTop = el.scrollHeight;
|
el.scrollTop = el.scrollHeight;
|
||||||
requestAnimationFrame(() => (programmatic.current = false));
|
// Rows measured after this frame grow the content: pin the end once more.
|
||||||
}, [lines, virtualizer]);
|
requestAnimationFrame(() => {
|
||||||
|
if (stick.current) el.scrollTop = el.scrollHeight;
|
||||||
|
requestAnimationFrame(() => (programmatic.current = false));
|
||||||
|
});
|
||||||
|
}, [lines, virtualizer, follow, softWrap]);
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
const e = input.trim();
|
const e = input.trim();
|
||||||
@@ -101,11 +116,12 @@ export function DebugConsole({ session, interactive = true }: { session: DebugSe
|
|||||||
<div className={styles.console}>
|
<div className={styles.console}>
|
||||||
<div
|
<div
|
||||||
ref={scroller}
|
ref={scroller}
|
||||||
className={clsx(styles.consoleOutput, ansi.palette)}
|
className={clsx(styles.consoleOutput, ansi.palette, !softWrap && styles.noWrap)}
|
||||||
onScroll={(e) => {
|
onScroll={(e) => {
|
||||||
if (programmatic.current) return;
|
if (programmatic.current) return;
|
||||||
const el = e.currentTarget;
|
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) => {
|
onContextMenu={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -170,6 +186,22 @@ export function DebugConsole({ session, interactive = true }: { session: DebugSe
|
|||||||
{completion.popup}
|
{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
|
<IconButton
|
||||||
icon="trash"
|
icon="trash"
|
||||||
title="Clear Console"
|
title="Clear Console"
|
||||||
|
|||||||
@@ -251,6 +251,12 @@
|
|||||||
cursor: text;
|
cursor: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Soft-Wrap off: long lines scroll horizontally. */
|
||||||
|
.noWrap {
|
||||||
|
white-space: pre;
|
||||||
|
word-break: normal;
|
||||||
|
}
|
||||||
|
|
||||||
.out {
|
.out {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|||||||
Reference in new issue
Block a user