diff --git a/Cargo.lock b/Cargo.lock index 0d665d86b0..b25bc6f815 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2243,6 +2243,17 @@ dependencies = [ "byteorder", ] +[[package]] +name = "gen-lsp-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4552cb20fa322e0ebc35c2bbbe3eed8ace907bbcedc92aace7a325c9064b80b" +dependencies = [ + "serde", + "serde_json", + "url", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -2781,7 +2792,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.58.0", + "windows-core 0.61.2", ] [[package]] @@ -3598,19 +3609,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" -[[package]] -name = "lsp-types" -version = "0.95.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "158c1911354ef73e8fe42da6b10c0484cb65c7f1007f28022e847706c1ab6984" -dependencies = [ - "bitflags 1.3.2", - "serde", - "serde_json", - "serde_repr", - "url", -] - [[package]] name = "mach" version = "0.3.2" @@ -5595,9 +5593,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.147" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6af14725505314343e673e9ecb7cd7e8a36aa9791eb936235a3567cc31447ae4" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", @@ -6036,9 +6034,9 @@ dependencies = [ "crossbeam-channel", "dapts", "futures", + "gen-lsp-types", "js-sys", "log", - "lsp-types", "parking_lot", "serde", "serde-wasm-bindgen", @@ -6163,9 +6161,9 @@ dependencies = [ name = "tests" version = "0.14.16" dependencies = [ + "gen-lsp-types", "insta", "insta-cmd", - "lsp-types", "serde", "serde_json", "sync-ls", @@ -6316,6 +6314,7 @@ dependencies = [ "dirs", "env_logger", "futures", + "gen-lsp-types", "http-body-util", "hyper", "hyper-tungstenite", @@ -6323,7 +6322,6 @@ dependencies = [ "itertools 0.13.0", "js-sys", "log", - "lsp-types", "open", "parking_lot", "paste", @@ -6378,11 +6376,11 @@ dependencies = [ "dashmap", "ecow", "ena", + "gen-lsp-types", "hashbrown 0.14.5", "insta", "itertools 0.13.0", "log", - "lsp-types", "parking_lot", "regex", "rpds", @@ -6443,13 +6441,13 @@ dependencies = [ "dirs", "env_logger", "futures", + "gen-lsp-types", "http-body-util", "hyper", "hyper-tungstenite", "hyper-util", "itertools 0.13.0", "log", - "lsp-types", "open", "parking_lot", "paste", @@ -6677,12 +6675,12 @@ dependencies = [ "dirs", "ecow", "ena", + "gen-lsp-types", "hayagriva", "hex", "indexmap 2.12.1", "itertools 0.13.0", "log", - "lsp-types", "parking_lot", "percent-encoding", "rayon", @@ -6745,11 +6743,11 @@ dependencies = [ "dashmap", "ecow", "fxhash", + "gen-lsp-types", "hex", "js-sys", "libc", "log", - "lsp-types", "parking_lot", "path-clean", "pathdiff", @@ -6888,10 +6886,10 @@ dependencies = [ "ecow", "flate2", "fontdb", + "gen-lsp-types", "hex", "js-sys", "log", - "lsp-types", "parking_lot", "rayon", "reqwest", @@ -7971,14 +7969,15 @@ dependencies = [ [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] @@ -8649,7 +8648,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -9675,9 +9674,9 @@ checksum = "40990edd51aae2c2b6907af74ffb635029d5788228222c4bb811e9351c0caad3" [[package]] name = "zmij" -version = "0.1.9" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0095ecd462946aa3927d9297b63ef82fb9a5316d7a37d134eeb36e58228615a" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "zune-core" diff --git a/Cargo.toml b/Cargo.toml index f152361360..051f78fca2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -187,7 +187,7 @@ typstyle-core = { version = "=0.14.0", default-features = false } # LSP crossbeam-channel = "0.5.15" dapts = "0.0.6" -lsp-types = { version = "=0.95.0", features = ["proposed"] } +lsp-types = { package = "gen-lsp-types", version = "0.5.0", features = ["url"] } # CLI clap = { version = "4.5", features = ["derive", "env", "unicode"] } diff --git a/crates/sync-lsp/src/server.rs b/crates/sync-lsp/src/server.rs index 9704ba156c..8a661cbf31 100644 --- a/crates/sync-lsp/src/server.rs +++ b/crates/sync-lsp/src/server.rs @@ -17,6 +17,7 @@ use std::sync::atomic::AtomicU32; use std::sync::{Arc, Weak}; use futures::future::MaybeDone; +use lsp_types::{LspNotificationMethod, LspRequestMethod}; use parking_lot::Mutex; use serde::Serialize; use serde_json::{Value as JsonValue, from_value}; @@ -614,8 +615,8 @@ type RawHandler = fn(srv: &mut S, args: T) -> ScheduleResult; type BoxPureHandler = Box LspResult<()>>; type BoxHandler = Box SchedulableResponse>; type ExecuteCmdMap = HashMap<&'static str, BoxHandler>>; -type RegularCmdMap = HashMap<&'static str, BoxHandler>; -type NotifyCmdMap = HashMap<&'static str, BoxPureHandler>; +type RegularCmdMap = HashMap>; +type NotifyCmdMap = HashMap>; type ResourceMap = HashMap>>; type MayInitBoxHandler = Box Fn(ServiceState<'a, A, S>, &LspClient, T) -> anyhow::Result<()>>; diff --git a/crates/sync-lsp/src/server/dap_srv.rs b/crates/sync-lsp/src/server/dap_srv.rs index fa33492481..776c1e0718 100644 --- a/crates/sync-lsp/src/server/dap_srv.rs +++ b/crates/sync-lsp/src/server/dap_srv.rs @@ -42,7 +42,8 @@ where mut self, handler: RawHandler, ) -> Self { - self.req_handlers.insert(R::COMMAND, Box::new(handler)); + self.req_handlers + .insert(R::COMMAND.into(), Box::new(handler)); self } @@ -54,7 +55,7 @@ where handler: fn(&mut Args::S, R::Arguments) -> ScheduleResult, ) -> Self { self.req_handlers.insert( - R::COMMAND, + R::COMMAND.into(), Box::new(move |s, req| handler(s, from_json(req)?)), ); self @@ -66,7 +67,7 @@ where handler: AsyncHandler, ) -> Self { self.req_handlers.insert( - R::COMMAND, + R::COMMAND.into(), Box::new(move |s, req| erased_response(handler(s, from_json(req)?))), ); self @@ -222,7 +223,7 @@ where let is_disconnect = method == dapts::request::Disconnect::COMMAND; - let Some(handler) = self.requests.get(method) else { + let Some(handler) = self.requests.get(&method.to_owned().into()) else { log::warn!("unhandled dap request: {method}"); break 'serve_req just_result(Err(method_not_found())); }; @@ -251,7 +252,7 @@ where event, body, }: dap::Event| { - let Some(handler) = self.notifications.get(event.as_str()) else { + let Some(handler) = self.notifications.get(&event.clone().into()) else { log::warn!("unhandled event: {event}"); return Ok(()); }; diff --git a/crates/sync-lsp/src/server/lsp_srv.rs b/crates/sync-lsp/src/server/lsp_srv.rs index 63e621ab4a..0b93f7cb39 100644 --- a/crates/sync-lsp/src/server/lsp_srv.rs +++ b/crates/sync-lsp/src/server/lsp_srv.rs @@ -1,4 +1,4 @@ -use lsp_types::{notification::Notification as Notif, request::Request as Req, *}; +use lsp_types::{Notification as Notif, Request as Req, *}; use super::*; @@ -27,7 +27,7 @@ impl LspClient { ) { let mut req_queue = self.req_queue.lock(); let request = req_queue.outgoing.register( - R::METHOD.to_owned(), + R::METHOD.to_string(), params, Box::new(|s, resp| handler(s, resp.try_into().unwrap())), ); @@ -42,7 +42,7 @@ impl LspClient { /// Sends a typed notification to the client. pub fn send_notification(&self, params: &N::Params) { - self.send_notification_(lsp::Notification::new(N::METHOD.to_owned(), params)); + self.send_notification_(lsp::Notification::new(N::METHOD.to_string(), params)); } /// Sends an untyped notification to the client. @@ -199,7 +199,7 @@ where // } while let Ok(msg) = inbox.recv() { - const EXIT_METHOD: &str = notification::Exit::METHOD; + const EXIT_METHOD: LspNotificationMethod = ExitNotification::METHOD; let loop_start = tinymist_std::time::now(); match msg { Evt(event) => { @@ -228,7 +228,7 @@ where self.client.handle.spawn(fut); } Msg(LspMessage::Notification(not)) => { - let is_exit = not.method == EXIT_METHOD; + let is_exit = not.method == EXIT_METHOD.as_str(); let track_id = self .next_not_id .fetch_add(1, std::sync::atomic::Ordering::Relaxed); @@ -294,8 +294,8 @@ where /// Registers and handles a request. This should only be called once per /// incoming request. pub fn on_lsp_request(&mut self, method: &str, params: JsonValue) -> ScheduleResult { - match (&mut self.state, method) { - (State::Uninitialized(args), request::Initialize::METHOD) => { + match (&mut self.state, LspRequestMethod::from(method.to_owned())) { + (State::Uninitialized(args), InitializeRequest::METHOD) => { // todo: what will happen if the request cannot be deserialized? let params = serde_json::from_value::(params); match params { @@ -311,15 +311,15 @@ where (State::Uninitialized(..) | State::Initializing(..), _) => { just_result(Err(not_initialized())) } - (_, request::Initialize::METHOD) => { + (_, InitializeRequest::METHOD) => { just_result(Err(invalid_request("server is already initialized"))) } // todo: generalize this - (State::Ready(..), request::ExecuteCommand::METHOD) => self.on_execute_command(params), + (State::Ready(..), ExecuteCommandRequest::METHOD) => self.on_execute_command(params), (State::Ready(s), method) => 'serve_req: { - let is_shutdown = method == request::Shutdown::METHOD; + let is_shutdown = method == ShutdownRequest::METHOD; - let Some(handler) = self.requests.get(method) else { + let Some(handler) = self.requests.get(&method) else { log::warn!("unhandled lsp request: {method}"); break 'serve_req just_result(Err(method_not_found())); }; @@ -351,20 +351,20 @@ where // todo: generalize this if command == "tinymist.getResources" { - self.get_resources(arguments) + self.get_resources(arguments.unwrap_or_default()) } else { let Some(handler) = self.commands.get(command.as_str()) else { log::error!("asked to execute unknown command: {command}"); return Err(method_not_found()); }; - handler(s, arguments) + handler(s, arguments.unwrap_or_default()) } } /// Handles an incoming notification. pub fn on_notification(&mut self, method: &str, params: JsonValue) -> LspResult<()> { let handle = |s, method: &str, params: JsonValue| { - let Some(handler) = self.notifications.get(method) else { + let Some(handler) = self.notifications.get(&method.to_owned().into()) else { log::warn!("unhandled notification: {method}"); return Ok(()); }; @@ -372,8 +372,11 @@ where handler(s, params) }; - match (&mut self.state, method) { - (state, notification::Initialized::METHOD) => { + match ( + &mut self.state, + LspNotificationMethod::from(method.to_owned()), + ) { + (state, InitializedNotification::METHOD) => { let mut s = State::ShuttingDown; std::mem::swap(state, &mut s); match s { @@ -394,7 +397,7 @@ where }; handle(s, method, params) } - (State::Ready(state), method) => handle(state, method, params), + (State::Ready(state), method) => handle(state, method.as_str(), params), // todo: whether it is safe to ignore notifications (State::Uninitialized(..) | State::Initializing(..), method) => { log::warn!("server is not ready yet, while received notification {method}"); diff --git a/crates/tinymist-query/src/analysis.rs b/crates/tinymist-query/src/analysis.rs index d9cdbb274c..3e46577131 100644 --- a/crates/tinymist-query/src/analysis.rs +++ b/crates/tinymist-query/src/analysis.rs @@ -35,7 +35,7 @@ pub(crate) use tyck::*; use std::sync::Arc; use ecow::eco_format; -use lsp_types::Url; +use lsp_types::Uri as Url; use tinymist_project::LspComputeGraph; use tinymist_std::error::WithContextUntyped; use tinymist_std::{Result, bail}; diff --git a/crates/tinymist-query/src/analysis/code_action.rs b/crates/tinymist-query/src/analysis/code_action.rs index 34841cd9a0..71614e8557 100644 --- a/crates/tinymist-query/src/analysis/code_action.rs +++ b/crates/tinymist-query/src/analysis/code_action.rs @@ -66,7 +66,7 @@ impl<'a> CodeActionWorker<'a> { && !only.is_empty() && !only .iter() - .any(|kind| *kind == CodeActionKind::EMPTY || *kind == CodeActionKind::QUICKFIX) + .any(|kind| *kind == CodeActionKind::Empty || *kind == CodeActionKind::QuickFix) { return None; } @@ -198,7 +198,7 @@ impl<'a> CodeActionWorker<'a> { let edit = self.local_edit(EcoSnippetTextEdit::new(range, new_text))?; let action = CodeAction { title: "Create missing variable".to_string(), - kind: Some(CodeActionKind::QUICKFIX), + kind: Some(CodeActionKind::QuickFix), edit: Some(edit), ..CodeAction::default() }; @@ -227,7 +227,7 @@ impl<'a> CodeActionWorker<'a> { let edit = self.local_edit(EcoSnippetTextEdit::new(range, new_text))?; let action = CodeAction { title: "Add spaces between letters".to_string(), - kind: Some(CodeActionKind::QUICKFIX), + kind: Some(CodeActionKind::QuickFix), edit: Some(edit), ..CodeAction::default() }; @@ -264,7 +264,7 @@ impl<'a> CodeActionWorker<'a> { let file_to_create = unix_slash(path_in_workspace.as_rooted_path()); let action = CodeAction { title: format!("Create missing file at `{file_to_create}`"), - kind: Some(CodeActionKind::QUICKFIX), + kind: Some(CodeActionKind::QuickFix), edit: Some(edit), ..CodeAction::default() }; @@ -354,7 +354,7 @@ impl<'a> CodeActionWorker<'a> { let edit = self.edit_str(node, unix_slash(&new_path))?; let action = CodeAction { title: "Convert to relative path".to_string(), - kind: Some(CodeActionKind::REFACTOR_REWRITE), + kind: Some(CodeActionKind::RefactorRewrite), edit: Some(edit), ..CodeAction::default() }; @@ -376,7 +376,7 @@ impl<'a> CodeActionWorker<'a> { let edit = self.edit_str(node, unix_slash(&new_path))?; let action = CodeAction { title: "Convert to absolute path".to_string(), - kind: Some(CodeActionKind::REFACTOR_REWRITE), + kind: Some(CodeActionKind::RefactorRewrite), edit: Some(edit), ..CodeAction::default() }; @@ -423,7 +423,7 @@ impl<'a> CodeActionWorker<'a> { let action = CodeAction { title: "Wrap with content block".to_string(), - kind: Some(CodeActionKind::REFACTOR_REWRITE), + kind: Some(CodeActionKind::RefactorRewrite), edit: Some(edit), ..CodeAction::default() }; @@ -446,7 +446,7 @@ impl<'a> CodeActionWorker<'a> { // Decrease depth of heading let action = CodeAction { title: "Decrease depth of heading".to_string(), - kind: Some(CodeActionKind::REFACTOR_REWRITE), + kind: Some(CodeActionKind::RefactorRewrite), edit: Some(self.local_edit(EcoSnippetTextEdit::new_plain( self.ctx.to_lsp_range(marker_range.clone(), &self.source), EcoString::inline("=").repeat(depth - 1), @@ -459,7 +459,7 @@ impl<'a> CodeActionWorker<'a> { // Increase depth of heading let action = CodeAction { title: "Increase depth of heading".to_string(), - kind: Some(CodeActionKind::REFACTOR_REWRITE), + kind: Some(CodeActionKind::RefactorRewrite), edit: Some(self.local_edit(EcoSnippetTextEdit::new_plain( self.ctx.to_lsp_range(marker_range, &self.source), EcoString::inline("=").repeat(depth + 1), @@ -551,7 +551,7 @@ impl<'a> CodeActionWorker<'a> { Some(CodeAction { title: title.to_owned(), - kind: Some(CodeActionKind::REFACTOR_REWRITE), + kind: Some(CodeActionKind::RefactorRewrite), edit: Some(self.local_edits(edits)?), ..CodeAction::default() }) @@ -576,14 +576,14 @@ impl<'a> CodeActionWorker<'a> { fn create_file(&self, uri: Url, needs_confirmation: bool) -> EcoWorkspaceEdit { let change_id = "Typst Create Missing Files".to_string(); - let create_op = EcoDocumentChangeOperation::Op(lsp_types::ResourceOp::Create(CreateFile { + let create_op = EcoDocumentChangeOperation::CreateFile(CreateFile { uri, options: Some(CreateFileOptions { overwrite: Some(false), ignore_if_exists: None, }), annotation_id: Some(change_id.clone()), - })); + }); let mut change_annotations = HashMap::new(); change_annotations.insert( diff --git a/crates/tinymist-query/src/analysis/completion.rs b/crates/tinymist-query/src/analysis/completion.rs index b28f7e0da6..2082c123ca 100644 --- a/crates/tinymist-query/src/analysis/completion.rs +++ b/crates/tinymist-query/src/analysis/completion.rs @@ -378,7 +378,7 @@ impl<'a> CompletionCursor<'a> { label_details: item.label_details.clone().map(From::from), text_edit: Some(text_edit), additional_text_edits: item.additional_text_edits.clone(), - insert_text_format: Some(InsertTextFormat::SNIPPET), + insert_text_format: Some(InsertTextFormat::Snippet), command: item.command.clone(), ..Default::default() } diff --git a/crates/tinymist-query/src/analysis/completion/path.rs b/crates/tinymist-query/src/analysis/completion/path.rs index f42429410b..6d00e2bafe 100644 --- a/crates/tinymist-query/src/analysis/completion/path.rs +++ b/crates/tinymist-query/src/analysis/completion/path.rs @@ -143,7 +143,7 @@ impl CompletionPair<'_, '_, '_> { // don't sort me sort_text: Some(sort_text), filter_text: Some("".into()), - insert_text_format: Some(InsertTextFormat::PLAIN_TEXT), + insert_text_format: Some(InsertTextFormat::PlainText), ..Default::default() } }) diff --git a/crates/tinymist-query/src/analysis/global.rs b/crates/tinymist-query/src/analysis/global.rs index 11b9822c8a..7f5c310639 100644 --- a/crates/tinymist-query/src/analysis/global.rs +++ b/crates/tinymist-query/src/analysis/global.rs @@ -5,7 +5,7 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::{collections::HashSet, ops::Deref}; use comemo::{Track, Tracked}; -use lsp_types::Url; +use lsp_types::Uri as Url; use parking_lot::Mutex; use rustc_hash::FxHashMap; use tinymist_analysis::docs::DocString; diff --git a/crates/tinymist-query/src/analysis/link_expr.rs b/crates/tinymist-query/src/analysis/link_expr.rs index 930b36ba06..8f0cf2ed75 100644 --- a/crates/tinymist-query/src/analysis/link_expr.rs +++ b/crates/tinymist-query/src/analysis/link_expr.rs @@ -2,7 +2,7 @@ use std::str::FromStr; -use lsp_types::Url; +use lsp_types::Uri as Url; use tinymist_world::package::PackageSpec; use super::prelude::*; diff --git a/crates/tinymist-query/src/analysis/semantic_tokens.rs b/crates/tinymist-query/src/analysis/semantic_tokens.rs index 0e37a6c3fe..02e1460669 100644 --- a/crates/tinymist-query/src/analysis/semantic_tokens.rs +++ b/crates/tinymist-query/src/analysis/semantic_tokens.rs @@ -9,7 +9,7 @@ use std::{ }; use lsp_types::SemanticToken; -use lsp_types::{SemanticTokenModifier, SemanticTokenType}; +use lsp_types::{SemanticTokenModifiers, SemanticTokenTypes}; use parking_lot::Mutex; use strum::EnumIter; use tinymist_std::ImmutPath; @@ -115,20 +115,20 @@ impl Drop for SemanticTokenContext { } } -const BOOL: SemanticTokenType = SemanticTokenType::new("bool"); -const PUNCTUATION: SemanticTokenType = SemanticTokenType::new("punct"); -const ESCAPE: SemanticTokenType = SemanticTokenType::new("escape"); -const LINK: SemanticTokenType = SemanticTokenType::new("link"); -const RAW: SemanticTokenType = SemanticTokenType::new("raw"); -const LABEL: SemanticTokenType = SemanticTokenType::new("label"); -const REF: SemanticTokenType = SemanticTokenType::new("ref"); -const HEADING: SemanticTokenType = SemanticTokenType::new("heading"); -const LIST_MARKER: SemanticTokenType = SemanticTokenType::new("marker"); -const LIST_TERM: SemanticTokenType = SemanticTokenType::new("term"); -const DELIMITER: SemanticTokenType = SemanticTokenType::new("delim"); -const INTERPOLATED: SemanticTokenType = SemanticTokenType::new("pol"); -const ERROR: SemanticTokenType = SemanticTokenType::new("error"); -const TEXT: SemanticTokenType = SemanticTokenType::new("text"); +const BOOL: SemanticTokenTypes = SemanticTokenTypes::new("bool"); +const PUNCTUATION: SemanticTokenTypes = SemanticTokenTypes::new("punct"); +const ESCAPE: SemanticTokenTypes = SemanticTokenTypes::new("escape"); +const LINK: SemanticTokenTypes = SemanticTokenTypes::new("link"); +const RAW: SemanticTokenTypes = SemanticTokenTypes::new("raw"); +const LABEL: SemanticTokenTypes = SemanticTokenTypes::new("label"); +const REF: SemanticTokenTypes = SemanticTokenTypes::new("ref"); +const HEADING: SemanticTokenTypes = SemanticTokenTypes::new("heading"); +const LIST_MARKER: SemanticTokenTypes = SemanticTokenTypes::new("marker"); +const LIST_TERM: SemanticTokenTypes = SemanticTokenTypes::new("term"); +const DELIMITER: SemanticTokenTypes = SemanticTokenTypes::new("delim"); +const INTERPOLATED: SemanticTokenTypes = SemanticTokenTypes::new("pol"); +const ERROR: SemanticTokenTypes = SemanticTokenTypes::new("error"); +const TEXT: SemanticTokenTypes = SemanticTokenTypes::new("text"); /// Very similar to `typst_ide::Tag`, but with convenience traits, and /// extensible because we want to further customize highlighting @@ -193,20 +193,20 @@ pub enum TokenType { None, } -impl From for SemanticTokenType { +impl From for SemanticTokenTypes { fn from(token_type: TokenType) -> Self { use TokenType::*; match token_type { - Comment => Self::COMMENT, - String => Self::STRING, - Keyword => Self::KEYWORD, - Operator => Self::OPERATOR, - Number => Self::NUMBER, - Function => Self::FUNCTION, - Decorator => Self::DECORATOR, - Type => Self::TYPE, - Namespace => Self::NAMESPACE, + Comment => Self::Comment, + String => Self::String, + Keyword => Self::Keyword, + Operator => Self::Operator, + Number => Self::Number, + Function => Self::Function, + Decorator => Self::Decorator, + Type => Self::Type, + Namespace => Self::Namespace, Bool => BOOL, Punctuation => PUNCTUATION, Escape => ESCAPE, @@ -226,9 +226,9 @@ impl From for SemanticTokenType { } } -const STRONG: SemanticTokenModifier = SemanticTokenModifier::new("strong"); -const EMPH: SemanticTokenModifier = SemanticTokenModifier::new("emph"); -const MATH: SemanticTokenModifier = SemanticTokenModifier::new("math"); +const STRONG: SemanticTokenModifiers = SemanticTokenModifiers::new("strong"); +const EMPH: SemanticTokenModifiers = SemanticTokenModifiers::new("emph"); +const MATH: SemanticTokenModifiers = SemanticTokenModifiers::new("math"); /// A modifier to some semantic token. #[derive(Clone, Copy, EnumIter)] @@ -260,7 +260,7 @@ impl Modifier { } } -impl From for SemanticTokenModifier { +impl From for SemanticTokenModifiers { fn from(modifier: Modifier) -> Self { use Modifier::*; @@ -268,9 +268,9 @@ impl From for SemanticTokenModifier { Strong => STRONG, Emph => EMPH, Math => MATH, - ReadOnly => Self::READONLY, - Static => Self::STATIC, - DefaultLibrary => Self::DEFAULT_LIBRARY, + ReadOnly => Self::Readonly, + Static => Self::Static, + DefaultLibrary => Self::DefaultLibrary, } } } diff --git a/crates/tinymist-query/src/code_action/proto.rs b/crates/tinymist-query/src/code_action/proto.rs index f37f51966a..e7197b3b49 100644 --- a/crates/tinymist-query/src/code_action/proto.rs +++ b/crates/tinymist-query/src/code_action/proto.rs @@ -3,7 +3,8 @@ use std::collections::HashMap; use ecow::EcoString; use lsp_types::{ ChangeAnnotation, ChangeAnnotationIdentifier, CodeActionDisabled, CodeActionKind, Command, - Diagnostic, InsertTextFormat, OneOf, OptionalVersionedTextDocumentIdentifier, ResourceOp, Url, + CreateFile, DeleteFile, Diagnostic, InsertTextFormat, OptionalVersionedTextDocumentIdentifier, + RenameFile, Uri as Url, }; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -27,7 +28,7 @@ impl EcoSnippetTextEdit { pub fn new_plain(range: LspRange, new_text: EcoString) -> EcoSnippetTextEdit { EcoSnippetTextEdit { edit: EcoTextEdit::new(range, new_text), - insert_text_format: Some(InsertTextFormat::PLAIN_TEXT), + insert_text_format: Some(InsertTextFormat::PlainText), } } @@ -35,7 +36,7 @@ impl EcoSnippetTextEdit { pub fn new(range: LspRange, new_text: EcoString) -> EcoSnippetTextEdit { EcoSnippetTextEdit { edit: EcoTextEdit::new(range, new_text), - insert_text_format: Some(InsertTextFormat::SNIPPET), + insert_text_format: Some(InsertTextFormat::Snippet), } } } @@ -54,6 +55,15 @@ pub struct EcoAnnotatedTextEdit { pub annotation_id: ChangeAnnotationIdentifier, } +/// A value that can be one of two types. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum OneOf { + #[allow(missing_docs)] + Left(T), + #[allow(missing_docs)] + Right(U), +} + /// Describes textual changes on a single text document. The text document is /// referred to as a `OptionalVersionedTextDocumentIdentifier` to allow clients /// to check the text document version before an edit is applied. A @@ -201,8 +211,12 @@ pub enum EcoDocumentChanges { #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] #[serde(untagged, rename_all = "lowercase")] pub enum EcoDocumentChangeOperation { - /// A resource operation. - Op(ResourceOp), + /// Create file operation. + CreateFile(CreateFile), + /// Rename file operation. + RenameFile(RenameFile), + /// Delete file operation. + DeleteFile(DeleteFile), /// A text document edit. Edit(EcoTextDocumentEdit), } @@ -211,7 +225,7 @@ mod url_map { use std::marker::PhantomData; use std::{collections::HashMap, fmt}; - use lsp_types::Url; + use lsp_types::Uri as Url; use serde::de; pub fn deserialize<'de, D, V>(deserializer: D) -> Result>, D::Error> diff --git a/crates/tinymist-query/src/code_lens.rs b/crates/tinymist-query/src/code_lens.rs index ee600e585f..e2299764fb 100644 --- a/crates/tinymist-query/src/code_lens.rs +++ b/crates/tinymist-query/src/code_lens.rs @@ -31,6 +31,7 @@ impl SemanticRequest for CodeLensRequest { title: title.to_string(), command: "tinymist.runCodeLens".to_string(), arguments: Some(args), + tooltip: None, }), data: None, }) @@ -87,6 +88,7 @@ impl SemanticRequest for CodeLensRequest { } .to_string(), arguments: Some(vec![uri]), + tooltip: None, }), data: None, }) diff --git a/crates/tinymist-query/src/completion/proto.rs b/crates/tinymist-query/src/completion/proto.rs index d37bfd921c..4e7185b0f2 100644 --- a/crates/tinymist-query/src/completion/proto.rs +++ b/crates/tinymist-query/src/completion/proto.rs @@ -39,18 +39,18 @@ pub enum CompletionKind { impl From<&CompletionKind> for lsp_types::CompletionItemKind { fn from(value: &CompletionKind) -> Self { match value { - CompletionKind::Syntax => Self::SNIPPET, - CompletionKind::Func => Self::FUNCTION, - CompletionKind::Param => Self::VARIABLE, - CompletionKind::Field => Self::FIELD, - CompletionKind::Variable => Self::VARIABLE, - CompletionKind::Constant => Self::CONSTANT, - CompletionKind::Reference => Self::REFERENCE, - CompletionKind::Symbol(_) => Self::FIELD, - CompletionKind::Type => Self::CLASS, - CompletionKind::Module => Self::MODULE, - CompletionKind::File => Self::FILE, - CompletionKind::Folder => Self::FOLDER, + CompletionKind::Syntax => Self::Snippet, + CompletionKind::Func => Self::Function, + CompletionKind::Param => Self::Variable, + CompletionKind::Field => Self::Field, + CompletionKind::Variable => Self::Variable, + CompletionKind::Constant => Self::Constant, + CompletionKind::Reference => Self::Reference, + CompletionKind::Symbol(_) => Self::Field, + CompletionKind::Type => Self::Class, + CompletionKind::Module => Self::Module, + CompletionKind::File => Self::File, + CompletionKind::Folder => Self::Folder, } } } @@ -71,16 +71,16 @@ impl<'de> serde::Deserialize<'de> for CompletionKind { { let kind = lsp_types::CompletionItemKind::deserialize(deserializer)?; Ok(match kind { - lsp_types::CompletionItemKind::SNIPPET => CompletionKind::Syntax, - lsp_types::CompletionItemKind::FUNCTION => CompletionKind::Func, - lsp_types::CompletionItemKind::VARIABLE => CompletionKind::Param, - lsp_types::CompletionItemKind::FIELD => CompletionKind::Field, - lsp_types::CompletionItemKind::CONSTANT => CompletionKind::Constant, - lsp_types::CompletionItemKind::REFERENCE => CompletionKind::Reference, - lsp_types::CompletionItemKind::CLASS => CompletionKind::Type, - lsp_types::CompletionItemKind::MODULE => CompletionKind::Module, - lsp_types::CompletionItemKind::FILE => CompletionKind::File, - lsp_types::CompletionItemKind::FOLDER => CompletionKind::Folder, + lsp_types::CompletionItemKind::Snippet => CompletionKind::Syntax, + lsp_types::CompletionItemKind::Function => CompletionKind::Func, + lsp_types::CompletionItemKind::Variable => CompletionKind::Param, + lsp_types::CompletionItemKind::Field => CompletionKind::Field, + lsp_types::CompletionItemKind::Constant => CompletionKind::Constant, + lsp_types::CompletionItemKind::Reference => CompletionKind::Reference, + lsp_types::CompletionItemKind::Class => CompletionKind::Type, + lsp_types::CompletionItemKind::Module => CompletionKind::Module, + lsp_types::CompletionItemKind::File => CompletionKind::File, + lsp_types::CompletionItemKind::Folder => CompletionKind::Folder, _ => CompletionKind::Variable, }) } diff --git a/crates/tinymist-query/src/diagnostics.rs b/crates/tinymist-query/src/diagnostics.rs index 5e3180383c..95619c93a8 100644 --- a/crates/tinymist-query/src/diagnostics.rs +++ b/crates/tinymist-query/src/diagnostics.rs @@ -190,8 +190,8 @@ impl<'w> DiagWorker<'w> { fn diagnostic_severity(typst_severity: TypstSeverity) -> DiagnosticSeverity { match typst_severity { - TypstSeverity::Error => DiagnosticSeverity::ERROR, - TypstSeverity::Warning => DiagnosticSeverity::WARNING, + TypstSeverity::Error => DiagnosticSeverity::Error, + TypstSeverity::Warning => DiagnosticSeverity::Warning, } } diff --git a/crates/tinymist-query/src/document_symbol.rs b/crates/tinymist-query/src/document_symbol.rs index 57f008c486..bef59c20de 100644 --- a/crates/tinymist-query/src/document_symbol.rs +++ b/crates/tinymist-query/src/document_symbol.rs @@ -32,7 +32,7 @@ impl SyntaxRequest for DocumentSymbolRequest { ) -> Option { let hierarchy = get_lexical_hierarchy(source, LexicalScopeKind::Symbol)?; let symbols = symbols_in_hierarchy(&hierarchy, source, position_encoding); - Some(DocumentSymbolResponse::Nested(symbols)) + Some(symbols.into()) } } diff --git a/crates/tinymist-query/src/goto_declaration.rs b/crates/tinymist-query/src/goto_declaration.rs index 7e7d08f1f8..fe5b656f7a 100644 --- a/crates/tinymist-query/src/goto_declaration.rs +++ b/crates/tinymist-query/src/goto_declaration.rs @@ -28,7 +28,7 @@ pub struct GotoDeclarationRequest { } impl SemanticRequest for GotoDeclarationRequest { - type Response = GotoDeclarationResponse; + type Response = DeclarationResponse; fn request(self, _ctx: &mut LocalContext) -> Option { let _ = find_declarations; diff --git a/crates/tinymist-query/src/goto_definition.rs b/crates/tinymist-query/src/goto_definition.rs index cba7a62a42..25e78aec85 100644 --- a/crates/tinymist-query/src/goto_definition.rs +++ b/crates/tinymist-query/src/goto_definition.rs @@ -24,7 +24,7 @@ pub struct GotoDefinitionRequest { } impl SemanticRequest for GotoDefinitionRequest { - type Response = GotoDefinitionResponse; + type Response = DefinitionResponse; fn request(self, ctx: &mut LocalContext) -> Option { let source = ctx.source_by_path(&self.path).ok()?; @@ -37,7 +37,7 @@ impl SemanticRequest for GotoDefinitionRequest { let name_range = def.name_range(ctx.shared()).unwrap_or_default(); let full_range = def.full_range().unwrap_or_else(|| name_range.clone()); - let res = Some(GotoDefinitionResponse::Link(vec![LocationLink { + let res = Some(DefinitionResponse::DefinitionLinkList(vec![LocationLink { origin_selection_range: Some(origin_selection_range), target_uri: ctx.uri_for_id(fid).ok()?, target_range: ctx.to_lsp_range_(full_range, fid)?, diff --git a/crates/tinymist-query/src/hover.rs b/crates/tinymist-query/src/hover.rs index 09ad9e3b53..9d68b044af 100644 --- a/crates/tinymist-query/src/hover.rs +++ b/crates/tinymist-query/src/hover.rs @@ -73,7 +73,7 @@ impl SemanticRequest for HoverRequest { Some(Hover { // Neovim shows ugly hover if the hover content is in array, so we join them // manually with divider bars. - contents: HoverContents::Scalar(MarkedString::String(contents.join("\n\n---\n\n"))), + contents: Contents::MarkedString(MarkedString::String(contents.join("\n\n---\n\n"))), range: Some(range), }) } @@ -641,22 +641,25 @@ mod tests { // write contents match contents { - HoverContents::Markup(content) => { + Contents::MarkupContent(content) => { writeln!(f, "{}", content.value)?; } - HoverContents::Scalar(MarkedString::String(content)) => { + Contents::MarkedString(MarkedString::String(content)) => { writeln!(f, "{content}")?; } - HoverContents::Scalar(MarkedString::LanguageString(lang_str)) => { + Contents::MarkedString(MarkedString::MarkedStringWithLanguage(lang_str)) => + { + #[allow(deprecated)] writeln!(f, "=== {} ===\n{}", lang_str.language, lang_str.value)? } - HoverContents::Array(contents) => { + Contents::MarkedStringList(contents) => { // interperse the contents with a divider let content = contents .iter() .map(|content| match content { MarkedString::String(text) => text.to_string(), - MarkedString::LanguageString(lang_str) => { + #[allow(deprecated)] + MarkedString::MarkedStringWithLanguage(lang_str) => { format!("=== {} ===\n{}", lang_str.language, lang_str.value) } }) diff --git a/crates/tinymist-query/src/index/mod.rs b/crates/tinymist-query/src/index/mod.rs index 0efe292fa3..e6469420c9 100644 --- a/crates/tinymist-query/src/index/mod.rs +++ b/crates/tinymist-query/src/index/mod.rs @@ -13,7 +13,7 @@ use crate::index::protocol::ResultSet; use crate::prelude::Definition; use crate::{LocalContext, path_to_url}; use ecow::EcoString; -use lsp_types::Url; +use lsp_types::Uri as Url; use tinymist_analysis::syntax::classify_syntax; use tinymist_std::error::WithContextUntyped; use tinymist_std::hash::FxHashMap; diff --git a/crates/tinymist-query/src/index/protocol.rs b/crates/tinymist-query/src/index/protocol.rs index 88a21f3240..a74dcdc4c3 100644 --- a/crates/tinymist-query/src/index/protocol.rs +++ b/crates/tinymist-query/src/index/protocol.rs @@ -9,7 +9,7 @@ // todo: large_enum_variant use ecow::EcoString; -use lsp_types::{Range, SemanticTokens, Url}; +use lsp_types::{Range, SemanticTokens, Uri as Url}; use serde::{Deserialize, Serialize}; pub type Id = i32; diff --git a/crates/tinymist-query/src/inlay_hint.rs b/crates/tinymist-query/src/inlay_hint.rs index d5c11590ab..2b5e91b7a7 100644 --- a/crates/tinymist-query/src/inlay_hint.rs +++ b/crates/tinymist-query/src/inlay_hint.rs @@ -1,4 +1,4 @@ -use lsp_types::{InlayHintKind, InlayHintLabel}; +use lsp_types::{InlayHintKind, Label}; use crate::{ analysis::{ParamKind, analyze_call}, @@ -243,7 +243,7 @@ impl InlayHintWorker<'_> { let pos = arg_node.range().start; let lsp_pos = self.ctx.to_lsp_pos(pos, self.source); - let label = InlayHintLabel::String(if info.kind == ParamKind::Rest { + let label = Label::String(if info.kind == ParamKind::Rest { format!("..{name}:") } else { format!("{name}:") @@ -252,7 +252,7 @@ impl InlayHintWorker<'_> { self.hints.push(InlayHint { position: lsp_pos, label, - kind: Some(InlayHintKind::PARAMETER), + kind: Some(InlayHintKind::Parameter), text_edits: None, tooltip: None, padding_left: None, diff --git a/crates/tinymist-query/src/lib.rs b/crates/tinymist-query/src/lib.rs index f1b8385a62..9cc1b956a2 100644 --- a/crates/tinymist-query/src/lib.rs +++ b/crates/tinymist-query/src/lib.rs @@ -380,9 +380,9 @@ mod polymorphic { /// The response to the hover request. Hover(Option), /// The response to the goto definition request. - GotoDefinition(Option), + GotoDefinition(Option), /// The response to the goto declaration request. - GotoDeclaration(Option), + GotoDeclaration(Option), /// The response to the references request. References(Option>), /// The response to the inlay hint request. @@ -404,7 +404,7 @@ mod polymorphic { /// The response to the signature help request. SignatureHelp(Option), /// The response to the prepare rename request. - PrepareRename(Option), + PrepareRename(Option), /// The response to the rename request. Rename(Option), /// The response to the will rename files request. @@ -416,9 +416,9 @@ mod polymorphic { /// The response to the workspace label request. WorkspaceLabel(Option>), /// The response to the semantic tokens full request. - SemanticTokensFull(Option), + SemanticTokensFull(Option), /// The response to the semantic tokens delta request. - SemanticTokensDelta(Option), + SemanticTokensDelta(Option), /// The response to the formatting request. Formatting(Option>), /// The response to the folding range request. diff --git a/crates/tinymist-query/src/prelude.rs b/crates/tinymist-query/src/prelude.rs index d8e65905a4..5c158f42e9 100644 --- a/crates/tinymist-query/src/prelude.rs +++ b/crates/tinymist-query/src/prelude.rs @@ -7,14 +7,15 @@ pub use std::sync::{Arc, LazyLock, OnceLock}; pub use ecow::{EcoVec, eco_vec}; pub use itertools::Itertools; pub use lsp_types::{ - CodeActionKind, CodeLens, ColorInformation, ColorPresentation, Diagnostic, - DiagnosticRelatedInformation, DiagnosticSeverity, DocumentHighlight, DocumentLink, - DocumentSymbol, DocumentSymbolResponse, Documentation, FoldingRange, GotoDefinitionResponse, - Hover, HoverContents, InlayHint, Location as LspLocation, LocationLink, MarkedString, - MarkupContent, MarkupKind, ParameterInformation, Position as LspPosition, - PrepareRenameResponse, SelectionRange, SemanticTokens, SemanticTokensDelta, - SemanticTokensFullDeltaResult, SemanticTokensResult, SignatureHelp, SignatureInformation, - SymbolInformation, TextEdit, Url, WorkspaceEdit, request::GotoDeclarationResponse, + ActiveParameter, BaseSymbolInformation, CodeActionKind, CodeLens, ColorInformation, + ColorPresentation, Contents, DeclarationResponse, DefinitionResponse, Diagnostic, + DiagnosticRelatedInformation, DiagnosticSeverity, DocumentChange, DocumentHighlight, + DocumentLink, DocumentSymbol, DocumentSymbolResponse, Documentation, FoldingRange, Hover, + InlayHint, Location as LspLocation, LocationLink, MarkedString, MarkupContent, MarkupKind, + ParameterInformation, Position as LspPosition, PrepareRenamePlaceholder, PrepareRenameResult, + SelectionRange, SemanticTokens, SemanticTokensDelta, SemanticTokensDeltaResponse, + SignatureHelp, SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit, + Uri as Url, WorkspaceEdit, }; pub use serde_json::Value as JsonValue; pub use tinymist_project::LspComputeGraph; diff --git a/crates/tinymist-query/src/prepare_rename.rs b/crates/tinymist-query/src/prepare_rename.rs index 4f89c3400d..7ec48df26d 100644 --- a/crates/tinymist-query/src/prepare_rename.rs +++ b/crates/tinymist-query/src/prepare_rename.rs @@ -32,7 +32,7 @@ pub struct PrepareRenameRequest { // todo: rename alias // todo: rename import path? impl SemanticRequest for PrepareRenameRequest { - type Response = PrepareRenameResponse; + type Response = PrepareRenameResult; fn request(self, ctx: &mut LocalContext) -> Option { let source = ctx.source_by_path(&self.path).ok()?; @@ -59,10 +59,12 @@ impl SemanticRequest for PrepareRenameRequest { let name = prepare_renaming(&syntax, &def)?; - Some(PrepareRenameResponse::RangeWithPlaceholder { - range: origin_selection_range, - placeholder: name, - }) + Some(PrepareRenameResult::PrepareRenamePlaceholder( + PrepareRenamePlaceholder { + range: origin_selection_range, + placeholder: name, + }, + )) } } diff --git a/crates/tinymist-query/src/rename.rs b/crates/tinymist-query/src/rename.rs index 4707f2bcc8..511089c557 100644 --- a/crates/tinymist-query/src/rename.rs +++ b/crates/tinymist-query/src/rename.rs @@ -1,6 +1,6 @@ use lsp_types::{ - AnnotatedTextEdit, ChangeAnnotation, DocumentChangeOperation, DocumentChanges, OneOf, - OptionalVersionedTextDocumentIdentifier, RenameFile, TextDocumentEdit, + AnnotatedTextEdit, ChangeAnnotation, OptionalVersionedTextDocumentIdentifier, RenameFile, + TextDocumentEdit, }; use rustc_hash::FxHashSet; use tinymist_std::path::{PathClean, unix_slash}; @@ -78,18 +78,16 @@ impl SemanticRequest for RenameRequest { let mut document_changes = edits_to_document_changes(edits, None); - document_changes.push(lsp_types::DocumentChangeOperation::Op( - lsp_types::ResourceOp::Rename(RenameFile { - old_uri, - new_uri, - options: None, - annotation_id: None, - }), - )); + document_changes.push(lsp_types::DocumentChange::RenameFile(RenameFile { + old_uri, + new_uri, + options: None, + annotation_id: None, + })); // todo: validate: workspace.workspaceEdit.resourceOperations Some(WorkspaceEdit { - document_changes: Some(DocumentChanges::Operations(document_changes)), + document_changes: Some(document_changes), ..Default::default() }) } @@ -128,7 +126,7 @@ impl SemanticRequest for RenameRequest { )); Some(WorkspaceEdit { - document_changes: Some(DocumentChanges::Operations(document_changes)), + document_changes: Some(document_changes), change_annotations, ..Default::default() }) @@ -326,23 +324,29 @@ impl RenameFileWorker<'_> { pub(crate) fn edits_to_document_changes( edits: HashMap>, change_id: Option<&str>, -) -> Vec { +) -> Vec { let mut document_changes = vec![]; for (uri, edits) in edits { - document_changes.push(lsp_types::DocumentChangeOperation::Edit(TextDocumentEdit { - text_document: OptionalVersionedTextDocumentIdentifier { uri, version: None }, - edits: edits - .into_iter() - .map(|edit| match change_id { - Some(change_id) => OneOf::Right(AnnotatedTextEdit { - text_edit: edit, - annotation_id: change_id.to_owned(), - }), - None => OneOf::Left(edit), - }) - .collect(), - })); + document_changes.push(lsp_types::DocumentChange::TextDocumentEdit( + TextDocumentEdit { + text_document: OptionalVersionedTextDocumentIdentifier { + text_document_identifier: TextDocumentIdentifier { uri }, + version: None, + }, + edits: edits + .into_iter() + .map(|edit| match change_id { + Some(change_id) => AnnotatedTextEdit { + text_edit: edit, + annotation_id: change_id.to_owned(), + } + .into(), + None => edit.into(), + }) + .collect(), + }, + )); } document_changes diff --git a/crates/tinymist-query/src/semantic_tokens_delta.rs b/crates/tinymist-query/src/semantic_tokens_delta.rs index 4b29fb540e..522a22d392 100644 --- a/crates/tinymist-query/src/semantic_tokens_delta.rs +++ b/crates/tinymist-query/src/semantic_tokens_delta.rs @@ -24,7 +24,7 @@ pub struct SemanticTokensDeltaRequest { } impl SemanticRequest for SemanticTokensDeltaRequest { - type Response = SemanticTokensFullDeltaResult; + type Response = SemanticTokensDeltaResponse; /// Handles the request to compute the semantic tokens delta for a given /// document. fn request(self, ctx: &mut LocalContext) -> Option { @@ -32,7 +32,7 @@ impl SemanticRequest for SemanticTokensDeltaRequest { let (tokens, result_id) = ctx.cached_tokens(&source); Some(match ctx.tokens.as_ref().and_then(|t| t.prev.as_ref()) { - Some(cached) => SemanticTokensFullDeltaResult::TokensDelta(SemanticTokensDelta { + Some(cached) => SemanticTokensDeltaResponse::SemanticTokensDelta(SemanticTokensDelta { result_id, edits: token_delta(cached, &tokens), }), @@ -42,7 +42,7 @@ impl SemanticRequest for SemanticTokensDeltaRequest { self.path.display(), self.previous_result_id ); - SemanticTokensFullDeltaResult::Tokens(SemanticTokens { + SemanticTokensDeltaResponse::SemanticTokens(SemanticTokens { result_id, data: tokens.as_ref().clone(), }) diff --git a/crates/tinymist-query/src/semantic_tokens_full.rs b/crates/tinymist-query/src/semantic_tokens_full.rs index c62f591570..d0301d0390 100644 --- a/crates/tinymist-query/src/semantic_tokens_full.rs +++ b/crates/tinymist-query/src/semantic_tokens_full.rs @@ -23,17 +23,17 @@ pub struct SemanticTokensFullRequest { } impl SemanticRequest for SemanticTokensFullRequest { - type Response = SemanticTokensResult; + type Response = SemanticTokens; /// Handles the request to compute the semantic tokens for a given document. fn request(self, ctx: &mut LocalContext) -> Option { let source = ctx.source_by_path(&self.path).ok()?; let (tokens, result_id) = ctx.cached_tokens(&source); - Some(SemanticTokensResult::Tokens(SemanticTokens { + Some(SemanticTokens { result_id, data: tokens.as_ref().clone(), - })) + }) } } @@ -139,18 +139,9 @@ mod tests { let request = SemanticTokensFullRequest { path: path.clone() }; let mut result = request.request(ctx).unwrap(); - if let SemanticTokensResult::Tokens(tokens) = &mut result { - tokens.result_id.take(); - } + result.result_id.take(); - match &result { - SemanticTokensResult::Tokens(tokens) => { - check_tokens(tokens); - } - SemanticTokensResult::Partial(_) => { - panic!("Unexpected partial result"); - } - } + check_tokens(&result); assert_snapshot!(serde_json::to_string(&result).unwrap()); }); diff --git a/crates/tinymist-query/src/signature_help.rs b/crates/tinymist-query/src/signature_help.rs index 25861a7d5e..24200865dd 100644 --- a/crates/tinymist-query/src/signature_help.rs +++ b/crates/tinymist-query/src/signature_help.rs @@ -89,7 +89,7 @@ impl SemanticRequest for SignatureHelpRequest { )); params.push(ParameterInformation { - label: lsp_types::ParameterLabel::Simple(format!("{}:", param.name)), + label: lsp_types::ParameterInformationLabel::String(format!("{}:", param.name)), documentation: param.docs.as_ref().map(|docs| { Documentation::MarkupContent(MarkupContent { value: docs.as_ref().into(), @@ -117,7 +117,7 @@ impl SemanticRequest for SignatureHelpRequest { label: label.to_string(), documentation: sig.primary().docs.as_deref().map(markdown_docs), parameters: Some(params), - active_parameter: active_parameter.map(|x| x as u32), + active_parameter: active_parameter.map(|x| ActiveParameter::Int(x as u32)), }], active_signature: Some(0), active_parameter: None, diff --git a/crates/tinymist-query/src/symbol.rs b/crates/tinymist-query/src/symbol.rs index 3e8c06e5be..3e89115b43 100644 --- a/crates/tinymist-query/src/symbol.rs +++ b/crates/tinymist-query/src/symbol.rs @@ -82,15 +82,17 @@ fn filter_document_symbols( let rng = to_lsp_range(hierarchy.info.range.clone(), source, position_encoding); Some(SymbolInformation { - name: hierarchy.info.name.to_string(), - kind: hierarchy.info.kind.clone().into(), - tags: None, + base_symbol_information: BaseSymbolInformation { + name: hierarchy.info.name.to_string(), + kind: hierarchy.info.kind.clone().into(), + tags: None, + container_name: None, + }, deprecated: None, location: LspLocation { uri: uri.clone(), range: rng, }, - container_name: None, }) }) .collect() @@ -120,8 +122,9 @@ mod tests { if let Some(result) = &mut result { // Sort the symbols by name for consistent output result.sort_by(|x, y| { - x.name - .cmp(&y.name) + x.base_symbol_information + .name + .cmp(&y.base_symbol_information.name) .then_with(|| x.location.uri.cmp(&y.location.uri)) }); } diff --git a/crates/tinymist-query/src/syntax/lexical_hierarchy.rs b/crates/tinymist-query/src/syntax/lexical_hierarchy.rs index 956e5e6845..9914d35249 100644 --- a/crates/tinymist-query/src/syntax/lexical_hierarchy.rs +++ b/crates/tinymist-query/src/syntax/lexical_hierarchy.rs @@ -115,11 +115,11 @@ impl From for SymbolKind { fn from(value: LexicalKind) -> Self { use LexicalVarKind::*; match value { - LexicalKind::Heading(..) => SymbolKind::NAMESPACE, - LexicalKind::Var(ValRef | Variable) => SymbolKind::VARIABLE, - LexicalKind::Var(Function) => SymbolKind::FUNCTION, - LexicalKind::Var(LabelRef | Label | BibKey) => SymbolKind::CONSTANT, - LexicalKind::Block | LexicalKind::CommentGroup => SymbolKind::CONSTANT, + LexicalKind::Heading(..) => SymbolKind::Namespace, + LexicalKind::Var(ValRef | Variable) => SymbolKind::Variable, + LexicalKind::Var(Function) => SymbolKind::Function, + LexicalKind::Var(LabelRef | Label | BibKey) => SymbolKind::Constant, + LexicalKind::Block | LexicalKind::CommentGroup => SymbolKind::Constant, } } } diff --git a/crates/tinymist-query/src/tests.rs b/crates/tinymist-query/src/tests.rs index 8b25d54a4e..8cedd742e6 100644 --- a/crates/tinymist-query/src/tests.rs +++ b/crates/tinymist-query/src/tests.rs @@ -524,10 +524,10 @@ impl Redact for RedactFields { } pub(crate) fn file_uri(uri: &str) -> String { - file_uri_(&lsp_types::Url::parse(uri).unwrap()) + file_uri_(&lsp_types::Uri::parse(uri).unwrap()) } -pub(crate) fn file_uri_(uri: &lsp_types::Url) -> String { +pub(crate) fn file_uri_(uri: &lsp_types::Uri) -> String { let uri = uri.to_file_path().unwrap(); file_path_(&uri) } diff --git a/crates/tinymist-query/src/will_rename_files.rs b/crates/tinymist-query/src/will_rename_files.rs index a717ad9326..2d9a7795ff 100644 --- a/crates/tinymist-query/src/will_rename_files.rs +++ b/crates/tinymist-query/src/will_rename_files.rs @@ -48,7 +48,7 @@ impl SemanticRequest for WillRenameFilesRequest { Some(WorkspaceEdit { changes: None, - document_changes: Some(lsp_types::DocumentChanges::Operations(document_changes)), + document_changes: Some(document_changes), change_annotations, }) } diff --git a/crates/tinymist-query/src/workspace_label.rs b/crates/tinymist-query/src/workspace_label.rs index aff778535e..77522a01e6 100644 --- a/crates/tinymist-query/src/workspace_label.rs +++ b/crates/tinymist-query/src/workspace_label.rs @@ -63,15 +63,17 @@ fn filter_document_labels( let rng = to_lsp_range(hierarchy.info.range.clone(), source, position_encoding); Some(SymbolInformation { - name: hierarchy.info.name.to_string(), - kind: hierarchy.info.kind.clone().into(), - tags: None, + base_symbol_information: BaseSymbolInformation { + name: hierarchy.info.name.to_string(), + kind: hierarchy.info.kind.clone().into(), + tags: None, + container_name: None, + }, deprecated: None, location: LspLocation { uri: uri.clone(), range: rng, }, - container_name: None, }) }) .collect() diff --git a/crates/tinymist/src/actor/editor.rs b/crates/tinymist/src/actor/editor.rs index 845416332c..b3101991c8 100644 --- a/crates/tinymist/src/actor/editor.rs +++ b/crates/tinymist/src/actor/editor.rs @@ -3,8 +3,10 @@ use std::collections::HashMap; -use lsp_types::notification::{Notification, PublishDiagnostics as PublishDiagnosticsBase}; -use lsp_types::{Diagnostic, Url}; +use lsp_types::{ + Diagnostic, LspNotificationMethod, Notification, + PublishDiagnosticsNotification as PublishDiagnosticsBase, Uri as Url, +}; use reflexo::path::unix_slash; use reflexo_typst::typst::prelude::{eco_vec, EcoVec}; use serde::{Deserialize, Serialize}; @@ -244,9 +246,11 @@ struct StatusAll { pub words_count: Option, } -impl lsp_types::notification::Notification for StatusAll { +impl lsp_types::Notification for StatusAll { type Params = Self; - const METHOD: &'static str = "tinymist/compileStatus"; + const MESSAGE_DIRECTION: lsp_types::MessageDirection = + lsp_types::MessageDirection::ClientToServer; + const METHOD: LspNotificationMethod = LspNotificationMethod::new("tinymist/compileStatus"); } #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] @@ -270,7 +274,9 @@ pub enum PublishDiagnostics {} impl Notification for PublishDiagnostics { type Params = PublishDiagnosticsParams; - const METHOD: &'static str = PublishDiagnosticsBase::METHOD; + const METHOD: LspNotificationMethod = PublishDiagnosticsBase::METHOD; + const MESSAGE_DIRECTION: lsp_types::MessageDirection = + lsp_types::MessageDirection::ServerToClient; } /// A scatter vector that is serialized as a flatten representation. diff --git a/crates/tinymist/src/actor/preview.rs b/crates/tinymist/src/actor/preview.rs index 2784eddd97..da804eb90b 100644 --- a/crates/tinymist/src/actor/preview.rs +++ b/crates/tinymist/src/actor/preview.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, sync::Arc}; -use lsp_types::notification::Notification; +use lsp_types::{LspNotificationMethod, Notification}; use serde::{Deserialize, Serialize}; use serde_json::Value as JsonValue; use sync_ls::{internal_error, LspClient, LspResult}; @@ -135,5 +135,7 @@ struct DisposePreview { impl Notification for DisposePreview { type Params = Self; - const METHOD: &'static str = "tinymist/preview/dispose"; + const METHOD: LspNotificationMethod = LspNotificationMethod::new("tinymist/preview/dispose"); + const MESSAGE_DIRECTION: lsp_types::MessageDirection = + lsp_types::MessageDirection::ClientToServer; } diff --git a/crates/tinymist/src/config.rs b/crates/tinymist/src/config.rs index 258ece288c..98b44c2f83 100644 --- a/crates/tinymist/src/config.rs +++ b/crates/tinymist/src/config.rs @@ -191,7 +191,14 @@ impl Config { font_args: CompileFontArgs, ) -> (Self, Option) { // Initialize configurations - let roots = match params.workspace_folders.as_ref() { + let roots = match params + .workspace_folders_initialize_params + .workspace_folders + .as_ref() + .and_then(|folders| match folders { + WorkspaceFolders::WorkspaceFolderList(folders) => Some(folders), + WorkspaceFolders::Null => None, + }) { Some(roots) => roots .iter() .map(|root| ImmutPath::from(url_to_path(&root.uri))) @@ -201,7 +208,15 @@ impl Config { .root_uri .as_ref() .map(|uri| ImmutPath::from(url_to_path(uri))) - .or_else(|| Some(Path::new(¶ms.root_path.as_ref()?).into())) + .or_else(|| { + Some( + Path::new(¶ms.root_path.as_ref().and_then(|p| match p { + RootPath::String(string) => Some(string), + RootPath::Null => None, + })?) + .into(), + ) + }) .into_iter() .collect(), }; @@ -1071,11 +1086,15 @@ pub(crate) fn get_semantic_tokens_options() -> SemanticTokensOptions { legend: SemanticTokensLegend { token_types: TokenType::iter() .filter(|e| *e != TokenType::None) - .map(Into::into) + .map(|e| SemanticTokenTypes::from(e).into()) + .collect(), + token_modifiers: Modifier::iter() + .map(|e| SemanticTokenModifiers::from(e).into()) .collect(), - token_modifiers: Modifier::iter().map(Into::into).collect(), }, - full: Some(SemanticTokensFullOptions::Delta { delta: Some(true) }), + full: Some(Full::SemanticTokensFullDelta(SemanticTokensFullDelta { + delta: Some(true), + })), ..SemanticTokensOptions::default() } } diff --git a/crates/tinymist/src/input.rs b/crates/tinymist/src/input.rs index 5365a32b1e..ac4e570968 100644 --- a/crates/tinymist/src/input.rs +++ b/crates/tinymist/src/input.rs @@ -77,15 +77,18 @@ impl ServerState { .ok_or_else(|| error_once!("file missing", path: path.display()))?; for change in content { - let replacement = change.text; - match change.range { - Some(lsp_range) => { - let range = to_typst_range(lsp_range, position_encoding, source) - .expect("invalid range"); - source.edit(range, &replacement); + match change { + TextDocumentContentChangeEvent::TextDocumentContentChangeWholeDocument( + TextDocumentContentChangeWholeDocument { text }, + ) => { + source.replace(&text); } - None => { - source.replace(&replacement); + TextDocumentContentChangeEvent::TextDocumentContentChangePartial( + TextDocumentContentChangePartial { text, range, .. }, + ) => { + let range = + to_typst_range(range, position_encoding, source).expect("invalid range"); + source.edit(range, &text); } } } @@ -135,7 +138,7 @@ impl ServerState { for change in params.inserts { let path: ImmutPath = - tinymist_query::url_to_path(&Url::parse(&change.uri).unwrap()).into(); + tinymist_query::url_to_path(&Uri::parse(&change.uri).unwrap()).into(); let content: FileResult = match change.content { FileChangeResult::Ok { content } => base64::engine::general_purpose::STANDARD .decode(content) @@ -150,7 +153,7 @@ impl ServerState { } for path in params.removes { - removes.push(tinymist_query::url_to_path(&Url::parse(&path).unwrap()).into()); + removes.push(tinymist_query::url_to_path(&Uri::parse(&path).unwrap()).into()); } let update = FilesystemEvent::Update(FileChangeSet { inserts, removes }, params.is_sync); @@ -344,10 +347,11 @@ impl ServerState { /// The file system change request. pub enum FsChange {} -impl lsp_types::request::Request for FsChange { +impl lsp_types::Request for FsChange { type Params = FsChangeParams; type Result = (); - const METHOD: &'static str = "tinymist/fsChange"; + const METHOD: LspRequestMethod = LspRequestMethod::new("tinymist/fsChange"); + const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; } /// The file system change parameters. diff --git a/crates/tinymist/src/input/watch.rs b/crates/tinymist/src/input/watch.rs index 266642f769..083d345cac 100644 --- a/crates/tinymist/src/input/watch.rs +++ b/crates/tinymist/src/input/watch.rs @@ -2,7 +2,7 @@ use std::collections::HashSet; use std::path::Path; use std::sync::{Arc, Mutex}; -use lsp_types::request::Request; +use lsp_types::{LspRequestMethod, Request}; use reflexo::ImmutPath; use reflexo_typst::vfs::{FileChangeSet, PathAccessModel}; use reflexo_typst::Bytes; @@ -123,12 +123,14 @@ impl PathAccessModel for WatchAccessModel { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct FsWatchRequest { - inserts: Vec, - removes: Vec, + inserts: Vec, + removes: Vec, } impl Request for FsWatchRequest { type Params = Self; type Result = (); - const METHOD: &'static str = "tinymist/fs/watch"; + const METHOD: LspRequestMethod = LspRequestMethod::new("tinymist/fs/watch"); + const MESSAGE_DIRECTION: lsp_types::MessageDirection = + lsp_types::MessageDirection::ServerToClient; } diff --git a/crates/tinymist/src/log.rs b/crates/tinymist/src/log.rs index 52219015e9..a98b7219b2 100644 --- a/crates/tinymist/src/log.rs +++ b/crates/tinymist/src/log.rs @@ -1,5 +1,6 @@ //! Logging Functionality +use lsp_types::LspNotificationMethod; use serde::{Deserialize, Serialize}; use super::*; @@ -102,7 +103,9 @@ struct Log { data: String, } -impl lsp_types::notification::Notification for Log { - const METHOD: &'static str = "tmLog"; +impl lsp_types::Notification for Log { + const METHOD: LspNotificationMethod = LspNotificationMethod::new("tmLog"); + const MESSAGE_DIRECTION: lsp_types::MessageDirection = + lsp_types::MessageDirection::ServerToClient; type Params = Self; } diff --git a/crates/tinymist/src/lsp.rs b/crates/tinymist/src/lsp.rs index c779a68d01..06bae409ca 100644 --- a/crates/tinymist/src/lsp.rs +++ b/crates/tinymist/src/lsp.rs @@ -1,9 +1,7 @@ use std::sync::OnceLock; -use lsp_types::request::*; use lsp_types::*; use reflexo::ImmutPath; -use request::{RegisterCapability, UnregisterCapability}; use serde_json::{Map, Value as JsonValue}; use sync_ls::*; use tinymist_std::error::{prelude::*, IgnoreLogging}; @@ -109,7 +107,9 @@ impl ServerState { } pub(crate) fn did_change(&mut self, params: DidChangeTextDocumentParams) -> LspResult<()> { - let path = as_path_(¶ms.text_document.uri).as_path().into(); + let path = as_path_(¶ms.text_document.text_document_identifier.uri) + .as_path() + .into(); let changes = params.content_changes; self.edit_source(path, changes, self.const_config().position_encoding) @@ -198,7 +198,7 @@ impl ServerState { return self.on_changed_configuration(settings); }; - self.client.send_lsp_request::( + self.client.send_lsp_request::( ConfigurationParams { items: Config::get_items(), }, @@ -234,7 +234,7 @@ impl ServerState { impl ServerState { // todo: handle error pub(crate) fn register_capability(&self, registrations: Vec) -> Result<()> { - self.client.send_lsp_request_::( + self.client.send_lsp_request_::( RegistrationParams { registrations }, |_, resp| { if let Some(err) = resp.error { @@ -249,7 +249,7 @@ impl ServerState { &self, unregisterations: Vec, ) -> Result<()> { - self.client.send_lsp_request_::( + self.client.send_lsp_request_::( UnregistrationParams { unregisterations }, |_, resp| { if let Some(err) = resp.error { @@ -319,7 +319,7 @@ impl ServerState { pub fn get_formatting_registration() -> Registration { Registration { id: FORMATTING_REGISTRATION_ID.to_owned(), - method: Formatting::METHOD.to_owned(), + method: DocumentFormattingRequest::METHOD.to_string(), register_options: None, } } @@ -327,7 +327,7 @@ impl ServerState { pub fn get_range_formatting_registration() -> Registration { Registration { id: RANGE_FORMATTING_REGISTRATION_ID.to_owned(), - method: RangeFormatting::METHOD.to_owned(), + method: DocumentRangeFormattingRequest::METHOD.to_string(), register_options: None, } } @@ -335,14 +335,14 @@ impl ServerState { pub fn get_formatting_unregistration() -> Unregistration { Unregistration { id: FORMATTING_REGISTRATION_ID.to_owned(), - method: Formatting::METHOD.to_owned(), + method: DocumentFormattingRequest::METHOD.to_string(), } } pub fn get_range_formatting_unregistration() -> Unregistration { Unregistration { id: RANGE_FORMATTING_REGISTRATION_ID.to_owned(), - method: RangeFormatting::METHOD.to_owned(), + method: DocumentRangeFormattingRequest::METHOD.to_string(), } } diff --git a/crates/tinymist/src/lsp/init.rs b/crates/tinymist/src/lsp/init.rs index 33e9d916b7..f04e849f69 100644 --- a/crates/tinymist/src/lsp/init.rs +++ b/crates/tinymist/src/lsp/init.rs @@ -97,16 +97,16 @@ impl Initializer for SuperInit { return (state, Err(err)); } - let semantic_tokens_provider = (!const_config.tokens_dynamic_registration).then(|| { - SemanticTokensServerCapabilities::SemanticTokensOptions(get_semantic_tokens_options()) - }); + let semantic_tokens_provider = (!const_config.tokens_dynamic_registration) + .then(|| SemanticTokensProvider::SemanticTokensOptions(get_semantic_tokens_options())); let document_formatting_provider = - (!const_config.doc_fmt_dynamic_registration).then_some(OneOf::Left(true)); + (!const_config.doc_fmt_dynamic_registration).then_some(true.into()); let document_range_formatting_provider = - (!const_config.doc_fmt_dynamic_registration).then_some(OneOf::Left(true)); + (!const_config.doc_fmt_dynamic_registration).then_some(true.into()); - let file_operations = const_config.notify_will_rename_files.then(|| { - WorkspaceFileOperationsServerCapabilities { + let file_operations = const_config + .notify_will_rename_files + .then(|| FileOperationOptions { will_rename: Some(FileOperationRegistrationOptions { filters: vec![FileOperationFilter { scheme: Some("file".to_string()), @@ -117,14 +117,13 @@ impl Initializer for SuperInit { }, }], }), - ..WorkspaceFileOperationsServerCapabilities::default() - } - }); + ..FileOperationOptions::default() + }); let res = InitializeResult { capabilities: ServerCapabilities { position_encoding: Some(const_config.position_encoding.into()), - hover_provider: Some(HoverProviderCapability::Simple(true)), + hover_provider: Some(true.into()), signature_help_provider: Some(SignatureHelpOptions { trigger_characters: Some(vec![ String::from("("), @@ -136,8 +135,8 @@ impl Initializer for SuperInit { work_done_progress: None, }, }), - definition_provider: Some(OneOf::Left(true)), - references_provider: Some(OneOf::Left(true)), + definition_provider: Some(true.into()), + references_provider: Some(true.into()), completion_provider: Some(CompletionOptions { // Please update the language-configuration.json if you are changing this // setting. @@ -154,14 +153,15 @@ impl Initializer for SuperInit { ]), ..CompletionOptions::default() }), - text_document_sync: Some(TextDocumentSyncCapability::Options( + text_document_sync: Some( TextDocumentSyncOptions { open_close: Some(true), - change: Some(TextDocumentSyncKind::INCREMENTAL), - save: Some(TextDocumentSyncSaveOptions::Supported(true)), + change: Some(TextDocumentSyncKind::Incremental), + save: Some(true.into()), ..TextDocumentSyncOptions::default() - }, - )), + } + .into(), + ), semantic_tokens_provider, execute_command_provider: Some(ExecuteCommandOptions { commands: exec_cmds, @@ -169,37 +169,44 @@ impl Initializer for SuperInit { work_done_progress: None, }, }), - color_provider: Some(ColorProviderCapability::Simple(true)), - document_highlight_provider: Some(OneOf::Left(true)), - document_symbol_provider: Some(OneOf::Left(true)), - workspace_symbol_provider: Some(OneOf::Left(true)), - selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), - rename_provider: Some(OneOf::Right(RenameOptions { - prepare_provider: Some(true), - work_done_progress_options: WorkDoneProgressOptions { - work_done_progress: None, - }, - })), + color_provider: Some(true.into()), + document_highlight_provider: Some(true.into()), + document_symbol_provider: Some(true.into()), + workspace_symbol_provider: Some(true.into()), + selection_range_provider: Some(true.into()), + rename_provider: Some( + RenameOptions { + prepare_provider: Some(true), + work_done_progress_options: WorkDoneProgressOptions { + work_done_progress: None, + }, + } + .into(), + ), document_link_provider: Some(DocumentLinkOptions { resolve_provider: None, work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None, }, }), - folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), - workspace: Some(WorkspaceServerCapabilities { + folding_range_provider: Some(true.into()), + workspace: Some(WorkspaceOptions { workspace_folders: Some(WorkspaceFoldersServerCapabilities { supported: Some(true), - change_notifications: Some(OneOf::Left(true)), + change_notifications: Some(true.into()), }), file_operations, + text_document_content: None, }), document_formatting_provider, document_range_formatting_provider, - inlay_hint_provider: Some(OneOf::Left(true)), - code_action_provider: Some(CodeActionProviderCapability::Simple(true)), + inlay_hint_provider: Some(true.into()), + code_action_provider: Some(true.into()), code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(false), + work_done_progress_options: WorkDoneProgressOptions { + work_done_progress: None, + }, }), experimental: Some(json!({ diff --git a/crates/tinymist/src/lsp/query.rs b/crates/tinymist/src/lsp/query.rs index 18aac858cc..059094c4ab 100644 --- a/crates/tinymist/src/lsp/query.rs +++ b/crates/tinymist/src/lsp/query.rs @@ -1,6 +1,6 @@ //! tinymist's language server -use lsp_types::request::GotoDeclarationParams; +use lsp_types::DeclarationParams; use lsp_types::*; use serde::{Deserialize, Serialize}; use sync_ls::*; @@ -26,18 +26,18 @@ pub(crate) use run_query; /// LSP Standard Language Features impl ServerState { - pub(crate) fn goto_definition(&mut self, params: GotoDefinitionParams) -> ScheduleResult { + pub(crate) fn goto_definition(&mut self, params: DefinitionParams) -> ScheduleResult { let (path, position) = as_path_pos(params.text_document_position_params); run_query!(self.GotoDefinition(path, position)) } - pub(crate) fn goto_declaration(&mut self, params: GotoDeclarationParams) -> ScheduleResult { + pub(crate) fn goto_declaration(&mut self, params: DeclarationParams) -> ScheduleResult { let (path, position) = as_path_pos(params.text_document_position_params); run_query!(self.GotoDeclaration(path, position)) } pub(crate) fn references(&mut self, params: ReferenceParams) -> ScheduleResult { - let (path, position) = as_path_pos(params.text_document_position); + let (path, position) = as_path_pos(params.text_document_position_params); run_query!(self.References(path, position)) } @@ -148,10 +148,10 @@ impl ServerState { } pub(crate) fn completion(&mut self, params: CompletionParams) -> ScheduleResult { - let (path, position) = as_path_pos(params.text_document_position); + let (path, position) = as_path_pos(params.text_document_position_params); let context = params.context.as_ref(); let explicit = - context.is_some_and(|context| context.trigger_kind == CompletionTriggerKind::INVOKED); + context.is_some_and(|context| context.trigger_kind == CompletionTriggerKind::Invoked); let trigger_character = context .and_then(|c| c.trigger_character.as_ref()) .and_then(|c| c.chars().next()); @@ -168,13 +168,13 @@ impl ServerState { } pub(crate) fn rename(&mut self, params: RenameParams) -> ScheduleResult { - let (path, position) = as_path_pos(params.text_document_position); + let (path, position) = as_path_pos(params.text_document_position_params); let new_name = params.new_name; run_query!(self.Rename(path, position, new_name)) } - pub(crate) fn prepare_rename(&mut self, params: TextDocumentPositionParams) -> ScheduleResult { - let (path, position) = as_path_pos(params); + pub(crate) fn prepare_rename(&mut self, params: PrepareRenameParams) -> ScheduleResult { + let (path, position) = as_path_pos(params.text_document_position_params); run_query!(self.PrepareRename(path, position)) } @@ -197,8 +197,8 @@ impl ServerState { .iter() .map(|f| { Some(( - as_path_(&Url::parse(&f.old_uri).ok()?), - as_path_(&Url::parse(&f.new_uri).ok()?), + as_path_(&Uri::parse(&f.old_uri).ok()?), + as_path_(&Uri::parse(&f.new_uri).ok()?), )) }) .collect::>>() @@ -330,8 +330,9 @@ pub struct OnEnterParams { } pub struct OnEnter; -impl lsp_types::request::Request for OnEnter { +impl lsp_types::Request for OnEnter { type Params = OnEnterParams; type Result = Option>; - const METHOD: &'static str = "experimental/onEnter"; + const MESSAGE_DIRECTION: MessageDirection = MessageDirection::ClientToServer; + const METHOD: LspRequestMethod = LspRequestMethod::new("experimental/onEnter"); } diff --git a/crates/tinymist/src/project.rs b/crates/tinymist/src/project.rs index 110adcd70a..8ad5fb1bfe 100644 --- a/crates/tinymist/src/project.rs +++ b/crates/tinymist/src/project.rs @@ -17,6 +17,7 @@ //! //! The [`CompileHandlerImpl`] will push information to other actors. +use lsp_types::LspNotificationMethod; use reflexo_typst::TypstDocument; use serde::{Deserialize, Serialize}; pub use tinymist_project::*; @@ -816,7 +817,9 @@ pub enum DevEvent { Export(DevExportEvent), } -impl lsp_types::notification::Notification for DevEvent { - const METHOD: &'static str = "tinymist/devEvent"; +impl lsp_types::Notification for DevEvent { + const METHOD: LspNotificationMethod = LspNotificationMethod::new("tinymist/devEvent"); + const MESSAGE_DIRECTION: lsp_types::MessageDirection = + lsp_types::MessageDirection::ServerToClient; type Params = Self; } diff --git a/crates/tinymist/src/server.rs b/crates/tinymist/src/server.rs index 314bbb17d2..5f34e4418b 100644 --- a/crates/tinymist/src/server.rs +++ b/crates/tinymist/src/server.rs @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; pub(crate) use futures::Future; -use lsp_types::request::ShowMessageRequest; +use lsp_types::ShowMessageRequest; use lsp_types::*; use reflexo::debug_loc::LspPosition; use sync_ls::*; @@ -31,7 +31,7 @@ pub(crate) fn as_path(inp: TextDocumentIdentifier) -> PathBuf { as_path_(&inp.uri) } -pub(crate) fn as_path_(uri: &Url) -> PathBuf { +pub(crate) fn as_path_(uri: &Uri) -> PathBuf { tinymist_query::url_to_path(uri) } @@ -248,8 +248,7 @@ impl ServerState { provider: LspBuilder, ) -> LspBuilder { type State = ServerState; - use lsp_types::notification::*; - use lsp_types::request::*; + use lsp_types::*; #[cfg(feature = "preview")] let provider = provider @@ -277,7 +276,7 @@ impl ServerState { // todo: .on_sync_mut::(handlers::handle_cancel)? let mut provider = provider - .with_request::(State::shutdown) + .with_request::(State::shutdown) // customized event .with_event( &LspInterrupt::Compile(ProjectInsId::default()), @@ -288,18 +287,18 @@ impl ServerState { State::server_event::, ) // lantency sensitive - .with_request_::(State::completion) - .with_request_::(State::semantic_tokens_full) - .with_request_::(State::semantic_tokens_full_delta) + .with_request_::(State::completion) + .with_request_::(State::semantic_tokens_full) + .with_request_::(State::semantic_tokens_full_delta) .with_request_::(State::document_highlight) .with_request_::(State::document_symbol) // Sync for low latency - .with_request_::(State::formatting) - .with_request_::(State::range_formatting) + .with_request_::(State::formatting) + .with_request_::(State::range_formatting) .with_request_::(State::selection_range) // latency insensitive .with_request_::(State::inlay_hint) - .with_request_::(State::document_color) + .with_request_::(State::document_color) .with_request_::(State::document_link) .with_request_::(State::color_presentation) .with_request_::(State::hover) @@ -308,21 +307,23 @@ impl ServerState { .with_request_::(State::folding_range) .with_request_::(State::signature_help) .with_request_::(State::prepare_rename) - .with_request_::(State::rename) - .with_request_::(State::goto_definition) - .with_request_::(State::goto_declaration) - .with_request_::(State::references) + .with_request_::(State::rename) + .with_request_::(State::goto_definition) + .with_request_::(State::goto_declaration) + .with_request_::(State::references) .with_request_::(State::symbol) .with_request_::(State::on_enter) - .with_request_::(State::will_rename_files) + .with_request_::(State::will_rename_files) .with_request_::(State::fs_change) // notifications - .with_notification::(State::initialized) - .with_notification::(State::did_open) - .with_notification::(State::did_close) - .with_notification::(State::did_change) - .with_notification::(State::did_save) - .with_notification::(State::did_change_configuration) + .with_notification::(State::initialized) + .with_notification::(State::did_open) + .with_notification::(State::did_close) + .with_notification::(State::did_change) + .with_notification::(State::did_save) + .with_notification::( + State::did_change_configuration, + ) // commands .with_command_("tinymist.exportPdf", State::export_pdf) .with_command_("tinymist.exportSvg", State::export_svg) @@ -473,7 +474,7 @@ impl ServerState { for warning in self.config.warnings.iter() { self.client.send_lsp_request::( ShowMessageRequestParams { - typ: MessageType::WARNING, + kind: MessageType::Warning, message: tinymist_l10n::t!( "tinymist.config.badServerConfig", "bad server configuration: {warning}", @@ -527,10 +528,10 @@ fn test_as_path() { use reflexo::path::PathClean; use std::path::Path; - let uri = Url::parse("untitled:/path/to/file").unwrap(); + let uri = Uri::parse("untitled:/path/to/file").unwrap(); assert_eq!(as_path_(&uri), Path::new("/untitled/path/to/file").clean()); - let uri = Url::parse("untitled:/path/to/file%20with%20space").unwrap(); + let uri = Uri::parse("untitled:/path/to/file%20with%20space").unwrap(); assert_eq!( as_path_(&uri), Path::new("/untitled/path/to/file with space").clean() diff --git a/crates/tinymist/src/tool/preview.rs b/crates/tinymist/src/tool/preview.rs index 98ccbf7985..4577d08993 100644 --- a/crates/tinymist/src/tool/preview.rs +++ b/crates/tinymist/src/tool/preview.rs @@ -2,6 +2,7 @@ pub use compile::{PreviewCompileView, ProjectPreviewHandler}; pub use http::{make_http_server, HttpServer}; +use lsp_types::LspNotificationMethod; mod compile; mod http; @@ -11,8 +12,8 @@ use std::{collections::HashMap, path::Path, sync::Arc}; use clap::{Parser, ValueEnum}; use futures::{SinkExt, TryStreamExt}; use hyper_tungstenite::{tungstenite::Message, HyperWebsocket, HyperWebsocketStream}; -use lsp_types::notification::Notification; -use lsp_types::Url; +use lsp_types::Notification; +use lsp_types::Uri as Url; use reflexo_typst::error::prelude::*; use serde::Serialize; use serde_json::Value as JsonValue; @@ -592,14 +593,19 @@ struct ScrollSource; impl Notification for ScrollSource { type Params = DocToSrcJumpInfo; - const METHOD: &'static str = "tinymist/preview/scrollSource"; + const MESSAGE_DIRECTION: lsp_types::MessageDirection = + lsp_types::MessageDirection::ClientToServer; + const METHOD: LspNotificationMethod = + LspNotificationMethod::new("tinymist/preview/scrollSource"); } struct NotifDocumentOutline; impl Notification for NotifDocumentOutline { type Params = tinymist_preview::Outline; - const METHOD: &'static str = "tinymist/documentOutline"; + const MESSAGE_DIRECTION: lsp_types::MessageDirection = + lsp_types::MessageDirection::ClientToServer; + const METHOD: LspNotificationMethod = LspNotificationMethod::new("tinymist/documentOutline"); } fn send_show_document(client: &TypedLspClient, s: &DocToSrcJumpInfo, tid: &str) { @@ -629,7 +635,7 @@ fn send_show_document(client: &TypedLspClient, s: &DocToSrcJumpInf } }; - client.send_lsp_request::( + client.send_lsp_request::( lsp_types::ShowDocumentParams { uri, external: None, diff --git a/crates/tinymist/src/tool/preview/http.rs b/crates/tinymist/src/tool/preview/http.rs index dcb65a8706..5327623ea0 100644 --- a/crates/tinymist/src/tool/preview/http.rs +++ b/crates/tinymist/src/tool/preview/http.rs @@ -8,7 +8,7 @@ use hyper::service::service_fn; use hyper_tungstenite::HyperWebsocket; use hyper_util::rt::TokioIo; use hyper_util::server::graceful::GracefulShutdown; -use lsp_types::Url; +use lsp_types::Uri as Url; use tinymist_std::error::IgnoreLogging; use tokio::sync::{mpsc, oneshot}; diff --git a/tests/e2e/e2e/lsp.rs b/tests/e2e/e2e/lsp.rs index 5b57630302..b157275c9d 100644 --- a/tests/e2e/e2e/lsp.rs +++ b/tests/e2e/e2e/lsp.rs @@ -105,8 +105,8 @@ impl ReplayBuilder { .push(lsp::Message::Request(lsp::Request::new(id, method, req))); } - fn request(&mut self, req: Value) { - self.request_(R::METHOD.to_owned(), req); + fn request(&mut self, req: Value) { + self.request_(R::METHOD.to_string(), req); } fn notify_(&mut self, method: String, params: Value) { @@ -116,8 +116,8 @@ impl ReplayBuilder { ))); } - fn notify(&mut self, params: Value) { - self.notify_(N::METHOD.to_owned(), params); + fn notify(&mut self, params: Value) { + self.notify_(N::METHOD.to_string(), params); } } @@ -162,14 +162,12 @@ struct SmokeArgs { } fn gen_smoke(args: SmokeArgs) { - use lsp_types::notification::*; - use lsp_types::request::*; use lsp_types::*; let SmokeArgs { root, init, log } = args; gen(&root, |srv| { - let root_uri = lsp_types::Url::from_directory_path(&root).unwrap(); - srv.request::(fixture(&init, |v| { + let root_uri = lsp_types::Uri::from_directory_path(&root).unwrap(); + srv.request::(fixture(&init, |v| { v["rootUri"] = json!(root_uri); v["rootPath"] = json!(root); v["workspaceFolders"] = json!([{ @@ -177,7 +175,7 @@ fn gen_smoke(args: SmokeArgs) { "name": "tinymist", }]); })); - srv.notify::(json!({})); + srv.notify::(json!({})); // open editions/base.log and readlines let log = std::fs::read_to_string(&log).unwrap(); @@ -205,7 +203,7 @@ fn gen_smoke(args: SmokeArgs) { let uri_name = v["params"]["textDocument"]["uri"].as_str().unwrap(); let url_v = if uri_name.starts_with("file:") || uri_name.starts_with("untitled:") { - lsp_types::Url::parse(uri_name).unwrap() + lsp_types::Uri::parse(uri_name).unwrap() } else { root_uri.join(uri_name).unwrap() }; @@ -228,20 +226,20 @@ fn gen_smoke(args: SmokeArgs) { text_document_position_params: pos.clone(), })); if log_lines == idx + 1 || log_lines == idx + 5 || log_lines == idx + 10 { - srv.request::(json!(CompletionParams { - text_document_position: pos.clone(), + srv.request::(json!(CompletionParams { + text_document_position_params: pos.clone(), context: None, work_done_progress_params: Default::default(), partial_result_params: Default::default(), })); } - srv.request::(json!(GotoDefinitionParams { + srv.request::(json!(DefinitionParams { text_document_position_params: pos.clone(), work_done_progress_params: Default::default(), partial_result_params: Default::default(), })); - srv.request::(json!(ReferenceParams { - text_document_position: pos.clone(), + srv.request::(json!(ReferenceParams { + text_document_position_params: pos.clone(), context: ReferenceContext { include_declaration: false, }, @@ -337,7 +335,7 @@ fn gen_smoke(args: SmokeArgs) { })); if log_lines == idx + 1 { - srv.request::(json!(SemanticTokensParams { + srv.request::(json!(SemanticTokensParams { text_document: TextDocumentIdentifier { uri: u.clone() }, work_done_progress_params: Default::default(), partial_result_params: Default::default(), @@ -479,7 +477,7 @@ fn may_redact_uri(uri: &str) -> Value { if uri == "file://" || uri == "file:///" { Value::String("".to_owned()) } else { - let uri = lsp_types::Url::parse(uri).unwrap(); + let uri = lsp_types::Uri::parse(uri).unwrap(); match uri.to_file_path() { Ok(path) => {