A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/lsp.rs')
-rw-r--r--src/lsp.rs1125
1 files changed, 14 insertions, 1111 deletions
diff --git a/src/lsp.rs b/src/lsp.rs
index 0a5be2c..332fd23 100644
--- a/src/lsp.rs
+++ b/src/lsp.rs
@@ -1,661 +1,24 @@
-use std::backtrace::Backtrace;
-use std::collections::HashMap;
-use std::fmt::{Debug, Display};
-use std::marker::PhantomData;
-use std::mem::forget;
-use std::path::{Path, PathBuf};
+use std::fmt::Debug;
use std::sync::Arc;
use std::sync::atomic::AtomicI32;
-use std::sync::atomic::Ordering::Relaxed;
use std::task::Poll;
use std::thread::spawn;
use std::time::Instant;
-use Default::default;
-use anyhow::bail;
-use crossbeam::channel::{
- Receiver, RecvError, SendError, Sender, unbounded,
-};
-use log::{debug, error, trace};
-use lsp_server::{
- ErrorCode, Message, Notification as N, Request as LRq, Response as Re,
- ResponseError,
-};
+use crossbeam::channel::{Receiver, Sender, unbounded};
+use lsp_server::Message;
use lsp_types::notification::*;
use lsp_types::request::*;
use lsp_types::*;
-use rust_analyzer::lsp::ext::*;
-use serde::{Deserialize, Serialize};
-use serde_json::json;
use tokio::sync::oneshot;
-use tokio::task;
-use tokio_util::task::AbortOnDropHandle;
use winit::window::Window;
+mod client;
+mod communication;
+pub use client::*;
+mod init_opts;
+mod rq;
+pub use rq::*;
-use crate::text::cursor::ceach;
-use crate::text::{RopeExt, SortTedits, TextArea};
-#[derive(Debug)]
-pub struct Client {
- pub runtime: tokio::runtime::Runtime,
-
- pub tx: Sender<Message>,
- pub id: AtomicI32,
- pub initialized: Option<InitializeResult>,
- // pub pending: HashMap<i32, oneshot::Sender<Re>>,
- pub send_to: Sender<(i32, oneshot::Sender<Re>, BehaviourAfter)>,
- pub progress: &'static papaya::HashMap<
- ProgressToken,
- Option<(WorkDoneProgress, WorkDoneProgressBegin)>,
- >,
- pub diagnostics: &'static papaya::HashMap<Url, Vec<Diagnostic>>,
- #[allow(dead_code)]
- // TODO: handle notifications from the server
- pub not_rx: Receiver<N>,
- pub req_rx: Receiver<LRq>,
-}
-
-impl Drop for Client {
- fn drop(&mut self) {
- panic!("please dont")
- }
-}
-#[derive(Serialize, Deserialize)]
-pub enum RequestError<X> {
- Rx(PhantomData<X>),
- Failure(Re, #[serde(skip)] Option<Backtrace>),
- Cancelled(Re, DiagnosticServerCancellationData),
- Send(Message),
-}
-pub type AQErr = RequestError<LSPError>;
-impl Request for LSPError {
- type Params = ();
- type Result = ();
- const METHOD: &'static str = "<unknown method>";
-}
-#[derive(Debug)]
-pub struct LSPError {}
-pub trait Anonymize<T> {
- fn anonymize(self) -> Result<T, RequestError<LSPError>>;
-}
-impl<T, E> Anonymize<T> for Result<T, RequestError<E>> {
- fn anonymize(self) -> Result<T, RequestError<LSPError>> {
- self.map_err(|e| match e {
- RequestError::Send(x) => RequestError::Send(x),
- RequestError::Rx(_) => RequestError::Rx(PhantomData),
- RequestError::Failure(r, b) => RequestError::Failure(r, b),
- RequestError::Cancelled(r, d) => RequestError::Cancelled(r, d),
- })
- }
-}
-
-// impl<X> Debug for RequestError<X> {}
-impl<X> From<oneshot::error::RecvError> for RequestError<X> {
- fn from(_: oneshot::error::RecvError) -> Self {
- Self::Rx(PhantomData)
- }
-}
-impl<X: Request + Debug> std::error::Error for RequestError<X> {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- None
- }
-}
-impl<X> From<SendError<Message>> for RequestError<X> {
- fn from(x: SendError<Message>) -> Self {
- Self::Send(x.into_inner())
- }
-}
-impl<X: Request> Display for RequestError<X> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- Self::Send(x) =>
- write!(f, "{} failed; couldnt send {x:?}", X::METHOD),
- Self::Rx(_) =>
- write!(f, "{} failed; couldnt get from thingy", X::METHOD),
- Self::Failure(x, bt) => write!(
- f,
- "{} failed; returned badge :( {x:?} ({bt:?})",
- X::METHOD
- ),
- Self::Cancelled(x, y) =>
- write!(f, "server cancelled {}. {x:?} {y:?}", X::METHOD),
- }
- }
-}
-impl Client {
- pub fn notify<X: Notification>(
- &self,
- y: &X::Params,
- ) -> Result<(), SendError<Message>> {
- self.tx.send(Message::Notification(N {
- method: X::METHOD.into(),
- params: serde_json::to_value(y).unwrap(),
- }))
- }
- pub fn cancel(&self, rid: i32) {
- _ = self.notify::<Cancel>(&CancelParams { id: rid.into() });
- }
- pub fn request_immediate<'me, X: Request>(
- &'me self,
- y: &X::Params,
- ) -> Result<X::Result, RequestError<X>> {
- self.runtime.block_on(self.request_::<X, { Nil }>(y)?.0)
- }
-
- pub fn request<'me, X: Request>(
- &'me self,
- y: &X::Params,
- ) -> Result<
- (
- impl Future<Output = Result<X::Result, RequestError<X>>>
- + use<'me, X>,
- i32,
- ),
- SendError<Message>,
- > {
- self.request_::<X, { Redraw }>(y)
- }
- #[must_use]
- fn request_<'me, X: Request, const THEN: BehaviourAfter>(
- &'me self,
- y: &X::Params,
- ) -> Result<
- (
- impl Future<Output = Result<X::Result, RequestError<X>>>
- + use<'me, X, THEN>,
- i32,
- ),
- SendError<Message>,
- > {
- let id = self.id.fetch_add(1, std::sync::atomic::Ordering::AcqRel);
- self.tx.send(Message::Request(LRq {
- id: id.into(),
- method: X::METHOD.into(),
- params: serde_json::to_value(y).unwrap(),
- }))?;
- let (tx, rx) = oneshot::channel();
- if self.initialized.is_some() {
- debug!("sent request {} ({id})'s handler", X::METHOD);
- self.send_to.send((id, tx, THEN)).expect("oughtnt really fail");
- }
- Ok((
- async move {
- let g = scopeguard::guard((), |()| {
- self.cancel(id);
- });
-
- let mut x = rx.await?;
- forget(g);
- if let Some(ResponseError { code, ref mut data, .. }) =
- x.error
- {
- if code == ErrorCode::ServerCancelled as i32 {
- let e = serde_json::from_value(
- data.take().unwrap_or_default(),
- );
- Err(RequestError::Cancelled(x, e.expect("lsp??")))
- } else {
- Err(RequestError::Failure(
- x,
- Some(Backtrace::capture()),
- ))
- }
- } else {
- Ok(serde_json::from_value::<X::Result>(
- x.result.clone().unwrap_or_default(),
- )
- .unwrap_or_else(|_| {
- panic!(
- "lsp failure for {x:?}\ndidnt follow spec \
- for {}\npossibly spec issue",
- X::METHOD
- )
- }))
- }
- },
- id,
- ))
- }
- pub fn open(
- &self,
- f: &Path,
- text: String,
- ) -> Result<(), SendError<Message>> {
- self.notify::<DidOpenTextDocument>(&DidOpenTextDocumentParams {
- text_document: TextDocumentItem {
- uri: url::Url::from_file_path(f).unwrap(),
- language_id: "rust".into(),
- version: 0,
- text,
- },
- })
- }
- pub fn close(&self, f: &Path) -> Result<(), SendError<Message>> {
- self.notify::<DidCloseTextDocument>(&DidCloseTextDocumentParams {
- text_document: f.tid(),
- })
- }
- pub fn edit(
- &self,
- f: &Path,
- text: String,
- ) -> Result<(), SendError<Message>> {
- static V: AtomicI32 = AtomicI32::new(0);
- self.notify::<lsp_types::notification::DidChangeTextDocument>(
- &DidChangeTextDocumentParams {
- text_document: VersionedTextDocumentIdentifier {
- uri: url::Url::from_file_path(f).unwrap(),
- version: V.fetch_add(1, Relaxed),
- },
- content_changes: vec![TextDocumentContentChangeEvent {
- range: None,
- range_length: None,
- text,
- }],
- },
- )
- }
-
- pub fn resolve(
- &self,
- x: CompletionItem,
- ) -> Result<
- impl Future<
- Output = Result<
- CompletionItem,
- RequestError<ResolveCompletionItem>,
- >,
- >,
- SendError<Message>,
- > {
- self.request::<ResolveCompletionItem>(&x).map(|x| x.0)
- }
-
- pub fn request_complete<'me>(
- &'me self,
- f: &Path,
- (x, y): (usize, usize),
- c: CompletionContext,
- ) -> impl Future<
- Output = Result<
- Option<CompletionResponse>,
- RequestError<Completion>,
- >,
- > + use<'me> {
- let (rx, _) = self
- .request_::<Completion, { Redraw }>(&CompletionParams {
- text_document_position: TextDocumentPositionParams {
- text_document: f.tid(),
- position: Position { line: y as _, character: x as _ },
- },
- work_done_progress_params: default(),
- partial_result_params: default(),
- context: Some(c),
- })
- .unwrap();
- rx
- }
-
- pub fn request_sig_help<'me>(
- &'me self,
- f: &Path,
- (x, y): (usize, usize),
- ) -> impl Future<
- Output = Result<
- Option<SignatureHelp>,
- RequestError<SignatureHelpRequest>,
- >,
- > + use<'me> {
- self.request_::<SignatureHelpRequest, { Redraw }>(&SignatureHelpParams {
- context: None,
- text_document_position_params: TextDocumentPositionParams {
- text_document: f.tid(),
- position: Position { line: y as _, character: x as _ },
- },
- work_done_progress_params: default(),
- })
- .unwrap()
- .0
- }
-
- pub fn _pull_all_diag(
- &self,
- _f: PathBuf,
- ) -> impl Future<Output = anyhow::Result<()>> {
- let r = self
- .request::<lsp_request!("workspace/diagnostic")>(&default())
- .unwrap()
- .0;
- log::info!("pulling diagnostics");
- async move {
- let x = r.await?;
- log::info!("{x:?}");
- // match x {
- // DocumentDiagnosticReportResult::Report(DocumentDiagnosticReport::Full(RelatedFullDocumentDiagnosticReport {
- // related_documents,
- // full_document_diagnostic_report:FullDocumentDiagnosticReport { items,.. },
- // })) => {
- // let l = self.diagnostics.guard();
- // self.diagnostics.insert(f.tid().uri, items, &l);
- // for (uri, rel) in related_documents.into_iter().flatten() {
- // match rel {
- // DocumentDiagnosticReportKind::Full(FullDocumentDiagnosticReport { items, .. }) => {
- // self.diagnostics.insert(uri, items, &l);
- // },
- // DocumentDiagnosticReportKind::Unchanged(_) => {},
- // }
- // }
- // log::info!("pulled diagnostics");
- // },
- // _ => bail!("fuck that"),
- // };
- Ok(())
- }
- }
- pub fn _pull_diag(
- &self,
- f: PathBuf,
- previous: Option<String>,
- ) -> impl Future<Output = anyhow::Result<Option<String>>> {
- let p = DocumentDiagnosticParams {
- text_document: f.tid(),
- identifier: try {
- match self
- .initialized
- .as_ref()?
- .capabilities
- .diagnostic_provider
- .as_ref()?
- {
- DiagnosticServerCapabilities::RegistrationOptions(
- x,
- ) => x.diagnostic_options.identifier.clone()?,
- _ => None?,
- }
- },
- previous_result_id: previous,
- work_done_progress_params: default(),
- partial_result_params: default(),
- };
- let (r, _) = self
- .request::<lsp_request!("textDocument/diagnostic")>(&p)
- .unwrap();
- log::info!("pulling diagnostics");
-
- async move {
- let x = match r.await {
- Ok(x) => x,
- Err(RequestError::Cancelled(_, y)) if y.retrigger_request => {
- self.request::<lsp_request!("textDocument/diagnostic")>(&p,).unwrap().0.await?
- },
- Err(e) => return Err(e.into()),
- };
- // dbg!(&x);
- match x.clone() {
- DocumentDiagnosticReportResult::Report(
- DocumentDiagnosticReport::Full(
- RelatedFullDocumentDiagnosticReport {
- related_documents,
- full_document_diagnostic_report:
- FullDocumentDiagnosticReport {
- items,
- result_id,
- },
- },
- ),
- ) => {
- let l = self.diagnostics.guard();
- self.diagnostics.insert(f.tid().uri, items, &l);
- for (uri, rel) in
- related_documents.into_iter().flatten()
- {
- match rel {
- DocumentDiagnosticReportKind::Full(
- FullDocumentDiagnosticReport {
- items, ..
- },
- ) => {
- self.diagnostics.insert(uri, items, &l);
- }
- DocumentDiagnosticReportKind::Unchanged(_) => {
- }
- }
- }
- log::info!("pulled diagnostics");
- Ok(result_id)
- }
- _ => bail!("fuck that"),
- }
- }
- }
- pub fn document_highlights<'me>(
- &'me self,
- f: &Path,
- cursor: Position,
- ) -> impl Future<
- Output = Result<
- Vec<DocumentHighlight>,
- RequestError<DocumentHighlightRequest>,
- >,
- > + use<'me> {
- let p = DocumentHighlightParams {
- text_document_position_params: TextDocumentPositionParams {
- text_document: f.tid(),
- position: cursor,
- },
- work_done_progress_params: default(),
- partial_result_params: default(),
- };
- 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,
- p: &Path,
- ) -> impl Future<
- Output = Result<
- Option<DocumentSymbolResponse>,
- RequestError<lsp_request!("textDocument/documentSymbol")>,
- >,
- > {
- self.request_::<lsp_request!("textDocument/documentSymbol"), { Redraw }>(
- &DocumentSymbolParams {
- text_document: p.tid(),
- work_done_progress_params: default(),
- partial_result_params: default(),
- },
- )
- .unwrap()
- .0
- }
- pub fn workspace_symbols(
- &'static self,
- f: String,
- ) -> impl Future<
- Output = Result<
- Option<WorkspaceSymbolResponse>,
- RequestError<lsp_request!("workspace/symbol")>,
- >,
- > {
- self.request_::<lsp_request!("workspace/symbol"), {Redraw}>(
- &lsp_types::WorkspaceSymbolParams {
- query: f,
- search_scope: Some(
- lsp_types::WorkspaceSymbolSearchScope::Workspace,
- ),
- search_kind: Some(
- lsp_types::WorkspaceSymbolSearchKind::AllSymbols,
- ),
- ..Default::default()
- },
- )
- .unwrap()
- .0
- }
-
- pub fn matching_brace_at(
- &self,
- f: &Path,
- x: Vec<Position>,
- ) -> Result<
- Vec<Option<(Position, Position)>>,
- RequestError<MatchingBrace>,
- > {
- self.request_immediate::<MatchingBrace>(&MatchingBraceParams {
- text_document: f.tid(),
- positions: x,
- })
- }
-
- pub fn matching_brace<'a>(
- &'static 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.1).unwrap();
- }
- }
- }
- }
-
- pub fn legend(&self) -> Option<&SemanticTokensLegend> {
- match &self.initialized{Some(lsp_types::InitializeResult {capabilities: ServerCapabilities {semantic_tokens_provider:Some(SemanticTokensServerCapabilities::SemanticTokensOptions(SemanticTokensOptions{legend,..})),..}, ..})=> {Some(legend)},_ => None,}
- }
- pub fn inlay(
- &'static self,
- f: &Path,
- t: &TextArea,
- ) -> impl Future<
- Output = Result<
- Vec<InlayHint>,
- RequestError<lsp_request!("textDocument/inlayHint")>,
- >,
- > + use<> {
- self.request_::<lsp_request!("textDocument/inlayHint"), { Redraw }>(&InlayHintParams {
- work_done_progress_params: default(),
- text_document: f.tid(),
- range: t.to_l_range(lower::saturating::math!{
- t.rope.try_line_to_char(t.vo-t.r).unwrap_or(0)..t.rope.try_line_to_char(t.vo + t.r + t.r).unwrap_or(t.rope.len_chars())
- }).unwrap()
- }).unwrap().0.map(|x| x.map(Option::unwrap_or_default))
- // async {
- // if let Ok(z) = z.await {
- // let mut into = vec![];
- // for lem in z.into_iter(){
- // // if let Some(_) = lem.data {
- // into.push(self.request::<lsp_request!("inlayHint/resolve")>(&lem).unwrap().0.await.unwrap());
- // // }
- // }
- // // std::fs::write("inlay", serde_json::to_string_pretty(&into).unwrap()).unwrap();
- // Ok(into)
- // } else {
- // panic!()
- // }
- // }
- }
- pub fn format(
- &'static self,
- f: &Path,
- ) -> impl Future<
- Output = Result<Option<Vec<TextEdit>>, RequestError<Formatting>>,
- > {
- 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
- }
- pub fn rq_semantic_tokens(
- &'static self,
- to: &mut Rq<
- Box<[SemanticToken]>,
- Box<[SemanticToken]>,
- (),
- RequestError<SemanticTokensFullRequest>,
- >,
- f: &Path,
- ) -> anyhow::Result<()> {
- debug!("requested semantic tokens");
-
- let Some(b"rs") = f.extension().map(|x| x.as_encoded_bytes())
- else {
- return Ok(());
- };
- let (rx, _) = self.request_::<SemanticTokensFullRequest, {Redraw}>(
- &SemanticTokensParams {
- 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?.unwrap();
- 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)
- });
- to.request(x);
-
- Ok(())
- }
-
- pub fn enter<'a>(&self, f: &Path, t: &'a mut TextArea) {
- ceach!(t.cursor, |c| {
- let r = self.request_immediate::<OnEnter>(&TextDocumentPositionParams {
- text_document: f.tid(),
- position: t.to_l_position(*c).unwrap(),
- })
- .unwrap();
- match r {
- None => t.enter(),
- Some(mut r) => {
- r.sort_tedits();
- for f in r {
- t.apply_snippet_tedit(&f).unwrap();
- }
- }
- }
- });
- }
- pub fn runnables(
- &'static self,
- t: &Path,
- c: Option<Position>,
- ) -> Result<
- impl Future<Output = Result<Vec<Runnable>, RequestError<Runnables>>>
- + use<>,
- SendError<Message>,
- > {
- self.request::<Runnables>(&RunnablesParams {
- text_document: t.tid(),
- position: c,
- })
- .map(|(x, _)| x)
- }
-}
pub fn run(
(tx, rx): (Sender<Message>, Receiver<Message>),
workspace: WorkspaceFolder,
@@ -683,269 +46,7 @@ pub fn run(
req_rx: _req_rx,
not_rx,
};
- _ = c
- .request::<Initialize>(&InitializeParams {
- process_id: Some(std::process::id()),
-
- capabilities: ClientCapabilities {
- window: Some(WindowClientCapabilities {
- work_done_progress: Some(true),
- ..default()
- }),
- workspace: Some(WorkspaceClientCapabilities {
- symbol: Some(WorkspaceSymbolClientCapabilities {
- symbol_kind: Some(SymbolKindCapability { value_set: Some(SymbolKind::ALL.to_vec()) }),
- tag_support: Some(TagSupport { value_set: SymbolTag::ALL.to_vec() }),
- resolve_support: Some(WorkspaceSymbolResolveSupportCapability {
- properties: vec!["location".into()],
- }),
- ..default()
- }),
- diagnostic: Some(DiagnosticWorkspaceClientCapabilities { refresh_support: Some(true) }),
- inlay_hint: Some(InlayHintWorkspaceClientCapabilities { refresh_support: Some(true) }),
- workspace_edit: Some(
- WorkspaceEditClientCapabilities { document_changes: Some(true),
- resource_operations: Some(vec![ResourceOperationKind::Create, ResourceOperationKind::Rename, ResourceOperationKind::Delete]),
- failure_handling: Some(FailureHandlingKind::Abort), normalizes_line_endings: Some(false),
- change_annotation_support: Some(ChangeAnnotationWorkspaceEditClientCapabilities { groups_on_label: Some(false) }) },
- ),
- ..default()
- }),
- text_document: Some(TextDocumentClientCapabilities {
- on_type_formatting: Some(DocumentOnTypeFormattingClientCapabilities {
- dynamic_registration: Some(false),
- }),
- document_highlight: Some(default()),
- formatting: Some(DynamicRegistrationClientCapabilities { dynamic_registration: Some(false) }),
- inlay_hint: Some(InlayHintClientCapabilities { dynamic_registration: None, resolve_support: Some(InlayHintResolveClientCapabilities {
- properties: vec!["textEdits".into(), "tooltip".into(), "label.tooltip".into(), "label.command".into()], })
- }),
- document_symbol: Some(DocumentSymbolClientCapabilities {
- tag_support: Some(TagSupport { value_set: SymbolTag::ALL.to_vec() }),
- symbol_kind: Some(SymbolKindCapability { value_set: Some(SymbolKind::ALL.to_vec()) }),
- hierarchical_document_symbol_support: Some(true),
- ..default()
- }),
- definition: Some(GotoCapability { link_support: Some(true), ..default() }),
- code_action: Some(
- CodeActionClientCapabilities {
- data_support: Some(true),
- resolve_support: Some(CodeActionCapabilityResolveSupport { properties: vec!["edit".to_string()] }),
- code_action_literal_support: Some(CodeActionLiteralSupport { code_action_kind: CodeActionKindLiteralSupport { value_set: [
- "", "Empty", "QuickFix", "Refactor",
- "RefactorExtract", "RefactorInline", "RefactorRewrite", "Source",
- "SourceOrganizeImports", "quickfix", "refactor", "refactor.extract",
- "refactor.inline", "refactor.rewrite", "source", "source.organizeImports"
- ].map(String::from).into()} }),
- ..default()
- }
- ),
- rename: Some(RenameClientCapabilities { prepare_support: Some(true),
- prepare_support_default_behavior: Some(PrepareSupportDefaultBehavior::IDENTIFIER), honors_change_annotations: Some(false),
- ..default() }),
- hover: Some(HoverClientCapabilities {
- dynamic_registration: None,
- content_format: Some(vec![MarkupKind::PlainText, MarkupKind::Markdown]),
- }),
- diagnostic: Some(DiagnosticClientCapabilities { dynamic_registration: None, related_document_support: Some(true) }),
- publish_diagnostics: Some(PublishDiagnosticsClientCapabilities {
- related_information: Some(true),
- code_description_support: Some(true),
- data_support: Some(true),
- ..default()
- }),
- signature_help: Some(SignatureHelpClientCapabilities {
- dynamic_registration: None, signature_information: Some(SignatureInformationSettings {
- documentation_format: Some(vec![
- MarkupKind::Markdown,
- MarkupKind::PlainText,
- ]),
- parameter_information: Some(ParameterInformationSettings {
- label_offset_support: Some(true) }),
- active_parameter_support: Some(true),
- }), context_support: Some(false) }),
- completion: Some(CompletionClientCapabilities {
- dynamic_registration: Some(false),
- completion_item: Some(CompletionItemCapability {
- snippet_support: Some(true),
- commit_characters_support: Some(true),
- documentation_format: Some(vec![
- MarkupKind::Markdown,
- MarkupKind::PlainText,
- ]),
- deprecated_support: None,
- preselect_support: None,
- tag_support: Some(TagSupport {
- value_set: vec![CompletionItemTag::DEPRECATED],
- }),
-
- resolve_support: Some(CompletionItemCapabilityResolveSupport {
- properties: vec![
- "additionalTextEdits".into(),
- "documentation".into(),
- ],
- }),
- insert_replace_support: Some(false),
- insert_text_mode_support: Some(InsertTextModeSupport {
- value_set: vec![InsertTextMode::AS_IS],
- }),
- label_details_support: Some(true),
- ..default()
- }),
- completion_item_kind: Some(CompletionItemKindCapability {
- value_set: Some(vec![
- CompletionItemKind::TEXT,
- CompletionItemKind::METHOD,
- CompletionItemKind::FUNCTION,
- CompletionItemKind::CONSTRUCTOR,
- CompletionItemKind::FIELD,
- CompletionItemKind::VARIABLE,
- CompletionItemKind::CLASS,
- CompletionItemKind::INTERFACE,
- CompletionItemKind::MODULE,
- CompletionItemKind::PROPERTY,
- CompletionItemKind::UNIT,
- CompletionItemKind::VALUE,
- CompletionItemKind::ENUM,
- CompletionItemKind::KEYWORD,
- CompletionItemKind::SNIPPET,
- CompletionItemKind::COLOR,
- CompletionItemKind::FILE,
- CompletionItemKind::REFERENCE,
- CompletionItemKind::FOLDER,
- CompletionItemKind::ENUM_MEMBER,
- CompletionItemKind::CONSTANT,
- CompletionItemKind::STRUCT,
- CompletionItemKind::EVENT,
- CompletionItemKind::OPERATOR,
- CompletionItemKind::TYPE_PARAMETER,
- ]),
- // value_set: Some(vec![CompletionItemKind::]),
- }),
- context_support: None,
- insert_text_mode: Some(InsertTextMode::AS_IS),
- completion_list: Some(CompletionListCapability { item_defaults: None }),
- }),
- semantic_tokens: Some(SemanticTokensClientCapabilities {
- dynamic_registration: Some(false),
- requests: SemanticTokensClientCapabilitiesRequests {
- range: Some(true),
- full: Some(lsp_types::SemanticTokensFullOptions::Bool(true)),
- },
- token_modifiers: [
- "associated",
- "attribute",
- "callable",
- "constant",
- "consuming",
- "controlFlow",
- "crateRoot",
- "injected",
- "intraDocLink",
- "library",
- "macro",
- "mutable",
- "procMacro",
- "public",
- "reference",
- "trait",
- "unsafe",
- ]
- .map(|x| x.into())
- .to_vec(),
- overlapping_token_support: Some(true),
- multiline_token_support: Some(true),
- server_cancel_support: Some(false),
- augments_syntax_tokens: Some(false),
- ..default()
- }),
- ..default()
- }),
-
- general: Some(GeneralClientCapabilities {
- markdown: Some(MarkdownClientCapabilities {
- version: Some("1.0.0".into()),
- parser: "markdown".into(),
- allowed_tags: Some(vec![]),
- }),
- position_encodings: Some(vec![PositionEncodingKind::UTF8]),
- ..default()
- }),
- experimental: Some(json! {{
- "matchingBrace": true,
- "snippetTextEdit": true,
- "colorDiagnosticOutput": true,
- "codeActionGroup": true,
- "serverStatusNotification": true,
- "hoverActions": true,
- "workspaceSymbolScopeKindFiltering": true,
- "onEnter": true,
- "localDocs": true,
- }}),
- ..default()
- },
- client_info: Some(ClientInfo {
- name: "gracilaria".into(),
- version: Some(env!("CARGO_PKG_VERSION").into()),
- }),
- initialization_options: Some(json! {{
- "cargo": {
- "buildScripts": { "enable": true }
- },
- "procMacro": {
- "enable": true,
- "attributes": { "enable": true }
- },
- "hover": {
- "documentation": {
- "keywords": { "enable": false },
- },
- },
- "inlayHints": {
- "closureReturnTypeHints": { "enable": "with_block" },
- "closingBraceHints": { "minLines": 5 },
- "closureStyle": "rust_analyzer",
- "genericParameterHints": { "type": { "enable": true } },
- "rangeExclusiveHints": { "enable": true },
- "closureCaptureHints": { "enable": true },
- },
- "typing": { "triggerChars": ".=<>{(+" },
- "assist": { "preferSelf": true },
- "checkOnSave": true,
- "diagnostics": { "enable": true },
- "semanticHighlighting": {
- "punctuation": {
- "separate": {
- "macroBang": true
- },
- "specialization": { "enable": true },
- "enable": true
- }
- },
- "workspace": {
- "symbol": {
- "search": { "limit": 1024 }
- }
- },
- "showUnlinkedFileNotification": false,
- "completion": {
- "fullFunctionSignatures": { "enable": true, },
- "autoIter": { "enable": false, },
- "autoImport": { "enable": true, },
- "termSearch": { "enable": true, },
- "autoself": { "enable": true, },
- "privateEditable": { "enable": true },
- },
- "imports": {
- "granularity": "group",
- },
- }}),
- trace: None,
- workspace_folders: Some(vec![workspace]),
-
- ..default()
- })
- .unwrap();
+ _ = c.request::<Initialize>(&init_opts::get(workspace)).unwrap();
let x = serde_json::from_value::<InitializeResult>(
rx.recv().unwrap().response().unwrap().result.unwrap(),
)
@@ -966,104 +67,11 @@ pub fn run(
let progress = c.progress;
let d = c.diagnostics;
log::info!("lsp took {:?} to initialize", now.elapsed());
+
let h = spawn(move || {
- let mut map = HashMap::new();
- let w = window_rx.blocking_recv().unwrap();
- loop {
- crossbeam::select! {
- recv(req_rx) -> x => match x {
- Ok((x, y, and)) => {
- debug!("received request {x}");
- assert!(map.insert(x, (y, Instant::now(), and)).is_none());
- }
- Err(RecvError) => return,
- },
- recv(rx) -> x => match x {
- Ok(Message::Request(rq @ LRq { method: "window/workDoneProgress/create", .. })) => {
- match rq.load::<WorkDoneProgressCreate>() {
- Ok((_, x)) => {
- let g = progress.guard();
- progress.insert(x.token, None, &g);
- },
- Err(lsp_server::ExtractError::MethodMismatch(..)) => {},
- e => {
- error!("{e:?}");
- }
- };
- }
- Ok(Message::Request(x)) => {
- if let Err(e) = _req_tx.send(x) {
- let m = e.to_string();
- error!("couldnt receive request {m}: {:?}", e.into_inner());
- }
- }
- Ok(Message::Response(x)) => {
- if let Some(e) = &x.error {
- if e.code == ErrorCode::RequestCanceled as i32 {}
- else if e.code == ErrorCode::ServerCancelled as i32 {
- if let Some((s, _, t)) = map.remove(&x.id.i32()) {
- log::info!("request {} cancelled", x.id);
- _ = s.send(x);
- if t == Redraw { w.request_redraw() }
- }
- } else {
- if let Some((s, _, t)) = map.remove(&x.id.i32()) {
- _ = s.send(x.clone());
- if t == Redraw { w.request_redraw() }
- trace!("received error from lsp for response {x:?}");
- } else {
- error!("received error from lsp for response {x:?}");
- }
- }
- }
- else if let Some((s, took, t)) = map.remove(&x.id.i32()) {
- log::info!("request {} took {:?}", x.id, took.elapsed());
- match s.send(x) {
- Ok(()) => {}
- Err(e) => {
- error!(
- "unable to respond to {e:?}",
- );
- }
- }
- // w.request_redraw();
- if t == Redraw { w.request_redraw() }
- } else {
- error!("request {x:?} was dropped.")
- }
- }
- Ok(Message::Notification(rq @ N { method: "textDocument/publishDiagnostics", .. })) => {
- debug!("got diagnostics");
- match rq.load::<PublishDiagnostics>() {
- Ok(x) => {
- d.insert(x.uri, x.diagnostics, &d.guard());
- w.request_redraw();
- },
- e => error!("{e:?}"),
- }
- },
- Ok(Message::Notification(x @ N { method: "$/progress", .. })) => {
- let ProgressParams {token,value:ProgressParamsValue::WorkDone(x) } = x.load::<Progress>().unwrap();
- match x.clone() {
- WorkDoneProgress::Begin(y) => {
- progress.update(token, move |_| Some((x.clone(), y.clone())), &progress.guard());
- },
- WorkDoneProgress::Report(_) | WorkDoneProgress::End(_) => {
- progress.update(token, move |v| Some((x.clone(), v.clone().expect("evil lsp").1)), &progress.guard());
- }
- }
- w.request_redraw();
- }
- Ok(Message::Notification(notification)) => {
- debug!("rx {notification:?}");
- not_tx
- .send(notification)
- .expect("why library drop this??? no drop!!");
- }
- Err(RecvError) => return,
- }
- }
- }
+ communication::handler(
+ window_rx, progress, _req_tx, d, not_tx, rx, req_rx,
+ )
});
(c, h, window_tx)
}
@@ -1073,7 +81,6 @@ pub enum BehaviourAfter {
// Poll, ? how impl.
Nil,
}
-pub use BehaviourAfter::*;
// trait RecvEepy<T>: Sized {
// fn recv_eepy(self) -> Result<T, RecvError> {
// self.recv_sleepy(100)
@@ -1135,107 +142,3 @@ impl<T, U, F: FnMut(T) -> U, Fu: Future<Output = T>> Map_<T, U, F> for Fu {
Map(self, f)
}
}
-
-impl<R: Request> Debug for RequestError<R> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- std::fmt::Display::fmt(&self, f)
- }
-}
-
-fn none<T>() -> Option<T> {
- None
-}
-impl<T: Clone, R, D, E> Clone for Rq<T, R, D, E> {
- fn clone(&self) -> Self {
- Self { result: self.result.clone(), request: None }
- }
-}
-#[derive(serde_derive::Serialize, serde_derive::Deserialize)]
-pub struct Rq<T, R, D = (), E = RequestError<R>> {
- #[serde(skip_serializing_if = "Option::is_none", default = "none")]
- pub result: Option<T>,
- #[serde(skip, default = "none")]
- pub request: Option<(AbortOnDropHandle<Result<R, E>>, D)>,
-}
-impl<T: Debug, R, D: Debug, E> Debug for Rq<T, R, D, E> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct(&format!("Rq<{}>", std::any::type_name::<R>()))
- .field("result", &self.result)
- .field("request", &self.request)
- .finish()
- }
-}
-
-pub type RqS<T, R: Request, D = ()> = Rq<T, R::Result, D, RequestError<R>>;
-impl<T, R, D, E> Default for Rq<T, R, D, E> {
- fn default() -> Self {
- Self { result: None, request: None }
- }
-}
-impl<T, R, E> Rq<T, R, (), E> {
- pub fn new(f: task::JoinHandle<Result<R, E>>) -> Self {
- Self {
- request: Some((AbortOnDropHandle::new(f), ())),
- result: None,
- }
- }
- pub fn request(&mut self, f: task::JoinHandle<Result<R, E>>) {
- self.request = Some((AbortOnDropHandle::new(f), ()));
- }
-}
-impl<T, R, D, E> Rq<T, R, D, E> {
- pub fn running(&self) -> bool {
- matches!(
- self,
- Self { result: Some(_), .. } | Self { request: Some(_), .. },
- )
- }
- pub fn poll(
- &mut self,
- f: impl FnOnce(Result<R, E>, (D, Option<T>)) -> Option<T>,
- runtime: &tokio::runtime::Runtime,
- ) -> bool {
- if self.request.as_mut().is_some_and(|(x, _)| x.is_finished())
- && let Some((task, d)) = self.request.take()
- {
- let x = match runtime.block_on(task) {
- Ok(x) => x,
- Err(e) => {
- log::error!(
- "unexpected join error from request poll: {e}"
- );
- return false;
- }
- };
- self.result = f(x, (d, self.result.take()));
- true
- } else { false }
- }
-
- pub fn poll_r(
- &mut self,
- f: impl FnOnce(Result<R, E>, (D, Option<T>)) -> Option<T>,
- runtime: &tokio::runtime::Runtime,
- _w: Option<&Arc<dyn Window>>,
- ) -> bool {
- self.poll(
- |x, y| {
- f(x, y).inspect(|_| {
- // w.map(|x| x.request_redraw());
- })
- },
- runtime,
- )
- }
-}
-
-pub trait PathURI {
- fn tid(&self) -> TextDocumentIdentifier;
-}
-impl PathURI for Path {
- fn tid(&self) -> TextDocumentIdentifier {
- TextDocumentIdentifier {
- uri: Url::from_file_path(self).expect("ok"),
- }
- }
-}