Add TCP protocol support for godot 3.2.2

Fix #154
Fix #177
Close #141
This commit is contained in:
Geequlim
2020-05-13 23:06:01 +08:00
parent 658a360c97
commit 56770d79f3
6 changed files with 117 additions and 61 deletions

View File

@@ -1,5 +1,9 @@
# Change Log
### 1.1.1
* Fix bug for GDScript debugger
* Add TCP protocol support for GDScript language server Godot 3.2.2
### 1.1
* Add the debugger to the extension

View File

@@ -2,7 +2,7 @@
"name": "godot-tools",
"displayName": "godot-tools",
"icon": "icon.png",
"version": "1.1.0",
"version": "1.1.1",
"description": "Tools for game development with godot game engine",
"repository": {
"type": "git",
@@ -80,10 +80,20 @@
"type": "object",
"title": "Godot Tools configuration",
"properties": {
"godot_tools.gdscript_lsp_server_protocol": {
"type": ["string"],
"enum": ["ws", "tcp"],
"default": "tcp",
"enumDescriptions": [
"Using WebSocket protocol to connect to Godot 3.2 and Godot 3.2.1",
"Using TCP protocol to connect to Godot 3.2.2 and newer versions"
],
"description": "The server protocol of the GDScript language server.\nYou have restart VSCode editor after change this value."
},
"godot_tools.gdscript_lsp_server_port": {
"type": "number",
"default": 6008,
"description": "The websocket server port of the GDScript language server"
"description": "The server port of the GDScript language server"
},
"godot_tools.editor_path": {
"type": "string",
@@ -267,18 +277,19 @@
"@types/mocha": "^2.2.42",
"@types/node": "^10.12.21",
"@types/prismjs": "^1.16.0",
"@types/vscode": "^1.33.0",
"@types/ws": "^6.0.1",
"tslint": "^5.16.0",
"typescript": "^3.5.1",
"@types/vscode": "^1.33.0"
"typescript": "^3.5.1"
},
"dependencies": {
"await-notify": "^1.0.1",
"global": "^4.4.0",
"marked": "^0.7.0",
"vscode-languageclient": "^5.2.1",
"ws": "^7.0.0",
"await-notify": "^1.0.1",
"net": "^1.0.2",
"terminate": "^2.1.2",
"vscode-debugadapter": "^1.38.0"
"vscode-debugadapter": "^1.38.0",
"vscode-languageclient": "^5.2.1",
"ws": "^7.0.0"
}
}

View File

@@ -23,7 +23,7 @@ export class InspectorProvider implements TreeDataProvider<RemoteProperty> {
public clean_up() {
if (this.tree) {
this.tree = undefined;
this._on_did_change_tree_data.fire();
this._on_did_change_tree_data.fire(this.tree);
}
}
@@ -37,7 +37,7 @@ export class InspectorProvider implements TreeDataProvider<RemoteProperty> {
this.tree.label = element_name;
this.tree.collapsibleState = TreeItemCollapsibleState.Expanded;
this.tree.description = class_name;
this._on_did_change_tree_data.fire();
this._on_did_change_tree_data.fire(this.tree);
}
public getChildren(

View File

@@ -22,7 +22,7 @@ export class SceneTreeProvider implements TreeDataProvider<SceneNode> {
public fill_tree(tree: SceneNode) {
this.tree = tree;
this._on_did_change_tree_data.fire();
this._on_did_change_tree_data.fire(this.tree);
}
public getChildren(element?: SceneNode): ProviderResult<SceneNode[]> {

View File

@@ -1,37 +1,11 @@
import * as vscode from 'vscode';
import { LanguageClient, LanguageClientOptions, ServerOptions, RequestMessage } from "vscode-languageclient";
import { is_debug_mode, get_configuration } from "../utils";
import { MessageIO, MessageIOReader, MessageIOWriter, Message } from "./MessageIO";
import { MessageIO, MessageIOReader, MessageIOWriter, Message, WebsocktMessageIO, TCPMessageIO } from "./MessageIO";
import logger from "../loggger";
import { EventEmitter } from "events";
import NativeDocumentManager from './NativeDocumentManager';
function getClientOptions(): LanguageClientOptions {
return {
// Register the server for plain text documents
documentSelector: [
{ scheme: "file", language: "gdscript" },
{ scheme: "untitled", language: "gdscript" },
],
synchronize: {
// Notify the server about file changes to '.gd files contain in the workspace
// fileEvents: workspace.createFileSystemWatcher("**/*.gd"),
},
};
}
function get_server_uri() : string {
let port = get_configuration("gdscript_lsp_server_port", 6008);
return `ws://localhost:${port}`;
}
const io = new MessageIO(get_server_uri());
const serverOptions: ServerOptions = () => {
return new Promise((resolve, reject) => {
resolve({reader: new MessageIOReader(io), writer: new MessageIOWriter(io)});
});
};
export enum ClientStatus {
PENDING,
DISCONNECTED,
@@ -41,7 +15,7 @@ const CUSTOM_MESSAGE = "gdscrip_client/";
export default class GDScriptLanguageClient extends LanguageClient {
public io: MessageIO = io;
public readonly io: MessageIO = (get_configuration("gdscript_lsp_server_protocol", "tcp") == "ws") ? new WebsocktMessageIO() : new TCPMessageIO();
private context: vscode.ExtensionContext;
private _started : boolean = false;
@@ -69,10 +43,28 @@ export default class GDScriptLanguageClient extends LanguageClient {
}
constructor(context: vscode.ExtensionContext) {
super(`GDScriptLanguageClient`, serverOptions, getClientOptions());
super(
`GDScriptLanguageClient`,
() => {
return new Promise((resolve, reject) => {
resolve({reader: new MessageIOReader(this.io), writer: new MessageIOWriter(this.io)});
});
},
{
// Register the server for plain text documents
documentSelector: [
{ scheme: "file", language: "gdscript" },
{ scheme: "untitled", language: "gdscript" },
],
synchronize: {
// Notify the server about file changes to '.gd files contain in the workspace
// fileEvents: workspace.createFileSystemWatcher("**/*.gd"),
},
}
);
this.context = context;
this.status = ClientStatus.PENDING;
this.message_handler = new MessageHandler();
this.message_handler = new MessageHandler(this.io);
this.io.on('disconnected', this.on_disconnected.bind(this));
this.io.on('connected', this.on_connected.bind(this));
this.io.on('message', this.on_message.bind(this));
@@ -82,7 +74,8 @@ export default class GDScriptLanguageClient extends LanguageClient {
connect_to_server() {
this.status = ClientStatus.PENDING;
io.connect_to_language_server(get_server_uri());
let port = get_configuration("gdscript_lsp_server_port", 6008);
this.io.connect_to_language_server(port);
}
start(): vscode.Disposable {
@@ -118,6 +111,13 @@ export default class GDScriptLanguageClient extends LanguageClient {
class MessageHandler extends EventEmitter {
private io: MessageIO = null;
constructor(io: MessageIO) {
super();
this.io = io;
}
changeWorkspace(params: {path: string}) {
vscode.window.showErrorMessage("The GDScript language server can't work properly!\nThe open workspace is different from the editor's.", 'Reload', 'Ignore').then(item=>{
if (item == "Reload") {
@@ -139,7 +139,7 @@ class MessageHandler extends EventEmitter {
if (this[method]) {
let ret = this[method](message.params);
if (ret) {
io.writer.write(ret);
this.io.writer.write(ret);
}
}
}

View File

@@ -1,6 +1,8 @@
import { AbstractMessageReader, MessageReader, DataCallback } from "vscode-jsonrpc/lib/messageReader";
import { EventEmitter } from "events";
import * as WebSocket from 'ws';
import * as WebSocket from 'ws';
import { Socket } from 'net';
import MessageBuffer from "./MessageBuffer";
import { AbstractMessageWriter, MessageWriter } from "vscode-jsonrpc/lib/messageWriter";
import { RequestMessage, ResponseMessage, NotificationMessage } from "vscode-jsonrpc/lib/messages";
@@ -10,18 +12,9 @@ export class MessageIO extends EventEmitter {
reader: MessageIOReader = null;
writer: MessageIOWriter = null;
private socket: WebSocket = null;
constructor(url: string) {
super();
}
public send_message(message: string) {
if (this.socket) {
this.socket.send(message);
}
// virtual
}
protected on_message(chunk: WebSocket.Data) {
@@ -37,27 +30,75 @@ export class MessageIO extends EventEmitter {
this.emit("message", message);
}
connect_to_language_server(url: string):Promise<void> {
async connect_to_language_server(port: number): Promise<void> {
// virtual
}
};
export class WebsocktMessageIO extends MessageIO {
private socket: WebSocket = null;
public send_message(message: string) {
if (this.socket) {
this.socket.send(message);
}
}
async connect_to_language_server(port: number): Promise<void> {
return new Promise((resolve, reject) => {
this.socket = null;
const ws = new WebSocket(url);
const ws = new WebSocket(`ws://localhost:${port}`);
ws.on('open', ()=>{ this.on_connected(ws); resolve(); });
ws.on('message', this.on_message.bind(this));
ws.on('error', this.on_disconnected.bind(this));
ws.on('close', this.on_disconnected.bind(this));
});
}
private on_connected(socket: WebSocket) {
protected on_connected(socket: WebSocket) {
this.socket = socket;
this.emit("connected");
}
private on_disconnected() {
protected on_disconnected() {
this.socket = null;
this.emit('disconnected');
}
};
}
export class TCPMessageIO extends MessageIO {
private socket: Socket = null;
public send_message(message: string) {
if (this.socket) {
this.socket.write(message);
}
}
async connect_to_language_server(port: number):Promise<void> {
return new Promise((resolve, reject) => {
this.socket = null;
const socket = new Socket();
socket.connect(port);
socket.on('connect', ()=>{ this.on_connected(socket); resolve(); });
socket.on('data', this.on_message.bind(this));
socket.on('end', this.on_disconnected.bind(this));
socket.on('close', this.on_disconnected.bind(this));
});
}
protected on_connected(socket: Socket) {
this.socket = socket;
this.emit("connected");
}
protected on_disconnected() {
this.socket = null;
this.emit('disconnected');
}
}
export class MessageIOReader extends AbstractMessageReader implements MessageReader {