Browse Source

Add TCP protocol support for godot 3.2.2
Fix #154
Fix #177
Close #141

Geequlim 5 years ago
parent
commit
56770d79f3

+ 4 - 0
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
 

+ 19 - 8
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"
 	}
 }

+ 2 - 2
src/debugger/scene_tree/inspector_provider.ts

@@ -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(

+ 1 - 1
src/debugger/scene_tree/scene_tree_provider.ts

@@ -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[]> {

+ 32 - 32
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);
 				}
 			}
 		}

+ 58 - 17
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<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));
 		});
 	}
+
+	protected on_connected(socket: WebSocket) {
+		this.socket = socket;
+		this.emit("connected");
+	}
 	
-	private on_connected(socket: WebSocket) {
+	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");
 	}
 	
-	private on_disconnected() {
+	protected on_disconnected() {
 		this.socket = null;
 		this.emit('disconnected');
 	}
-};
+}
 
 
 export class MessageIOReader extends AbstractMessageReader implements MessageReader {