1 use crate::{
2     transport::{Payload, Transport},
3     Call, Error, OffsetEncoding, Result,
4 };
5 
6 use helix_core::{find_root, ChangeSet, Rope};
7 use jsonrpc_core as jsonrpc;
8 use lsp_types as lsp;
9 use serde_json::Value;
10 use std::future::Future;
11 use std::process::Stdio;
12 use std::sync::{
13     atomic::{AtomicU64, Ordering},
14     Arc,
15 };
16 use tokio::{
17     io::{BufReader, BufWriter},
18     process::{Child, Command},
19     sync::{
20         mpsc::{channel, UnboundedReceiver, UnboundedSender},
21         Notify, OnceCell,
22     },
23 };
24 
25 #[derive(Debug)]
26 pub struct Client {
27     id: usize,
28     _process: Child,
29     server_tx: UnboundedSender<Payload>,
30     request_counter: AtomicU64,
31     pub(crate) capabilities: OnceCell<lsp::ServerCapabilities>,
32     offset_encoding: OffsetEncoding,
33     config: Option<Value>,
34 }
35 
36 impl Client {
37     #[allow(clippy::type_complexity)]
start( cmd: &str, args: &[String], config: Option<Value>, id: usize, ) -> Result<(Self, UnboundedReceiver<(usize, Call)>, Arc<Notify>)>38     pub fn start(
39         cmd: &str,
40         args: &[String],
41         config: Option<Value>,
42         id: usize,
43     ) -> Result<(Self, UnboundedReceiver<(usize, Call)>, Arc<Notify>)> {
44         let process = Command::new(cmd)
45             .args(args)
46             .stdin(Stdio::piped())
47             .stdout(Stdio::piped())
48             .stderr(Stdio::piped())
49             // make sure the process is reaped on drop
50             .kill_on_drop(true)
51             .spawn();
52 
53         let mut process = process?;
54 
55         // TODO: do we need bufreader/writer here? or do we use async wrappers on unblock?
56         let writer = BufWriter::new(process.stdin.take().expect("Failed to open stdin"));
57         let reader = BufReader::new(process.stdout.take().expect("Failed to open stdout"));
58         let stderr = BufReader::new(process.stderr.take().expect("Failed to open stderr"));
59 
60         let (server_rx, server_tx, initialize_notify) =
61             Transport::start(reader, writer, stderr, id);
62 
63         let client = Self {
64             id,
65             _process: process,
66             server_tx,
67             request_counter: AtomicU64::new(0),
68             capabilities: OnceCell::new(),
69             offset_encoding: OffsetEncoding::Utf8,
70             config,
71         };
72 
73         Ok((client, server_rx, initialize_notify))
74     }
75 
id(&self) -> usize76     pub fn id(&self) -> usize {
77         self.id
78     }
79 
next_request_id(&self) -> jsonrpc::Id80     fn next_request_id(&self) -> jsonrpc::Id {
81         let id = self.request_counter.fetch_add(1, Ordering::Relaxed);
82         jsonrpc::Id::Num(id)
83     }
84 
value_into_params(value: Value) -> jsonrpc::Params85     fn value_into_params(value: Value) -> jsonrpc::Params {
86         use jsonrpc::Params;
87 
88         match value {
89             Value::Null => Params::None,
90             Value::Bool(_) | Value::Number(_) | Value::String(_) => Params::Array(vec![value]),
91             Value::Array(vec) => Params::Array(vec),
92             Value::Object(map) => Params::Map(map),
93         }
94     }
95 
is_initialized(&self) -> bool96     pub fn is_initialized(&self) -> bool {
97         self.capabilities.get().is_some()
98     }
99 
capabilities(&self) -> &lsp::ServerCapabilities100     pub fn capabilities(&self) -> &lsp::ServerCapabilities {
101         self.capabilities
102             .get()
103             .expect("language server not yet initialized!")
104     }
105 
offset_encoding(&self) -> OffsetEncoding106     pub fn offset_encoding(&self) -> OffsetEncoding {
107         self.offset_encoding
108     }
109 
110     /// Execute a RPC request on the language server.
request<R: lsp::request::Request>(&self, params: R::Params) -> Result<R::Result> where R::Params: serde::Serialize, R::Result: core::fmt::Debug,111     async fn request<R: lsp::request::Request>(&self, params: R::Params) -> Result<R::Result>
112     where
113         R::Params: serde::Serialize,
114         R::Result: core::fmt::Debug, // TODO: temporary
115     {
116         // a future that resolves into the response
117         let json = self.call::<R>(params).await?;
118         let response = serde_json::from_value(json)?;
119         Ok(response)
120     }
121 
122     /// Execute a RPC request on the language server.
call<R: lsp::request::Request>( &self, params: R::Params, ) -> impl Future<Output = Result<Value>> where R::Params: serde::Serialize,123     fn call<R: lsp::request::Request>(
124         &self,
125         params: R::Params,
126     ) -> impl Future<Output = Result<Value>>
127     where
128         R::Params: serde::Serialize,
129     {
130         let server_tx = self.server_tx.clone();
131         let id = self.next_request_id();
132 
133         async move {
134             use std::time::Duration;
135             use tokio::time::timeout;
136 
137             let params = serde_json::to_value(params)?;
138 
139             let request = jsonrpc::MethodCall {
140                 jsonrpc: Some(jsonrpc::Version::V2),
141                 id,
142                 method: R::METHOD.to_string(),
143                 params: Self::value_into_params(params),
144             };
145 
146             let (tx, mut rx) = channel::<Result<Value>>(1);
147 
148             server_tx
149                 .send(Payload::Request {
150                     chan: tx,
151                     value: request,
152                 })
153                 .map_err(|e| Error::Other(e.into()))?;
154 
155             // TODO: specifiable timeout, delay other calls until initialize success
156             timeout(Duration::from_secs(20), rx.recv())
157                 .await
158                 .map_err(|_| Error::Timeout)? // return Timeout
159                 .ok_or(Error::StreamClosed)?
160         }
161     }
162 
163     /// Send a RPC notification to the language server.
notify<R: lsp::notification::Notification>( &self, params: R::Params, ) -> impl Future<Output = Result<()>> where R::Params: serde::Serialize,164     pub fn notify<R: lsp::notification::Notification>(
165         &self,
166         params: R::Params,
167     ) -> impl Future<Output = Result<()>>
168     where
169         R::Params: serde::Serialize,
170     {
171         let server_tx = self.server_tx.clone();
172 
173         async move {
174             let params = serde_json::to_value(params)?;
175 
176             let notification = jsonrpc::Notification {
177                 jsonrpc: Some(jsonrpc::Version::V2),
178                 method: R::METHOD.to_string(),
179                 params: Self::value_into_params(params),
180             };
181 
182             server_tx
183                 .send(Payload::Notification(notification))
184                 .map_err(|e| Error::Other(e.into()))?;
185 
186             Ok(())
187         }
188     }
189 
190     /// Reply to a language server RPC call.
reply( &self, id: jsonrpc::Id, result: core::result::Result<Value, jsonrpc::Error>, ) -> impl Future<Output = Result<()>>191     pub fn reply(
192         &self,
193         id: jsonrpc::Id,
194         result: core::result::Result<Value, jsonrpc::Error>,
195     ) -> impl Future<Output = Result<()>> {
196         use jsonrpc::{Failure, Output, Success, Version};
197 
198         let server_tx = self.server_tx.clone();
199 
200         async move {
201             let output = match result {
202                 Ok(result) => Output::Success(Success {
203                     jsonrpc: Some(Version::V2),
204                     id,
205                     result,
206                 }),
207                 Err(error) => Output::Failure(Failure {
208                     jsonrpc: Some(Version::V2),
209                     id,
210                     error,
211                 }),
212             };
213 
214             server_tx
215                 .send(Payload::Response(output))
216                 .map_err(|e| Error::Other(e.into()))?;
217 
218             Ok(())
219         }
220     }
221 
222     // -------------------------------------------------------------------------------------------
223     // General messages
224     // -------------------------------------------------------------------------------------------
225 
initialize(&self) -> Result<lsp::InitializeResult>226     pub(crate) async fn initialize(&self) -> Result<lsp::InitializeResult> {
227         // TODO: delay any requests that are triggered prior to initialize
228         let root = find_root(None).and_then(|root| lsp::Url::from_file_path(root).ok());
229 
230         if self.config.is_some() {
231             log::info!("Using custom LSP config: {}", self.config.as_ref().unwrap());
232         }
233 
234         #[allow(deprecated)]
235         let params = lsp::InitializeParams {
236             process_id: Some(std::process::id()),
237             // root_path is obsolete, use root_uri
238             root_path: None,
239             root_uri: root,
240             initialization_options: self.config.clone(),
241             capabilities: lsp::ClientCapabilities {
242                 text_document: Some(lsp::TextDocumentClientCapabilities {
243                     completion: Some(lsp::CompletionClientCapabilities {
244                         completion_item: Some(lsp::CompletionItemCapability {
245                             snippet_support: Some(false),
246                             ..Default::default()
247                         }),
248                         completion_item_kind: Some(lsp::CompletionItemKindCapability {
249                             ..Default::default()
250                         }),
251                         context_support: None, // additional context information Some(true)
252                         ..Default::default()
253                     }),
254                     hover: Some(lsp::HoverClientCapabilities {
255                         // if not specified, rust-analyzer returns plaintext marked as markdown but
256                         // badly formatted.
257                         content_format: Some(vec![lsp::MarkupKind::Markdown]),
258                         ..Default::default()
259                     }),
260                     code_action: Some(lsp::CodeActionClientCapabilities {
261                         code_action_literal_support: Some(lsp::CodeActionLiteralSupport {
262                             code_action_kind: lsp::CodeActionKindLiteralSupport {
263                                 value_set: [
264                                     lsp::CodeActionKind::EMPTY,
265                                     lsp::CodeActionKind::QUICKFIX,
266                                     lsp::CodeActionKind::REFACTOR,
267                                     lsp::CodeActionKind::REFACTOR_EXTRACT,
268                                     lsp::CodeActionKind::REFACTOR_INLINE,
269                                     lsp::CodeActionKind::REFACTOR_REWRITE,
270                                     lsp::CodeActionKind::SOURCE,
271                                     lsp::CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
272                                 ]
273                                 .iter()
274                                 .map(|kind| kind.as_str().to_string())
275                                 .collect(),
276                             },
277                         }),
278                         ..Default::default()
279                     }),
280                     ..Default::default()
281                 }),
282                 window: Some(lsp::WindowClientCapabilities {
283                     work_done_progress: Some(true),
284                     ..Default::default()
285                 }),
286                 ..Default::default()
287             },
288             trace: None,
289             workspace_folders: None,
290             client_info: None,
291             locale: None, // TODO
292         };
293 
294         self.request::<lsp::request::Initialize>(params).await
295     }
296 
shutdown(&self) -> Result<()>297     pub async fn shutdown(&self) -> Result<()> {
298         self.request::<lsp::request::Shutdown>(()).await
299     }
300 
exit(&self) -> impl Future<Output = Result<()>>301     pub fn exit(&self) -> impl Future<Output = Result<()>> {
302         self.notify::<lsp::notification::Exit>(())
303     }
304 
305     /// Tries to shut down the language server but returns
306     /// early if server responds with an error.
shutdown_and_exit(&self) -> Result<()>307     pub async fn shutdown_and_exit(&self) -> Result<()> {
308         self.shutdown().await?;
309         self.exit().await
310     }
311 
312     /// Forcefully shuts down the language server ignoring any errors.
force_shutdown(&self) -> Result<()>313     pub async fn force_shutdown(&self) -> Result<()> {
314         if let Err(e) = self.shutdown().await {
315             log::warn!("language server failed to terminate gracefully - {}", e);
316         }
317         self.exit().await
318     }
319 
320     // -------------------------------------------------------------------------------------------
321     // Text document
322     // -------------------------------------------------------------------------------------------
323 
text_document_did_open( &self, uri: lsp::Url, version: i32, doc: &Rope, language_id: String, ) -> impl Future<Output = Result<()>>324     pub fn text_document_did_open(
325         &self,
326         uri: lsp::Url,
327         version: i32,
328         doc: &Rope,
329         language_id: String,
330     ) -> impl Future<Output = Result<()>> {
331         self.notify::<lsp::notification::DidOpenTextDocument>(lsp::DidOpenTextDocumentParams {
332             text_document: lsp::TextDocumentItem {
333                 uri,
334                 language_id,
335                 version,
336                 text: String::from(doc),
337             },
338         })
339     }
340 
changeset_to_changes( old_text: &Rope, new_text: &Rope, changeset: &ChangeSet, offset_encoding: OffsetEncoding, ) -> Vec<lsp::TextDocumentContentChangeEvent>341     pub fn changeset_to_changes(
342         old_text: &Rope,
343         new_text: &Rope,
344         changeset: &ChangeSet,
345         offset_encoding: OffsetEncoding,
346     ) -> Vec<lsp::TextDocumentContentChangeEvent> {
347         let mut iter = changeset.changes().iter().peekable();
348         let mut old_pos = 0;
349         let mut new_pos = 0;
350 
351         let mut changes = Vec::new();
352 
353         use crate::util::pos_to_lsp_pos;
354         use helix_core::Operation::*;
355 
356         // this is dumb. TextEdit describes changes to the initial doc (concurrent), but
357         // TextDocumentContentChangeEvent describes a series of changes (sequential).
358         // So S -> S1 -> S2, meaning positioning depends on the previous edits.
359         //
360         // Calculation is therefore a bunch trickier.
361 
362         use helix_core::RopeSlice;
363         fn traverse(pos: lsp::Position, text: RopeSlice) -> lsp::Position {
364             let lsp::Position {
365                 mut line,
366                 mut character,
367             } = pos;
368 
369             let mut chars = text.chars().peekable();
370             while let Some(ch) = chars.next() {
371                 // LSP only considers \n, \r or \r\n as line endings
372                 if ch == '\n' || ch == '\r' {
373                     // consume a \r\n
374                     if ch == '\r' && chars.peek() == Some(&'\n') {
375                         chars.next();
376                     }
377                     line += 1;
378                     character = 0;
379                 } else {
380                     character += ch.len_utf16() as u32;
381                 }
382             }
383             lsp::Position { line, character }
384         }
385 
386         let old_text = old_text.slice(..);
387 
388         while let Some(change) = iter.next() {
389             let len = match change {
390                 Delete(i) | Retain(i) => *i,
391                 Insert(_) => 0,
392             };
393             let mut old_end = old_pos + len;
394 
395             match change {
396                 Retain(i) => {
397                     new_pos += i;
398                 }
399                 Delete(_) => {
400                     let start = pos_to_lsp_pos(new_text, new_pos, offset_encoding);
401                     let end = traverse(start, old_text.slice(old_pos..old_end));
402 
403                     // deletion
404                     changes.push(lsp::TextDocumentContentChangeEvent {
405                         range: Some(lsp::Range::new(start, end)),
406                         text: "".to_string(),
407                         range_length: None,
408                     });
409                 }
410                 Insert(s) => {
411                     let start = pos_to_lsp_pos(new_text, new_pos, offset_encoding);
412 
413                     new_pos += s.chars().count();
414 
415                     // a subsequent delete means a replace, consume it
416                     let end = if let Some(Delete(len)) = iter.peek() {
417                         old_end = old_pos + len;
418                         let end = traverse(start, old_text.slice(old_pos..old_end));
419 
420                         iter.next();
421 
422                         // replacement
423                         end
424                     } else {
425                         // insert
426                         start
427                     };
428 
429                     changes.push(lsp::TextDocumentContentChangeEvent {
430                         range: Some(lsp::Range::new(start, end)),
431                         text: s.into(),
432                         range_length: None,
433                     });
434                 }
435             }
436             old_pos = old_end;
437         }
438 
439         changes
440     }
441 
text_document_did_change( &self, text_document: lsp::VersionedTextDocumentIdentifier, old_text: &Rope, new_text: &Rope, changes: &ChangeSet, ) -> Option<impl Future<Output = Result<()>>>442     pub fn text_document_did_change(
443         &self,
444         text_document: lsp::VersionedTextDocumentIdentifier,
445         old_text: &Rope,
446         new_text: &Rope,
447         changes: &ChangeSet,
448     ) -> Option<impl Future<Output = Result<()>>> {
449         // figure out what kind of sync the server supports
450 
451         let capabilities = self.capabilities.get().unwrap();
452 
453         let sync_capabilities = match capabilities.text_document_sync {
454             Some(lsp::TextDocumentSyncCapability::Kind(kind))
455             | Some(lsp::TextDocumentSyncCapability::Options(lsp::TextDocumentSyncOptions {
456                 change: Some(kind),
457                 ..
458             })) => kind,
459             // None | SyncOptions { changes: None }
460             _ => return None,
461         };
462 
463         let changes = match sync_capabilities {
464             lsp::TextDocumentSyncKind::Full => {
465                 vec![lsp::TextDocumentContentChangeEvent {
466                     // range = None -> whole document
467                     range: None,        //Some(Range)
468                     range_length: None, // u64 apparently deprecated
469                     text: new_text.to_string(),
470                 }]
471             }
472             lsp::TextDocumentSyncKind::Incremental => {
473                 Self::changeset_to_changes(old_text, new_text, changes, self.offset_encoding)
474             }
475             lsp::TextDocumentSyncKind::None => return None,
476         };
477 
478         Some(self.notify::<lsp::notification::DidChangeTextDocument>(
479             lsp::DidChangeTextDocumentParams {
480                 text_document,
481                 content_changes: changes,
482             },
483         ))
484     }
485 
text_document_did_close( &self, text_document: lsp::TextDocumentIdentifier, ) -> impl Future<Output = Result<()>>486     pub fn text_document_did_close(
487         &self,
488         text_document: lsp::TextDocumentIdentifier,
489     ) -> impl Future<Output = Result<()>> {
490         self.notify::<lsp::notification::DidCloseTextDocument>(lsp::DidCloseTextDocumentParams {
491             text_document,
492         })
493     }
494 
495     // will_save / will_save_wait_until
496 
text_document_did_save( &self, text_document: lsp::TextDocumentIdentifier, text: &Rope, ) -> Option<impl Future<Output = Result<()>>>497     pub fn text_document_did_save(
498         &self,
499         text_document: lsp::TextDocumentIdentifier,
500         text: &Rope,
501     ) -> Option<impl Future<Output = Result<()>>> {
502         let capabilities = self.capabilities.get().unwrap();
503 
504         let include_text = match &capabilities.text_document_sync {
505             Some(lsp::TextDocumentSyncCapability::Options(lsp::TextDocumentSyncOptions {
506                 save: Some(options),
507                 ..
508             })) => match options {
509                 lsp::TextDocumentSyncSaveOptions::Supported(true) => false,
510                 lsp::TextDocumentSyncSaveOptions::SaveOptions(lsp_types::SaveOptions {
511                     include_text,
512                 }) => include_text.unwrap_or(false),
513                 // Supported(false)
514                 _ => return None,
515             },
516             // unsupported
517             _ => return None,
518         };
519 
520         Some(self.notify::<lsp::notification::DidSaveTextDocument>(
521             lsp::DidSaveTextDocumentParams {
522                 text_document,
523                 text: include_text.then(|| text.into()),
524             },
525         ))
526     }
527 
completion( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>>528     pub fn completion(
529         &self,
530         text_document: lsp::TextDocumentIdentifier,
531         position: lsp::Position,
532         work_done_token: Option<lsp::ProgressToken>,
533     ) -> impl Future<Output = Result<Value>> {
534         // ) -> Result<Vec<lsp::CompletionItem>> {
535         let params = lsp::CompletionParams {
536             text_document_position: lsp::TextDocumentPositionParams {
537                 text_document,
538                 position,
539             },
540             // TODO: support these tokens by async receiving and updating the choice list
541             work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token },
542             partial_result_params: lsp::PartialResultParams {
543                 partial_result_token: None,
544             },
545             context: None,
546             // lsp::CompletionContext { trigger_kind: , trigger_character: Some(), }
547         };
548 
549         self.call::<lsp::request::Completion>(params)
550     }
551 
text_document_signature_help( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>>552     pub fn text_document_signature_help(
553         &self,
554         text_document: lsp::TextDocumentIdentifier,
555         position: lsp::Position,
556         work_done_token: Option<lsp::ProgressToken>,
557     ) -> impl Future<Output = Result<Value>> {
558         let params = lsp::SignatureHelpParams {
559             text_document_position_params: lsp::TextDocumentPositionParams {
560                 text_document,
561                 position,
562             },
563             work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token },
564             context: None,
565             // lsp::SignatureHelpContext
566         };
567 
568         self.call::<lsp::request::SignatureHelpRequest>(params)
569     }
570 
text_document_hover( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>>571     pub fn text_document_hover(
572         &self,
573         text_document: lsp::TextDocumentIdentifier,
574         position: lsp::Position,
575         work_done_token: Option<lsp::ProgressToken>,
576     ) -> impl Future<Output = Result<Value>> {
577         let params = lsp::HoverParams {
578             text_document_position_params: lsp::TextDocumentPositionParams {
579                 text_document,
580                 position,
581             },
582             work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token },
583             // lsp::SignatureHelpContext
584         };
585 
586         self.call::<lsp::request::HoverRequest>(params)
587     }
588 
589     // formatting
590 
text_document_formatting( &self, text_document: lsp::TextDocumentIdentifier, options: lsp::FormattingOptions, work_done_token: Option<lsp::ProgressToken>, ) -> Option<impl Future<Output = Result<Vec<lsp::TextEdit>>>>591     pub fn text_document_formatting(
592         &self,
593         text_document: lsp::TextDocumentIdentifier,
594         options: lsp::FormattingOptions,
595         work_done_token: Option<lsp::ProgressToken>,
596     ) -> Option<impl Future<Output = Result<Vec<lsp::TextEdit>>>> {
597         let capabilities = self.capabilities.get().unwrap();
598 
599         // check if we're able to format
600         match capabilities.document_formatting_provider {
601             Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (),
602             // None | Some(false)
603             _ => return None,
604         };
605         // TODO: return err::unavailable so we can fall back to tree sitter formatting
606 
607         let params = lsp::DocumentFormattingParams {
608             text_document,
609             options,
610             work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token },
611         };
612 
613         let request = self.call::<lsp::request::Formatting>(params);
614 
615         Some(async move {
616             let json = request.await?;
617             let response: Option<Vec<lsp::TextEdit>> = serde_json::from_value(json)?;
618             Ok(response.unwrap_or_default())
619         })
620     }
621 
text_document_range_formatting( &self, text_document: lsp::TextDocumentIdentifier, range: lsp::Range, options: lsp::FormattingOptions, work_done_token: Option<lsp::ProgressToken>, ) -> anyhow::Result<Vec<lsp::TextEdit>>622     pub async fn text_document_range_formatting(
623         &self,
624         text_document: lsp::TextDocumentIdentifier,
625         range: lsp::Range,
626         options: lsp::FormattingOptions,
627         work_done_token: Option<lsp::ProgressToken>,
628     ) -> anyhow::Result<Vec<lsp::TextEdit>> {
629         let capabilities = self.capabilities.get().unwrap();
630 
631         // check if we're able to format
632         match capabilities.document_range_formatting_provider {
633             Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (),
634             // None | Some(false)
635             _ => return Ok(Vec::new()),
636         };
637         // TODO: return err::unavailable so we can fall back to tree sitter formatting
638 
639         let params = lsp::DocumentRangeFormattingParams {
640             text_document,
641             range,
642             options,
643             work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token },
644         };
645 
646         let response = self
647             .request::<lsp::request::RangeFormatting>(params)
648             .await?;
649 
650         Ok(response.unwrap_or_default())
651     }
652 
goto_request< T: lsp::request::Request< Params = lsp::GotoDefinitionParams, Result = Option<lsp::GotoDefinitionResponse>, >, >( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>>653     fn goto_request<
654         T: lsp::request::Request<
655             Params = lsp::GotoDefinitionParams,
656             Result = Option<lsp::GotoDefinitionResponse>,
657         >,
658     >(
659         &self,
660         text_document: lsp::TextDocumentIdentifier,
661         position: lsp::Position,
662         work_done_token: Option<lsp::ProgressToken>,
663     ) -> impl Future<Output = Result<Value>> {
664         let params = lsp::GotoDefinitionParams {
665             text_document_position_params: lsp::TextDocumentPositionParams {
666                 text_document,
667                 position,
668             },
669             work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token },
670             partial_result_params: lsp::PartialResultParams {
671                 partial_result_token: None,
672             },
673         };
674 
675         self.call::<T>(params)
676     }
677 
goto_definition( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>>678     pub fn goto_definition(
679         &self,
680         text_document: lsp::TextDocumentIdentifier,
681         position: lsp::Position,
682         work_done_token: Option<lsp::ProgressToken>,
683     ) -> impl Future<Output = Result<Value>> {
684         self.goto_request::<lsp::request::GotoDefinition>(text_document, position, work_done_token)
685     }
686 
goto_type_definition( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>>687     pub fn goto_type_definition(
688         &self,
689         text_document: lsp::TextDocumentIdentifier,
690         position: lsp::Position,
691         work_done_token: Option<lsp::ProgressToken>,
692     ) -> impl Future<Output = Result<Value>> {
693         self.goto_request::<lsp::request::GotoTypeDefinition>(
694             text_document,
695             position,
696             work_done_token,
697         )
698     }
699 
goto_implementation( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>>700     pub fn goto_implementation(
701         &self,
702         text_document: lsp::TextDocumentIdentifier,
703         position: lsp::Position,
704         work_done_token: Option<lsp::ProgressToken>,
705     ) -> impl Future<Output = Result<Value>> {
706         self.goto_request::<lsp::request::GotoImplementation>(
707             text_document,
708             position,
709             work_done_token,
710         )
711     }
712 
goto_reference( &self, text_document: lsp::TextDocumentIdentifier, position: lsp::Position, work_done_token: Option<lsp::ProgressToken>, ) -> impl Future<Output = Result<Value>>713     pub fn goto_reference(
714         &self,
715         text_document: lsp::TextDocumentIdentifier,
716         position: lsp::Position,
717         work_done_token: Option<lsp::ProgressToken>,
718     ) -> impl Future<Output = Result<Value>> {
719         let params = lsp::ReferenceParams {
720             text_document_position: lsp::TextDocumentPositionParams {
721                 text_document,
722                 position,
723             },
724             context: lsp::ReferenceContext {
725                 include_declaration: true,
726             },
727             work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token },
728             partial_result_params: lsp::PartialResultParams {
729                 partial_result_token: None,
730             },
731         };
732 
733         self.call::<lsp::request::References>(params)
734     }
735 
document_symbols( &self, text_document: lsp::TextDocumentIdentifier, ) -> impl Future<Output = Result<Value>>736     pub fn document_symbols(
737         &self,
738         text_document: lsp::TextDocumentIdentifier,
739     ) -> impl Future<Output = Result<Value>> {
740         let params = lsp::DocumentSymbolParams {
741             text_document,
742             work_done_progress_params: lsp::WorkDoneProgressParams::default(),
743             partial_result_params: lsp::PartialResultParams::default(),
744         };
745 
746         self.call::<lsp::request::DocumentSymbolRequest>(params)
747     }
748 
749     // empty string to get all symbols
workspace_symbols(&self, query: String) -> impl Future<Output = Result<Value>>750     pub fn workspace_symbols(&self, query: String) -> impl Future<Output = Result<Value>> {
751         let params = lsp::WorkspaceSymbolParams {
752             query,
753             work_done_progress_params: lsp::WorkDoneProgressParams::default(),
754             partial_result_params: lsp::PartialResultParams::default(),
755         };
756 
757         self.call::<lsp::request::WorkspaceSymbol>(params)
758     }
759 
code_actions( &self, text_document: lsp::TextDocumentIdentifier, range: lsp::Range, ) -> impl Future<Output = Result<Value>>760     pub fn code_actions(
761         &self,
762         text_document: lsp::TextDocumentIdentifier,
763         range: lsp::Range,
764     ) -> impl Future<Output = Result<Value>> {
765         let params = lsp::CodeActionParams {
766             text_document,
767             range,
768             context: lsp::CodeActionContext::default(),
769             work_done_progress_params: lsp::WorkDoneProgressParams::default(),
770             partial_result_params: lsp::PartialResultParams::default(),
771         };
772 
773         self.call::<lsp::request::CodeActionRequest>(params)
774     }
775 }
776