diff options
author | Jan Hrastnik | 2021-06-19 12:51:53 +0000 |
---|---|---|
committer | Jan Hrastnik | 2021-06-19 12:51:53 +0000 |
commit | cdd9347457f0608346894cd0aab35b412cb59a7b (patch) | |
tree | 468078c37311cb1c7f9e7d4bd8a03c493d25e669 /helix-lsp/src/client.rs | |
parent | 97323dc2f90f81afc82bd929d111abda540bebe5 (diff) | |
parent | 2cbec2b0470d0759578929b224c445b69617b6b6 (diff) |
Merge remote-tracking branch 'origin/master' into line_ending_detection
Diffstat (limited to 'helix-lsp/src/client.rs')
-rw-r--r-- | helix-lsp/src/client.rs | 124 |
1 files changed, 78 insertions, 46 deletions
diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 9ca708a7..101d2f9b 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<Payload>, request_counter: AtomicU64, @@ -26,7 +27,11 @@ pub struct Client { } impl Client { - pub fn start(cmd: &str, args: &[String]) -> Result<(Self, UnboundedReceiver<Call>)> { + 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) @@ -165,31 +175,35 @@ impl Client { } /// Reply to a language server RPC call. - pub async fn reply( + pub fn reply( &self, id: jsonrpc::Id, result: core::result::Result<Value, jsonrpc::Error>, - ) -> Result<()> { + ) -> impl Future<Output = Result<()>> { use jsonrpc::{Failure, Output, Success, Version}; - 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 server_tx = self.server_tx.clone(); - self.server_tx - .send(Payload::Response(output)) - .map_err(|e| Error::Other(e.into()))?; + 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, + }), + }; - Ok(()) + server_tx + .send(Payload::Response(output)) + .map_err(|e| Error::Other(e.into()))?; + + Ok(()) + } } // ------------------------------------------------------------------------------------------- @@ -229,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() @@ -259,6 +272,21 @@ impl Client { self.notify::<lsp::notification::Exit>(()) } + /// 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 // ------------------------------------------------------------------------------------------- @@ -465,6 +493,7 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>> { // ) -> Result<Vec<lsp::CompletionItem>> { let params = lsp::CompletionParams { @@ -473,9 +502,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 +517,14 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>> { 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 +536,14 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>> { 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 +556,7 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, options: lsp::FormattingOptions, + work_done_token: Option<lsp::ProgressToken>, ) -> anyhow::Result<Vec<lsp::TextEdit>> { let capabilities = self.capabilities.as_ref().unwrap(); @@ -545,9 +571,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::<lsp::request::Formatting>(params).await?; @@ -560,6 +584,7 @@ impl Client { text_document: lsp::TextDocumentIdentifier, range: lsp::Range, options: lsp::FormattingOptions, + work_done_token: Option<lsp::ProgressToken>, ) -> anyhow::Result<Vec<lsp::TextEdit>> { let capabilities = self.capabilities.as_ref().unwrap(); @@ -575,9 +600,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 +619,14 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>> { 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 +639,42 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>> { - self.goto_request::<lsp::request::GotoDefinition>(text_document, position) + self.goto_request::<lsp::request::GotoDefinition>(text_document, position, work_done_token) } pub fn goto_type_definition( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>> { - self.goto_request::<lsp::request::GotoTypeDefinition>(text_document, position) + self.goto_request::<lsp::request::GotoTypeDefinition>( + text_document, + position, + work_done_token, + ) } pub fn goto_implementation( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>> { - self.goto_request::<lsp::request::GotoImplementation>(text_document, position) + self.goto_request::<lsp::request::GotoImplementation>( + text_document, + position, + work_done_token, + ) } pub fn goto_reference( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, + work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>> { let params = lsp::ReferenceParams { text_document_position: lsp::TextDocumentPositionParams { @@ -650,9 +684,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, }, |