Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve LSP connection behavior (fixes Godot3/4 port issue) #511

Merged
merged 6 commits into from
Oct 29, 2023
Merged
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
101 changes: 63 additions & 38 deletions src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,64 +44,89 @@ export class Logger {
}
}

export class Logger2 {
protected tag: string = "";
protected level: string = "";
protected time: boolean = false;
export enum LOG_LEVEL {
SILENT,
ERROR,
WARNING,
INFO,
DEBUG,
}

constructor(tag: string) {
this.tag = tag;
const LOG_LEVEL_NAMES = [
"SILENT",
"ERROR",
"WARN ",
"INFO ",
"DEBUG",
]

const RESET = "\u001b[0m"

const LOG_COLORS = [
RESET, // SILENT, normal
"\u001b[1;31m", // ERROR, red
"\u001b[1;33m", // WARNING, yellow
"\u001b[1;36m", // INFO, cyan
"\u001b[1;32m", // DEBUG, green
]

export class Logger2 {
private show_tag: boolean = true;
private show_time: boolean;
private show_label: boolean;
private show_level: boolean = false;

constructor(
private tag: string,
private level: LOG_LEVEL = LOG_LEVEL.DEBUG,
{ time = false, label = false }: { time?: boolean, label?: boolean } = {},
) {
this.show_time = time;
this.show_label = label;
}

log(...messages) {
let line = "[godotTools]";
if (this.time) {
line += `[${new Date().toISOString()}]`;
private log(level: LOG_LEVEL, ...messages) {
let prefix = "";
if (this.show_label) {
prefix += "[godotTools]";
}
if (this.level) {
line += `[${this.level}]`;
this.level = "";
if (this.show_time) {
prefix += `[${new Date().toISOString()}]`;
}
if (this.tag) {
line += `[${this.tag}]`;
if (this.show_level) {
prefix += "[" + LOG_COLORS[level] + LOG_LEVEL_NAMES[level] + RESET + "]";
}
if (line) {
line += " ";
if (this.show_tag) {
prefix += "[" + LOG_COLORS[level] + this.tag + RESET + "]";
}

for (let index = 0; index < messages.length; index++) {
line += messages[index];
if (index < messages.length) {
line += " ";
} else {
line += "\n";
}
}

console.log(line);
console.log(prefix, ...messages);
}

info(...messages) {
this.level = "INFO";
this.log(messages);
if (LOG_LEVEL.INFO <= this.level) {
this.log(LOG_LEVEL.INFO, ...messages);
}
}
debug(...messages) {
this.level = "DEBUG";
this.log(messages);
if (LOG_LEVEL.DEBUG <= this.level) {
this.log(LOG_LEVEL.DEBUG, ...messages);
}
}
warn(...messages) {
this.level = "WARNING";
this.log(messages);
if (LOG_LEVEL.WARNING <= this.level) {
this.log(LOG_LEVEL.WARNING, ...messages);
}
}
error(...messages) {
this.level = "ERROR";
this.log(messages);
if (LOG_LEVEL.ERROR <= this.level) {
this.log(LOG_LEVEL.ERROR, ...messages);
}
}
}


export function createLogger(tag) {
return new Logger2(tag);
export function createLogger(tag, level: LOG_LEVEL = LOG_LEVEL.DEBUG) {
return new Logger2(tag, level);
}

const logger = new Logger("godot-tools", true);
Expand Down
100 changes: 63 additions & 37 deletions src/lsp/ClientConnectionManager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as vscode from "vscode";
import * as fs from "fs";
import GDScriptLanguageClient, { ClientStatus } from "./GDScriptLanguageClient";
import GDScriptLanguageClient, { ClientStatus, TargetLSP } from "./GDScriptLanguageClient";
import {
get_configuration,
get_free_port,
Expand Down Expand Up @@ -30,11 +30,14 @@ export class ClientConnectionManager {
private context: vscode.ExtensionContext;
public client: GDScriptLanguageClient = null;

private reconnection_attempts = 0;
private reconnectionAttempts = 0;

private target: TargetLSP = TargetLSP.EDITOR;
private status: ManagerStatus = ManagerStatus.INITIALIZING;
private statusWidget: vscode.StatusBarItem = null;

private connectedVersion: string = "";

constructor(p_context: vscode.ExtensionContext) {
this.context = p_context;

Expand All @@ -46,9 +49,11 @@ export class ClientConnectionManager {
}, get_configuration("lsp.autoReconnect.cooldown"));

register_command("startLanguageServer", () => {
// TODO: this might leave the manager in a wierd state
this.start_language_server();
this.reconnection_attempts = 0;
this.client.connect_to_server();
this.reconnectionAttempts = 0;
this.target = TargetLSP.HEADLESS;
this.client.connect_to_server(this.target);
});
register_command("stopLanguageServer", this.stop_language_server.bind(this));
register_command("checkStatus", this.on_status_item_click.bind(this));
Expand All @@ -65,13 +70,16 @@ export class ClientConnectionManager {

private async connect_to_language_server() {
this.client.port = -1;
this.target = TargetLSP.EDITOR;
this.connectedVersion = undefined;

if (get_configuration("lsp.headless")) {
this.target = TargetLSP.HEADLESS;
await this.start_language_server();
}

this.reconnection_attempts = 0;
this.client.connect_to_server();
this.reconnectionAttempts = 0;
this.client.connect_to_server(this.target);
}

private stop_language_server() {
Expand Down Expand Up @@ -112,7 +120,7 @@ export class ClientConnectionManager {
});
return;
}

this.connectedVersion = output;
if (match[1] !== projectVersion[0]) {
const message = `Cannot launch headless LSP: The current project uses Godot v${projectVersion}, but the specified Godot executable is version ${match[0]}`;
vscode.window.showErrorMessage(message, "Select Godot executable", "Ignore").then(item => {
Expand Down Expand Up @@ -207,7 +215,7 @@ export class ClientConnectionManager {
}

private on_status_item_click() {
const lsp_target = this.get_lsp_connection_string();
const lspTarget = this.get_lsp_connection_string();
// TODO: fill these out with the ACTIONS a user could perform in each state
switch (this.status) {
case ManagerStatus.INITIALIZING:
Expand All @@ -217,11 +225,21 @@ export class ClientConnectionManager {
// vscode.window.showInformationMessage("Initializing LSP");
break;
case ManagerStatus.PENDING:
// vscode.window.showInformationMessage(`Connecting to the GDScript language server at ${lsp_target}`);
// vscode.window.showInformationMessage(`Connecting to the GDScript language server at ${lspTarget}`);
break;
case ManagerStatus.CONNECTED:
// vscode.window.showInformationMessage("Connected to the GDScript language server.");
case ManagerStatus.CONNECTED: {
const message = `Connected to the GDScript language server at ${lspTarget}.`;
vscode.window.showInformationMessage(
message,
"Restart LSP",
"Ok"
).then(item => {
if (item === "Restart LSP") {
this.connect_to_language_server();
}
});
break;
}
case ManagerStatus.DISCONNECTED:
this.retry_connect_client();
break;
Expand All @@ -231,39 +249,47 @@ export class ClientConnectionManager {
}

private update_status_widget() {
const lsp_target = this.get_lsp_connection_string();
const lspTarget = this.get_lsp_connection_string();
const maxAttempts = get_configuration("lsp.autoReconnect.attempts")
let text = "";
let tooltip = "";
switch (this.status) {
case ManagerStatus.INITIALIZING:
// this.statusWidget.text = `INITIALIZING`;
this.statusWidget.text = `$(sync~spin) Initializing`;
this.statusWidget.tooltip = `Initializing extension...`;
text = `$(sync~spin) Initializing`;
tooltip = `Initializing extension...`;
break;
case ManagerStatus.INITIALIZING_LSP:
// this.statusWidget.text = `INITIALIZING_LSP ` + this.reconnection_attempts;
this.statusWidget.text = `$(sync~spin) Initializing LSP`;
this.statusWidget.tooltip = `Connecting to headless GDScript language server at ${lsp_target}`;
text = `$(sync~spin) Initializing LSP ${this.reconnectionAttempts}/${maxAttempts}`;
tooltip = `Connecting to headless GDScript language server.\n${lspTarget}`;
if (this.connectedVersion) {
tooltip += `\n${this.connectedVersion}`;
}
break;
case ManagerStatus.PENDING:
// this.statusWidget.text = `PENDING`;
this.statusWidget.text = `$(sync~spin) Connecting`;
this.statusWidget.tooltip = `Connecting to the GDScript language server at ${lsp_target}`;
text = `$(sync~spin) Connecting`;
tooltip = `Connecting to the GDScript language server at ${lspTarget}`;
break;
case ManagerStatus.CONNECTED:
// this.statusWidget.text = `CONNECTED`;
this.statusWidget.text = `$(check) Connected`;
this.statusWidget.tooltip = `Connected to the GDScript language server.`;
text = `$(check) Connected`;
tooltip = `Connected to the GDScript language server.\n${lspTarget}`;
if (this.connectedVersion) {
tooltip += `\n${this.connectedVersion}`;
}
break;
case ManagerStatus.DISCONNECTED:
// this.statusWidget.text = `DISCONNECTED`;
this.statusWidget.text = `$(x) Disconnected`;
this.statusWidget.tooltip = `Disconnected from the GDScript language server.`;
text = `$(x) Disconnected`;
tooltip = `Disconnected from the GDScript language server.`;
break;
case ManagerStatus.RETRYING:
// this.statusWidget.text = `RETRYING ` + this.reconnection_attempts;
this.statusWidget.text = `$(sync~spin) Connecting ` + this.reconnection_attempts;
this.statusWidget.tooltip = `Connecting to the GDScript language server at ${lsp_target}`;
text = `$(sync~spin) Connecting ${this.reconnectionAttempts}/${maxAttempts}`;
tooltip = `Connecting to the GDScript language server.\n${lspTarget}`;
if (this.connectedVersion) {
tooltip += `\n${this.connectedVersion}`;
}
break;
}
this.statusWidget.text = text;
this.statusWidget.tooltip = tooltip;
}

private on_client_status_changed(status: ClientStatus) {
Expand Down Expand Up @@ -307,11 +333,11 @@ export class ClientConnectionManager {
}

private retry_connect_client() {
const auto_retry = get_configuration("lsp.autoReconnect.enabled");
const max_attempts = get_configuration("lsp.autoReconnect.attempts");
if (auto_retry && this.reconnection_attempts <= max_attempts - 1) {
this.reconnection_attempts++;
this.client.connect_to_server();
const autoRetry = get_configuration("lsp.autoReconnect.enabled");
const maxAttempts = get_configuration("lsp.autoReconnect.attempts");
if (autoRetry && this.reconnectionAttempts <= maxAttempts - 1) {
this.reconnectionAttempts++;
this.client.connect_to_server(this.target);
this.retry = true;
return;
}
Expand All @@ -320,8 +346,8 @@ export class ClientConnectionManager {
this.status = ManagerStatus.DISCONNECTED;
this.update_status_widget();

const lsp_target = this.get_lsp_connection_string();
let message = `Couldn't connect to the GDScript language server at ${lsp_target}. Is the Godot editor or language server running?`;
const lspTarget = this.get_lsp_connection_string();
let message = `Couldn't connect to the GDScript language server at ${lspTarget}. Is the Godot editor or language server running?`;
vscode.window.showErrorMessage(message, "Retry", "Ignore").then(item => {
if (item == "Retry") {
this.connect_to_language_server();
Expand Down
Loading