Skip to content

Commit

Permalink
ditch tower_lsp in favor of lsp_server
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidLee18 committed Oct 30, 2024
1 parent 711a4e9 commit b35dd28
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 142 deletions.
9 changes: 2 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,9 @@ version = "0.1.0"
edition = "2021"

[dependencies]
lsp-server = "0.7.7"
lsp-types = "0.97.0"
nom = "7.1.3"
serde_json = "1.0.128"
tokio = { version = "1.40.0", features = [
"rt-multi-thread",
"macros",
"io-std",
] }
tokio-macros = "2.4.0"
tower-lsp = "0.20.0"
tracing-subscriber = "0.3.18"
serde = "1.0.210"
250 changes: 116 additions & 134 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,140 +1,32 @@
pub mod norminette_msg;
pub mod parser;

use lsp_server::{Connection, ExtractError, Message, Request, RequestId, Response};
use lsp_types::request::DocumentDiagnosticRequest;
use lsp_types::{
Diagnostic, DiagnosticOptions, DiagnosticServerCapabilities, InitializeParams,
LogMessageParams, MessageType, PublishDiagnosticsParams, ServerCapabilities,
WorkDoneProgressOptions,
};
use parser::parse_norminette;
use std::error::Error;
use std::io;
use std::path::Path;

use parser::parse_norminette;
use serde_json::Value;
use tower_lsp::jsonrpc::{self, Result};
use tower_lsp::lsp_types::*;
use tower_lsp::{Client, LanguageServer, LspService, Server};

#[derive(Debug)]
struct Backend {
client: Client,
// norminette_options: Arc<Mutex<?>>
}

#[tower_lsp::async_trait]
impl LanguageServer for Backend {
async fn initialize(&self, _: InitializeParams) -> Result<InitializeResult> {
Ok(InitializeResult {
server_info: None,
capabilities: ServerCapabilities {
diagnostic_provider: Some(DiagnosticServerCapabilities::Options(
DiagnosticOptions::default(),
)),
workspace: Some(WorkspaceServerCapabilities {
workspace_folders: Some(WorkspaceFoldersServerCapabilities {
supported: Some(true),
change_notifications: None,
}),
file_operations: None,
}),
..Default::default()
},
})
}

async fn initialized(&self, _: InitializedParams) {
self.client
.log_message(MessageType::INFO, "initialized!")
.await;
}

async fn shutdown(&self) -> Result<()> {
Ok(())
}

async fn did_open(&self, p: DidOpenTextDocumentParams) {
self.client
.log_message(MessageType::INFO, "file opened!")
.await;
match read_norminette(&Path::new(p.text_document.uri.path())) {
Ok(diags) => {
self.client
.publish_diagnostics(p.text_document.uri, diags, None)
.await;
}
Err(e) => {
self.client.log_message(MessageType::ERROR, format!("norminette read of {} failed: {}", p.text_document.uri, e)).await;
}
}
}

async fn did_change(&self, p: DidChangeTextDocumentParams) {
self.client
.log_message(MessageType::INFO, "file changed!")
.await;
match read_norminette(&Path::new(p.text_document.uri.path())) {
Ok(diags) => {
self.client
.publish_diagnostics(p.text_document.uri, diags, None)
.await;
}
Err(e) => {
self.client.log_message(MessageType::ERROR, format!("norminette read of {} failed: {}", p.text_document.uri, e)).await;
}
}

}

async fn did_save(&self, p: DidSaveTextDocumentParams) {
self.client
.log_message(MessageType::INFO, format!("file saved: {:?}", p.text))
.await;
match read_norminette(&Path::new(p.text_document.uri.path())) {
Ok(diags) => {
self.client
.publish_diagnostics(p.text_document.uri, diags, None)
.await;
},
Err(e) => {
self.client.log_message(MessageType::ERROR, format!("norminette read of {} failed: {}", p.text_document.uri, e)).await;
}
}
}

async fn did_close(&self, _: DidCloseTextDocumentParams) {
self.client
.log_message(MessageType::INFO, "file closed!")
.await;
}

async fn completion(&self, _: CompletionParams) -> Result<Option<CompletionResponse>> {
Err(jsonrpc::Error::method_not_found())
}

async fn did_change_configuration(&self, _: DidChangeConfigurationParams) {
self.client
.log_message(MessageType::INFO, "configuration changed!")
.await;
}

async fn did_change_workspace_folders(&self, _: DidChangeWorkspaceFoldersParams) {
self.client
.log_message(MessageType::INFO, "workspace folders changed!")
.await;
}

async fn did_change_watched_files(&self, _: DidChangeWatchedFilesParams) {
self.client
.log_message(MessageType::INFO, "watched files have changed!")
.await;
}

async fn execute_command(&self, _: ExecuteCommandParams) -> Result<Option<Value>> {
Err(jsonrpc::Error::method_not_found())
}
}

pub fn read_norminette(path: &Path) -> io::Result<Vec<Diagnostic>> {
fn read_norminette(path: &Path) -> io::Result<Vec<Diagnostic>> {
let output = std::process::Command::new("norminette")
.arg(path)
.output()?;
let (_, diags) = parse_norminette(&String::from_utf8(output.stdout).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?)
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("norminette parse error: {:?}", err)))?;
let (_, diags) = parse_norminette(
&String::from_utf8(output.stdout)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?,
)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("norminette parse error: {:?}", err),
)
})?;

Ok(diags
.into_iter()
Expand All @@ -144,12 +36,102 @@ pub fn read_norminette(path: &Path) -> io::Result<Vec<Diagnostic>> {
.collect())
}

#[tokio::main]
async fn main() {
tracing_subscriber::fmt().init();
fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
eprintln!("starting norminette LSP server");

let (connection, io_threads) = Connection::stdio();

let server_capabilities = serde_json::to_value(&ServerCapabilities {
diagnostic_provider: Some(DiagnosticServerCapabilities::Options(DiagnosticOptions {
identifier: None,
inter_file_dependencies: false,
workspace_diagnostics: false,
work_done_progress_options: WorkDoneProgressOptions::default(),
})),
..Default::default()
})?;
let initialization_params = match connection.initialize(server_capabilities) {
Ok(it) => it,
Err(e) => {
if e.channel_is_disconnected() {
io_threads.join()?;
}
return Err(e.into());
}
};
eprintln!("initialized connection!");
main_loop(connection, initialization_params)?;
io_threads.join()?;
eprintln!("shutting down server");
Ok(())
}

let (stdin, stdout) = (tokio::io::stdin(), tokio::io::stdout());
fn main_loop(
connection: Connection,
params: serde_json::Value,
) -> Result<(), Box<dyn Error + Sync + Send>> {
let _params: InitializeParams = serde_json::from_value(params)?;

for msg in &connection.receiver {
eprintln!("got msg: {msg:?}");
match msg {
Message::Request(req) => {
if connection.handle_shutdown(&req)? {
return Ok(());
}
eprintln!("got request: {req:?}");
match cast::<DocumentDiagnosticRequest>(req) {
Ok((id, params)) => {
eprintln!("got doc diagnostic request #{id} params: {params:?}");
match read_norminette(&Path::new(params.text_document.uri.path().as_str()))
{
Ok(diags) => {
connection.sender.send(Message::Response(Response {
id,
result: Some(serde_json::to_value(
&PublishDiagnosticsParams {
uri: params.text_document.uri,
diagnostics: diags,
version: None,
},
)?),
error: None,
}))?;
}
Err(e) => {
connection.sender.send(Message::Response(Response {
id,
result: Some(serde_json::to_value(&LogMessageParams {
typ: MessageType::ERROR,
message: format!(
"norminette read of {} failed: {}",
params.text_document.uri.path(),
e
),
})?),
error: None,
}))?;
}
}
}
Err(e) => return Err(Box::new(e)),
};
}
Message::Response(resp) => {
eprintln!("got response: {resp:?}");
}
Message::Notification(not) => {
eprintln!("got notification: {not:?}");
}
}
}
Ok(())
}

let (service, socket) = LspService::new(|client| Backend { client });
Server::new(stdin, stdout, socket).serve(service).await;
fn cast<R>(req: Request) -> Result<(RequestId, R::Params), ExtractError<Request>>
where
R: lsp_types::request::Request,
R::Params: serde::de::DeserializeOwned,
{
req.extract(R::METHOD)
}
2 changes: 1 addition & 1 deletion src/norminette_msg.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::u32;

use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, NumberOrString, Position, Range};
use lsp_types::{Diagnostic, DiagnosticSeverity, NumberOrString, Position, Range};

#[derive(Debug)]
pub enum NorminetteMsg {
Expand Down

0 comments on commit b35dd28

Please sign in to comment.