Skip to content

Commit

Permalink
Suppress "workspace/symbol" not found error (#723)
Browse files Browse the repository at this point in the history
* Discard outgoing "workspace/symbol" LSP messages
  • Loading branch information
DaelonSuzuka authored Sep 23, 2024
1 parent 1a84a57 commit 170d3d4
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 90 deletions.
40 changes: 21 additions & 19 deletions src/lsp/ClientConnectionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ import { subProcess, killSubProcesses } from "../utils/subspawn";
const log = createLogger("lsp.manager", { output: "Godot LSP" });

enum ManagerStatus {
INITIALIZING,
INITIALIZING_LSP,
PENDING,
PENDING_LSP,
DISCONNECTED,
CONNECTED,
RETRYING,
INITIALIZING = 0,
INITIALIZING_LSP = 1,
PENDING = 2,
PENDING_LSP = 3,
DISCONNECTED = 4,
CONNECTED = 5,
RETRYING = 6,
}

export class ClientConnectionManager {
Expand Down Expand Up @@ -126,16 +126,18 @@ export class ClientConnectionManager {

if (result.version[2] < minimumVersion) {
const message = `Cannot launch headless LSP: Headless LSP mode is only available on v${targetVersion} or newer, but the specified Godot executable is v${result.version}.`;
vscode.window.showErrorMessage(message, "Select Godot executable", "Open Settings", "Disable Headless LSP", "Ignore").then(item => {
if (item === "Select Godot executable") {
select_godot_executable(settingName);
} else if (item === "Open Settings") {
vscode.commands.executeCommand("workbench.action.openSettings", settingName);
} else if (item === "Disable Headless LSP") {
set_configuration("lsp.headless", false);
prompt_for_reload();
}
});
vscode.window
.showErrorMessage(message, "Select Godot executable", "Open Settings", "Disable Headless LSP", "Ignore")
.then((item) => {
if (item === "Select Godot executable") {
select_godot_executable(settingName);
} else if (item === "Open Settings") {
vscode.commands.executeCommand("workbench.action.openSettings", settingName);
} else if (item === "Disable Headless LSP") {
set_configuration("lsp.headless", false);
prompt_for_reload();
}
});
return;
}

Expand Down Expand Up @@ -197,7 +199,7 @@ export class ClientConnectionManager {
if (this.target === TargetLSP.HEADLESS) {
options = ["Restart LSP", ...options];
}
vscode.window.showInformationMessage(message, ...options).then(item => {
vscode.window.showInformationMessage(message, ...options).then((item) => {
if (item === "Restart LSP") {
this.connect_to_language_server();
}
Expand Down Expand Up @@ -324,7 +326,7 @@ export class ClientConnectionManager {
options = ["Open workspace with Godot Editor", ...options];
}

vscode.window.showErrorMessage(message, ...options).then(item => {
vscode.window.showErrorMessage(message, ...options).then((item) => {
if (item === "Retry") {
this.connect_to_language_server();
}
Expand Down
49 changes: 33 additions & 16 deletions src/lsp/GDScriptLanguageClient.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,40 @@
import * as vscode from "vscode";
import { LanguageClient, NotificationMessage, RequestMessage, ResponseMessage } from "vscode-languageclient/node";
import { EventEmitter } from "events";
import {
LanguageClient,
type NotificationMessage,
type RequestMessage,
type ResponseMessage,
} from "vscode-languageclient/node";
import { EventEmitter } from "node:events";
import { get_configuration, createLogger } from "../utils";
import { Message, MessageIO, MessageIOReader, MessageIOWriter, TCPMessageIO, WebSocketMessageIO } from "./MessageIO";
import {
type Message,
type MessageIO,
MessageIOReader,
MessageIOWriter,
TCPMessageIO,
WebSocketMessageIO,
} from "./MessageIO";
import { globals } from "../extension";

const log = createLogger("lsp.client", { output: "Godot LSP" });

export enum ClientStatus {
PENDING,
DISCONNECTED,
CONNECTED,
PENDING = 0,
DISCONNECTED = 1,
CONNECTED = 2,
}

export enum TargetLSP {
HEADLESS,
EDITOR,
HEADLESS = 0,
EDITOR = 1,
}

const CUSTOM_MESSAGE = "gdscript_client/";

export default class GDScriptLanguageClient extends LanguageClient {
public readonly io: MessageIO = (get_configuration("lsp.serverProtocol") === "ws") ? new WebSocketMessageIO() : new TCPMessageIO();
public readonly io: MessageIO =
get_configuration("lsp.serverProtocol") === "ws" ? new WebSocketMessageIO() : new TCPMessageIO();

private _status_changed_callbacks: ((v: ClientStatus) => void)[] = [];
private _initialize_request: Message = null;
Expand All @@ -35,10 +48,14 @@ export default class GDScriptLanguageClient extends LanguageClient {
public lastSymbolHovered = "";

private _started = false;
public get started(): boolean { return this._started; }
public get started(): boolean {
return this._started;
}

private _status: ClientStatus;
public get status(): ClientStatus { return this._status; }
public get status(): ClientStatus {
return this._status;
}
public set status(v: ClientStatus) {
if (this._status !== v) {
this._status = v;
Expand Down Expand Up @@ -72,7 +89,7 @@ export default class GDScriptLanguageClient extends LanguageClient {
// Notify the server about file changes to '.gd files contain in the workspace
fileEvents: vscode.workspace.createFileSystemWatcher("**/*.gd"),
},
}
},
);
this.status = ClientStatus.PENDING;
this.io.on("disconnected", this.on_disconnected.bind(this));
Expand Down Expand Up @@ -149,7 +166,7 @@ export default class GDScriptLanguageClient extends LanguageClient {
let value: string = message.result["contents"]?.value;
if (value) {
// this is a dirty hack to fix language server sending us prerendered
// markdown but not correctly stripping leading #'s, leading to
// markdown but not correctly stripping leading #'s, leading to
// docstrings being displayed as titles
value = value.replace(/\n[#]+/g, "\n");

Expand Down Expand Up @@ -216,7 +233,7 @@ export default class GDScriptLanguageClient extends LanguageClient {
this.io.writer.write(this._initialize_request);
}
this.status = ClientStatus.CONNECTED;

const host = get_configuration("lsp.serverHost");
log.info(`connected to LSP at ${host}:${this.lastPortTried}`);
}
Expand Down Expand Up @@ -260,12 +277,12 @@ class MessageHandler extends EventEmitter {

on_message(message: any) {
// FIXME: Hot fix VSCode 1.42 hover position
if (message && message.result && message.result.range && message.result.contents) {
if (message?.result?.range && message.result.contents) {
message.result.range = undefined;
}

// What does this do?
if (message && message.method && (message.method as string).startsWith(CUSTOM_MESSAGE)) {
if (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]) {
const ret = this[method](message.params);
Expand Down
53 changes: 29 additions & 24 deletions src/lsp/MessageBuffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,33 @@
* ------------------------------------------------------------------------------------------ */

const DefaultSize: number = 8192;
const CR: number = Buffer.from('\r', 'ascii')[0];
const LF: number = Buffer.from('\n', 'ascii')[0];
const CRLF: string = '\r\n';
const CR: number = Buffer.from("\r", "ascii")[0];
const LF: number = Buffer.from("\n", "ascii")[0];
const CRLF: string = "\r\n";

export default class MessageBuffer {

private encoding: BufferEncoding;
private index: number;
private buffer: Buffer;

constructor(encoding: string = 'utf8') {
constructor(encoding = "utf8") {
this.encoding = encoding as BufferEncoding;
this.index = 0;
this.buffer = Buffer.allocUnsafe(DefaultSize);
}

public append(chunk: Buffer | String): void {
var toAppend: Buffer = <Buffer>chunk;
if (typeof (chunk) === 'string') {
var str = <string>chunk;
var bufferLen = Buffer.byteLength(str, this.encoding);
public append(chunk: Buffer | string): void {
let toAppend: Buffer = <Buffer>chunk;
if (typeof chunk === "string") {
const str = <string>chunk;
const bufferLen = Buffer.byteLength(str, this.encoding);
toAppend = Buffer.allocUnsafe(bufferLen);
toAppend.write(str, 0, bufferLen, this.encoding);
}
if (this.buffer.length - this.index >= toAppend.length) {
toAppend.copy(this.buffer, this.index, 0, toAppend.length);
} else {
var newSize = (Math.ceil((this.index + toAppend.length) / DefaultSize) + 1) * DefaultSize;
const newSize = (Math.ceil((this.index + toAppend.length) / DefaultSize) + 1) * DefaultSize;
if (this.index === 0) {
this.buffer = Buffer.allocUnsafe(newSize);
toAppend.copy(this.buffer, 0, 0, toAppend.length);
Expand All @@ -42,29 +41,35 @@ export default class MessageBuffer {
this.index += toAppend.length;
}

public tryReadHeaders(): { [key: string]: string; } | undefined {
let result: { [key: string]: string; } | undefined = undefined;
public tryReadHeaders(): { [key: string]: string } | undefined {
let result: { [key: string]: string } | undefined = undefined;
let current = 0;
while (current + 3 < this.index && (this.buffer[current] !== CR || this.buffer[current + 1] !== LF || this.buffer[current + 2] !== CR || this.buffer[current + 3] !== LF)) {
while (
current + 3 < this.index &&
(this.buffer[current] !== CR ||
this.buffer[current + 1] !== LF ||
this.buffer[current + 2] !== CR ||
this.buffer[current + 3] !== LF)
) {
current++;
}
// No header / body separator found (e.g CRLFCRLF)
if (current + 3 >= this.index) {
return result;
}
result = Object.create(null);
let headers = this.buffer.toString('ascii', 0, current).split(CRLF);
headers.forEach((header) => {
let index: number = header.indexOf(':');
const headers = this.buffer.toString("ascii", 0, current).split(CRLF);
for (const header of headers) {
const index: number = header.indexOf(":");
if (index === -1) {
throw new Error('Message header must separate key and value using :');
throw new Error("Message header must separate key and value using :");
}
let key = header.substr(0, index);
let value = header.substr(index + 1).trim();
const key = header.substr(0, index);
const value = header.substr(index + 1).trim();
result![key] = value;
});
}

let nextStart = current + 4;
const nextStart = current + 4;
this.buffer = this.buffer.slice(nextStart);
this.index = this.index - nextStart;
return result;
Expand All @@ -74,8 +79,8 @@ export default class MessageBuffer {
if (this.index < length) {
return null;
}
let result = this.buffer.toString(this.encoding, 0, length);
let nextStart = length;
const result = this.buffer.toString(this.encoding, 0, length);
const nextStart = length;
this.buffer.copy(this.buffer, 0, nextStart);
this.index = this.index - nextStart;
return result;
Expand Down
Loading

0 comments on commit 170d3d4

Please sign in to comment.