Skip to content

Commit

Permalink
refactor(lsp): LSP refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Princesseuh committed Dec 15, 2024
1 parent e4880c7 commit 77081a1
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 142 deletions.
35 changes: 13 additions & 22 deletions crates/weblsp/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ mod requests;
mod response;
mod server;
use lsp_server::{Connection, Message};
use lsp_types::{notification::Notification, InitializeParams};
use lsp_types::InitializeParams;
use server::get_server_capabilities;
use std::{error::Error, process::ExitCode};

Expand Down Expand Up @@ -49,34 +49,25 @@ fn main_loop(
init_params: serde_json::Value,
mut css_language_service: csslsrs::service::LanguageService,
) -> Result<ExitCode, Box<dyn Error + Sync + Send>> {
let mut awaiting_exit = false;
let _init_params: InitializeParams = serde_json::from_value(init_params).unwrap();

for msg in &connection.receiver {
// TODO: Handle trace levels and notifications instead of just printing them to stderr.
eprintln!("new msg: {:?}", msg);

// If we're waiting for an exit notification, any message other than it is an error, and will cause the server to exit with a failure exit code.
// As such, we can handle this outside of the match statement.
if awaiting_exit {
if let Message::Notification(not) = &msg {
if not.method == lsp_types::notification::Exit::METHOD {
return Ok(ExitCode::SUCCESS);
}
}
eprintln!("Shutting down without receiving `Exit` notification.");
return Ok(ExitCode::FAILURE);
}

// Handle the rest of the messages.
match msg {
Message::Request(req) => {
let request =
requests::handle_request(req, &mut css_language_service, &connection)?;
match connection.handle_shutdown(&req) {
Ok(value) => {
if value {
return Ok(ExitCode::SUCCESS);
}
}
Err(err) => {
eprintln!("Error handling shutdown request: {:?}", err);
return Ok(ExitCode::FAILURE);
}
};

if request.is_shutdown {
awaiting_exit = true;
}
requests::handle_request(req, &mut css_language_service, &connection)?;
}
Message::Response(resp) => {
response::handle_response(resp)?;
Expand Down
3 changes: 0 additions & 3 deletions crates/weblsp/src/notifications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ pub fn handle_notification(
serde_json::from_value(notification.params).unwrap();
match params.text_document.language_id.as_str() {
"css" => {
eprintln!(
"textDocument/didOpen: adding CSS document to CSS Language Service store"
);
css_language_service.upsert_document(params.text_document);
}
_ => {
Expand Down
21 changes: 2 additions & 19 deletions crates/weblsp/src/requests.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,16 @@
use lsp_server::{Connection, ExtractError, Request, RequestId};
use lsp_types::request::Request as _;
use std::error::Error;
use std::str::FromStr;

use crate::css;

#[derive(Default)]
pub struct RequestOutcome {
pub(crate) is_shutdown: bool,
}

/// Used by the main loop. Based on the document's language, this function will dispatch the request to the appropriate language handler.
/// Requests are LSP features that the client wants to use, and the server must respond to each request.
pub fn handle_request(
req: lsp_server::Request,
css_language_service: &mut csslsrs::service::LanguageService,
connection: &Connection,
) -> Result<RequestOutcome, Box<dyn Error + Sync + Send>> {
if req.method == lsp_types::request::Shutdown::METHOD {
connection
.sender
.send(lsp_server::Message::Response(lsp_server::Response::new_ok(
req.id,
(),
)))?;

return Ok(RequestOutcome { is_shutdown: true });
}

) -> Result<(), Box<dyn Error + Sync + Send>> {
let language_id = get_language_id(&req, css_language_service)?;
match language_id.as_str() {
"css" => {
Expand All @@ -38,7 +21,7 @@ pub fn handle_request(
}
}

Ok(RequestOutcome::default())
Ok(())
}

// TMP: TODO: For now, we use CSSlsrs' store, because we only support CSS. So I can just retrieve the document from this store from its URI.
Expand Down
101 changes: 56 additions & 45 deletions packages/vscode/package.json
Original file line number Diff line number Diff line change
@@ -1,47 +1,58 @@
{
"name": "@weblsp/vscode",
"displayName": "WEBlsp",
"version": "1.0.0",
"description": "A better Language Server for the Web, made with Rust — WORK IN PROGRESS ⚠️",
"repository": {
"type": "git",
"url": "https://github.com/web-lsp/weblsp"
},
"license": "MIT",
"engines": {
"vscode": "^1.82.0"
},
"categories": [
"Programming Languages"
],
"activationEvents": [
"onLanguage:css"
],
"main": "./dist/extension.js",
"contributes": {
"configuration": {
"type": "object",
"title": "CSS Language Server Settings",
"properties": {
"cssLanguageServer.path": {
"type": "string",
"description": "Path to the CSS language server executable",
"default": ""
}
}
}
},
"scripts": {
"vscode:prepublish": "npm run compile",
"build": "tsc -p ./",
"watch": "tsc -watch -p ./"
},
"devDependencies": {
"@types/node": "^22.9.1",
"@types/vscode": "^1.95.0",
"typescript": "^5.6.3"
},
"dependencies": {
"vscode-languageclient": "^9.0.1"
}
"name": "@weblsp/vscode",
"displayName": "WEBlsp",
"version": "1.0.0",
"description": "A better Language Server for the Web, made with Rust — WORK IN PROGRESS ⚠️",
"repository": {
"type": "git",
"url": "https://github.com/web-lsp/weblsp"
},
"license": "MIT",
"engines": {
"vscode": "^1.82.0"
},
"categories": [
"Programming Languages"
],
"activationEvents": [
"onLanguage:css"
],
"main": "./dist/extension.js",
"contributes": {
"configuration": {
"type": "object",
"title": "WEBlsp configuration",
"properties": {
"weblsp.trace.server": {
"scope": "window",
"type": "string",
"enum": [
"off",
"messages",
"verbose"
],
"default": "off",
"description": "Traces the communication between VS Code and the language server."
},
"weblsp.server.path": {
"type": "string",
"description": "Path to the WEBlsp executable",
"default": ""
}
}
}
},
"scripts": {
"vscode:prepublish": "npm run build",
"build": "tsc -p ./",
"watch": "tsc -watch -p ./"
},
"devDependencies": {
"@types/node": "^22.9.1",
"@types/vscode": "^1.95.0",
"typescript": "^5.6.3"
},
"dependencies": {
"vscode-languageclient": "^9.0.1"
}
}
98 changes: 45 additions & 53 deletions packages/vscode/src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,78 +1,70 @@
import * as path from "path"
import * as vscode from "vscode"
import * as lsp from "vscode-languageclient/node"
import * as path from "path";
import * as vscode from "vscode";
import * as lsp from "vscode-languageclient/node";

let client: lsp.LanguageClient
let client: lsp.LanguageClient;

/**
* Turn on WEBlsp's vscode extension 🚀
*/
export async function activate(context: vscode.ExtensionContext) {
const serverExecutable = getServerExecutablePath(context)
const serverExecutable = getServerExecutablePath(context);

const serverOptions: lsp.ServerOptions = {
command: serverExecutable,
args: [],
options: {
// vscode.workspace.rootPath is deprecated, so we'll just run on the first workspace folder
cwd:
(vscode.workspace.workspaceFolders &&
vscode.workspace.workspaceFolders[0].uri.fsPath) ||
process.cwd(),
},
}
const serverOptions: lsp.ServerOptions = {
command: serverExecutable,
};

const clientOptions: lsp.LanguageClientOptions = {
// TODO: We should add the support of HTML later
documentSelector: [{ scheme: "file", language: "css" }],
synchronize: {
fileEvents: vscode.workspace.createFileSystemWatcher("**/*.css"),
},
}
const clientOptions: lsp.LanguageClientOptions = {
// TODO: We should add the support of HTML later
documentSelector: [{ scheme: "file", language: "css" }],
synchronize: {
fileEvents: vscode.workspace.createFileSystemWatcher("**/*.css"),
},
};

client = new lsp.LanguageClient(
"cssLanguageServer",
"CSS Language Server",
serverOptions,
clientOptions
)
client = new lsp.LanguageClient(
"weblsp",
"WEBlsp Language Server",
serverOptions,
clientOptions
);

await client.start()
await client.start();
}

/**
* Cut off WEBlsp's vscode extension 😢
*/
export function deactivate(): Thenable<void> | undefined {
if (!client) {
return undefined
}
return client.stop()
if (!client) {
return undefined;
}
return client.stop();
}

/**
* Get the Rust WEBlsp binary path from the configuration.
*/
function getServerExecutablePath(context: vscode.ExtensionContext): string {
const config = vscode.workspace.getConfiguration("cssLanguageServer")
let serverPath = config.get<string>("path")
const config = vscode.workspace.getConfiguration("weblsp");
let serverPath = config.get<string>("server.path");

if (serverPath) {
if (!path.isAbsolute(serverPath)) {
if (
vscode.workspace.workspaceFolders &&
vscode.workspace.workspaceFolders.length > 0
) {
const rootPath = vscode.workspace.workspaceFolders[0].uri.fsPath
serverPath = path.join(rootPath, serverPath)
}
}
} else {
serverPath = vscode.Uri.joinPath(
context.extensionUri,
"../../target/debug/weblsp"
).fsPath
}
if (serverPath) {
if (!path.isAbsolute(serverPath)) {
if (
vscode.workspace.workspaceFolders &&
vscode.workspace.workspaceFolders.length > 0
) {
const rootPath = vscode.workspace.workspaceFolders[0].uri.fsPath;
serverPath = path.join(rootPath, serverPath);
}
}
} else {
serverPath = vscode.Uri.joinPath(
context.extensionUri,
"../../target/debug/weblsp"
).fsPath;
}

return serverPath
return serverPath;
}

0 comments on commit 77081a1

Please sign in to comment.