Файли
openidea/src/features/debugger/index.ts
T
l0ng-ai e150101244 feat(debugger): Remote debug run configurations (Remote JVM, Go, Python, Node.js) (#50)
Root cause: run configurations could only launch a process; there was no "attach to a debugger that is already listening" type, and debugServer only connected to 127.0.0.1.
Fix (IDEA / GoLand / PyCharm): debug-only Remote JVM Debug (attach / listen, live JDWP agent args per JDK version), Go Remote (dlv --headless, substitutePath), Python Remote Debug (debugpy --listen, pathMappings) and Attach to Node.js (inspector, localRoot/remoteRoot); debugServer accepts host:port and [v6]:port; JVM listen mode via a cancellable relay so java-debug can attach.
Verified: ide-dap tests (host:port, relay handshake, cancel), run/debugger vitest, in-app on macOS: Python Remote Debug attached to a debugpy server, paused at app.py:3 with variables. Remote JVM/Go/Node not exercised in-app.

Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
2026-10-27 10:38:38 +08:00

81 рядки
3.3 KiB
TypeScript
Неформатований Анотація Історія

Цей файл містить неоднозначні символи Юнікоду
Цей файл містить символи Юнікоду, які можна сплутати з іншими символами. Якщо ви вважаєте, що це зроблено навмисно, можете сміливо ігнорувати це попередження. Щоб показати їх, скористайтеся кнопкою Escape.
/**
* Debugger: breakpoints (editor gutter + per-project store synced to the
* backend), DAP sessions driven by `IdeEvent::Debug`, the Debug tool window,
* execution point + inline values, Evaluate / View Breakpoints dialogs.
*/
import { lazyComponent } from "@/ui";
import { onIdeEvent } from "@/platform/ipc";
import { useProject } from "@/platform/project";
import { valueTooltip } from "./editor/valueTooltip";
import { registerEditorContribution } from "@/editor/api";
import {
registerMenuGroup,
registerOverlay,
registerRunConfigType,
registerToolWindow,
} from "@/workbench/contributions";
import { registerDebugActions } from "./actions";
import { loadBreakpoints } from "./breakpoints/store";
import { loadExceptionBreakpoints } from "./breakpoints/exceptions";
import { loadSpecialBreakpoints } from "./breakpoints/special";
import { breakpointGutter } from "./editor/breakpointGutter";
import { executionPoint } from "./editor/execution";
import { installSmartStepPicking, smartStepTargets } from "./editor/smartStep";
import { onHotCodeReplace } from "./hotswap";
import { handleDebugEvent, isLive, loadWatches, publishContext, resetSessions, stopSession, useDebug } from "./state";
import { DebuggerOverlays } from "./ui/Overlays";
import { REMOTE_TYPES } from "./remote";
export function activate(): () => void {
loadWatches();
publishContext();
loadBreakpoints(useProject.getState().project?.root ?? null);
loadExceptionBreakpoints(useProject.getState().project?.root ?? null);
loadSpecialBreakpoints(useProject.getState().project?.root ?? null);
const disposers = [
registerDebugActions(),
// Remote JVM Debug, Go Remote, …: Run/Debug Configurations › Add New Configuration.
...REMOTE_TYPES.map(registerRunConfigType),
registerToolWindow({
id: "debug",
title: "Debug",
icon: "toolwindow-debug",
anchor: "bottom",
stripe: "onUse",
order: 20,
component: lazyComponent(() => import("./ui/DebugToolWindow").then((m) => m.DebugToolWindow)),
headerContent: lazyComponent(() => import("./ui/DebugToolWindow").then((m) => m.DebugTabs)),
}),
registerOverlay({ id: "debugger", component: DebuggerOverlays }),
// Stop (⌘F2) offers the running debug sessions beside run processes.
registerMenuGroup({
id: "debugger.stop",
menus: ["stopProcess"],
items: () =>
Object.values(useDebug.getState().sessions)
.filter((s) => s.parent == null && isLive(s))
.map((s) => ({ label: s.name, verbatim: true, icon: "debug", run: () => void stopSession(s.id) })),
}),
registerEditorContribution({
id: "debugger",
order: 60,
extensions: (ctx) => [breakpointGutter(ctx), executionPoint(ctx), valueTooltip(), smartStepTargets(ctx)],
}),
installSmartStepPicking(),
onIdeEvent("debug", (e) => {
if (e.event.kind === "hotCodeReplace") onHotCodeReplace(e.session, e.event);
else handleDebugEvent(e.session, e.event);
}),
useProject.subscribe((s, prev) => {
const root = s.project?.root ?? null;
if (root !== (prev.project?.root ?? null)) {
resetSessions();
loadBreakpoints(root);
loadExceptionBreakpoints(root);
loadSpecialBreakpoints(root);
}
}),
];
return () => disposers.reverse().forEach((d) => d());
}