@@ -9,11 +9,17 @@ use lsp_types as lsp;
9use serde_json::Value;
9use serde_json::Value;
10use std::future::Future;
10use std::future::Future;
11use std::process::Stdio;
11use std::process::Stdio;
12−use std::sync::atomic::{AtomicU64, Ordering};
13+ atomic::{AtomicU64, Ordering},
13use tokio::{
16use tokio::{
14 io::{BufReader, BufWriter},
17 io::{BufReader, BufWriter},
15 process::{Child, Command},
18 process::{Child, Command},
16− sync::mpsc::{channel, UnboundedReceiver, UnboundedSender},
20+ mpsc::{channel, UnboundedReceiver, UnboundedSender},
19#[derive(Debug)]
25#[derive(Debug)]
@@ -22,18 +28,19 @@ pub struct Client {
22 _process: Child,
28 _process: Child,
23 server_tx: UnboundedSender<Payload>,
29 server_tx: UnboundedSender<Payload>,
24 request_counter: AtomicU64,
30 request_counter: AtomicU64,
25− capabilities: Option<lsp::ServerCapabilities>,
31+ pub(crate) capabilities: OnceCell<lsp::ServerCapabilities>,
26 offset_encoding: OffsetEncoding,
32 offset_encoding: OffsetEncoding,
27 config: Option<Value>,
33 config: Option<Value>,
30impl Client {
36impl Client {
37+ #[allow(clippy::type_complexity)]
31 pub fn start(
38 pub fn start(
32 cmd: &str,
39 cmd: &str,
33 args: &[String],
40 args: &[String],
34 config: Option<Value>,
41 config: Option<Value>,
35 id: usize,
42 id: usize,
36− ) -> Result<(Self, UnboundedReceiver<(usize, Call)>)> {
43+ ) -> Result<(Self, UnboundedReceiver<(usize, Call)>, Arc<Notify>)> {
37 let process = Command::new(cmd)
44 let process = Command::new(cmd)
38 .args(args)
45 .args(args)
39 .stdin(Stdio::piped())
46 .stdin(Stdio::piped())
@@ -50,22 +57,20 @@ impl Client {
50 let reader = BufReader::new(process.stdout.take().expect("Failed to open stdout"));
57 let reader = BufReader::new(process.stdout.take().expect("Failed to open stdout"));
51 let stderr = BufReader::new(process.stderr.take().expect("Failed to open stderr"));
58 let stderr = BufReader::new(process.stderr.take().expect("Failed to open stderr"));
60+ let (server_rx, server_tx, initialize_notify) =
53− let (server_rx, server_tx) = Transport::start(reader, writer, stderr, id);
61+ Transport::start(reader, writer, stderr, id);
55 let client = Self {
63 let client = Self {
57 _process: process,
65 _process: process,
58 server_tx,
66 server_tx,
59 request_counter: AtomicU64::new(0),
67 request_counter: AtomicU64::new(0),
60− capabilities: None,
68+ capabilities: OnceCell::new(),
61 offset_encoding: OffsetEncoding::Utf8,
69 offset_encoding: OffsetEncoding::Utf8,
65− // TODO: async client.initialize()
66− // maybe use an arc<atomic> flag
68− Ok((client, server_rx))
73+ Ok((client, server_rx, initialize_notify))
71 pub fn id(&self) -> usize {
76 pub fn id(&self) -> usize {
@@ -88,9 +93,13 @@ impl Client {
96+ pub fn is_initialized(&self) -> bool {
97+ self.capabilities.get().is_some()
91 pub fn capabilities(&self) -> &lsp::ServerCapabilities {
100 pub fn capabilities(&self) -> &lsp::ServerCapabilities {
92 self.capabilities
101 self.capabilities
94 .expect("language server not yet initialized!")
103 .expect("language server not yet initialized!")
@@ -143,7 +152,8 @@ impl Client {
144 .map_err(|e| Error::Other(e.into()))?;
153 .map_err(|e| Error::Other(e.into()))?;
155+ // TODO: specifiable timeout, delay other calls until initialize success
146− timeout(Duration::from_secs(2), rx.recv())
156+ timeout(Duration::from_secs(20), rx.recv())
148 .map_err(|_| Error::Timeout)? // return Timeout
158 .map_err(|_| Error::Timeout)? // return Timeout
149 .ok_or(Error::StreamClosed)?
159 .ok_or(Error::StreamClosed)?
@@ -151,7 +161,7 @@ impl Client {
153 /// Send a RPC notification to the language server.
163 /// Send a RPC notification to the language server.
154− fn notify<R: lsp::notification::Notification>(
164+ pub fn notify<R: lsp::notification::Notification>(
156 params: R::Params,
166 params: R::Params,
157 ) -> impl Future<Output = Result<()>>
167 ) -> impl Future<Output = Result<()>>
@@ -213,7 +223,7 @@ impl Client {
213 // General messages
223 // General messages
214 // -------------------------------------------------------------------------------------------
224 // -------------------------------------------------------------------------------------------
216− pub(crate) async fn initialize(&mut self) -> Result<()> {
226+ pub(crate) async fn initialize(&self) -> Result<lsp::InitializeResult> {
217 // TODO: delay any requests that are triggered prior to initialize
227 // TODO: delay any requests that are triggered prior to initialize
218 let root = find_root(None).and_then(|root| lsp::Url::from_file_path(root).ok());
228 let root = find_root(None).and_then(|root| lsp::Url::from_file_path(root).ok());
@@ -281,14 +291,7 @@ impl Client {
281 locale: None, // TODO
291 locale: None, // TODO
284− let response = self.request::<lsp::request::Initialize>(params).await?;
294+ self.request::<lsp::request::Initialize>(params).await
285− self.capabilities = Some(response.capabilities);
287− // next up, notify<initialized>
288− self.notify::<lsp::notification::Initialized>(lsp::InitializedParams {})
294 pub async fn shutdown(&self) -> Result<()> {
297 pub async fn shutdown(&self) -> Result<()> {
@@ -445,7 +448,7 @@ impl Client {
445 ) -> Option<impl Future<Output = Result<()>>> {
448 ) -> Option<impl Future<Output = Result<()>>> {
446 // figure out what kind of sync the server supports
449 // figure out what kind of sync the server supports
448− let capabilities = self.capabilities.as_ref().unwrap();
451+ let capabilities = self.capabilities.get().unwrap();
450 let sync_capabilities = match capabilities.text_document_sync {
453 let sync_capabilities = match capabilities.text_document_sync {
451 Some(lsp::TextDocumentSyncCapability::Kind(kind))
454 Some(lsp::TextDocumentSyncCapability::Kind(kind))
@@ -463,7 +466,7 @@ impl Client {
463 // range = None -> whole document
466 // range = None -> whole document
464 range: None, //Some(Range)
467 range: None, //Some(Range)
465 range_length: None, // u64 apparently deprecated
468 range_length: None, // u64 apparently deprecated
466− text: "".to_string(),
469+ text: new_text.to_string(),
469 lsp::TextDocumentSyncKind::Incremental => {
472 lsp::TextDocumentSyncKind::Incremental => {
@@ -491,12 +494,12 @@ impl Client {
492 // will_save / will_save_wait_until
495 // will_save / will_save_wait_until
494− pub async fn text_document_did_save(
497+ pub fn text_document_did_save(
496 text_document: lsp::TextDocumentIdentifier,
499 text_document: lsp::TextDocumentIdentifier,
497 text: &Rope,
500 text: &Rope,
498− ) -> Result<()> {
501+ ) -> Option<impl Future<Output = Result<()>>> {
499− let capabilities = self.capabilities.as_ref().unwrap();
502+ let capabilities = self.capabilities.get().unwrap();
501 let include_text = match &capabilities.text_document_sync {
504 let include_text = match &capabilities.text_document_sync {
502 Some(lsp::TextDocumentSyncCapability::Options(lsp::TextDocumentSyncOptions {
505 Some(lsp::TextDocumentSyncCapability::Options(lsp::TextDocumentSyncOptions {
@@ -508,17 +511,18 @@ impl Client {
508 include_text,
511 include_text,
509 }) => include_text.unwrap_or(false),
512 }) => include_text.unwrap_or(false),
510 // Supported(false)
513 // Supported(false)
511− _ => return Ok(()),
514+ _ => return None,
513 // unsupported
516 // unsupported
514− _ => return Ok(()),
517+ _ => return None,
517− self.notify::<lsp::notification::DidSaveTextDocument>(lsp::DidSaveTextDocumentParams {
520+ Some(self.notify::<lsp::notification::DidSaveTextDocument>(
521+ lsp::DidSaveTextDocumentParams {
518− text_document,
522+ text_document,
519− text: include_text.then(|| text.into()),
523+ text: include_text.then(|| text.into()),
524 pub fn completion(
528 pub fn completion(
@@ -584,19 +588,19 @@ impl Client {
585 // formatting
589 // formatting
587− pub async fn text_document_formatting(
591+ pub fn text_document_formatting(
589 text_document: lsp::TextDocumentIdentifier,
593 text_document: lsp::TextDocumentIdentifier,
590 options: lsp::FormattingOptions,
594 options: lsp::FormattingOptions,
591 work_done_token: Option<lsp::ProgressToken>,
595 work_done_token: Option<lsp::ProgressToken>,
592− ) -> anyhow::Result<Vec<lsp::TextEdit>> {
596+ ) -> Option<impl Future<Output = Result<Vec<lsp::TextEdit>>>> {
593− let capabilities = self.capabilities.as_ref().unwrap();
597+ let capabilities = self.capabilities.get().unwrap();
595 // check if we're able to format
599 // check if we're able to format
596 match capabilities.document_formatting_provider {
600 match capabilities.document_formatting_provider {
597 Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (),
601 Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (),
598 // None | Some(false)
602 // None | Some(false)
599− _ => return Ok(Vec::new()),
603+ _ => return None,
601 // TODO: return err::unavailable so we can fall back to tree sitter formatting
605 // TODO: return err::unavailable so we can fall back to tree sitter formatting
@@ -606,9 +610,13 @@ impl Client {
606 work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token },
610 work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token },
609− let response = self.request::<lsp::request::Formatting>(params).await?;
613+ let request = self.call::<lsp::request::Formatting>(params);
616+ let json = request.await?;
617+ let response: Vec<lsp::TextEdit> = serde_json::from_value(json)?;
611− Ok(response.unwrap_or_default())
618+ Ok(response)
614 pub async fn text_document_range_formatting(
622 pub async fn text_document_range_formatting(
@@ -618,7 +626,7 @@ impl Client {
618 options: lsp::FormattingOptions,
626 options: lsp::FormattingOptions,
619 work_done_token: Option<lsp::ProgressToken>,
627 work_done_token: Option<lsp::ProgressToken>,
620 ) -> anyhow::Result<Vec<lsp::TextEdit>> {
628 ) -> anyhow::Result<Vec<lsp::TextEdit>> {
621− let capabilities = self.capabilities.as_ref().unwrap();
629+ let capabilities = self.capabilities.get().unwrap();
623 // check if we're able to format
631 // check if we're able to format
624 match capabilities.document_range_formatting_provider {
632 match capabilities.document_range_formatting_provider {