diff --git a/CHANGELOG.md b/CHANGELOG.md index c978dbd..c520fcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/package.json b/package.json index e837196..081c312 100644 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/src/debugger/scene_tree/inspector_provider.ts b/src/debugger/scene_tree/inspector_provider.ts index 1cd85e2..79f66a0 100644 --- a/src/debugger/scene_tree/inspector_provider.ts +++ b/src/debugger/scene_tree/inspector_provider.ts @@ -23,7 +23,7 @@ export class InspectorProvider implements TreeDataProvider { 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 { 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( diff --git a/src/debugger/scene_tree/scene_tree_provider.ts b/src/debugger/scene_tree/scene_tree_provider.ts index c54087f..968a62f 100644 --- a/src/debugger/scene_tree/scene_tree_provider.ts +++ b/src/debugger/scene_tree/scene_tree_provider.ts @@ -22,7 +22,7 @@ export class SceneTreeProvider implements TreeDataProvider { 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 { diff --git a/src/lsp/GDScriptLanguageClient.ts b/src/lsp/GDScriptLanguageClient.ts index be41cbb..a893898 100644 --- a/src/lsp/GDScriptLanguageClient.ts +++ b/src/lsp/GDScriptLanguageClient.ts @@ -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); } } } diff --git a/src/lsp/MessageIO.ts b/src/lsp/MessageIO.ts index 47ec5ca..94d1d63 100644 --- a/src/lsp/MessageIO.ts +++ b/src/lsp/MessageIO.ts @@ -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 { + async connect_to_language_server(port: number): Promise { + // 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 { 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 { + 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 {