дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 11:15:40 +02:00
feat(languages): Add Godot / GDScript support (#73)
Adds GDScript, Godot resource and shader file types with tree-sitter highlighting, the GDScript language server over TCP (a headless Godot editor started on demand), "Godot Project" / current-scene run configurations, and debugging through Godot's debug adapter. Breakpoints set through symlinked paths (/tmp, /var on macOS) were reported verified but never hit; the adapter now sends resolved paths and maps stack frames back to the paths the IDE opened. The duplicate exit event Godot sends after disconnect is ignored. Fixes #68 Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
Цей коміт міститься в:
1 джерело
2eaa6cb0c7
коміт
e3dae02de7
52 files changed
+1584
-33
No files matched your search
@@ -197,4 +197,15 @@ describe("run config → launch config", () => {
|
||||
// lldb-dap takes `KEY=VALUE` strings.
|
||||
expect(extra(dap)).toEqual({ env: ["K=v"] });
|
||||
});
|
||||
|
||||
it("Godot: the editor's adapter plays the main scene or the chosen one of the project", () => {
|
||||
const project = rc({ kind: "godot", command: "/Apps/Godot", args: ["--path", "."], cwd: "game", debugAdapter: "godot" });
|
||||
const main = launchConfigFor(project, "/p")!;
|
||||
expect(main).toMatchObject({ adapter: "godot", request: "launch", cwd: "/p/game", program: null });
|
||||
expect(extra(main)).toEqual({ project: "/p/game", scene: "main" });
|
||||
const scene = launchConfigFor({ ...project, args: ["--path", ".", "res://levels/one.tscn"] }, "/p")!;
|
||||
expect(extra(scene)).toEqual({ project: "/p/game", scene: "res://levels/one.tscn" });
|
||||
const relative = launchConfigFor({ ...project, cwd: null, args: ["--path", "game", "menu.tscn"] }, "/p")!;
|
||||
expect(extra(relative)).toEqual({ project: "/p/game", scene: "res://menu.tscn" });
|
||||
});
|
||||
});
|
||||
@@ -137,6 +137,14 @@ describe("remote attach requests", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("Attach to Godot connects to the editor's debug adapter for the project", () => {
|
||||
const l = remoteAttachConfig(configOf(remote.godotAttachType), "/p/game")!;
|
||||
expect(l).toMatchObject({ adapter: "godot", request: "attach", cwd: "/p/game" });
|
||||
expect(JSON.parse(l.extraJson!)).toEqual({ debugServer: "localhost:6006", project: "/p/game" });
|
||||
const custom = remoteAttachConfig(configOf(remote.godotAttachType, { port: "6010" }), "/p")!;
|
||||
expect(JSON.parse(custom.extraJson!).debugServer).toBe("localhost:6010");
|
||||
});
|
||||
|
||||
it("Attach to Node.js attaches js-debug to the inspector with local/remote roots", () => {
|
||||
const l = remoteAttachConfig(configOf(nodeRemoteType, { host: "web", remoteRoot: "/usr/src/app" }), "/p")!;
|
||||
expect(l.adapter).toBe("js-debug");
|
||||
|
||||
@@ -196,6 +196,24 @@ function delveLaunch(rc: RunConfig, cwd: string): LaunchConfig {
|
||||
return out;
|
||||
}
|
||||
|
||||
/** The scene a `godot --path <dir> [scene]` command line plays: `main`, or a `res://` path. */
|
||||
export function godotScene(args: readonly string[]): string {
|
||||
const scene = args.find((a, i) => args[i - 1] !== "--path" && /\.t?scn$/i.test(a));
|
||||
if (!scene) return "main";
|
||||
return scene.startsWith("res://") ? scene : `res://${scene.replace(/^\.\//, "")}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Godot: the adapter inside the editor plays the scene itself (with the editor's run
|
||||
* settings), so the launch names the project (checked against the editor's) and the scene.
|
||||
*/
|
||||
function godotLaunch(rc: RunConfig, cwd: string): LaunchConfig {
|
||||
const i = rc.args.indexOf("--path");
|
||||
const dir = i >= 0 ? rc.args[i + 1] : undefined;
|
||||
const project = dir ? join(cwd, dir) : cwd;
|
||||
return { ...base(rc, "godot", project), extraJson: JSON.stringify({ project, scene: godotScene(rc.args) }) };
|
||||
}
|
||||
|
||||
/** A native program under CodeLLDB or lldb-dap: program, args, cwd, env. */
|
||||
function nativeLaunch(rc: RunConfig, cwd: string, adapter: string): LaunchConfig {
|
||||
const out: LaunchConfig = { ...base(rc, adapter, cwd), program: resolveCommand(rc.command, cwd), args: [...rc.args] };
|
||||
@@ -219,6 +237,7 @@ export function launchConfigFor(rc: RunConfig, root: string): LaunchConfig | nul
|
||||
if (adapter === "debugpy") return debugpyLaunch(rc, cwd);
|
||||
if (adapter === "js-debug") return jsDebugLaunch(rc, cwd);
|
||||
if (adapter === "delve") return delveLaunch(rc, cwd);
|
||||
if (adapter === "godot") return godotLaunch(rc, cwd);
|
||||
// Adapters without a template (hidden in Edit Configurations): generic arguments.
|
||||
return {
|
||||
...base(rc, adapter, cwd),
|
||||
|
||||
@@ -12,6 +12,7 @@ export const REMOTE_JVM = "remote-jvm";
|
||||
export const GO_REMOTE = "go-remote";
|
||||
export const PYTHON_REMOTE = "python-remote";
|
||||
export const NODE_REMOTE = "node-remote";
|
||||
export const GODOT_ATTACH = "godot-attach";
|
||||
|
||||
type Params = Readonly<Record<string, string>>;
|
||||
|
||||
@@ -220,11 +221,36 @@ export const nodeRemoteType: RunConfigTypeContribution = {
|
||||
commandLine: () => null,
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Attach to Godot (the editor's debug adapter, Editor Settings › Network › Debug Adapter)
|
||||
|
||||
export const godotAttachType: RunConfigTypeContribution = {
|
||||
id: GODOT_ATTACH,
|
||||
label: "Attach to Godot",
|
||||
icon: "file-gdscript",
|
||||
description: "Debug the game the Godot editor is running, through the editor's debug adapter",
|
||||
defaults: { host: "localhost", port: "6006" },
|
||||
debugOnly: true,
|
||||
debugAdapter: "godot",
|
||||
fields: [
|
||||
hostField,
|
||||
portField,
|
||||
{
|
||||
key: "hint",
|
||||
label: "Before attaching",
|
||||
control: "output",
|
||||
value: () => "Open the project in the Godot editor and run a scene (F5 / F6)",
|
||||
},
|
||||
],
|
||||
commandLine: () => null,
|
||||
};
|
||||
|
||||
export const REMOTE_TYPES: readonly RunConfigTypeContribution[] = [
|
||||
remoteJvmType,
|
||||
goRemoteType,
|
||||
pythonRemoteType,
|
||||
nodeRemoteType,
|
||||
godotAttachType,
|
||||
];
|
||||
|
||||
export const isRemoteConfig = (c: Pick<RunConfig, "kind">) => REMOTE_TYPES.some((t) => t.id === c.kind);
|
||||
@@ -291,6 +317,8 @@ export function remoteAttachConfig(rc: RunConfig, root: string): LaunchConfig |
|
||||
justMyCode: skip,
|
||||
...(map ? { pathMappings: [{ localRoot: map.local, remoteRoot: map.remote }] } : {}),
|
||||
});
|
||||
case GODOT_ATTACH:
|
||||
return attachBase(rc, "godot", root, { debugServer: serverAddress(host, portOf(p, 6006)), project: root });
|
||||
case NODE_REMOTE:
|
||||
return attachBase(rc, "js-debug", root, {
|
||||
type: "pwa-node",
|
||||
|
||||
Reference in new issue
Заблокувати користувача