Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'src/lsp/client.rs')
-rw-r--r--src/lsp/client.rs346
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)
+}