mirror of
https://github.com/godotengine/godot-vscode-plugin.git
synced 2026-01-04 10:09:58 +03:00
The GDScript LSP Client is works correctly !
This commit is contained in:
20
package.json
20
package.json
@@ -2,7 +2,7 @@
|
||||
"name": "godot-tools",
|
||||
"displayName": "godot-tools",
|
||||
"icon": "icon.png",
|
||||
"version": "1.0.0",
|
||||
"version": "0.9.0",
|
||||
"description": "Tools for game development with godot game engine",
|
||||
"repository": "https://github.com/GodotExplorer/godot-tools",
|
||||
"publisher": "geequlim",
|
||||
@@ -25,7 +25,16 @@
|
||||
"test": "yarn run compile && node ./node_modules/vscode/bin/test"
|
||||
},
|
||||
"contributes": {
|
||||
"commands": [],
|
||||
"commands": [
|
||||
{
|
||||
"command": "godot-tool.open_editor",
|
||||
"title": "Godot Tools: Open workspace with Godot editor"
|
||||
},
|
||||
{
|
||||
"command": "godot-tool.run_project",
|
||||
"title": "Godot Tools: Run workspace as Godot project"
|
||||
}
|
||||
],
|
||||
"configuration": {
|
||||
"type": "object",
|
||||
"title": "Godot Tools configuration",
|
||||
@@ -33,7 +42,12 @@
|
||||
"godot_tools.gdscript_lsp_server_port": {
|
||||
"type": "number",
|
||||
"default": 6008,
|
||||
"description": "The websocket server port of the GDScript Langugae Protocol server"
|
||||
"description": "The websocket server port of the GDScript langugae server"
|
||||
},
|
||||
"godot_tools.editor_path": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "The absolute path to the Godot editor executable"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { ExtensionContext } from "vscode";
|
||||
import GDScriptLanguageClient from "./lsp/GDScriptLanguageClient";
|
||||
import { GodotTools } from "./godot-tools";
|
||||
|
||||
let client: GDScriptLanguageClient = null;
|
||||
|
||||
let tools: GodotTools = null;
|
||||
|
||||
export function activate(context: ExtensionContext) {
|
||||
client = new GDScriptLanguageClient();
|
||||
context.subscriptions.push(client.start());
|
||||
tools = new GodotTools(context);
|
||||
tools.activate();
|
||||
}
|
||||
|
||||
export function deactivate(): Thenable<void> {
|
||||
if (client) {
|
||||
return client.stop();
|
||||
}
|
||||
return new Promise((resolve, reject) => {});
|
||||
return new Promise((resolve, reject) => {
|
||||
tools.deactivate();
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
209
src/godot-tools.ts
Normal file
209
src/godot-tools.ts
Normal file
@@ -0,0 +1,209 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import GDScriptLanguageClient from "./lsp/GDScriptLanguageClient";
|
||||
import { get_configuration, set_configuration } from "./utils";
|
||||
import { MessageIO } from "./lsp/MessageIO";
|
||||
|
||||
const CONFIG_CONTAINER = "godot_tools";
|
||||
const TOOL_NAME = "GodotTools";
|
||||
|
||||
enum ClientStatus {
|
||||
PENDING,
|
||||
DISCONNECTED,
|
||||
CONNECTED,
|
||||
}
|
||||
|
||||
export class GodotTools {
|
||||
|
||||
private context: vscode.ExtensionContext;
|
||||
private client: GDScriptLanguageClient = null;
|
||||
private workspace_dir = vscode.workspace.rootPath;
|
||||
private project_file = "project.godot";
|
||||
private connection_status: vscode.StatusBarItem = null;
|
||||
private message_handler: MessageHandler = null;
|
||||
|
||||
constructor(p_context: vscode.ExtensionContext) {
|
||||
this.context = p_context;
|
||||
this.client = new GDScriptLanguageClient();
|
||||
this.message_handler = new MessageHandler(this.client.io);
|
||||
this.client.io.on('disconnected', this.on_client_disconnected.bind(this));
|
||||
this.client.io.on('connected', this.on_server_connected.bind(this));
|
||||
this.connection_status = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
|
||||
}
|
||||
|
||||
public activate() {
|
||||
vscode.commands.registerCommand("godot-tool.open_editor", ()=>{
|
||||
this.open_workspace_with_editor("-e").catch(err=>vscode.window.showErrorMessage(err));
|
||||
});
|
||||
vscode.commands.registerCommand("godot-tool.run_project", ()=>{
|
||||
this.open_workspace_with_editor().catch(err=>vscode.window.showErrorMessage(err));
|
||||
});
|
||||
this.connection_status.text = "starting";
|
||||
this.connection_status.show();
|
||||
this.try_connect_to_server();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public deactivate() {
|
||||
this.client.stop();
|
||||
}
|
||||
|
||||
|
||||
private open_workspace_with_editor(params = "") {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let valid = false
|
||||
if (this.workspace_dir) {
|
||||
let cfg = path.join(this.workspace_dir, this.project_file);
|
||||
valid = (fs.existsSync(cfg) && fs.statSync(cfg).isFile());
|
||||
}
|
||||
if (valid) {
|
||||
this.run_editor(`--path "${this.workspace_dir}" ${params}`).then(()=>resolve()).catch(err=>{
|
||||
reject(err);
|
||||
});
|
||||
} else {
|
||||
reject("Current workspace is not a Godot project");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private run_editor(params = "") {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const run_godot = (path: string, params: string) => {
|
||||
const escape_command = (cmd: string) => {
|
||||
let cmdEsc = `"${cmd}"`;
|
||||
let shell = vscode.workspace.getConfiguration("terminal.integrated.shell").get("windows", "");
|
||||
if (shell.endsWith("powershell.exe") && process.platform === "win32") {
|
||||
cmdEsc = `&${cmdEsc}`;
|
||||
}
|
||||
return cmdEsc;
|
||||
};
|
||||
let existingTerminal = vscode.window.terminals.find(t => t.name === TOOL_NAME)
|
||||
if (existingTerminal) {
|
||||
existingTerminal.dispose()
|
||||
}
|
||||
let terminal = vscode.window.createTerminal(TOOL_NAME);
|
||||
let editorPath = escape_command(path);
|
||||
let cmmand = `${editorPath} ${params}`;
|
||||
terminal.sendText(cmmand, true);
|
||||
terminal.show();
|
||||
resolve();
|
||||
};
|
||||
|
||||
let editorPath = get_configuration("editor_path", "")
|
||||
editorPath = editorPath.replace("${workspaceRoot}", this.workspace_dir);
|
||||
if (!fs.existsSync(editorPath) || !fs.statSync(editorPath).isFile()) {
|
||||
vscode.window.showOpenDialog({
|
||||
openLabel: "Run",
|
||||
filters: process.platform === "win32" ? {"Godot Editor Binary": ["exe", "EXE"]} : undefined
|
||||
}).then((uris: vscode.Uri[])=> {
|
||||
if (!uris) return;
|
||||
let path = uris[0].fsPath;
|
||||
if (!fs.existsSync(path) || !fs.statSync(path).isFile()) {
|
||||
reject("Invalid editor path to run the project");
|
||||
} else {
|
||||
run_godot(path, params);
|
||||
set_configuration("editor_path", path);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
run_godot(editorPath, params);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private try_connect_to_server() {
|
||||
this.client.connect_to_server();
|
||||
this.update_client_status(ClientStatus.PENDING);
|
||||
}
|
||||
|
||||
private update_client_status(status: ClientStatus) {
|
||||
this.connection_status.color = vscode.ThemeColor;
|
||||
switch (status) {
|
||||
case ClientStatus.PENDING:
|
||||
this.connection_status.text = `$(sync) Connecting`;
|
||||
this.connection_status.tooltip = `Connecting to GDScript Language Server`;
|
||||
break;
|
||||
case ClientStatus.CONNECTED:
|
||||
this.connection_status.text = `$(check) Connected`;
|
||||
this.connection_status.tooltip = `Connected to GDScript Language Server`;
|
||||
break;
|
||||
case ClientStatus.DISCONNECTED:
|
||||
this.connection_status.text = `$(x) Disconnected`;
|
||||
this.connection_status.tooltip = `Disconnect to GDScript Language Server`;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private on_server_connected() {
|
||||
this.context.subscriptions.push(this.client.start());
|
||||
this.update_client_status(ClientStatus.CONNECTED);
|
||||
}
|
||||
|
||||
private on_client_disconnected() {
|
||||
this.update_client_status(ClientStatus.DISCONNECTED);
|
||||
vscode.window.showErrorMessage(`Failed connect to GDScript Language Server`, 'Open Godot Editor', 'Retry', 'Ignore').then(item=>{
|
||||
if (item == 'Retry') {
|
||||
this.try_connect_to_server();
|
||||
} else if (item == 'Open Godot Editor') {
|
||||
this.update_client_status(ClientStatus.PENDING);
|
||||
this.open_workspace_with_editor("-e").then(()=>{
|
||||
setTimeout(()=>{
|
||||
this.try_connect_to_server();
|
||||
}, 10 * 1000);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
const CUSTOM_MESSAGE = "gdscrip_client/";
|
||||
|
||||
class MessageHandler {
|
||||
io: MessageIO = null;
|
||||
|
||||
constructor(io: MessageIO) {
|
||||
this.io = io;
|
||||
this.io.on('message', this.on_server_message.bind(this));
|
||||
}
|
||||
|
||||
changeWorkspace(params: {path: string}) {
|
||||
vscode.window.showErrorMessage("The GDScript Language Server can't work properly!\nThe opening workspace is diffrent with the editor's.", 'Reload', 'Ignore').then(item=>{
|
||||
if (item == "Reload") {
|
||||
let folderUrl = vscode.Uri.file(params.path);
|
||||
vscode.commands.executeCommand('vscode.openFolder', folderUrl, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private on_server_message(message: any) {
|
||||
if (message && message.method && (message.method as string).startsWith(CUSTOM_MESSAGE)) {
|
||||
const method = (message.method as string).substring(CUSTOM_MESSAGE.length, message.method.length);
|
||||
if (this[method]) {
|
||||
let ret = this[method](message.params);
|
||||
if (ret) {
|
||||
ret = this.handle_result(message, ret);
|
||||
if (ret) {
|
||||
this.io.send_message(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private handle_result(request: any, ret: any) {
|
||||
let data = ret;
|
||||
if (ret) {
|
||||
data = JSON.stringify(data);
|
||||
}
|
||||
return data
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
import { workspace } from "vscode";
|
||||
import { LanguageClient, LanguageClientOptions, ServerOptions } from "vscode-languageclient";
|
||||
import { is_debug_mode, get_configuration } from "../utils";
|
||||
import logger from "../loggger";
|
||||
import * as WebSocket from 'ws';
|
||||
import * as vscode from 'vscode';
|
||||
import { EventEmitter } from "events";
|
||||
import { MessageIO, MessageIOReader, MessageIOWriter } from "./MessageIO";
|
||||
|
||||
function getClientOptions(): LanguageClientOptions {
|
||||
@@ -16,7 +13,7 @@ function getClientOptions(): LanguageClientOptions {
|
||||
],
|
||||
synchronize: {
|
||||
// Notify the server about file changes to '.gd files contain in the workspace
|
||||
fileEvents: workspace.createFileSystemWatcher("**/*.gd"),
|
||||
// fileEvents: workspace.createFileSystemWatcher("**/*.gd"),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -29,23 +26,19 @@ function get_server_uri() : string {
|
||||
const io = new MessageIO(get_server_uri());
|
||||
const serverOptions: ServerOptions = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.connect_to_language_server().then(()=>{
|
||||
resolve({reader: new MessageIOReader(io), writer: new MessageIOWriter(io)});
|
||||
});
|
||||
resolve({reader: new MessageIOReader(io), writer: new MessageIOWriter(io)});
|
||||
});
|
||||
};
|
||||
|
||||
export default class GDScriptLanguageClient extends LanguageClient {
|
||||
export default class GDScriptLanguageClient extends LanguageClient {
|
||||
|
||||
public io: MessageIO = io;
|
||||
|
||||
constructor() {
|
||||
super(`GDScriptLanguageClient`, serverOptions, getClientOptions());
|
||||
io.on('disconnected', this.on_disconnected.bind(this));
|
||||
}
|
||||
|
||||
private on_disconnected() {
|
||||
vscode.window.showErrorMessage(`Failed connect to GDScript Language Server`, 'Retry', 'Close').then(item=>{
|
||||
if (item == 'Retry') {
|
||||
io.connect_to_language_server();
|
||||
}
|
||||
});
|
||||
connect_to_server() {
|
||||
io.connect_to_language_server();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import MessageBuffer from "./MessageBuffer";
|
||||
import logger from "../loggger";
|
||||
import { AbstractMessageWriter, MessageWriter } from "vscode-jsonrpc/lib/messageWriter";
|
||||
import { Message } from "vscode-jsonrpc";
|
||||
import { is_debug_mode } from "../utils";
|
||||
|
||||
export class MessageIO extends EventEmitter {
|
||||
|
||||
@@ -20,13 +21,17 @@ export class MessageIO extends EventEmitter {
|
||||
if (this.socket) {
|
||||
this.socket.send(message);
|
||||
}
|
||||
logger.log("[client]", message);
|
||||
if (is_debug_mode) logger.log("[client]", message);
|
||||
}
|
||||
|
||||
protected on_message(chunk: WebSocket.Data) {
|
||||
let message = chunk.toString();
|
||||
this.emit('data', message);
|
||||
logger.log("[server]", message);
|
||||
if (is_debug_mode) logger.log("[server]", message);
|
||||
}
|
||||
|
||||
on_message_callback(message: Object) {
|
||||
this.emit("message", message);
|
||||
}
|
||||
|
||||
connect_to_language_server():Promise<void> {
|
||||
@@ -120,6 +125,7 @@ export class MessageIOReader extends AbstractMessageReader implements MessageRea
|
||||
this.messageToken++;
|
||||
var json = JSON.parse(msg);
|
||||
this.callback(json);
|
||||
this.io.on_message_callback(json);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
src/utils.ts
10
src/utils.ts
@@ -1,7 +1,13 @@
|
||||
import { workspace } from "vscode";
|
||||
import * as vscode from "vscode";
|
||||
|
||||
const CONFIG_CONTAINER = "godot_tools";
|
||||
|
||||
export function get_configuration(name: string, default_value: any = null) {
|
||||
return workspace.getConfiguration("godot_tools").get(name, default_value);
|
||||
return vscode.workspace.getConfiguration(CONFIG_CONTAINER).get(name, default_value);
|
||||
}
|
||||
|
||||
export function set_configuration(name: string, value: any) {
|
||||
return vscode.workspace.getConfiguration(CONFIG_CONTAINER).update(name, value);
|
||||
}
|
||||
|
||||
export function is_debug_mode(): boolean {
|
||||
|
||||
Reference in New Issue
Block a user