From 52fb90b81eb6eb48ed64aceb7e6e1527b25cd998 Mon Sep 17 00:00:00 2001 From: wojciechkepka Date: Fri, 18 Jun 2021 05:37:40 +0200 Subject: Add `MethodCall`, `ProgressStatus`, `LspProgressMap` --- helix-lsp/src/lib.rs | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) (limited to 'helix-lsp') diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index cff62492..be1e23a5 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -181,6 +181,30 @@ pub mod util { } } +#[derive(Debug, PartialEq, Clone)] +pub enum MethodCall { + WorkDoneProgressCreate(lsp::WorkDoneProgressCreateParams), +} + +impl MethodCall { + pub fn parse(method: &str, params: jsonrpc::Params) -> Option { + use lsp::request::Request; + let request = match method { + lsp::request::WorkDoneProgressCreate::METHOD => { + let params: lsp::WorkDoneProgressCreateParams = params + .parse() + .expect("Failed to parse WorkDoneCreate params"); + Self::WorkDoneProgressCreate(params) + } + _ => { + log::warn!("unhandled lsp request: {}", method); + return None; + } + }; + Some(request) + } +} + #[derive(Debug, PartialEq, Clone)] pub enum Notification { PublishDiagnostics(lsp::PublishDiagnosticsParams), @@ -275,6 +299,80 @@ impl Registry { } } +#[derive(Debug)] +pub enum ProgressStatus { + Created, + Started(lsp::WorkDoneProgress), +} + +impl ProgressStatus { + pub fn progress(&self) -> Option<&lsp::WorkDoneProgress> { + match &self { + ProgressStatus::Created => None, + ProgressStatus::Started(progress) => Some(&progress), + } + } +} + +#[derive(Default, Debug)] +/// Acts as a container for progress reported by language servers. Each server +/// has a unique id assigned at creation through [`Registry`]. This id is then used +/// to store the progress in this map. +pub struct LspProgressMap(HashMap>); + +impl LspProgressMap { + pub fn new() -> Self { + Self::default() + } + + /// Returns a map of all tokens coresponding to the lanaguage server with `id`. + pub fn progress_map(&self, id: usize) -> Option<&HashMap> { + self.0.get(&id) + } + + /// Returns last progress status for a given server with `id` and `token`. + pub fn progress(&self, id: usize, token: &lsp::ProgressToken) -> Option<&ProgressStatus> { + self.0.get(&id).and_then(|values| values.get(token)) + } + + /// Checks if progress `token` for server with `id` is created. + pub fn is_created(&mut self, id: usize, token: &lsp::ProgressToken) -> bool { + self.0 + .get(&id) + .map(|values| values.get(token).is_some()) + .unwrap_or_default() + } + + pub fn create(&mut self, id: usize, token: lsp::ProgressToken) { + self.0 + .entry(id) + .or_default() + .insert(token, ProgressStatus::Created); + } + + /// Ends the progress by removing the `token` from server with `id`, if removed returns the value. + pub fn end_progress( + &mut self, + id: usize, + token: &lsp::ProgressToken, + ) -> Option { + self.0.get_mut(&id).and_then(|vals| vals.remove(token)) + } + + /// Updates the progess of `token` for server with `id` to `status`, returns the value replaced or `None`. + pub fn update( + &mut self, + id: usize, + token: lsp::ProgressToken, + status: lsp::WorkDoneProgress, + ) -> Option { + self.0 + .entry(id) + .or_default() + .insert(token, ProgressStatus::Started(status)) + } +} + // REGISTRY = HashMap>> // spawn one server per language type, need to spawn one per workspace if server doesn't support // workspaces -- cgit v1.2.3-70-g09d2 From a6d39585d8a1cf260262e7f3e3c4741791582049 Mon Sep 17 00:00:00 2001 From: wojciechkepka Date: Fri, 18 Jun 2021 05:39:37 +0200 Subject: Add `work_done_token` as parameter to lsp methods --- helix-lsp/src/client.rs | 52 +++++++++++++++++++++++++--------------------- helix-term/src/commands.rs | 14 ++++++------- helix-view/src/document.rs | 9 ++++---- 3 files changed, 40 insertions(+), 35 deletions(-) (limited to 'helix-lsp') diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 9ca708a7..0b52681c 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -465,6 +465,7 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option, ) -> impl Future> { // ) -> Result> { let params = lsp::CompletionParams { @@ -473,9 +474,7 @@ impl Client { position, }, // TODO: support these tokens by async receiving and updating the choice list - work_done_progress_params: lsp::WorkDoneProgressParams { - work_done_token: None, - }, + work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token }, partial_result_params: lsp::PartialResultParams { partial_result_token: None, }, @@ -490,15 +489,14 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option, ) -> impl Future> { let params = lsp::SignatureHelpParams { text_document_position_params: lsp::TextDocumentPositionParams { text_document, position, }, - work_done_progress_params: lsp::WorkDoneProgressParams { - work_done_token: None, - }, + work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token }, context: None, // lsp::SignatureHelpContext }; @@ -510,15 +508,14 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option, ) -> impl Future> { let params = lsp::HoverParams { text_document_position_params: lsp::TextDocumentPositionParams { text_document, position, }, - work_done_progress_params: lsp::WorkDoneProgressParams { - work_done_token: None, - }, + work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token }, // lsp::SignatureHelpContext }; @@ -531,6 +528,7 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, options: lsp::FormattingOptions, + work_done_token: Option, ) -> anyhow::Result> { let capabilities = self.capabilities.as_ref().unwrap(); @@ -545,9 +543,7 @@ impl Client { let params = lsp::DocumentFormattingParams { text_document, options, - work_done_progress_params: lsp::WorkDoneProgressParams { - work_done_token: None, - }, + work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token }, }; let response = self.request::(params).await?; @@ -560,6 +556,7 @@ impl Client { text_document: lsp::TextDocumentIdentifier, range: lsp::Range, options: lsp::FormattingOptions, + work_done_token: Option, ) -> anyhow::Result> { let capabilities = self.capabilities.as_ref().unwrap(); @@ -575,9 +572,7 @@ impl Client { text_document, range, options, - work_done_progress_params: lsp::WorkDoneProgressParams { - work_done_token: None, - }, + work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token }, }; let response = self @@ -596,15 +591,14 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option, ) -> impl Future> { let params = lsp::GotoDefinitionParams { text_document_position_params: lsp::TextDocumentPositionParams { text_document, position, }, - work_done_progress_params: lsp::WorkDoneProgressParams { - work_done_token: None, - }, + work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token }, partial_result_params: lsp::PartialResultParams { partial_result_token: None, }, @@ -617,30 +611,42 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option, ) -> impl Future> { - self.goto_request::(text_document, position) + self.goto_request::(text_document, position, work_done_token) } pub fn goto_type_definition( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option, ) -> impl Future> { - self.goto_request::(text_document, position) + self.goto_request::( + text_document, + position, + work_done_token, + ) } pub fn goto_implementation( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option, ) -> impl Future> { - self.goto_request::(text_document, position) + self.goto_request::( + text_document, + position, + work_done_token, + ) } pub fn goto_reference( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option, ) -> impl Future> { let params = lsp::ReferenceParams { text_document_position: lsp::TextDocumentPositionParams { @@ -650,9 +656,7 @@ impl Client { context: lsp::ReferenceContext { include_declaration: true, }, - work_done_progress_params: lsp::WorkDoneProgressParams { - work_done_token: None, - }, + work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token }, partial_result_params: lsp::PartialResultParams { partial_result_token: None, }, diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index b2dd0d11..9b916a5e 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1852,7 +1852,7 @@ fn goto_definition(cx: &mut Context) { let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding); // TODO: handle fails - let future = language_server.goto_definition(doc.identifier(), pos); + let future = language_server.goto_definition(doc.identifier(), pos, None); cx.callback( future, @@ -1889,7 +1889,7 @@ fn goto_type_definition(cx: &mut Context) { let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding); // TODO: handle fails - let future = language_server.goto_type_definition(doc.identifier(), pos); + let future = language_server.goto_type_definition(doc.identifier(), pos, None); cx.callback( future, @@ -1926,7 +1926,7 @@ fn goto_implementation(cx: &mut Context) { let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding); // TODO: handle fails - let future = language_server.goto_implementation(doc.identifier(), pos); + let future = language_server.goto_implementation(doc.identifier(), pos, None); cx.callback( future, @@ -1963,7 +1963,7 @@ fn goto_reference(cx: &mut Context) { let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding); // TODO: handle fails - let future = language_server.goto_reference(doc.identifier(), pos); + let future = language_server.goto_reference(doc.identifier(), pos, None); cx.callback( future, @@ -2075,7 +2075,7 @@ fn signature_help(cx: &mut Context) { ); // TODO: handle fails - let future = language_server.text_document_signature_help(doc.identifier(), pos); + let future = language_server.text_document_signature_help(doc.identifier(), pos, None); cx.callback( future, @@ -2718,7 +2718,7 @@ fn completion(cx: &mut Context) { let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding); // TODO: handle fails - let future = language_server.completion(doc.identifier(), pos); + let future = language_server.completion(doc.identifier(), pos, None); let trigger_offset = doc.selection(view.id).cursor(); @@ -2776,7 +2776,7 @@ fn hover(cx: &mut Context) { ); // TODO: handle fails - let future = language_server.text_document_hover(doc.identifier(), pos); + let future = language_server.text_document_hover(doc.identifier(), pos, None); cx.callback( future, diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index fe9c87f7..e9a8097c 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -263,10 +263,11 @@ impl Document { pub fn format(&mut self, view_id: ViewId) { if let Some(language_server) = self.language_server() { // TODO: await, no blocking - let transaction = helix_lsp::block_on( - language_server - .text_document_formatting(self.identifier(), lsp::FormattingOptions::default()), - ) + let transaction = helix_lsp::block_on(language_server.text_document_formatting( + self.identifier(), + lsp::FormattingOptions::default(), + None, + )) .map(|edits| { helix_lsp::util::generate_transaction_from_edits( self.text(), -- cgit v1.2.3-70-g09d2 From 80b4a690535b2171cc7db2ee6b4daf3bcb4c4f11 Mon Sep 17 00:00:00 2001 From: wojciechkepka Date: Fri, 18 Jun 2021 05:40:57 +0200 Subject: Update `client::reply` to be non async --- helix-lsp/src/client.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'helix-lsp') diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 0b52681c..6554e996 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -165,13 +165,16 @@ impl Client { } /// Reply to a language server RPC call. - pub async fn reply( + pub fn reply( &self, id: jsonrpc::Id, result: core::result::Result, - ) -> Result<()> { + ) -> impl Future> { use jsonrpc::{Failure, Output, Success, Version}; + let server_tx = self.server_tx.clone(); + + async move { let output = match result { Ok(result) => Output::Success(Success { jsonrpc: Some(Version::V2), @@ -185,12 +188,13 @@ impl Client { }), }; - self.server_tx + server_tx .send(Payload::Response(output)) .map_err(|e| Error::Other(e.into()))?; Ok(()) } + } // ------------------------------------------------------------------------------------------- // General messages -- cgit v1.2.3-70-g09d2 From 38cb934d8f579663ff13496bf79293103863b60b Mon Sep 17 00:00:00 2001 From: wojciechkepka Date: Fri, 18 Jun 2021 05:42:34 +0200 Subject: Add unique id to each lsp client/server pair --- helix-lsp/src/client.rs | 14 ++++++++++++-- helix-lsp/src/lib.rs | 25 +++++++++++++++++++------ helix-lsp/src/transport.rs | 12 +++++++++--- helix-term/src/application.rs | 12 ++++++++---- 4 files changed, 48 insertions(+), 15 deletions(-) (limited to 'helix-lsp') diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 6554e996..e14d0197 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -18,6 +18,7 @@ use tokio::{ #[derive(Debug)] pub struct Client { + id: usize, _process: Child, server_tx: UnboundedSender, request_counter: AtomicU64, @@ -26,7 +27,11 @@ pub struct Client { } impl Client { - pub fn start(cmd: &str, args: &[String]) -> Result<(Self, UnboundedReceiver)> { + pub fn start( + cmd: &str, + args: &[String], + id: usize, + ) -> Result<(Self, UnboundedReceiver<(usize, Call)>)> { let process = Command::new(cmd) .args(args) .stdin(Stdio::piped()) @@ -43,9 +48,10 @@ impl Client { let reader = BufReader::new(process.stdout.take().expect("Failed to open stdout")); let stderr = BufReader::new(process.stderr.take().expect("Failed to open stderr")); - let (server_rx, server_tx) = Transport::start(reader, writer, stderr); + let (server_rx, server_tx) = Transport::start(reader, writer, stderr, id); let client = Self { + id, _process: process, server_tx, request_counter: AtomicU64::new(0), @@ -59,6 +65,10 @@ impl Client { Ok((client, server_rx)) } + pub fn id(&self) -> usize { + self.id + } + fn next_request_id(&self) -> jsonrpc::Id { let id = self.request_counter.fetch_add(1, Ordering::Relaxed); jsonrpc::Id::Num(id) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index be1e23a5..774de075 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -13,7 +13,10 @@ use helix_core::syntax::LanguageConfiguration; use std::{ collections::{hash_map::Entry, HashMap}, - sync::Arc, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, + }, }; use serde::{Deserialize, Serialize}; @@ -254,9 +257,10 @@ impl Notification { #[derive(Debug)] pub struct Registry { - inner: HashMap>, + inner: HashMap)>, - pub incoming: SelectAll>, + counter: AtomicUsize, + pub incoming: SelectAll>, } impl Default for Registry { @@ -269,10 +273,18 @@ impl Registry { pub fn new() -> Self { Self { inner: HashMap::new(), + counter: AtomicUsize::new(0), incoming: SelectAll::new(), } } + pub fn get_by_id(&mut self, id: usize) -> Option<&Client> { + self.inner + .values() + .find(|(client_id, _)| client_id == &id) + .map(|(_, client)| client.as_ref()) + } + pub fn get(&mut self, language_config: &LanguageConfiguration) -> Result> { if let Some(config) = &language_config.language_server { // avoid borrow issues @@ -280,16 +292,17 @@ impl Registry { let s_incoming = &mut self.incoming; match inner.entry(language_config.scope.clone()) { - Entry::Occupied(language_server) => Ok(language_server.get().clone()), + Entry::Occupied(entry) => Ok(entry.get().1.clone()), Entry::Vacant(entry) => { // initialize a new client - let (mut client, incoming) = Client::start(&config.command, &config.args)?; + let id = self.counter.fetch_add(1, Ordering::Relaxed); + let (mut client, incoming) = Client::start(&config.command, &config.args, id)?; // TODO: run this async without blocking futures_executor::block_on(client.initialize())?; s_incoming.push(UnboundedReceiverStream::new(incoming)); let client = Arc::new(client); - entry.insert(client.clone()); + entry.insert((id, client.clone())); Ok(client) } } diff --git a/helix-lsp/src/transport.rs b/helix-lsp/src/transport.rs index e8068323..29ce2e84 100644 --- a/helix-lsp/src/transport.rs +++ b/helix-lsp/src/transport.rs @@ -33,7 +33,8 @@ enum ServerMessage { #[derive(Debug)] pub struct Transport { - client_tx: UnboundedSender, + id: usize, + client_tx: UnboundedSender<(usize, jsonrpc::Call)>, client_rx: UnboundedReceiver, pending_requests: HashMap>>, @@ -48,11 +49,16 @@ impl Transport { server_stdout: BufReader, server_stdin: BufWriter, server_stderr: BufReader, - ) -> (UnboundedReceiver, UnboundedSender) { + id: usize, + ) -> ( + UnboundedReceiver<(usize, jsonrpc::Call)>, + UnboundedSender, + ) { let (client_tx, rx) = unbounded_channel(); let (tx, client_rx) = unbounded_channel(); let transport = Self { + id, server_stdout, server_stdin, server_stderr, @@ -156,7 +162,7 @@ impl Transport { match msg { ServerMessage::Output(output) => self.process_request_response(output).await?, ServerMessage::Call(call) => { - self.client_tx.send(call).unwrap(); + self.client_tx.send((self.id, call)).unwrap(); // let notification = Notification::parse(&method, params); } }; diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index f5cba365..3f1d6a10 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -109,8 +109,8 @@ impl Application { event = reader.next() => { self.handle_terminal_events(event) } - Some(call) = self.editor.language_servers.incoming.next() => { - self.handle_language_server_message(call).await + Some((id, call)) = self.editor.language_servers.incoming.next() => { + self.handle_language_server_message(call, id).await } Some(callback) = &mut self.callbacks.next() => { self.handle_language_server_callback(callback) @@ -153,8 +153,12 @@ impl Application { } } - pub async fn handle_language_server_message(&mut self, call: helix_lsp::Call) { - use helix_lsp::{Call, Notification}; + pub async fn handle_language_server_message( + &mut self, + call: helix_lsp::Call, + server_id: usize, + ) { + use helix_lsp::{Call, MethodCall, Notification}; match call { Call::Notification(helix_lsp::jsonrpc::Notification { method, params, .. }) => { let notification = match Notification::parse(&method, params) { -- cgit v1.2.3-70-g09d2 From d095ec15d4672ec5fb3b1f4a85282db31f40c6ea Mon Sep 17 00:00:00 2001 From: wojciechkepka Date: Fri, 18 Jun 2021 05:44:01 +0200 Subject: Reenable `work_done_progress` capability --- helix-lsp/src/client.rs | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'helix-lsp') diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index e14d0197..245eb854 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -185,25 +185,25 @@ impl Client { let server_tx = self.server_tx.clone(); async move { - let output = match result { - Ok(result) => Output::Success(Success { - jsonrpc: Some(Version::V2), - id, - result, - }), - Err(error) => Output::Failure(Failure { - jsonrpc: Some(Version::V2), - id, - error, - }), - }; + let output = match result { + Ok(result) => Output::Success(Success { + jsonrpc: Some(Version::V2), + id, + result, + }), + Err(error) => Output::Failure(Failure { + jsonrpc: Some(Version::V2), + id, + error, + }), + }; server_tx - .send(Payload::Response(output)) - .map_err(|e| Error::Other(e.into()))?; + .send(Payload::Response(output)) + .map_err(|e| Error::Other(e.into()))?; - Ok(()) - } + Ok(()) + } } // ------------------------------------------------------------------------------------------- @@ -243,8 +243,7 @@ impl Client { ..Default::default() }), window: Some(lsp::WindowClientCapabilities { - // TODO: temporarily disabled until we implement handling for window/workDoneProgress/create - // work_done_progress: Some(true), + work_done_progress: Some(true), ..Default::default() }), ..Default::default() -- cgit v1.2.3-70-g09d2 From b48054f3ee28db64110f9ddcc13d7f01bb78b357 Mon Sep 17 00:00:00 2001 From: Benoît CORTIER Date: Fri, 18 Jun 2021 09:48:31 -0400 Subject: cargo: add version to local dependencies First step towards enabling us to publish on crates.io. See: https://github.com/helix-editor/helix/issues/42 --- helix-core/Cargo.toml | 2 +- helix-lsp/Cargo.toml | 4 ++-- helix-term/Cargo.toml | 6 +++--- helix-view/Cargo.toml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'helix-lsp') diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 0f532f5b..9ae7aff0 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -12,7 +12,7 @@ license = "MPL-2.0" embed_runtime = ["rust-embed"] [dependencies] -helix-syntax = { path = "../helix-syntax" } +helix-syntax = { version = "0.2", path = "../helix-syntax" } ropey = "1.3" smallvec = "1.4" diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index bcd18a38..185fe447 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -8,7 +8,7 @@ license = "MPL-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -helix-core = { path = "../helix-core" } +helix-core = { version = "0.2", path = "../helix-core" } anyhow = "1.0" futures-executor = "0.3" @@ -20,4 +20,4 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" tokio = { version = "1.6", features = ["full"] } -tokio-stream = "0.1.6" \ No newline at end of file +tokio-stream = "0.1.6" diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index cda238fe..1b9df2ef 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -18,9 +18,9 @@ name = "hx" path = "src/main.rs" [dependencies] -helix-core = { path = "../helix-core" } -helix-view = { path = "../helix-view", features = ["term"]} -helix-lsp = { path = "../helix-lsp"} +helix-core = { version = "0.2", path = "../helix-core" } +helix-view = { version = "0.2", path = "../helix-view", features = ["term"]} +helix-lsp = { version = "0.2", path = "../helix-lsp"} anyhow = "1" once_cell = "1.8" diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index 593f00e0..db96c9aa 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -13,8 +13,8 @@ default = ["term"] [dependencies] anyhow = "1" -helix-core = { path = "../helix-core" } -helix-lsp = { path = "../helix-lsp"} +helix-core = { version = "0.2", path = "../helix-core" } +helix-lsp = { version = "0.2", path = "../helix-lsp"} # Conversion traits tui = { path = "../helix-tui", package = "helix-tui", default-features = false, features = ["crossterm"], optional = true } -- cgit v1.2.3-70-g09d2 From 03d1ca7b0a2610b5a5ee2956722c0a1fbdc2180c Mon Sep 17 00:00:00 2001 From: Benoît CORTIER Date: Fri, 18 Jun 2021 10:41:03 -0400 Subject: cargo: add more metadata to manifests --- helix-core/Cargo.toml | 7 ++++--- helix-lsp/Cargo.toml | 4 ++++ helix-term/Cargo.toml | 3 +++ helix-tui/Cargo.toml | 3 +++ helix-view/Cargo.toml | 4 ++++ 5 files changed, 18 insertions(+), 3 deletions(-) (limited to 'helix-lsp') diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 9c1c6802..13ac35fb 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -4,11 +4,12 @@ version = "0.2.0" authors = ["Blaž Hrastnik "] edition = "2018" license = "MPL-2.0" +description = "Helix editor core editing primitives" +categories = ["editor"] +repository = "https://github.com/helix-editor/helix" +homepage = "https://helix-editor.com" include = ["src/**/*", "README.md"] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - - [features] embed_runtime = ["rust-embed"] diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index 185fe447..2c1b813d 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -4,6 +4,10 @@ version = "0.2.0" authors = ["Blaž Hrastnik "] edition = "2018" license = "MPL-2.0" +description = "LSP client implementation for Helix project" +categories = ["editor"] +repository = "https://github.com/helix-editor/helix" +homepage = "https://helix-editor.com" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index e1e5da56..385af64c 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -5,6 +5,9 @@ description = "A post-modern text editor." authors = ["Blaž Hrastnik "] edition = "2018" license = "MPL-2.0" +categories = ["editor", "command-line-utilities"] +repository = "https://github.com/helix-editor/helix" +homepage = "https://helix-editor.com" include = ["src/**/*", "README.md"] [package.metadata.nix] diff --git a/helix-tui/Cargo.toml b/helix-tui/Cargo.toml index beab049c..89fa755d 100644 --- a/helix-tui/Cargo.toml +++ b/helix-tui/Cargo.toml @@ -7,6 +7,9 @@ A library to build rich terminal user interfaces or dashboards """ edition = "2018" license = "MPL-2.0" +categories = ["editor"] +repository = "https://github.com/helix-editor/helix" +homepage = "https://helix-editor.com" include = ["src/**/*", "README.md"] [features] diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index db96c9aa..13539a5a 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -4,6 +4,10 @@ version = "0.2.0" authors = ["Blaž Hrastnik "] edition = "2018" license = "MPL-2.0" +description = "UI abstractions for use in backends" +categories = ["editor"] +repository = "https://github.com/helix-editor/helix" +homepage = "https://helix-editor.com" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -- cgit v1.2.3-70-g09d2 From c2aad859b12e01c7724f16ddf957e6db2b3c8a60 Mon Sep 17 00:00:00 2001 From: wojciechkepka Date: Sat, 19 Jun 2021 04:56:50 +0200 Subject: Handle language server shutdown with timeout --- helix-lsp/src/client.rs | 15 +++++++++++++++ helix-lsp/src/lib.rs | 4 ++++ helix-term/src/application.rs | 13 ++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) (limited to 'helix-lsp') diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 245eb854..101d2f9b 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -272,6 +272,21 @@ impl Client { self.notify::(()) } + /// Tries to shut down the language server but returns + /// early if server responds with an error. + pub async fn shutdown_and_exit(&self) -> Result<()> { + self.shutdown().await?; + self.exit().await + } + + /// Forcefully shuts down the language server ignoring any errors. + pub async fn force_shutdown(&self) -> Result<()> { + if let Err(e) = self.shutdown().await { + log::warn!("language server failed to terminate gracefully - {}", e); + } + self.exit().await + } + // ------------------------------------------------------------------------------------------- // Text document // ------------------------------------------------------------------------------------------- diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 774de075..49d5527f 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -310,6 +310,10 @@ impl Registry { Err(Error::LspNotDefined) } } + + pub fn iter_clients(&self) -> impl Iterator> { + self.inner.values().map(|(_, client)| client) + } } #[derive(Debug)] diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index aa2ce884..1f02ac4f 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -23,7 +23,7 @@ use crossterm::{ use tui::layout::Rect; -use futures_util::stream::FuturesUnordered; +use futures_util::{future, stream::FuturesUnordered}; type BoxFuture = Pin + Send>>; pub type LspCallback = @@ -406,6 +406,17 @@ impl Application { self.event_loop().await; + tokio::time::timeout( + Duration::from_millis(500), + future::join_all( + self.editor + .language_servers + .iter_clients() + .map(|client| client.force_shutdown()), + ), + ) + .await; + // reset cursor shape write!(stdout, "\x1B[2 q"); -- cgit v1.2.3-70-g09d2 From dd0af78079342b46ae1f4d1b265c7e0cd7519631 Mon Sep 17 00:00:00 2001 From: wojciechkepka Date: Sat, 19 Jun 2021 04:57:05 +0200 Subject: Fix unwraps in lsp::transport --- helix-lsp/src/transport.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'helix-lsp') diff --git a/helix-lsp/src/transport.rs b/helix-lsp/src/transport.rs index 29ce2e84..df55bbf6 100644 --- a/helix-lsp/src/transport.rs +++ b/helix-lsp/src/transport.rs @@ -1,4 +1,5 @@ use crate::Result; +use anyhow::Context; use jsonrpc_core as jsonrpc; use log::{error, info}; use serde::{Deserialize, Serialize}; @@ -90,7 +91,7 @@ impl Transport { match (parts.next(), parts.next(), parts.next()) { (Some("Content-Length"), Some(value), None) => { - content_length = Some(value.parse().unwrap()); + content_length = Some(value.parse().context("invalid content length")?); } (Some(_), Some(_), None) => {} _ => { @@ -103,12 +104,12 @@ impl Transport { } } - let content_length = content_length.unwrap(); + let content_length = content_length.context("missing content length")?; //TODO: reuse vector let mut content = vec![0; content_length]; reader.read_exact(&mut content).await?; - let msg = String::from_utf8(content).unwrap(); + let msg = String::from_utf8(content).context("invalid utf8 from server")?; info!("<- {}", msg); @@ -162,7 +163,9 @@ impl Transport { match msg { ServerMessage::Output(output) => self.process_request_response(output).await?, ServerMessage::Call(call) => { - self.client_tx.send((self.id, call)).unwrap(); + self.client_tx + .send((self.id, call)) + .context("failed to send a message to server")?; // let notification = Notification::parse(&method, params); } }; -- cgit v1.2.3-70-g09d2