Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,42 @@
"godotTools.editorPath.godot3": {
"type": "string",
"default": "godot3",
"description": "Path to the Godot 3 editor executable. Supports environment variables using '${env:VAR_NAME}'."
"description": "Path to the Godot 3 editor executable. Workspace relative. Supports environment variables using '${env:VAR_NAME}'."
},
"godotTools.editorPath.godot4": {
"type": "string",
"default": "godot",
"description": "Path to the Godot 4 editor executable. Supports environment variables using '${env:VAR_NAME}'."
"description": "Path to the Godot 4 editor executable. Workspace relative. Supports environment variables using '${env:VAR_NAME}'."
},
"godotTools.editorPath.windows-arm64.godot4": {
"type": "string",
"default": "",
"description": "Platform-specific editor path. If specified, overrides `godotTools.editorPath.godot4`."
},
"godotTools.editorPath.macos-arm64.godot4": {
"type": "string",
"default": "",
"description": "Platform-specific editor path. If specified, overrides `godotTools.editorPath.godot4`."
},
"godotTools.editorPath.linux-arm64.godot4": {
"type": "string",
"default": "",
"description": "Platform-specific editor path. If specified, overrides `godotTools.editorPath.godot4`."
},
"godotTools.editorPath.windows-x86_64.godot4": {
"type": "string",
"default": "",
"description": "Platform-specific editor path. If specified, overrides `godotTools.editorPath.godot4`."
},
"godotTools.editorPath.macos-x86_64.godot4": {
"type": "string",
"default": "",
"description": "Platform-specific editor path. If specified, overrides `godotTools.editorPath.godot4`."
},
"godotTools.editorPath.linux-x86_64.godot4": {
"type": "string",
"default": "",
"description": "Platform-specific editor path. If specified, overrides `godotTools.editorPath.godot4`."
},
"godotTools.editor.verbose": {
"type": "boolean",
Expand Down
11 changes: 6 additions & 5 deletions src/debugger/godot3/server_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import {
get_free_port,
get_project_version,
verify_godot_version,
clean_godot_path,
VERIFY_RESULT,
get_editor_path,
} from "../../utils";
import { prompt_for_godot_executable } from "../../utils/prompts";
import { killSubProcesses, subProcess } from "../../utils/subspawn";
Expand Down Expand Up @@ -115,9 +117,9 @@ export class ServerController {
if (args.editor_path) {
log.info("Using 'editor_path' variable from launch.json");

log.info(`Verifying version of '${args.editor_path}'`);
result = verify_godot_version(args.editor_path, "3");
godotPath = result.godotPath;
godotPath = clean_godot_path(args.editor_path);
log.info(`Verifying version of '${godotPath}'`);
result = verify_godot_version(godotPath, "3");
log.info(`Verification result: ${result.status}, version: "${result.version}"`);

switch (result.status) {
Expand All @@ -144,11 +146,10 @@ export class ServerController {
log.info("Using 'editorPath.godot3' from settings");

const settingName = "editorPath.godot3";
godotPath = get_configuration(settingName);
godotPath = get_editor_path("3");

log.info(`Verifying version of '${godotPath}'`);
result = verify_godot_version(godotPath, "3");
godotPath = result.godotPath;
log.info(`Verification result: ${result.status}, version: "${result.version}"`);

switch (result.status) {
Expand Down
12 changes: 6 additions & 6 deletions src/debugger/godot4/server_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import {
ansi,
convert_resource_path_to_uri,
createLogger,
get_configuration,
get_free_port,
get_project_version,
verify_godot_version,
clean_godot_path,
get_editor_path,
} from "../../utils";
import { prompt_for_godot_executable } from "../../utils/prompts";
import { killSubProcesses, subProcess } from "../../utils/subspawn";
Expand Down Expand Up @@ -157,9 +158,9 @@ export class ServerController {
if (args.editor_path) {
log.info("Using 'editor_path' variable from launch.json");

log.info(`Verifying version of '${args.editor_path}'`);
result = verify_godot_version(args.editor_path, "4");
godotPath = result.godotPath;
godotPath = clean_godot_path(args.editor_path);
log.info(`Verifying version of '${godotPath}'`);
result = verify_godot_version(godotPath, "4");
log.info(`Verification result: ${result.status}, version: "${result.version}"`);

switch (result.status) {
Expand All @@ -186,11 +187,10 @@ export class ServerController {
log.info("Using 'editorPath.godot4' from settings");

const settingName = "editorPath.godot4";
godotPath = get_configuration(settingName);
godotPath = get_editor_path("4");

log.info(`Verifying version of '${godotPath}'`);
result = verify_godot_version(godotPath, "4");
godotPath = result.godotPath;
log.info(`Verification result: ${result.status}, version: "${result.version}"`);

switch (result.status) {
Expand Down
7 changes: 2 additions & 5 deletions src/debugger/godot4/variables/debugger_variables.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ chaiAsPromised.then((module) => {

import { promisify } from "node:util";
import { execFile } from "node:child_process";
import { clean_godot_path } from "../../../utils";
import { get_editor_path } from "../../../utils";

const execFileAsync = promisify(execFile);

Expand Down Expand Up @@ -226,10 +226,7 @@ suite("DAP Integration Tests - Variable Scopes", () => {
}

// init the godot project by importing it in godot engine:
const config = vscode.workspace.getConfiguration("godotTools");
// config.update("editorPath.godot4", "godot4", vscode.ConfigurationTarget.Workspace);

const godot4_path = clean_godot_path(config.get<string>("editorPath.godot4"));
const godot4_path = get_editor_path("4");

// get the path for currently opened project in vscode test instance:
console.log("Executing", [godot4_path, "--headless", "--import", workspaceFolder]);
Expand Down
13 changes: 6 additions & 7 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as fs from "node:fs";
import * as path from "node:path";
import * as vscode from "vscode";
import { attemptSettingsUpdate, get_extension_uri, clean_godot_path } from "./utils";
import { attemptSettingsUpdate, get_extension_uri, get_editor_path } from "./utils";
import {
GDInlayHintsProvider,
GDHoverProvider,
Expand Down Expand Up @@ -93,8 +93,8 @@ async function initial_setup() {
return;
}
const settingName = `editorPath.godot${projectVersion[0]}`;
const result = verify_godot_version(get_configuration(settingName), projectVersion[0]);
const godotPath = result.godotPath;
const godotPath = get_editor_path(projectVersion[0]);
const result = verify_godot_version(godotPath, projectVersion[0]);

switch (result.status) {
case "SUCCESS": {
Expand Down Expand Up @@ -157,8 +157,8 @@ async function open_workspace_with_editor() {
const projectVersion = await get_project_version();

const settingName = `editorPath.godot${projectVersion[0]}`;
const result = verify_godot_version(get_configuration(settingName), projectVersion[0]);
const godotPath = result.godotPath;
const godotPath = get_editor_path(projectVersion[0]);
const result = verify_godot_version(godotPath, projectVersion[0]);

switch (result.status) {
case "SUCCESS": {
Expand Down Expand Up @@ -240,8 +240,7 @@ async function get_godot_path(): Promise<string | undefined> {
if (projectVersion === undefined) {
return undefined;
}
const settingName = `editorPath.godot${projectVersion[0]}`;
return clean_godot_path(get_configuration(settingName));
return get_editor_path(projectVersion[0]);
}

class GodotEditorTerminal implements vscode.Pseudoterminal {
Expand Down
5 changes: 2 additions & 3 deletions src/lsp/ClientConnectionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as vscode from "vscode";
import {
createLogger,
get_configuration,
get_editor_path,
get_free_port,
get_project_dir,
get_project_version,
Expand Down Expand Up @@ -116,10 +117,8 @@ export class ClientConnectionManager {
targetVersion = "4.2";
}
const settingName = `editorPath.godot${projectVersion[0]}`;
let godotPath = get_configuration(settingName);

const godotPath = get_editor_path(projectVersion[0]);
const result = verify_godot_version(godotPath, projectVersion[0]);
godotPath = result.godotPath;

switch (result.status) {
case "WRONG_VERSION": {
Expand Down
101 changes: 72 additions & 29 deletions src/utils/godot_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as path from "node:path";
import * as fs from "node:fs";
import * as os from "node:os";
import { execSync } from "node:child_process";
import { get_configuration } from "./vscode_utils";

export function get_editor_data_dir(): string {
// from: https://stackoverflow.com/a/26227660
Expand Down Expand Up @@ -193,60 +194,102 @@ export async function convert_uid_to_uri(uid: string): Promise<vscode.Uri | unde
export type VERIFY_STATUS = "SUCCESS" | "WRONG_VERSION" | "INVALID_EXE";
export type VERIFY_RESULT = {
status: VERIFY_STATUS;
godotPath: string;
version?: string;
};

export function verify_godot_version(godotPath: string, expectedVersion: "3" | "4" | string): VERIFY_RESULT {
let target = clean_godot_path(godotPath);

let output = "";
try {
output = execSync(`"${target}" --version`).toString().trim();
output = execSync(`"${godotPath}" --version`).toString().trim();
} catch {
if (path.isAbsolute(target)) {
return { status: "INVALID_EXE", godotPath: target };
}
const workspacePath = vscode.workspace.workspaceFolders[0].uri.fsPath;
target = path.resolve(workspacePath, target);
try {
output = execSync(`"${target}" --version`).toString().trim();
} catch {
return { status: "INVALID_EXE", godotPath: target };
}
return { status: "INVALID_EXE" };
}

const pattern = /^(([34])\.([0-9]+)(?:\.[0-9]+)?)/m;
const match = output.match(pattern);
if (!match) {
return { status: "INVALID_EXE", godotPath: target };
return { status: "INVALID_EXE" };
}
if (match[2] !== expectedVersion) {
return { status: "WRONG_VERSION", godotPath: target, version: match[1] };
return { status: "WRONG_VERSION", version: match[1] };
}
return { status: "SUCCESS", godotPath: target, version: match[1] };
return { status: "SUCCESS", version: match[1] };
}

export function clean_godot_path(godotPath: string): string {
let pathToClean = godotPath;
export function get_editor_path(major_version: string): string {
// try the platform and architecture specific setting
// these are converted to match the godot build system's platform and arch names
let configValue = ""
switch (os.platform()) {
case "win32": {
switch (os.arch()) {
case "x64": {
configValue = get_configuration(`editorPath.windows-x86_64.godot${major_version}`);
break;
}
case "arm64": {
configValue = get_configuration(`editorPath.windows-arm64.godot${major_version}`);
break;
}
}
break;
}
case "darwin": {
switch (os.arch()) {
case "x64": {
configValue = get_configuration(`editorPath.macos-x86_64.godot${major_version}`);
break;
}
case "arm64": {
configValue = get_configuration(`editorPath.macos-arm64.godot${major_version}`);
break;
}
}
break;
}
case "linux": {
switch (os.arch()) {
case "x64": {
configValue = get_configuration(`editorPath.linux-x86_64.godot${major_version}`);
break;
}
case "arm64": {
configValue = get_configuration(`editorPath.linux-arm64.godot${major_version}`);
break;
}
}
break;
}
}
if (!configValue) {
configValue = get_configuration(`editorPath.godot${major_version}`);
}
return clean_godot_path(configValue);
}

export function clean_godot_path(godotPath: string): string {
// check for environment variable syntax
// looking for: ${env:FOOBAR}
// extracts "FOOBAR"
const pattern = /\$\{env:(.+?)\}/;
const match = godotPath.match(pattern);

if (match && match.length >= 2) {
pathToClean = process.env[match[1]];
}
godotPath = godotPath.replaceAll(/\$\{env:(.+?)\}/g, (_, key) => {
return process.env[key] || "";
});

// strip leading and trailing quotes
let target = pathToClean.replace(/^"/, "").replace(/"$/, "");
godotPath = godotPath.replace(/^"/, "").replace(/"$/, "");

// try to fix macos paths
if (os.platform() === "darwin" && target.endsWith(".app")) {
target = path.join(target, "Contents", "MacOS", "Godot");
if (os.platform() === "darwin" && godotPath.endsWith(".app")) {
godotPath = path.join(godotPath, "Contents", "MacOS", "Godot");
}

// convert any relative path to absolute using the workspace dir
// not using path.isAbsolute here because the default "godot" may be an executable in the PATH
if ((godotPath.startsWith("./") || godotPath.startsWith("../") || godotPath.startsWith(".\\") || godotPath.startsWith("..\\"))
&& vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) {
const workspaceDir = vscode.workspace.workspaceFolders[0].uri.fsPath;
godotPath = path.join(workspaceDir, godotPath);
}

return target;
return godotPath;
}
Loading