Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'src/lsp/client.rs')
| -rw-r--r-- | src/lsp/client.rs | 346 |
1 files changed, 194 insertions, 152 deletions
diff --git a/src/lsp/client.rs b/src/lsp/client.rs index 9bc85b5..ddbe7c4 100644 --- a/src/lsp/client.rs +++ b/src/lsp/client.rs @@ -1,5 +1,6 @@ use std::fmt::Debug; use std::path::{Path, PathBuf}; +use std::sync::Arc; use std::sync::atomic::AtomicI32; use std::sync::atomic::Ordering::Relaxed; @@ -13,24 +14,39 @@ use log::debug; use lsp_server::{ Message, Notification as N, Request as LRq, Response as Re, }; -use lsp_types::notification::*; -use lsp_types::request::*; use lsp_types::*; use rootcause::option_ext::OptionExt; use rust_analyzer::lsp::ext::*; use tokio::sync::oneshot; use ttools::*; +use url::Url; use crate::lsp::BehaviourAfter::{self, *}; -use crate::lsp::{RequestError, Require, Requiring, Rq}; +use crate::lsp::communication::{WorkDoneProgress, send}; +use crate::lsp::{RequestError, Require, Requiring, Rq, RqSendError}; use crate::text::cursor::ceach; use crate::text::{LOADER, RopeExt, SortTedits, TextArea}; +#[derive(Debug, Clone)] +pub struct Tx(pub Sender<Message>); +impl std::ops::Deref for Client { + type Target = Tx; + fn deref(&self) -> &Self::Target { + &self.tx + } +} +impl std::ops::Deref for Tx { + type Target = Sender<Message>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} #[derive(Debug)] pub struct Client { pub runtime: tokio::runtime::Runtime, - pub tx: Sender<Message>, + pub tx: Tx, pub id: AtomicI32, pub initialized: Option<InitializeResult>, // pub pending: HashMap<i32, oneshot::Sender<Re>>, @@ -39,7 +55,7 @@ pub struct Client { ProgressToken, Option<(WorkDoneProgress, WorkDoneProgressBegin)>, >, - pub diagnostics: &'static papaya::HashMap<Url, Vec<Diagnostic>>, + pub diagnostics: &'static papaya::HashMap<url::Url, Vec<Diagnostic>>, #[allow(dead_code)] // TODO: handle notifications from the server pub not_rx: Receiver<N>, @@ -49,11 +65,17 @@ pub struct Client { &'static LanguageServerConfiguration, &'static LanguageServerFeatures, ), + pub workspace: WorkspaceFolder, } impl Drop for Client { fn drop(&mut self) { - panic!("please dont"); + _ = self.notify::<ExitNotification>(&()); + println!( + "dropped lsp({}) @ {}", + self.lsp_data.1.name, self.workspace.uri + ); + // panic!("please dont"); } } @@ -68,22 +90,25 @@ impl Client { l: helix_core::Language, ) -> Result<(), SendError<Message>> { let l = LOADER.language(l).config(); - self.notify::<DidOpenTextDocument>(&DidOpenTextDocumentParams { - text_document: TextDocumentItem { - uri: url::Url::from_file_path(f).unwrap(), - language_id: l - .language_server_language_id - .clone() - .unwrap_or(l.language_id.clone()), - version: 0, - text, + self.notify::<DidOpenTextDocumentNotification>( + &DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: url::Url::from_file_path(f).unwrap(), + language_id: l + .language_server_language_id + .clone() + .unwrap_or(l.language_id.clone()) + .into(), + version: 0, + text, + }, }, - }) + ) } pub fn close(&self, f: &Path) -> Result<(), SendError<Message>> { - self.notify::<DidCloseTextDocument>(&DidCloseTextDocumentParams { - text_document: f.tid(), - }) + self.notify::<DidCloseTextDocumentNotification>( + &DidCloseTextDocumentParams { text_document: f.tid() }, + ) } pub fn edit( &self, @@ -91,17 +116,16 @@ impl Client { text: String, ) -> Result<(), SendError<Message>> { static V: AtomicI32 = AtomicI32::new(0); - self.notify::<lsp_types::notification::DidChangeTextDocument>( + self.notify::<lsp_types::DidChangeTextDocumentNotification>( &DidChangeTextDocumentParams { text_document: VersionedTextDocumentIdentifier { - uri: url::Url::from_file_path(f).unwrap(), + text_document_identifier: f.tid(), version: V.fetch_add(1, Relaxed), }, - content_changes: vec![TextDocumentContentChangeEvent { - range: None, - range_length: None, - text, - }], + content_changes: vec![ + (TextDocumentContentChangeWholeDocument { text }) + .into(), + ], }, ) } @@ -109,8 +133,13 @@ impl Client { pub fn resolve( &self, x: CompletionItem, - ) -> Result<CompletionItem, RequestError<ResolveCompletionItem>> { - self.request_immediate::<ResolveCompletionItem>(&x) + ) -> Result< + CompletionItem, + RequestError<lsp_request!("completionItem/resolve")>, + > { + self.request_immediate::<lsp_request!("completionItem/resolve")>( + &x, + ) } pub fn request_complete<'me>( @@ -123,18 +152,15 @@ impl Client { impl Future< Output = Result< Option<CompletionResponse>, - RequestError<Completion>, + RequestError<lsp_request!("textDocument/completion")>, >, - > + use<'me>, + > + use<>, > { self.caps().completion_provider.require()?; let (rx, _) = self - .request_::<Completion, { Redraw }>(&CompletionParams { - text_document_position: TextDocumentPositionParams { - text_document: f.tid(), - position: Position { line: y as _, character: x as _ }, - }, + .request_::<lsp_request!("textDocument/completion"), { Redraw }>(&CompletionParams { + text_document_position_params: TextDocumentPositionParams::new(f.tid(), Position { line: y as _, character: x as _ }), work_done_progress_params: default(), partial_result_params: default(), context: Some(c), @@ -154,7 +180,7 @@ impl Client { Option<SignatureHelp>, RequestError<SignatureHelpRequest>, >, - > + use<'me>, + > + use<>, > { self.caps().signature_help_provider.require()?; Ok(self @@ -246,7 +272,7 @@ impl Client { .diagnostic_provider .as_ref()? { - DiagnosticServerCapabilities::RegistrationOptions( + DiagnosticProvider::DiagnosticRegistrationOptions( x, ) => x.diagnostic_options.identifier.clone()?, _ => None?, @@ -271,8 +297,8 @@ impl Client { }; // dbg!(&x); match x.clone() { - DocumentDiagnosticReportResult::Report( - DocumentDiagnosticReport::Full( + // DocumentDiagnosticReport::DocumentDiagnosticReport( + DocumentDiagnosticReport::RelatedFullDocumentDiagnosticReport( RelatedFullDocumentDiagnosticReport { related_documents, full_document_diagnostic_report: @@ -281,7 +307,7 @@ impl Client { result_id, }, }, - ), + ) => { let l = self.diagnostics.guard(); self.diagnostics.insert(f.tid().uri, items, &l); @@ -289,14 +315,14 @@ impl Client { related_documents.into_iter().flatten() { match rel { - DocumentDiagnosticReportKind::Full( + RelatedDocument::FullDocumentDiagnosticReport( FullDocumentDiagnosticReport { items, .. }, ) => { self.diagnostics.insert(uri, items, &l); } - DocumentDiagnosticReportKind::Unchanged(_) => { + RelatedDocument::UnchangedDocumentDiagnosticReport(_) => { } } } @@ -318,24 +344,23 @@ impl Client { Vec<DocumentHighlight>, RequestError<DocumentHighlightRequest>, >, - > + use<'me>, + > + use<>, > { self.caps().document_highlight_provider.require()?; - let p = DocumentHighlightParams { + Ok(send!(self.request_::<{Redraw}>, "textDocument/documentHighlight", _ { text_document_position_params: TextDocumentPositionParams { text_document: f.tid(), position: cursor, }, work_done_progress_params: default(), partial_result_params: default(), - }; - Ok(self.request_::<lsp_request!("textDocument/documentHighlight"), {Redraw}>(&p) + }) .unwrap() .0 .map(|x| x.map(|x| x.unwrap_or_default()))) } pub fn document_symbols( - &'static self, + &self, p: &Path, ) -> Requiring< "document_symbol", @@ -347,8 +372,7 @@ impl Client { > + use<>, > { self.caps().document_symbol_provider.require()?; - Ok(self.request_::<lsp_request!("textDocument/documentSymbol"), { Redraw }>( - &DocumentSymbolParams { + Ok(send!(self.request_::<{ Redraw }>, "textDocument/documentSymbol", _ { text_document: p.tid(), work_done_progress_params: default(), partial_result_params: default(), @@ -358,27 +382,29 @@ impl Client { .0) } pub fn workspace_symbols( - &'static self, + &self, f: String, ) -> Requiring< "workspace_symbol", impl Future< Output = Result< Option<WorkspaceSymbolResponse>, - RequestError<lsp_request!("workspace/symbol")>, + RequestError< + rust_analyzer::lsp::ext::WorkspaceSymbolRequest, + >, >, - >, + > + use<>, > { self.caps().workspace_symbol_provider.require()?; Ok(self - .request_::<lsp_request!("workspace/symbol"), { Redraw }>( - &lsp_types::WorkspaceSymbolParams { + .request_::<rust_analyzer::lsp::ext::WorkspaceSymbolRequest, { Redraw }>( + &rust_analyzer::lsp::ext::WorkspaceSymbolParams { query: f, search_scope: Some( - lsp_types::WorkspaceSymbolSearchScope::Workspace, + WorkspaceSymbolSearchScope::Workspace, ), search_kind: Some( - lsp_types::WorkspaceSymbolSearchKind::AllSymbols, + WorkspaceSymbolSearchKind::AllSymbols, ), ..Default::default() }, @@ -391,36 +417,38 @@ impl Client { &self, f: &Path, x: Vec<Position>, - ) -> Result<Vec<Option<Position>>, RequestError<MatchingBrace>> { - self.request_immediate::<MatchingBrace>(&MatchingBraceParams { - text_document: f.tid(), - positions: x, - }) + ) -> Result<Vec<[Position;2]>, RequestError<MatchingBraceRequest>> { + self.request_immediate::<MatchingBraceRequest>( + &MatchingBraceParams { text_document: f.tid(), positions: x }, + ) } - pub fn matching_brace<'a>( - &'static self, - f: &Path, - t: &'a mut TextArea, - ) { + pub fn matching_brace<'a>(&self, f: &Path, t: &'a mut TextArea) { if let Ok(x) = self.matching_brace_at(f, t.cursor.positions(&t.rope)) { for (c, p) in t.cursor.inner.iter_mut().zip(x) { - if let Some(p) = p { - c.position = t.rope.l_position(p).unwrap(); - } + // if let Some(p) = p { + c.position = t.rope.l_position(p[1]).unwrap(); + // } } } } pub fn legend(&self) -> Option<&SemanticTokensLegend> { - match &self.caps(){ - ServerCapabilities {semantic_tokens_provider:Some(SemanticTokensServerCapabilities::SemanticTokensOptions(SemanticTokensOptions{legend,..})), ..}=> {Some(legend)},_ => None, + match &self.caps() { + ServerCapabilities { + semantic_tokens_provider: + Some(SemanticTokensProvider::SemanticTokensOptions( + SemanticTokensOptions { legend, .. }, + )), + .. + } => Some(legend), + _ => None, } } pub fn inlay( - &'static self, + &self, f: &Path, t: &TextArea, ) -> Requiring< @@ -433,7 +461,7 @@ impl Client { > + use<>, > { self.caps().inlay_hint_provider.require()?; - Ok(self.request_::<lsp_request!("textDocument/inlayHint"), { Redraw }>(&InlayHintParams { + Ok(send!(self.request_::<{ Redraw }>, "textDocument/inlayHint", _ { work_done_progress_params: default(), text_document: f.tid(), range: t.to_l_range(lower::saturating::math!{ @@ -456,48 +484,49 @@ impl Client { // } } pub fn format( - &'static self, + &self, f: &Path, ) -> Requiring< "document_formatting", impl Future< Output = Result< Option<Vec<TextEdit>>, - RequestError<Formatting>, + RequestError<lsp_request!("textDocument/formatting")>, >, >, > { self.caps().document_formatting_provider.require()?; - Ok(self - .request::<lsp_request!("textDocument/formatting")>( - &DocumentFormattingParams { - text_document: f.tid(), - options: FormattingOptions { - tab_size: 4, - insert_spaces: false, - properties: default(), - trim_trailing_whitespace: Some(true), - insert_final_newline: Some(true), - trim_final_newlines: Some(false), - }, - work_done_progress_params: default(), - }, - ) - .unwrap() - .0) + Ok(send!(self.request, "textDocument/formatting", + _ { + text_document: f.tid(), + options: FormattingOptions { + tab_size: 4, + insert_spaces: false, + // properties: default(), + trim_trailing_whitespace: Some(true), + insert_final_newline: Some(true), + trim_final_newlines: Some(false), + }, + work_done_progress_params: default(), + }) + .unwrap() + .0) } pub fn rq_semantic_tokens( - &'static self, + &self, to: &mut Rq< Box<[SemanticToken]>, Box<[SemanticToken]>, (), - RequestError<SemanticTokensFullRequest>, + RequestError<lsp_request!("textDocument/semanticTokens/full")>, >, f: &Path, ) -> Requiring< "semantic_tokens", - Result<(), RequestError<SemanticTokensFullRequest>>, + Result< + (), + RequestError<lsp_request!("textDocument/semanticTokens/full")>, + >, > { self.caps().semantic_tokens_provider.require()?; debug!("requested semantic tokens"); @@ -506,25 +535,23 @@ impl Client { // return Ok(()); // }; Ok(try bikeshed Result<(), RequestError<_>> { - let (rx, _) = self.request::<SemanticTokensFullRequest>( - &SemanticTokensParams { - work_done_progress_params: default(), - partial_result_params: default(), - text_document: f.tid(), - }, - )?; + let (rx, _) = send!(self.request, "textDocument/semanticTokens/full", _ { + work_done_progress_params: default(), + partial_result_params: default(), + text_document: f.tid(), + })?; let x = self.runtime.spawn(async move { let t = rx.await; let y = t?.ok_or(RequestError::Rx(std::marker::PhantomData))?; debug!("received semantic tokens"); - let r = match y { - SemanticTokensResult::Partial(_) => - panic!("i told the lsp i dont support this"), - SemanticTokensResult::Tokens(x) => - x.data.into_boxed_slice(), - }; - Ok(r) + // let r = match y { + // SemanticTokensResult::Partial(_) => + // panic!("i told the lsp i dont support this"), + // SemanticTokensResult::Tokens(x) => + // x.data.into_boxed_slice(), + // }; + Ok(y.data.into_boxed_slice()) }); to.request(x); }) @@ -537,15 +564,17 @@ impl Client { ) -> rootcause::Result<()> { ceach!(t.cursor, |c| try bikeshed rootcause::Result<()> { let r = self - .request_immediate::<OnEnter>( + .request_by::<OnEnterRequest>( &TextDocumentPositionParams { text_document: f.tid(), position: t.to_l_position(*c).unwrap(), }, + acceptable_duration(), ); match r { - Ok(None) | Err(_) => t.enter(), - Ok(Some(mut r)) => { + Ok(Ok(None)) | Err(_) | Ok(Err(_)) => { println!("hmm") ;t.enter() }, + Ok(Ok(Some(mut r))) => { + println!("applying"); r.sort_tedits(); for f in r { t.apply_snippet_tedit(&f)?; @@ -556,15 +585,16 @@ impl Client { Ok(()) } pub fn runnables( - &'static self, + &self, t: &Path, c: Option<Position>, ) -> Result< - impl Future<Output = Result<Vec<Runnable>, RequestError<Runnables>>> - + use<>, - SendError<Message>, + impl Future< + Output = Result<Vec<Runnable>, RequestError<RunnablesRequest>>, + > + use<>, + RqSendError<RunnablesRequest>, > { - self.request::<Runnables>(&RunnablesParams { + self.request::<RunnablesRequest>(&RunnablesParams { text_document: t.tid(), position: c, }) @@ -572,19 +602,19 @@ impl Client { } pub fn _child_modules( - &'static self, + &self, p: Position, t: &Path, ) -> Result< impl Future< Output = Result< - <ChildModules as Request>::Result, - RequestError<ChildModules>, + <ChildModulesRequest as Request>::Result, + RequestError<ChildModulesRequest>, >, >, - SendError<Message>, + RqSendError<ChildModulesRequest>, > { - self.request::<ChildModules>(&TextDocumentPositionParams { + self.request::<ChildModulesRequest>(&TextDocumentPositionParams { position: p, text_document: t.tid(), }) @@ -596,17 +626,19 @@ impl Client { ) -> Result< impl Future< Output = Result< - <GotoImplementation as Request>::Result, - RequestError<GotoImplementation>, + <lsp_request!("textDocument/implementation") as Request>::Result, + RequestError<lsp_request!("textDocument/implementation")>, >, - >, - SendError<Message>, - > { - self.request::<GotoImplementation>(&GotoImplementationParams { - text_document_position_params: tdpp, - work_done_progress_params: default(), - partial_result_params: default(), - }) + > + use<>, + RqSendError<lsp_request!("textDocument/implementation")>, + >{ + send!(self.request, "textDocument/implementation", + _ { + text_document_position_params: tdpp, + work_done_progress_params: default(), + partial_result_params: default(), + }, + ) .map(fst) } @@ -617,17 +649,19 @@ impl Client { impl Future< Output = Result< Option<Vec<Location>>, - RequestError<References>, + RequestError<lsp_request!("textDocument/references")>, >, - >, - SendError<Message>, + > + use<>, + RqSendError<lsp_request!("textDocument/references")>, > { - self.request::<References>(&ReferenceParams { - text_document_position: tdpp, - work_done_progress_params: default(), - partial_result_params: default(), - context: ReferenceContext { include_declaration: false }, - }) + send!(self.request, "textDocument/references", + _ { + text_document_position_params: tdpp, + work_done_progress_params: default(), + partial_result_params: default(), + context: ReferenceContext { include_declaration: false }, + }, + ) .map(fst) } @@ -646,24 +680,28 @@ impl Client { impl Future< Output = Result< Option<CallHierarchyItem>, - RequestError<CallHierarchyPrepare>, + RequestError< + lsp_request!("textDocument/prepareCallHierarchy"), + >, >, - >, - SendError<Message>, + > + use<>, + RqSendError<lsp_request!("textDocument/prepareCallHierarchy")>, > { - self.request::<CallHierarchyPrepare>(&CallHierarchyPrepareParams { - text_document_position_params: at, - work_done_progress_params: default(), - }) + send!(self.request, "textDocument/prepareCallHierarchy", + _ { + text_document_position_params: at, + work_done_progress_params: default(), + } + ) .map(fst) .map(|x| x.map(|x| x.map(|x| x.and_then(|mut x| x.try_remove(0))))) } pub async fn callers( - &self, + self: Arc<Self>, at: TextDocumentPositionParams, ) -> rootcause::Result<Vec<CallHierarchyIncomingCall>> { let calls = self - .request::<CallHierarchyIncomingCalls>( + .request::<CallHierarchyIncomingCallsRequest>( &CallHierarchyIncomingCallsParams { item: self .find_function(at)? @@ -679,11 +717,11 @@ impl Client { Ok(calls) } pub async fn calling( - &self, + self: Arc<Self>, at: TextDocumentPositionParams, ) -> rootcause::Result<Vec<CallHierarchyOutgoingCall>> { let calls = self - .request::<CallHierarchyOutgoingCalls>( + .request::<CallHierarchyOutgoingCallsRequest>( &CallHierarchyOutgoingCallsParams { item: self .find_function(at)? @@ -716,3 +754,7 @@ pub macro tdpp($e:expr) { position: $e.text.to_l_position(*$e.text.cursor.first()).unwrap(), } } + +pub fn acceptable_duration() -> tokio::time::Duration { + tokio::time::Duration::from_millis(50) +} |