From 77966f6bbea8790a1b260701d41adf5212afc498 Mon Sep 17 00:00:00 2001 From: hongjr03 Date: Sat, 23 May 2026 00:27:06 +0800 Subject: [PATCH 1/2] chore(lsp): migrate protocol types to lspt --- Cargo.toml | 2 +- src/config.rs | 4 +- src/config/caps.rs | 200 ++++---- src/global_state.rs | 8 +- src/global_state/dispatcher.rs | 36 +- src/global_state/handlers/notification.rs | 70 +-- src/global_state/handlers/request.rs | 279 +++++------ .../handlers/request/code_action.rs | 29 +- src/global_state/main_loop.rs | 112 ++--- src/global_state/process_changes.rs | 8 +- src/global_state/project_status.rs | 8 +- src/global_state/qihe.rs | 38 +- src/global_state/reload.rs | 22 +- src/global_state/respond.rs | 37 +- src/global_state/snapshot.rs | 10 +- src/global_state/trace.rs | 6 +- src/lsp_ext/ext.rs | 208 ++++---- src/lsp_ext/from_proto.rs | 23 +- src/lsp_ext/to_proto.rs | 287 ++++++----- src/main.rs | 37 +- src/tests.rs | 464 ++++++++---------- 21 files changed, 930 insertions(+), 958 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fe11c41b..e861302c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ dunce.workspace = true itertools.workspace = true la-arena.workspace = true lsp-server = "0.7.6" -lsp-types = "0.95.0" +lspt = { version = "0.3.0", features = ["url"] } nohash-hasher.workspace = true num_cpus = "1.16.0" parking_lot = "0.12.1" diff --git a/src/config.rs b/src/config.rs index 6686ad1f..ca96a554 100644 --- a/src/config.rs +++ b/src/config.rs @@ -4,7 +4,7 @@ pub mod user_config; use std::fmt; use itertools::Itertools; -use lsp_types::ClientCapabilities; +use lspt::ClientCapabilities; use project_model::project_manifest::ProjectManifest; use utils::{ lines::PositionEncoding, @@ -77,7 +77,7 @@ impl ConfigError { pub struct Config { pub(crate) opt: Opt, pub(crate) workspace_roots: Vec, - pub(crate) client_caps: lsp_types::ClientCapabilities, + pub(crate) client_caps: lspt::ClientCapabilities, pub(crate) root_path: AbsPathBuf, pub(crate) i18n: I18n, pub(crate) user_config: UserConfig, diff --git a/src/config/caps.rs b/src/config/caps.rs index 3274dd63..3f33b03f 100644 --- a/src/config/caps.rs +++ b/src/config/caps.rs @@ -1,14 +1,12 @@ use ide::hover::HoverFormat; -use lsp_types::{ - CodeActionKind, CodeActionOptions, CodeActionProviderCapability, CodeLensOptions, - DeclarationCapability, DiagnosticOptions, DiagnosticServerCapabilities, - DocumentOnTypeFormattingOptions, FileOperationFilter, FileOperationPattern, - FileOperationPatternKind, FileOperationRegistrationOptions, InlayHintOptions, - InlayHintServerCapabilities, OneOf, PositionEncodingKind, RenameOptions, SaveOptions, - SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions, ServerCapabilities, - SignatureHelpOptions, TextDocumentSyncKind, TextDocumentSyncOptions, - WorkspaceFileOperationsServerCapabilities, WorkspaceFoldersServerCapabilities, - WorkspaceServerCapabilities, +use lspt::{ + CodeActionKind, CodeActionOptions, CodeLensOptions, DiagnosticOptions, + DocumentOnTypeFormattingOptions, FileOperationFilter, FileOperationOptions, + FileOperationPattern, FileOperationPatternKind, FileOperationRegistrationOptions, + InlayHintOptions, PositionEncodingKind, RenameOptions, SaveOptions, SemanticTokensFullDelta, + SemanticTokensLegend, SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, + TextDocumentSyncKind, TextDocumentSyncOptions, Union2, Union3, + WorkspaceFoldersServerCapabilities, WorkspaceOptions, }; use utils::{line_index::WideEncoding, lines::PositionEncoding, try_, try_or_default}; @@ -78,7 +76,7 @@ impl Config { } pub fn location_link(&self) -> bool { - try_or_default!(self.client_caps.text_document.as_ref()?.definition?.link_support?) + try_or_default!(self.client_caps.text_document.as_ref()?.definition.as_ref()?.link_support?) } pub fn cli_did_save_dyn_reg(&self) -> bool { @@ -117,7 +115,7 @@ impl Config { .text_document.as_ref()? .hover.as_ref()? .content_format.as_ref()? - .contains(&lsp_types::MarkupKind::Markdown) + .contains(&lspt::MarkupKind::Markdown) }; if support_markdown { HoverFormat::Markdown } else { HoverFormat::PlainText } @@ -145,7 +143,7 @@ impl Config { try_or_default! { self.client_caps .workspace.as_ref()? - .diagnostic.as_ref()? + .diagnostics.as_ref()? .refresh_support? } } @@ -204,9 +202,9 @@ impl Config { }; for enc in client_encodings { - if enc == &PositionEncodingKind::UTF8 { + if enc == &PositionEncodingKind::Utf8 { return PositionEncoding::Utf8; - } else if enc == &PositionEncodingKind::UTF32 { + } else if enc == &PositionEncodingKind::Utf32 { return PositionEncoding::Wide(WideEncoding::Utf32); } // NB: intentionally prefer just about anything else to utf-16. @@ -220,26 +218,24 @@ impl Config { pub fn server_caps(&self) -> ServerCapabilities { ServerCapabilities { position_encoding: match self.negotiated_encoding() { - PositionEncoding::Utf8 => Some(PositionEncodingKind::UTF8), + PositionEncoding::Utf8 => Some(PositionEncodingKind::Utf8), PositionEncoding::Wide(wide) => match wide { - WideEncoding::Utf16 => Some(PositionEncodingKind::UTF16), - WideEncoding::Utf32 => Some(PositionEncodingKind::UTF32), + WideEncoding::Utf16 => Some(PositionEncodingKind::Utf16), + WideEncoding::Utf32 => Some(PositionEncodingKind::Utf32), _ => None, }, }, - text_document_sync: Some( - TextDocumentSyncOptions { - open_close: true.into(), - change: TextDocumentSyncKind::INCREMENTAL.into(), - will_save: None, - will_save_wait_until: None, - save: Some(SaveOptions::default().into()), - } - .into(), - ), - selection_range_provider: Some(true.into()), - hover_provider: Some(true.into()), - completion_provider: Some(lsp_types::CompletionOptions { + text_document_sync: Some(Union2::A(TextDocumentSyncOptions { + open_close: Some(true), + change: Some(TextDocumentSyncKind::Incremental), + will_save: None, + will_save_wait_until: None, + save: Some(Union2::B(SaveOptions::default())), + })), + notebook_document_sync: None, + selection_range_provider: Some(Union3::A(true)), + hover_provider: Some(Union2::A(true)), + completion_provider: Some(lspt::CompletionOptions { resolve_provider: Some(false), trigger_characters: Some(vec![ ".".into(), @@ -254,121 +250,115 @@ impl Config { ]), ..Default::default() }), - signature_help_provider: SignatureHelpOptions { + signature_help_provider: Some(SignatureHelpOptions { trigger_characters: Some(["(", ",", "."].map(String::from).into()), retrigger_characters: None, - work_done_progress_options: Default::default(), - } - .into(), - declaration_provider: Some(DeclarationCapability::Simple(true)), - definition_provider: OneOf::Left(true).into(), - type_definition_provider: Some(true.into()), - implementation_provider: Some(false.into()), - references_provider: OneOf::Left(true).into(), - document_highlight_provider: OneOf::Left(true).into(), - document_symbol_provider: OneOf::Left(true).into(), - workspace_symbol_provider: OneOf::Left(true).into(), - code_action_provider: Some(CodeActionProviderCapability::Options(CodeActionOptions { + work_done_progress: Default::default(), + }), + declaration_provider: Some(Union3::A(true)), + definition_provider: Some(Union2::A(true)), + type_definition_provider: Some(Union3::A(true)), + implementation_provider: Some(Union3::A(false)), + references_provider: Some(Union2::A(true)), + document_highlight_provider: Some(Union2::A(true)), + document_symbol_provider: Some(Union2::A(true)), + workspace_symbol_provider: Some(Union2::A(true)), + code_action_provider: Some(Union2::B(CodeActionOptions { code_action_kinds: Some(vec![ - CodeActionKind::EMPTY, - CodeActionKind::QUICKFIX, - CodeActionKind::REFACTOR, - CodeActionKind::REFACTOR_EXTRACT, - CodeActionKind::REFACTOR_INLINE, - CodeActionKind::REFACTOR_REWRITE, + CodeActionKind::Empty, + CodeActionKind::QuickFix, + CodeActionKind::Refactor, + CodeActionKind::RefactorExtract, + CodeActionKind::RefactorInline, + CodeActionKind::RefactorRewrite, ]), - work_done_progress_options: Default::default(), + work_done_progress: Default::default(), resolve_provider: Some(true), })), - code_lens_provider: CodeLensOptions { resolve_provider: true.into() }.into(), - document_formatting_provider: OneOf::Left(true).into(), - document_range_formatting_provider: OneOf::Left(true).into(), - document_on_type_formatting_provider: DocumentOnTypeFormattingOptions { + code_lens_provider: Some(CodeLensOptions { + resolve_provider: Some(true), + work_done_progress: None, + }), + document_formatting_provider: Some(Union2::A(true)), + document_range_formatting_provider: Some(Union2::A(true)), + document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { first_trigger_character: "\n".to_owned(), more_trigger_character: None, - } - .into(), - rename_provider: OneOf::Right(RenameOptions { - prepare_provider: true.into(), - work_done_progress_options: Default::default(), - }) - .into(), + }), + rename_provider: Some(Union2::B(RenameOptions { + prepare_provider: Some(true), + work_done_progress: Default::default(), + })), document_link_provider: None, color_provider: None, - folding_range_provider: Some(true.into()), - execute_command_provider: Some(lsp_types::ExecuteCommandOptions { + folding_range_provider: Some(Union3::A(true)), + execute_command_provider: Some(lspt::ExecuteCommandOptions { commands: vec![ RUN_QIHE_ANALYSIS_COMMAND.to_string(), RELOAD_WORKSPACE_COMMAND.to_string(), ], - work_done_progress_options: Default::default(), + work_done_progress: Default::default(), }), - workspace: WorkspaceServerCapabilities { - workspace_folders: WorkspaceFoldersServerCapabilities { - supported: true.into(), - change_notifications: OneOf::Left(true).into(), - } - .into(), - file_operations: WorkspaceFileOperationsServerCapabilities { + workspace: Some(WorkspaceOptions { + workspace_folders: Some(WorkspaceFoldersServerCapabilities { + supported: Some(true), + change_notifications: Some(Union2::B(true)), + }), + file_operations: Some(FileOperationOptions { did_create: None, will_create: None, did_rename: None, - will_rename: FileOperationRegistrationOptions { + will_rename: Some(FileOperationRegistrationOptions { filters: vec![ FileOperationFilter { - scheme: String::from("file").into(), + scheme: Some(String::from("file")), pattern: FileOperationPattern { glob: String::from("**/*.{v,sv}"), - matches: FileOperationPatternKind::File.into(), + matches: Some(FileOperationPatternKind::File), options: None, }, }, FileOperationFilter { - scheme: String::from("file").into(), + scheme: Some(String::from("file")), pattern: FileOperationPattern { glob: String::from("**"), - matches: FileOperationPatternKind::Folder.into(), + matches: Some(FileOperationPatternKind::Folder), options: None, }, }, ], - } - .into(), + }), did_delete: None, will_delete: None, - } - .into(), - } - .into(), - call_hierarchy_provider: Some(true.into()), - semantic_tokens_provider: Some( - SemanticTokensOptions { - legend: SemanticTokensLegend { - token_types: ext::SEMA_TOKENS_TYPES.to_vec(), - token_modifiers: ext::SEMA_TOKENS_MODIFIERS.to_vec(), - }, + }), + }), + call_hierarchy_provider: Some(Union3::A(true)), + semantic_tokens_provider: Some(Union2::A(SemanticTokensOptions { + legend: SemanticTokensLegend { + token_types: ext::SEMA_TOKENS_TYPES.iter().map(|it| it.to_string()).collect(), + token_modifiers: ext::SEMA_TOKENS_MODIFIERS + .iter() + .map(|it| it.to_string()) + .collect(), + }, - full: Some(SemanticTokensFullOptions::Delta { delta: Some(true) }), - range: Some(true), - work_done_progress_options: Default::default(), - } - .into(), - ), + full: Some(Union2::B(SemanticTokensFullDelta { delta: Some(true) })), + range: Some(Union2::A(true)), + work_done_progress: Default::default(), + })), moniker_provider: None, linked_editing_range_provider: None, + type_hierarchy_provider: None, inline_value_provider: None, - inlay_hint_provider: OneOf::Right(InlayHintServerCapabilities::Options( - InlayHintOptions { - work_done_progress_options: Default::default(), - resolve_provider: false.into(), - }, - )) - .into(), - diagnostic_provider: Some(DiagnosticServerCapabilities::Options(DiagnosticOptions { + inlay_hint_provider: Some(Union3::B(InlayHintOptions { + work_done_progress: Default::default(), + resolve_provider: Some(false), + })), + diagnostic_provider: Some(Union2::A(DiagnosticOptions { identifier: None, inter_file_dependencies: true, workspace_diagnostics: true, - work_done_progress_options: Default::default(), + work_done_progress: Default::default(), })), experimental: None, } diff --git a/src/global_state.rs b/src/global_state.rs index 6e639d79..9c9bb1c5 100644 --- a/src/global_state.rs +++ b/src/global_state.rs @@ -20,7 +20,7 @@ use base_db::{ use crossbeam_channel::{Receiver, Sender, unbounded}; use ide::analysis_host::AnalysisHost; use lsp_server::{Message, ReqQueue, Request}; -use lsp_types::{TraceValue, Url}; +use lspt::{TraceValue, Uri as Url}; use nohash_hasher::IntMap; use parking_lot::{Mutex, RwLock}; use project_model::Workspace; @@ -112,8 +112,8 @@ pub(crate) struct GlobalState { pub(crate) shutdown_requested: bool, - pub(crate) semantic_tokens_cache: Arc>>, - pub(crate) diagnostics: FxHashMap>, + pub(crate) semantic_tokens_cache: Arc>>, + pub(crate) diagnostics: FxHashMap>, pub(crate) diagnostics_revision: u64, pub(crate) qihe_diagnostics: Arc>>, @@ -200,7 +200,7 @@ impl GlobalState { #[derive(Debug, Clone, Default)] pub(crate) struct QiheDiagnosticState { pub(crate) generation: u64, - pub(crate) diagnostics: Vec, + pub(crate) diagnostics: Vec, } // handle request diff --git a/src/global_state/dispatcher.rs b/src/global_state/dispatcher.rs index 20e3b644..b9e35f1e 100644 --- a/src/global_state/dispatcher.rs +++ b/src/global_state/dispatcher.rs @@ -19,18 +19,18 @@ pub(crate) struct ReqDispatcher<'a> { type FnReqSynMut = fn( &mut GlobalState, - ::Params, -) -> anyhow::Result<::Result>; + ::Params, +) -> anyhow::Result<::Result>; type FnReqSynSnap = fn( GlobalStateSnapshot, - ::Params, -) -> anyhow::Result<::Result>; + ::Params, +) -> anyhow::Result<::Result>; type FnReqErrHandler = fn(Request) -> Task; impl ReqDispatcher<'_> { fn parse(&mut self) -> Option<(Request, R::Params, String)> where - R: lsp_types::request::Request, + R: lspt::request::Request, R::Params: DeserializeOwned + fmt::Debug, { let req = match &self.req { @@ -54,7 +54,7 @@ impl ReqDispatcher<'_> { pub(crate) fn on_sync_mut(&mut self, f: FnReqSynMut) -> &mut Self where - R: lsp_types::request::Request, + R: lspt::request::Request, R::Params: DeserializeOwned + UnwindSafe + fmt::Debug, R::Result: Serialize, { @@ -76,7 +76,7 @@ impl ReqDispatcher<'_> { pub(crate) fn on_sync(&mut self, f: FnReqSynSnap) -> &mut Self where - R: lsp_types::request::Request, + R: lspt::request::Request, R::Params: DeserializeOwned + UnwindSafe + fmt::Debug, R::Result: Serialize, { @@ -100,7 +100,7 @@ impl ReqDispatcher<'_> { pub(crate) fn on_no_retry(&mut self, f: FnReqSynSnap) -> &mut Self where - R: lsp_types::request::Request + 'static, + R: lspt::request::Request + 'static, R::Params: DeserializeOwned + UnwindSafe + Send + fmt::Debug, R::Result: Serialize, { @@ -118,7 +118,7 @@ impl ReqDispatcher<'_> { f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result, ) -> &mut Self where - R: lsp_types::request::Request + 'static, + R: lspt::request::Request + 'static, R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug, R::Result: Serialize, { @@ -138,7 +138,7 @@ impl ReqDispatcher<'_> { err_handler: FnReqErrHandler, ) -> &mut Self where - R: lsp_types::request::Request + 'static, + R: lspt::request::Request + 'static, R::Params: DeserializeOwned + UnwindSafe + Send + fmt::Debug, R::Result: Serialize, { @@ -164,7 +164,7 @@ impl ReqDispatcher<'_> { pub(crate) fn on(&mut self, f: FnReqSynSnap) -> &mut Self where - R: lsp_types::request::Request + 'static, + R: lspt::request::Request + 'static, R::Params: DeserializeOwned + UnwindSafe + Send + fmt::Debug, R::Result: Serialize, { @@ -173,7 +173,7 @@ impl ReqDispatcher<'_> { pub(crate) fn on_latency_sensitive(&mut self, f: FnReqSynSnap) -> &mut Self where - R: lsp_types::request::Request + 'static, + R: lspt::request::Request + 'static, R::Params: DeserializeOwned + UnwindSafe + Send + fmt::Debug, R::Result: Serialize, { @@ -201,7 +201,7 @@ fn result_to_response( result: anyhow::Result, ) -> Result where - R: lsp_types::request::Request, + R: lspt::request::Request, R::Params: DeserializeOwned, R::Result: Serialize, { @@ -227,7 +227,7 @@ fn thread_result_to_response( result: thread::Result>, ) -> Result where - R: lsp_types::request::Request, + R: lspt::request::Request, R::Params: DeserializeOwned, R::Result: Serialize, { @@ -255,15 +255,13 @@ pub(crate) struct NotifDispatcher<'a> { pub(crate) global_state: &'a mut GlobalState, } -type FnNotifSynMut = fn( - &mut GlobalState, - ::Params, -) -> anyhow::Result<()>; +type FnNotifSynMut = + fn(&mut GlobalState, ::Params) -> anyhow::Result<()>; impl NotifDispatcher<'_> { pub(crate) fn on_sync_mut(&mut self, f: FnNotifSynMut) -> &mut Self where - N: lsp_types::notification::Notification, + N: lspt::notification::Notification, N::Params: DeserializeOwned + Send, { let notif = match self.notif.take() { diff --git a/src/global_state/handlers/notification.rs b/src/global_state/handlers/notification.rs index e801a010..26dfcb54 100644 --- a/src/global_state/handlers/notification.rs +++ b/src/global_state/handlers/notification.rs @@ -1,6 +1,6 @@ use std::ops::Range; -use lsp_types::{ +use lspt::{ DidChangeConfigurationParams, DidChangeTextDocumentParams, DidChangeWatchedFilesParams, DidChangeWorkspaceFoldersParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams, @@ -22,11 +22,11 @@ use crate::{ pub(crate) fn handle_cancel( state: &mut GlobalState, - params: lsp_types::CancelParams, + params: lspt::CancelParams, ) -> anyhow::Result<()> { let id: lsp_server::RequestId = match params.id { - lsp_types::NumberOrString::Number(id) => id.into(), - lsp_types::NumberOrString::String(id) => id.into(), + lspt::Union2::A(id) => id.into(), + lspt::Union2::B(id) => id.into(), }; state.cancel(id); Ok(()) @@ -124,9 +124,9 @@ pub(crate) fn handle_did_change_configuration( // this notification's parameters should be ignored and the actual config queried separately. _params: DidChangeConfigurationParams, ) -> anyhow::Result<()> { - state.send_request::( - lsp_types::ConfigurationParams { - items: vec![lsp_types::ConfigurationItem { + state.send_request::( + lspt::ConfigurationParams { + items: vec![lspt::ConfigurationItem { scope_uri: None, section: Some(DEFAULT_PROCESS_NAME.into()), }], @@ -188,10 +188,8 @@ pub(crate) fn handle_did_change_watched_files( for change in params.changes { if let Ok(path) = from_proto::abs_path(&change.uri) { - if reload::should_refresh_for_change( - &path, - change.typ != lsp_types::FileChangeType::CHANGED, - ) { + if reload::should_refresh_for_change(&path, change.ty != lspt::FileChangeType::Changed) + { workspace_structure_change.get_or_insert(path); continue; } @@ -212,7 +210,7 @@ pub(crate) fn handle_did_change_watched_files( pub(crate) fn handle_set_trace( state: &mut GlobalState, - params: lsp_types::SetTraceParams, + params: lspt::SetTraceParams, ) -> anyhow::Result<()> { state.set_lsp_trace(params.value); Ok(()) @@ -232,7 +230,7 @@ fn set_vfs_file_contents( fn update_document_text( encoding: PositionEncoding, data: &mut String, - content_changes: Vec, + content_changes: Vec, ) -> Option { let text = apply_document_changes(encoding, data, content_changes); @@ -247,16 +245,19 @@ fn update_document_text( fn apply_document_changes( encoding: PositionEncoding, file_contents: &str, - content_changes: Vec, + content_changes: Vec, ) -> String { // Skip to the last full document change and peek at the first content change let (mut text, content_changes) = { - match content_changes.iter().rposition(|change| change.range.is_none()) { + match content_changes.iter().rposition(|change| matches!(change, lspt::Union2::B(_))) { Some(idx) => { let (full_doc_changes, rest) = content_changes.split_at(idx + 1); match full_doc_changes.last() { - Some(full_doc_change) => (full_doc_change.text.clone(), rest), + Some(lspt::Union2::B(full_doc_change)) => (full_doc_change.text.clone(), rest), None => (file_contents.to_owned(), rest), + Some(lspt::Union2::A(_)) => { + unreachable!("rposition selected a whole document change") + } } } None => (file_contents.to_owned(), &content_changes[..]), @@ -281,18 +282,21 @@ fn apply_document_changes( // set to infinity at first, to avoid rebuilding the index on the first change let mut index_valid_until = !0u32; for change in content_changes { - let Some(range) = change.range else { - text = change.text.clone(); - *Arc::make_mut(&mut line_info.index) = LineIndex::new(&text); - index_valid_until = !0u32; - continue; + let (range, change_text) = match change { + lspt::Union2::A(change) => (change.range, &change.text), + lspt::Union2::B(change) => { + text = change.text.clone(); + *Arc::make_mut(&mut line_info.index) = LineIndex::new(&text); + index_valid_until = !0u32; + continue; + } }; if index_valid_until <= range.end.line { *Arc::make_mut(&mut line_info.index) = LineIndex::new(&text); } index_valid_until = range.start.line; if let Ok(range) = from_proto::text_range(&line_info, range) { - text.replace_range(Range::::from(range), &change.text); + text.replace_range(Range::::from(range), change_text); } } text @@ -303,9 +307,9 @@ mod tests { use std::time::Duration; use lsp_server::Connection; - use lsp_types::{ - DidChangeWatchedFilesParams, FileChangeType, FileEvent, SetTraceParams, - TextDocumentContentChangeEvent, TraceValue, Url, + use lspt::{ + DidChangeWatchedFilesParams, FileChangeType, FileEvent, SetTraceParams, TraceValue, + Uri as Url, }; use project_model::project_manifest; use utils::{lines::PositionEncoding, paths::AbsPathBuf, test_support::TestDir}; @@ -331,7 +335,7 @@ mod tests { log_filename: None, }, root_path.clone(), - lsp_types::ClientCapabilities::default(), + lspt::ClientCapabilities::default(), vec![root_path], I18n::default(), UserConfig::default(), @@ -348,11 +352,9 @@ mod tests { let vfs_text = update_document_text( PositionEncoding::Utf8, &mut text, - vec![TextDocumentContentChangeEvent { - range: None, - range_length: None, + vec![lspt::Union2::B(lspt::TextDocumentContentChangeWholeDocument { text: String::new(), - }], + })], ); assert_eq!(text, ""); @@ -365,11 +367,9 @@ mod tests { let vfs_text = update_document_text( PositionEncoding::Utf8, &mut text, - vec![TextDocumentContentChangeEvent { - range: None, - range_length: None, + vec![lspt::Union2::B(lspt::TextDocumentContentChangeWholeDocument { text: "module top;\nendmodule\n".to_owned(), - }], + })], ); assert_eq!(text, "module top;\nendmodule\n"); @@ -396,7 +396,7 @@ mod tests { handle_did_change_watched_files( &mut state, DidChangeWatchedFilesParams { - changes: vec![FileEvent::new(manifest_uri, FileChangeType::DELETED)], + changes: vec![FileEvent { uri: manifest_uri, ty: FileChangeType::Deleted }], }, ) .unwrap(); diff --git a/src/global_state/handlers/request.rs b/src/global_state/handlers/request.rs index 704b22cd..54304679 100644 --- a/src/global_state/handlers/request.rs +++ b/src/global_state/handlers/request.rs @@ -20,26 +20,24 @@ pub(crate) use code_action::{handle_code_action, handle_code_action_resolve}; pub(crate) fn handle_goto_definition( snap: GlobalStateSnapshot, - params: lsp_types::GotoDefinitionParams, -) -> anyhow::Result> { - let position = from_proto::file_position(&snap, params.text_document_position_params)?; + params: lspt::DefinitionParams, +) -> anyhow::Result<::Result> { + let position = from_proto::file_position(&snap, params.text_document, params.position)?; let Some(nav_info) = snap.analysis.goto_definition(position)? else { return Ok(None); }; let src = FileRange { file_id: position.file_id, range: nav_info.range }; - let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; - Ok(Some(res)) + to_proto::goto_definition_response(&snap, Some(src), nav_info.info) } pub(crate) fn handle_completion( snap: GlobalStateSnapshot, - params: lsp_types::CompletionParams, -) -> anyhow::Result> { + params: lspt::CompletionParams, +) -> anyhow::Result<::Result> { use ide::completion::{CompletionItemKind as IdeCompletionItemKind, context::TriggerChar}; - use lsp_types::CompletionTextEdit; - let position = from_proto::file_position(&snap, params.text_document_position)?; + let position = from_proto::file_position(&snap, params.text_document, params.position)?; let line_info = snap.line_info(position.file_id)?; let trigger = params @@ -68,7 +66,7 @@ pub(crate) fn handle_completion( let sort_text = item.sort_text(); let (edit, insert_text_format) = if snippet_support { match (item.snippet_edit, item.edit) { - (Some(edit), _) => Some((edit, Some(lsp_types::InsertTextFormat::SNIPPET))), + (Some(edit), _) => Some((edit, Some(lspt::InsertTextFormat::Snippet))), (None, Some(edit)) => Some((edit, None)), (None, None) => None, } @@ -77,52 +75,55 @@ pub(crate) fn handle_completion( }?; let kind = match item.kind { - IdeCompletionItemKind::Text => lsp_types::CompletionItemKind::TEXT, - IdeCompletionItemKind::Keyword => lsp_types::CompletionItemKind::KEYWORD, - IdeCompletionItemKind::Snippet => lsp_types::CompletionItemKind::SNIPPET, + IdeCompletionItemKind::Text => lspt::CompletionItemKind::Text, + IdeCompletionItemKind::Keyword => lspt::CompletionItemKind::Keyword, + IdeCompletionItemKind::Snippet => lspt::CompletionItemKind::Snippet, }; - Some(lsp_types::CompletionItem { + Some(lspt::CompletionItem { label: item.label, kind: Some(kind), sort_text: Some(sort_text), insert_text_format, - text_edit: Some(CompletionTextEdit::Edit(to_proto::text_edit(&line_info, edit))), + text_edit: Some(lspt::Union2::A(to_proto::text_edit(&line_info, edit))), ..Default::default() }) }) .collect(); - Ok(Some(lsp_types::CompletionResponse::Array(items))) + Ok(Some(lspt::Union2::A(items))) } pub(crate) fn handle_goto_declaration( snap: GlobalStateSnapshot, - params: lsp_types::request::GotoDeclarationParams, -) -> anyhow::Result> { - let position = from_proto::file_position(&snap, params.text_document_position_params.clone())?; + params: lspt::DeclarationParams, +) -> anyhow::Result<::Result> { + let position = from_proto::file_position(&snap, params.text_document, params.position)?; let Some(nav_info) = snap.analysis.goto_declaration(position)? else { - return handle_goto_definition(snap, params); + return Ok(None); }; let src = FileRange { file_id: position.file_id, range: nav_info.range }; - let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; - Ok(Some(res)) + to_proto::goto_definition_response(&snap, Some(src), nav_info.info) } pub(crate) fn handle_document_diagnostic( snap: GlobalStateSnapshot, - params: lsp_types::DocumentDiagnosticParams, -) -> anyhow::Result { + params: lspt::DocumentDiagnosticParams, +) -> anyhow::Result<::Result> { let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let result_id = snap.diagnostic_result_id(file_id); let items = snap.lsp_diagnostics(file_id); - Ok(document_diagnostic_report(result_id, items, params.previous_result_id.as_deref()).into()) + Ok(lspt::Union2::A(document_diagnostic_report( + result_id, + items, + params.previous_result_id.as_deref(), + ))) } pub(crate) fn handle_workspace_diagnostic( snap: GlobalStateSnapshot, - params: lsp_types::WorkspaceDiagnosticParams, -) -> anyhow::Result { + params: lspt::WorkspaceDiagnosticParams, +) -> anyhow::Result<::Result> { let previous_result_ids = params .previous_result_ids .into_iter() @@ -182,7 +183,7 @@ pub(crate) fn handle_workspace_diagnostic( diag_items.extend(snap.qihe_diagnostics(file_id)); let result_id = snap.diagnostic_result_id(file_id); - let version = snap.file_version(file_id).map(|version| version as i64); + let version = snap.file_version(file_id); let previous_result_id = previous_result_ids.get(&uri).map(String::as_str); items.push(workspace_diagnostic_report( @@ -202,44 +203,43 @@ pub(crate) fn handle_workspace_diagnostic( items.push(workspace_diagnostic_report(uri, None, None, Vec::new(), None)); } - Ok(lsp_types::WorkspaceDiagnosticReportResult::Report(lsp_types::WorkspaceDiagnosticReport { - items, - })) + Ok(lspt::Union2::A(lspt::WorkspaceDiagnosticReport { items })) } fn document_diagnostic_report( result_id: Option, - items: Vec, + items: Vec, previous_result_id: Option<&str>, -) -> lsp_types::DocumentDiagnosticReport { +) -> lspt::DocumentDiagnosticReport { if let Some(result_id) = result_id.as_ref() && Some(result_id.as_str()) == previous_result_id { - return lsp_types::DocumentDiagnosticReport::Unchanged( - lsp_types::RelatedUnchangedDocumentDiagnosticReport { - related_documents: None, - unchanged_document_diagnostic_report: - lsp_types::UnchangedDocumentDiagnosticReport { result_id: result_id.clone() }, - }, - ); + return lspt::Union2::B(lspt::RelatedUnchangedDocumentDiagnosticReport { + kind: "unchanged".to_owned(), + result_id: result_id.clone(), + related_documents: None, + }); } - lsp_types::DocumentDiagnosticReport::Full(lsp_types::RelatedFullDocumentDiagnosticReport { + lspt::Union2::A(lspt::RelatedFullDocumentDiagnosticReport { + kind: "full".to_owned(), + result_id: result_id.clone(), + items, related_documents: None, - full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport { - result_id: result_id.clone(), - items, - }, }) } fn handle_qihe_analysis_command( state: &mut crate::global_state::GlobalState, - params: lsp_types::ExecuteCommandParams, + params: lspt::ExecuteCommandParams, ) -> anyhow::Result> { - let args = params.arguments.first().cloned().ok_or_else(|| { - anyhow::format_err!("{}", state.config.i18n.text(keys::EXECUTE_COMMAND_MISSING_ARGUMENTS)) - })?; + let args = + params.arguments.as_ref().and_then(|args| args.first()).cloned().ok_or_else(|| { + anyhow::format_err!( + "{}", + state.config.i18n.text(keys::EXECUTE_COMMAND_MISSING_ARGUMENTS) + ) + })?; let params = serde_json::from_value::(args)?; state.spawn_qihe_analysis(params); Ok(None) @@ -256,7 +256,7 @@ fn handle_reload_workspace_command( pub(crate) fn handle_execute_command( state: &mut crate::global_state::GlobalState, - params: lsp_types::ExecuteCommandParams, + params: lspt::ExecuteCommandParams, ) -> anyhow::Result> { match params.command.as_str() { RUN_QIHE_ANALYSIS_COMMAND => handle_qihe_analysis_command(state, params), @@ -272,58 +272,53 @@ pub(crate) fn handle_execute_command( } fn workspace_diagnostic_report( - uri: lsp_types::Url, - version: Option, + uri: lspt::Uri, + version: Option, result_id: Option, - items: Vec, + items: Vec, previous_result_id: Option<&str>, -) -> lsp_types::WorkspaceDocumentDiagnosticReport { +) -> lspt::WorkspaceDocumentDiagnosticReport { if let Some(result_id) = result_id.as_ref() && Some(result_id.as_str()) == previous_result_id { - return lsp_types::WorkspaceDocumentDiagnosticReport::Unchanged( - lsp_types::WorkspaceUnchangedDocumentDiagnosticReport { - uri, - version, - unchanged_document_diagnostic_report: - lsp_types::UnchangedDocumentDiagnosticReport { result_id: result_id.clone() }, - }, - ); - } - - lsp_types::WorkspaceDocumentDiagnosticReport::Full( - lsp_types::WorkspaceFullDocumentDiagnosticReport { + return lspt::Union2::B(lspt::WorkspaceUnchangedDocumentDiagnosticReport { + kind: "unchanged".to_owned(), + result_id: result_id.clone(), uri, version, - full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport { - result_id: result_id.clone(), - items, - }, - }, - ) + }); + } + + lspt::Union2::A(lspt::WorkspaceFullDocumentDiagnosticReport { + kind: "full".to_owned(), + result_id: result_id.clone(), + items, + uri, + version, + }) } pub(crate) fn handle_document_symbol( snap: GlobalStateSnapshot, - params: lsp_types::DocumentSymbolParams, -) -> anyhow::Result> { + params: lspt::DocumentSymbolParams, +) -> anyhow::Result<::Result> { let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_info = snap.line_info(file_id)?; let symbols = snap.analysis.document_symbol(file_id)?; let res = if snap.config.hierarchical_symbols() { - symbols + let res = symbols .into_iter() .map(|symbol| to_proto::document_symbol(&line_info, symbol)) - .collect_vec() - .into() + .collect_vec(); + lspt::Union2::B(res) } else { let mut res = Vec::new(); let url = to_proto::url(&snap, file_id)?; symbols.into_iter().for_each(|symbol| { to_proto::document_symbol_information(symbol, url.clone(), &line_info, &mut res); }); - res.into() + lspt::Union2::A(res) }; Ok(Some(res)) @@ -331,9 +326,9 @@ pub(crate) fn handle_document_symbol( pub(crate) fn handle_document_highlight( snap: GlobalStateSnapshot, - params: lsp_types::DocumentHighlightParams, -) -> anyhow::Result>> { - let position = from_proto::file_position(&snap, params.text_document_position_params)?; + params: lspt::DocumentHighlightParams, +) -> anyhow::Result>> { + let position = from_proto::file_position(&snap, params.text_document, params.position)?; let line_info = snap.line_info(position.file_id)?; let config = snap.config.document_highlight(); let Some(highlights) = snap.analysis.document_highlight(position, config)? else { @@ -349,9 +344,9 @@ pub(crate) fn handle_document_highlight( pub(crate) fn handle_references( snap: GlobalStateSnapshot, - params: lsp_types::ReferenceParams, -) -> anyhow::Result>> { - let position = from_proto::file_position(&snap, params.text_document_position)?; + params: lspt::ReferenceParams, +) -> anyhow::Result>> { + let position = from_proto::file_position(&snap, params.text_document, params.position)?; let config = snap.config.references(); let Some(refs) = snap.analysis.references(position, config)? else { return Ok(None); @@ -380,9 +375,9 @@ pub(crate) fn handle_references( pub(crate) fn handle_prepare_rename( snap: GlobalStateSnapshot, - params: lsp_types::TextDocumentPositionParams, -) -> anyhow::Result> { - let position = from_proto::file_position(&snap, params)?; + params: lspt::PrepareRenameParams, +) -> anyhow::Result> { + let position = from_proto::file_position(&snap, params.text_document, params.position)?; if !snap.file_allows_workspace_edits(position.file_id) { return Ok(None); } @@ -393,14 +388,14 @@ pub(crate) fn handle_prepare_rename( .prepare_rename(position)? .map_err(|err| to_proto::rename_error(snap.config.i18n, err))?; let range = to_proto::range(&line_index, text_range); - Ok(Some(lsp_types::PrepareRenameResponse::Range(range))) + Ok(Some(lspt::Union3::A(range))) } pub(crate) fn handle_rename( snap: GlobalStateSnapshot, - params: lsp_types::RenameParams, -) -> anyhow::Result> { - let position = from_proto::file_position(&snap, params.text_document_position)?; + params: lspt::RenameParams, +) -> anyhow::Result> { + let position = from_proto::file_position(&snap, params.text_document, params.position)?; if !snap.file_allows_workspace_edits(position.file_id) { return Ok(None); } @@ -416,8 +411,8 @@ pub(crate) fn handle_rename( pub(crate) fn handle_formatting( snap: GlobalStateSnapshot, - params: lsp_types::DocumentFormattingParams, -) -> anyhow::Result>> { + params: lspt::DocumentFormattingParams, +) -> anyhow::Result>> { let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_info = snap.line_info(file_id)?; @@ -431,8 +426,8 @@ pub(crate) fn handle_formatting( pub(crate) fn handle_range_formatting( snap: GlobalStateSnapshot, - params: lsp_types::DocumentRangeFormattingParams, -) -> anyhow::Result>> { + params: lspt::DocumentRangeFormattingParams, +) -> anyhow::Result>> { let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_info = snap.line_info(file_id)?; let line_ranges = @@ -450,9 +445,9 @@ pub(crate) fn handle_range_formatting( pub(crate) fn handle_on_type_formatting( snap: GlobalStateSnapshot, - params: lsp_types::DocumentOnTypeFormattingParams, -) -> anyhow::Result>> { - let position = from_proto::file_position(&snap, params.text_document_position)?; + params: lspt::DocumentOnTypeFormattingParams, +) -> anyhow::Result>> { + let position = from_proto::file_position(&snap, params.text_document, params.position)?; let line_info = snap.line_info(position.file_id)?; let config = formatting_config(&snap, ¶ms.options); @@ -467,7 +462,7 @@ pub(crate) fn handle_on_type_formatting( fn formatting_config( snap: &GlobalStateSnapshot, - options: &lsp_types::FormattingOptions, + options: &lspt::FormattingOptions, ) -> ide::formatting::FmtConfig { let mut config = snap.config.fmt(); config.apply_editor_options(options.tab_size, options.insert_spaces); @@ -476,8 +471,8 @@ fn formatting_config( pub(crate) fn handle_selection_range( snap: GlobalStateSnapshot, - params: lsp_types::SelectionRangeParams, -) -> anyhow::Result>> { + params: lspt::SelectionRangeParams, +) -> anyhow::Result>> { let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_info = snap.line_info(file_id)?; @@ -488,7 +483,7 @@ pub(crate) fn handle_selection_range( let offset = from_proto::offset(&line_info, pos)?; let ranges = snap.analysis.selection_ranges(FilePosition { file_id, offset })?; Ok(to_proto::selection_ranges(&line_info, ranges).unwrap_or_else(|| { - lsp_types::SelectionRange { + lspt::SelectionRange { range: to_proto::range(&line_info, TextRange::empty(offset)), parent: None, } @@ -501,8 +496,8 @@ pub(crate) fn handle_selection_range( pub(crate) fn handle_folding_ranges( snap: GlobalStateSnapshot, - params: lsp_types::FoldingRangeParams, -) -> anyhow::Result>> { + params: lspt::FoldingRangeParams, +) -> anyhow::Result>> { let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let config = FoldingConfig { line_fold_only: snap.config.cli_line_folding_only() }; let text = snap.file_text(file_id)?; @@ -520,9 +515,9 @@ pub(crate) fn handle_folding_ranges( pub(crate) fn handle_hover( snap: GlobalStateSnapshot, - params: lsp_types::HoverParams, -) -> anyhow::Result> { - let position = from_proto::file_position(&snap, params.text_document_position_params)?; + params: lspt::HoverParams, +) -> anyhow::Result> { + let position = from_proto::file_position(&snap, params.text_document, params.position)?; let config = snap.config.hover(); let hover_format = config.format; @@ -533,7 +528,7 @@ pub(crate) fn handle_hover( let line_info = snap.line_info(position.file_id)?; let range = to_proto::range(&line_info, hover_info.range); - let res = lsp_types::Hover { + let res = lspt::Hover { contents: to_proto::hover_contents(hover_info.info, hover_format), range: Some(range), }; @@ -543,8 +538,8 @@ pub(crate) fn handle_hover( pub(crate) fn handle_inlay_hint( snap: GlobalStateSnapshot, - params: lsp_types::InlayHintParams, -) -> anyhow::Result>> { + params: lspt::InlayHintParams, +) -> anyhow::Result>> { let FileRange { file_id, range } = from_proto::file_range(&snap, ¶ms.text_document.uri, params.range)?; @@ -567,8 +562,8 @@ pub(crate) fn handle_inlay_hint( pub(crate) fn handle_code_lens( snap: GlobalStateSnapshot, - params: lsp_types::CodeLensParams, -) -> anyhow::Result>> { + params: lspt::CodeLensParams, +) -> anyhow::Result>> { let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_info = snap.line_info(file_id)?; let config = snap.config.code_lens(); @@ -585,8 +580,8 @@ pub(crate) fn handle_code_lens( pub(crate) fn handle_code_lens_resolve( snap: GlobalStateSnapshot, - mut code_lens: lsp_types::CodeLens, -) -> anyhow::Result { + mut code_lens: lspt::CodeLens, +) -> anyhow::Result { let Some(data) = code_lens.data.take() else { return Ok(code_lens); }; @@ -596,59 +591,58 @@ pub(crate) fn handle_code_lens_resolve( let line_info = snap.line_info(file_id)?; let (command, data) = to_proto::code_lens_kind(&snap, file_id, &line_info, code_lens_kind)?; - let res = lsp_types::CodeLens { range: code_lens.range, command, data }; + let res = lspt::CodeLens { range: code_lens.range, command, data }; Ok(res) } pub(crate) fn handle_semantic_tokens_full( snap: GlobalStateSnapshot, - params: lsp_types::SemanticTokensParams, -) -> anyhow::Result> { + params: lspt::SemanticTokensParams, +) -> anyhow::Result<::Result> { let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let res = compute_sema_tokens_helper(&snap, file_id, None)?; snap.sema_tokens_cache.lock().insert(params.text_document.uri, res.clone()); - Ok(Some(res.into())) + Ok(Some(lspt::Union2::A(res))) } pub(crate) fn handle_semantic_tokens_full_delta( snap: GlobalStateSnapshot, - params: lsp_types::SemanticTokensDeltaParams, -) -> anyhow::Result> { + params: lspt::SemanticTokensDeltaParams, +) -> anyhow::Result<::Result> { let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let res = compute_sema_tokens_helper(&snap, file_id, None)?; let old_tokens = snap.sema_tokens_cache.lock().remove(¶ms.text_document.uri); - if let Some(old_tokens @ lsp_types::SemanticTokens { result_id: Some(prev_id), .. }) = - &old_tokens + if let Some(old_tokens @ lspt::SemanticTokens { result_id: Some(prev_id), .. }) = &old_tokens && *prev_id == params.previous_result_id { let delta = to_proto::semantic_token_delta(old_tokens, &res); snap.sema_tokens_cache.lock().insert(params.text_document.uri, res); - Ok(Some(delta.into())) + Ok(Some(lspt::Union4::B(delta))) } else { // Clone first to keep the lock short let semantic_tokens_clone = res.clone(); snap.sema_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens_clone); - Ok(Some(res.into())) + Ok(Some(lspt::Union4::A(res))) } } pub(crate) fn handle_semantic_tokens_range( snap: GlobalStateSnapshot, - params: lsp_types::SemanticTokensRangeParams, -) -> anyhow::Result> { + params: lspt::SemanticTokensRangeParams, +) -> anyhow::Result<::Result> { let FileRange { file_id, range } = from_proto::file_range(&snap, ¶ms.text_document.uri, params.range)?; let res = compute_sema_tokens_helper(&snap, file_id, Some(range))?; - Ok(Some(res.into())) + Ok(Some(lspt::Union2::A(res))) } fn compute_sema_tokens_helper( snap: &GlobalStateSnapshot, file_id: FileId, range: Option, -) -> anyhow::Result { +) -> anyhow::Result { let text = snap.analysis.file_text(file_id)?; let line_info = snap.line_info(file_id)?; let config = snap.config.semantic_tokens(); @@ -660,9 +654,9 @@ fn compute_sema_tokens_helper( pub(crate) fn handle_signature_help( snap: GlobalStateSnapshot, - params: lsp_types::SignatureHelpParams, -) -> anyhow::Result> { - let position = from_proto::file_position(&snap, params.text_document_position_params)?; + params: lspt::SignatureHelpParams, +) -> anyhow::Result> { + let position = from_proto::file_position(&snap, params.text_document, params.position)?; let config = snap.config.signature_help(); let Some(res) = snap.analysis.signature_help(position, config)? else { return Ok(None); @@ -675,10 +669,7 @@ pub(crate) fn handle_signature_help( #[cfg(test)] mod tests { - use lsp_types::{ - DocumentDiagnosticReport, UnchangedDocumentDiagnosticReport, Url, - WorkspaceDocumentDiagnosticReport, - }; + use lspt::{DocumentDiagnosticReport, Uri as Url, WorkspaceDocumentDiagnosticReport}; use super::{document_diagnostic_report, workspace_diagnostic_report}; @@ -694,11 +685,11 @@ mod tests { ); match report { - WorkspaceDocumentDiagnosticReport::Full(report) => { + WorkspaceDocumentDiagnosticReport::A(report) => { assert_eq!(report.uri, uri); assert_eq!(report.version, Some(3)); - assert_eq!(report.full_document_diagnostic_report.result_id.as_deref(), Some("4")); - assert!(report.full_document_diagnostic_report.items.is_empty()); + assert_eq!(report.result_id.as_deref(), Some("4")); + assert!(report.items.is_empty()); } other => panic!("expected full report, got {other:?}"), } @@ -716,10 +707,10 @@ mod tests { ); match report { - WorkspaceDocumentDiagnosticReport::Unchanged(report) => { + WorkspaceDocumentDiagnosticReport::B(report) => { assert_eq!(report.uri, uri); assert_eq!(report.version, Some(5)); - assert_eq!(report.unchanged_document_diagnostic_report.result_id, "5"); + assert_eq!(report.result_id, "5"); } other => panic!("expected unchanged report, got {other:?}"), } @@ -729,10 +720,10 @@ mod tests { let report = document_diagnostic_report(Some("7".to_string()), Vec::new(), Some("7")); match report { - DocumentDiagnosticReport::Unchanged(report) => assert_eq!( - report.unchanged_document_diagnostic_report, - UnchangedDocumentDiagnosticReport { result_id: "7".to_string() } - ), + DocumentDiagnosticReport::B(report) => { + assert_eq!(report.kind, "unchanged"); + assert_eq!(report.result_id, "7"); + } other => panic!("expected unchanged report, got {other:?}"), } } diff --git a/src/global_state/handlers/request/code_action.rs b/src/global_state/handlers/request/code_action.rs index 73aad253..40ce711f 100644 --- a/src/global_state/handlers/request/code_action.rs +++ b/src/global_state/handlers/request/code_action.rs @@ -16,8 +16,8 @@ use crate::{ pub(crate) fn handle_code_action( snap: GlobalStateSnapshot, - params: lsp_types::CodeActionParams, -) -> anyhow::Result>> { + params: lspt::CodeActionParams, +) -> anyhow::Result<::Result> { if !snap.config.cli_code_action_literals() { return Ok(None); } @@ -60,7 +60,7 @@ pub(crate) fn handle_code_action( None }; let code_action = to_proto::code_action(&snap, assist, resolve_data, action_diags)?; - res.push(lsp_types::CodeActionOrCommand::CodeAction(code_action)) + res.push(lspt::Union2::B(code_action)) } Ok(Some(res)) @@ -88,7 +88,7 @@ fn server_diagnostics_for_code_action( snap: &GlobalStateSnapshot, file_id: FileId, range: TextRange, - client_diagnostics: &[lsp_types::Diagnostic], + client_diagnostics: &[lspt::Diagnostic], line_info: &utils::lines::LineInfo, ) -> anyhow::Result> { let server_diagnostics = snap.diagnostics(file_id)?; @@ -126,7 +126,7 @@ impl DiagnosticLocator { Self { range: diag.range, code: format!("{}:{}", diag.subsystem, diag.code) } } - fn from_lsp(line_info: &utils::lines::LineInfo, diag: &lsp_types::Diagnostic) -> Option { + fn from_lsp(line_info: &utils::lines::LineInfo, diag: &lspt::Diagnostic) -> Option { if diag.source.as_deref() != Some("slang") { return None; } @@ -138,10 +138,10 @@ impl DiagnosticLocator { } } -fn diagnostic_code_string(code: &lsp_types::NumberOrString) -> String { +fn diagnostic_code_string(code: &lspt::Union2) -> String { match code { - lsp_types::NumberOrString::Number(code) => code.to_string(), - lsp_types::NumberOrString::String(code) => code.clone(), + lspt::Union2::A(code) => code.to_string(), + lspt::Union2::B(code) => code.clone(), } } @@ -186,8 +186,8 @@ fn code_action_diagnostic_from_ide(diag: &ide_diagnostics::Diagnostic) -> CodeAc pub(crate) fn handle_code_action_resolve( snap: GlobalStateSnapshot, - mut code_action: lsp_types::CodeAction, -) -> anyhow::Result { + mut code_action: lspt::CodeAction, +) -> anyhow::Result { let data = from_proto::code_action_data( code_action.data.replace(Default::default()).ok_or_else(|| { to_proto::code_action_resolve_error(snap.config.i18n, CodeActionResolveError::NoData) @@ -258,7 +258,7 @@ mod tests { code_action::RepairKind, diagnostics::{Diagnostic as IdeDiagnostic, DiagnosticSource as IdeDiagnosticSource}, }; - use lsp_types::{Diagnostic as LspDiagnostic, NumberOrString, Position, Range}; + use lspt::{Diagnostic as LspDiagnostic, Position, Range, Union2}; use syntax::DiagnosticSeverity; use triomphe::Arc; use utils::{ @@ -333,11 +333,14 @@ mod tests { ending: LineEnding::Unix, encoding: PositionEncoding::Utf8, }; - let range = Range::new(Position::new(0, 6), Position::new(0, 6)); + let range = Range { + start: Position { line: 0, character: 6 }, + end: Position { line: 0, character: 6 }, + }; let lsp_diag = LspDiagnostic { range, severity: None, - code: Some(NumberOrString::String("6:129".to_owned())), + code: Some(Union2::B("6:129".to_owned())), code_description: None, source: Some("slang".to_owned()), message: "mixing ordered and named port connections is not allowed".to_owned(), diff --git a/src/global_state/main_loop.rs b/src/global_state/main_loop.rs index 40be38fa..9afe9bff 100644 --- a/src/global_state/main_loop.rs +++ b/src/global_state/main_loop.rs @@ -3,7 +3,7 @@ use std::time::{Duration, Instant}; use always_assert::always; use crossbeam_channel::{Receiver, select}; use lsp_server::{Connection, Message, Notification, Request, Response}; -use lsp_types::{TraceValue, notification::Notification as _}; +use lspt::{TraceValue, notification::Notification as _}; use project_model::project_manifest; use triomphe::Arc; use utils::thread::ThreadIntent; @@ -29,9 +29,9 @@ enum Event { #[derive(Debug)] pub(crate) struct PublishDiagnosticsTask { pub(crate) file_id: FileId, - pub(crate) uri: lsp_types::Url, + pub(crate) uri: lspt::Uri, pub(crate) version: Option, - pub(crate) diagnostics: Vec, + pub(crate) diagnostics: Vec, } #[derive(Debug)] @@ -69,6 +69,14 @@ pub fn main_loop( GlobalState::new(connection.sender, config, initial_trace).run(connection.receiver) } +fn document_filter(pattern: impl Into) -> lspt::DocumentFilter { + lspt::Union2::A(lspt::Union3::C(lspt::TextDocumentFilterPattern { + language: None, + scheme: None, + pattern: lspt::Union2::A(pattern.into()), + })) +} + impl GlobalState { pub(crate) fn run(&mut self, client_receiver: Receiver) -> anyhow::Result<()> { // TODO: check for status @@ -84,7 +92,7 @@ impl GlobalState { while let Some(event) = self.next_event(&client_receiver) { if let Event::Lsp(Message::Notification(Notification { method, .. })) = &event - && method == lsp_types::notification::Exit::METHOD + && method == lspt::notification::ExitNotification::METHOD { return Ok(()); } @@ -94,27 +102,19 @@ impl GlobalState { } fn register_did_save_cap(&mut self) { - let mut document_selector = vec![lsp_types::DocumentFilter { - language: None, - scheme: None, - pattern: Some("**/*.{v,sv,vh,svh,svi}".into()), - }]; - document_selector.extend(project_manifest::MANIFEST_FILE_NAMES.iter().map(|file_name| { - lsp_types::DocumentFilter { - language: None, - scheme: None, - pattern: Some(format!("**/{file_name}")), - } - })); + let mut document_selector = vec![document_filter("**/*.{v,sv,vh,svh,svi}")]; + document_selector.extend( + project_manifest::MANIFEST_FILE_NAMES + .iter() + .map(|file_name| document_filter(format!("**/{file_name}"))), + ); - let save_registration_options = lsp_types::TextDocumentSaveRegistrationOptions { - include_text: false.into(), - text_document_registration_options: lsp_types::TextDocumentRegistrationOptions { - document_selector: document_selector.into(), - }, + let save_registration_options = lspt::TextDocumentSaveRegistrationOptions { + document_selector: Some(document_selector), + include_text: Some(false), }; - let registration = lsp_types::Registration { + let registration = lspt::Registration { id: "textDocument/didSave".into(), method: "textDocument/didSave".into(), register_options: match serde_json::to_value(save_registration_options) { @@ -125,8 +125,8 @@ impl GlobalState { } }, }; - self.send_request::( - lsp_types::RegistrationParams { registrations: vec![registration] }, + self.send_request::( + lspt::RegistrationParams { registrations: vec![registration] }, DEFAULT_REQ_HANDLER, ); } @@ -168,11 +168,11 @@ impl GlobalState { let client_refresh = !was_stuck || state_changed; if client_refresh && self.config.cli_code_lens_refresh_support() { - self.send_request::((), DEFAULT_REQ_HANDLER); + self.send_request::((), DEFAULT_REQ_HANDLER); } if client_refresh && self.config.cli_inlay_hint_refresh_support() { - self.send_request::( + self.send_request::( (), DEFAULT_REQ_HANDLER, ); @@ -200,8 +200,8 @@ impl GlobalState { fn handle_request(&mut self, req: Request) { if matches!( req.method.as_str(), - lsp_types::request::DocumentDiagnosticRequest::METHOD - | lsp_types::request::WorkspaceDiagnosticRequest::METHOD + lspt::request::DocumentDiagnosticRequest::METHOD + | lspt::request::WorkspaceDiagnosticRequest::METHOD ) && !self.is_stuck() { self.task_pool.handle.spawn_and_send(ThreadIntent::Worker, move || Task::Retry(req)); @@ -211,7 +211,7 @@ impl GlobalState { let mut dispatcher = ReqDispatcher { req: Some(req), global_state: self }; // Handle shutdown req first - dispatcher.on_sync_mut::(|this, ()| { + dispatcher.on_sync_mut::(|this, ()| { this.shutdown_requested = true; Ok(()) }); @@ -229,13 +229,11 @@ impl GlobalState { } use handlers::request::*; - use lsp_types::request::*; + use lspt::request::*; dispatcher - .on_no_retry::(handle_completion) - .on_latency_sensitive::(handle_semantic_tokens_full) - .on_latency_sensitive::( - handle_semantic_tokens_full_delta, - ) + .on_no_retry::(handle_completion) + .on_latency_sensitive::(handle_semantic_tokens_full) + .on_latency_sensitive::(handle_semantic_tokens_full_delta) .on_latency_sensitive::(handle_semantic_tokens_range) .on::(handle_document_symbol) .on::(handle_folding_ranges) @@ -244,39 +242,41 @@ impl GlobalState { .on_no_retry::(handle_signature_help) .on_no_retry::(handle_inlay_hint) .on_no_retry::(handle_code_lens) - .on_no_retry::(handle_code_lens_resolve) + .on_no_retry::(handle_code_lens_resolve) .on_no_retry::(handle_hover) - .on_no_retry::(handle_goto_definition) - .on_no_retry::(handle_goto_declaration) + .on_no_retry::(handle_goto_definition) + .on_no_retry::(handle_goto_declaration) .on_no_retry::(handle_document_highlight) - .on_no_retry::(handle_references) + .on_no_retry::(handle_references) .on_no_retry::(handle_prepare_rename) - .on_no_retry::(handle_rename) - .on_fmt_thread::(handle_formatting) - .on_fmt_thread::(handle_range_formatting) - .on_sync::(handle_on_type_formatting) + .on_no_retry::(handle_rename) + .on_fmt_thread::(handle_formatting) + .on_fmt_thread::(handle_range_formatting) + .on_sync::(handle_on_type_formatting) .on_no_retry::(handle_code_action) .on_no_retry::(handle_code_action_resolve) - .on_sync_mut::(handle_execute_command) + .on_sync_mut::(handle_execute_command) .on::(handle_selection_range) .finish(); } fn handle_notification(&mut self, notif: Notification) { use handlers::notification::*; - use lsp_types::notification::*; + use lspt::notification::*; let mut dispatcher = NotifDispatcher { notif: Some(notif), global_state: self }; dispatcher - .on_sync_mut::(handle_cancel) - .on_sync_mut::(handle_did_open_text_document) - .on_sync_mut::(handle_did_change_text_document) - .on_sync_mut::(handle_did_close_text_document) - .on_sync_mut::(handle_did_save_text_document) - .on_sync_mut::(handle_did_change_configuration) - .on_sync_mut::(handle_did_change_workspace_folders) - .on_sync_mut::(handle_did_change_watched_files) - .on_sync_mut::(handle_set_trace) + .on_sync_mut::(handle_cancel) + .on_sync_mut::(handle_did_open_text_document) + .on_sync_mut::(handle_did_change_text_document) + .on_sync_mut::(handle_did_close_text_document) + .on_sync_mut::(handle_did_save_text_document) + .on_sync_mut::(handle_did_change_configuration) + .on_sync_mut::( + handle_did_change_workspace_folders, + ) + .on_sync_mut::(handle_did_change_watched_files) + .on_sync_mut::(handle_set_trace) .finish(); } @@ -415,8 +415,8 @@ impl GlobalState { self.diagnostics.insert(diag.file_id, diag.diagnostics.clone()); } - self.send_notification::( - lsp_types::PublishDiagnosticsParams { + self.send_notification::( + lspt::PublishDiagnosticsParams { uri: diag.uri, diagnostics: diag.diagnostics, version: diag.version, diff --git a/src/global_state/process_changes.rs b/src/global_state/process_changes.rs index 89c564ed..c18ce878 100644 --- a/src/global_state/process_changes.rs +++ b/src/global_state/process_changes.rs @@ -2,7 +2,7 @@ use std::collections::hash_map::Entry::{Occupied, Vacant}; use base_db::change::Change; use itertools::Itertools; -use lsp_types::request::WorkspaceDiagnosticRefresh; +use lspt::request::DiagnosticRefreshRequest; use nohash_hasher::IntMap; use parking_lot::{RwLockUpgradableReadGuard, RwLockWriteGuard}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -98,7 +98,7 @@ impl GlobalState { DiagnosticInvalidation::WorkspaceChanged => true, } { - self.send_request::((), DEFAULT_REQ_HANDLER); + self.send_request::((), DEFAULT_REQ_HANDLER); return; } @@ -262,7 +262,7 @@ impl GlobalState { if self.config.cli_pull_diagnostics_support() { if self.config.cli_workspace_diagnostic_refresh_support() { - self.send_request::((), DEFAULT_REQ_HANDLER); + self.send_request::((), DEFAULT_REQ_HANDLER); } return; } @@ -293,7 +293,7 @@ impl GlobalState { #[cfg(test)] mod tests { use lsp_server::Connection; - use lsp_types::{ClientCapabilities, TraceValue}; + use lspt::{ClientCapabilities, TraceValue}; use utils::{lines::LineEnding, test_support::TestDir}; use vfs::{VfsPath, loader::LoadResult}; diff --git a/src/global_state/project_status.rs b/src/global_state/project_status.rs index 4e11667c..47810148 100644 --- a/src/global_state/project_status.rs +++ b/src/global_state/project_status.rs @@ -1,4 +1,4 @@ -use lsp_types::Url; +use lspt::Uri as Url; use project_model::project_manifest::ProjectManifest; use utils::paths::AbsPath; @@ -75,7 +75,7 @@ fn url_from_path(path: &AbsPath) -> Option { #[cfg(test)] mod tests { use lsp_server::{Connection, Message, Notification as LspNotification}; - use lsp_types::notification::Notification as _; + use lspt::notification::Notification as _; use project_model::project_manifest::MANIFEST_FILE_NAME; use utils::{paths::AbsPathBuf, test_support::TestDir}; @@ -95,7 +95,7 @@ mod tests { log_filename: None, }, root_path.clone(), - lsp_types::ClientCapabilities::default(), + lspt::ClientCapabilities::default(), vec![root_path], I18n::default(), UserConfig::default(), @@ -103,7 +103,7 @@ mod tests { ); let (server, client) = Connection::memory(); - (GlobalState::new(server.sender, config, lsp_types::TraceValue::Off), client) + (GlobalState::new(server.sender, config, lspt::TraceValue::Off), client) } fn drain_client_notifications(client: &Connection) -> Vec { diff --git a/src/global_state/qihe.rs b/src/global_state/qihe.rs index 134eff62..bd59e988 100644 --- a/src/global_state/qihe.rs +++ b/src/global_state/qihe.rs @@ -11,9 +11,8 @@ use std::{ use anyhow::{Context, Result, anyhow, bail}; use base_db::compilation_plan::CompilationPlan; -use lsp_types::{ - Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, MessageType, NumberOrString, - ShowMessageParams, +use lspt::{ + Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, MessageType, ShowMessageParams, }; use project_model::project_manifest::MANIFEST_FILE_NAME; use regex::Regex; @@ -134,10 +133,9 @@ impl GlobalState { message.clone(), self.config.i18n.text(keys::QIHE_FAILED).to_owned(), ); - self.send_notification::(ShowMessageParams { - typ: MessageType::ERROR, - message, - }); + self.send_notification::( + ShowMessageParams { ty: MessageType::Error, message }, + ); } } } @@ -639,15 +637,17 @@ impl<'a> DiagnosticConverter<'a> { Ok(( file_id, - Diagnostic::new( + Diagnostic { range, - Some(map_severity(&severity)), - Some(NumberOrString::String(analysis_code(&analysis_class))), - Some(QIHE.to_owned()), + severity: Some(map_severity(&severity)), + code: Some(lspt::Union2::B(analysis_code(&analysis_class))), + code_description: None, + source: Some(QIHE.to_owned()), message, - related_info, - None, - ), + related_information: related_info, + tags: None, + data: None, + }, )) } @@ -719,11 +719,11 @@ fn resolve_file_name(base_dir: &Path, file_name: &str) -> Option { fn map_severity(severity: &str) -> DiagnosticSeverity { match severity.trim().to_ascii_uppercase().as_str() { - "ERROR" => DiagnosticSeverity::ERROR, - "WARNING" | "WARN" => DiagnosticSeverity::WARNING, - "INFO" | "INFORMATION" => DiagnosticSeverity::INFORMATION, - "HINT" => DiagnosticSeverity::HINT, - _ => DiagnosticSeverity::WARNING, + "ERROR" => DiagnosticSeverity::Error, + "WARNING" | "WARN" => DiagnosticSeverity::Warning, + "INFO" | "INFORMATION" => DiagnosticSeverity::Information, + "HINT" => DiagnosticSeverity::Hint, + _ => DiagnosticSeverity::Warning, } } diff --git a/src/global_state/reload.rs b/src/global_state/reload.rs index 6014c723..3ef6445a 100644 --- a/src/global_state/reload.rs +++ b/src/global_state/reload.rs @@ -195,12 +195,12 @@ impl GlobalState { return; } - let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { + let registration_options = lspt::DidChangeWatchedFilesRegistrationOptions { watchers: globs .iter() .cloned() - .map(|glob_pattern| lsp_types::FileSystemWatcher { - glob_pattern: lsp_types::GlobPattern::String(glob_pattern), + .map(|glob_pattern| lspt::FileSystemWatcher { + glob_pattern: lspt::Union2::A(glob_pattern), kind: None, }) .collect(), @@ -208,14 +208,14 @@ impl GlobalState { match serde_json::to_value(registration_options) { Ok(register_options) => { - let registration = lsp_types::Registration { + let registration = lspt::Registration { id: CLIENT_FILE_WATCHER_REGISTRATION_ID.to_string(), method: CLIENT_FILE_WATCHER_METHOD.to_string(), register_options: Some(register_options), }; - self.send_request::( - lsp_types::RegistrationParams { registrations: vec![registration] }, + self.send_request::( + lspt::RegistrationParams { registrations: vec![registration] }, DEFAULT_REQ_HANDLER, ); self.registered_client_file_watcher_globs = Some(globs); @@ -231,9 +231,9 @@ impl GlobalState { return; } - self.send_request::( - lsp_types::UnregistrationParams { - unregisterations: vec![lsp_types::Unregistration { + self.send_request::( + lspt::UnregistrationParams { + unregisterations: vec![lspt::Unregistration { id: CLIENT_FILE_WATCHER_REGISTRATION_ID.to_string(), method: CLIENT_FILE_WATCHER_METHOD.to_string(), }], @@ -281,7 +281,7 @@ mod tests { log_filename: None, }, root_path.clone(), - lsp_types::ClientCapabilities::default(), + lspt::ClientCapabilities::default(), vec![root_path], I18n::default(), UserConfig::default(), @@ -289,7 +289,7 @@ mod tests { ); let (server, client) = Connection::memory(); - (GlobalState::new(server.sender, config, lsp_types::TraceValue::Off), client) + (GlobalState::new(server.sender, config, lspt::TraceValue::Off), client) } fn drain_client_requests(client: &Connection) -> Vec { diff --git a/src/global_state/respond.rs b/src/global_state/respond.rs index d7bf4ca1..0b5586d8 100644 --- a/src/global_state/respond.rs +++ b/src/global_state/respond.rs @@ -1,4 +1,5 @@ -use lsp_types::{notification, request}; +use lspt::{notification, request}; +use serde::Serialize; use super::DEFAULT_REQ_HANDLER; use crate::global_state::{GlobalState, ReqHandler}; @@ -18,6 +19,10 @@ impl Progress { } } +fn progress_value(value: T) -> serde_json::Value { + serde_json::to_value(value).expect("work-done progress payload should serialize") +} + impl GlobalState { pub(crate) fn send(&self, message: lsp_server::Message) { if self.sender.send(message).is_err() { @@ -72,39 +77,39 @@ impl GlobalState { let cancellable = Some(cancel_token.is_some()); - let token = lsp_types::ProgressToken::String( + let token = lspt::Union2::B( cancel_token.unwrap_or_else(|| format!("{}/{title}", self.config.opt.process_name)), ); let work_done_progress = match state { Progress::Begin => { - self.send_request::( - lsp_types::WorkDoneProgressCreateParams { token: token.clone() }, + self.send_request::( + lspt::WorkDoneProgressCreateParams { token: token.clone() }, DEFAULT_REQ_HANDLER, ); - lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin { - title: title.into(), - cancellable, - message, - percentage, - }) - } - Progress::Report => { - lsp_types::WorkDoneProgress::Report(lsp_types::WorkDoneProgressReport { + progress_value(lspt::WorkDoneProgressBegin { + kind: "begin".to_owned(), + title: title.to_owned(), cancellable, message, percentage, }) } + Progress::Report => progress_value(lspt::WorkDoneProgressReport { + kind: "report".to_owned(), + cancellable, + message, + percentage, + }), Progress::End => { - lsp_types::WorkDoneProgress::End(lsp_types::WorkDoneProgressEnd { message }) + progress_value(lspt::WorkDoneProgressEnd { kind: "end".to_owned(), message }) } }; - self.send_notification::(lsp_types::ProgressParams { + self.send_notification::(lspt::ProgressParams { token, - value: lsp_types::ProgressParamsValue::WorkDone(work_done_progress), + value: work_done_progress, }); } } diff --git a/src/global_state/snapshot.rs b/src/global_state/snapshot.rs index 0f2eba2a..f3638f96 100644 --- a/src/global_state/snapshot.rs +++ b/src/global_state/snapshot.rs @@ -3,7 +3,7 @@ use std::path::Path; use anyhow::Context; use base_db::source_root::SourceRootRole; use ide::{Cancellable, analysis::Analysis}; -use lsp_types::Url; +use lspt::Uri as Url; use nohash_hasher::IntMap; use parking_lot::{MappedRwLockReadGuard, Mutex, RwLock, RwLockReadGuard}; use project_model::Workspace; @@ -27,7 +27,7 @@ pub(crate) struct GlobalStateSnapshot { pub(crate) config: Arc, pub(crate) analysis: Analysis, // pub(crate) check_fixes: CheckFixes, - pub(crate) sema_tokens_cache: Arc>>, + pub(crate) sema_tokens_cache: Arc>>, pub(crate) qihe_diagnostics: Arc>>, pub(crate) diagnostics_revision: u64, pub(crate) mem_docs: MemDocs, @@ -43,7 +43,7 @@ impl GlobalStateSnapshot { RwLockReadGuard::map(self.vfs.read(), |(it, _)| it) } - pub(crate) fn file_id(&self, url: &lsp_types::Url) -> anyhow::Result { + pub(crate) fn file_id(&self, url: &lspt::Uri) -> anyhow::Result { let path = from_proto::vfs_path(url)?; let vfs = self.vfs_read(); let file_id = @@ -106,7 +106,7 @@ impl GlobalStateSnapshot { Ok(diagnostics) } - pub(crate) fn lsp_diagnostics(&self, file_id: FileId) -> Vec { + pub(crate) fn lsp_diagnostics(&self, file_id: FileId) -> Vec { let mut diagnostics = match (self.diagnostics(file_id), self.line_info(file_id)) { (Ok(diagnostics), Ok(line_info)) => diagnostics .into_iter() @@ -120,7 +120,7 @@ impl GlobalStateSnapshot { diagnostics } - pub(crate) fn qihe_diagnostics(&self, file_id: FileId) -> Vec { + pub(crate) fn qihe_diagnostics(&self, file_id: FileId) -> Vec { self.qihe_diagnostics .lock() .get(&file_id) diff --git a/src/global_state/trace.rs b/src/global_state/trace.rs index 6505f03d..6978d436 100644 --- a/src/global_state/trace.rs +++ b/src/global_state/trace.rs @@ -1,4 +1,4 @@ -use lsp_types::TraceValue; +use lspt::TraceValue; use crate::global_state::GlobalState; @@ -21,7 +21,7 @@ impl LspTrace { #[cfg(test)] pub(crate) fn level(&self) -> TraceValue { - self.level + self.level.clone() } } @@ -33,7 +33,7 @@ impl GlobalState { #[cfg(test)] mod tests { - use lsp_types::TraceValue; + use lspt::TraceValue; use super::LspTrace; diff --git a/src/lsp_ext/ext.rs b/src/lsp_ext/ext.rs index 0ab486ea..d1aa8907 100644 --- a/src/lsp_ext/ext.rs +++ b/src/lsp_ext/ext.rs @@ -1,6 +1,4 @@ -use std::ops; - -use lsp_types::notification::Notification; +use lspt::notification::Notification; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -14,72 +12,84 @@ pub struct CodeLensData { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum CodeLensDataKind { - Instantiation(lsp_types::TextDocumentPositionParams), + Instantiation(TextDocumentPositionParams), } -macro_rules! define_semantic_token_kind { - ( ($name:ident: [$ty:ty] @ $mod:ident) => - standard { - $($standard:ident),*$(,)? - } - custom { - $(($custom:ident, $string:literal) $(=> $fallback:ident)?),*$(,)? - } - ) => { - pub(crate) mod $mod { - $(pub(crate) const $standard: $ty = <$ty>::$standard;)* - $(pub(crate) const $custom: $ty = <$ty>::new($string);)* - - pub(crate) fn fallback(token: $ty) -> Option<$ty> { - $( - if token == $custom { - None $(.or(Some($fallback)))? - } else - )* - { Some(token)} - } +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentPositionParams { + pub text_document: lspt::TextDocumentIdentifier, + pub position: lspt::Position, +} + +pub(crate) mod sema_token_types { + pub(crate) const COMMENT: &str = "comment"; + pub(crate) const DECORATOR: &str = "decorator"; + pub(crate) const ENUM_MEMBER: &str = "enumMember"; + pub(crate) const ENUM: &str = "enum"; + pub(crate) const FUNCTION: &str = "function"; + pub(crate) const INTERFACE: &str = "interface"; + pub(crate) const KEYWORD: &str = "keyword"; + pub(crate) const MACRO: &str = "macro"; + pub(crate) const METHOD: &str = "method"; + pub(crate) const NAMESPACE: &str = "namespace"; + pub(crate) const NUMBER: &str = "number"; + pub(crate) const OPERATOR: &str = "operator"; + pub(crate) const PARAMETER: &str = "parameter"; + pub(crate) const PROPERTY: &str = "property"; + pub(crate) const STRING: &str = "string"; + pub(crate) const STRUCT: &str = "struct"; + pub(crate) const TYPE_PARAMETER: &str = "typeParameter"; + pub(crate) const VARIABLE: &str = "variable"; + pub(crate) const TYPE: &str = "type"; + + pub(crate) const CLK_PORT: &str = "port_clock"; + pub(crate) const RST_PORT: &str = "port_reset"; + pub(crate) const OTHERS_PORT: &str = "port_generic"; + pub(crate) const INSTANCE: &str = "instance"; + pub(crate) const TYPE_ALIAS: &str = "type_alias"; + pub(crate) const GENERIC: &str = "generic"; + + pub(crate) fn fallback(token: &'static str) -> Option<&'static str> { + match token { + CLK_PORT => Some(KEYWORD), + RST_PORT => Some(PROPERTY), + OTHERS_PORT => Some(PARAMETER), + INSTANCE => Some(VARIABLE), + TYPE_ALIAS => Some(TYPE), + GENERIC => Some(TYPE_PARAMETER), + _ => Some(token), } - - pub(crate) const $name: &[$ty] = &[ - $(self::$mod::$standard,)* - $(self::$mod::$custom),* - ]; - }; -} - -define_semantic_token_kind! { - (SEMA_TOKENS_TYPES: [lsp_types::SemanticTokenType] @ sema_token_types) => - standard { - COMMENT, - DECORATOR, - ENUM_MEMBER, - ENUM, - FUNCTION, - INTERFACE, - KEYWORD, - MACRO, - METHOD, - NAMESPACE, - NUMBER, - OPERATOR, - PARAMETER, - PROPERTY, - STRING, - STRUCT, - TYPE_PARAMETER, - VARIABLE, - TYPE, - } - - custom { - (CLK_PORT, "port_clock") => KEYWORD, - (RST_PORT, "port_reset") => PROPERTY, - (OTHERS_PORT, "port_generic") => PARAMETER, - (INSTANCE, "instance") => VARIABLE, - (TYPE_ALIAS, "type_alias") => TYPE, - (GENERIC, "generic") => TYPE_PARAMETER, } } + +pub(crate) const SEMA_TOKENS_TYPES: &[&str] = &[ + sema_token_types::COMMENT, + sema_token_types::DECORATOR, + sema_token_types::ENUM_MEMBER, + sema_token_types::ENUM, + sema_token_types::FUNCTION, + sema_token_types::INTERFACE, + sema_token_types::KEYWORD, + sema_token_types::MACRO, + sema_token_types::METHOD, + sema_token_types::NAMESPACE, + sema_token_types::NUMBER, + sema_token_types::OPERATOR, + sema_token_types::PARAMETER, + sema_token_types::PROPERTY, + sema_token_types::STRING, + sema_token_types::STRUCT, + sema_token_types::TYPE_PARAMETER, + sema_token_types::VARIABLE, + sema_token_types::TYPE, + sema_token_types::CLK_PORT, + sema_token_types::RST_PORT, + sema_token_types::OTHERS_PORT, + sema_token_types::INSTANCE, + sema_token_types::TYPE_ALIAS, + sema_token_types::GENERIC, +]; #[derive(Default)] pub(crate) struct SemaTokenModifierSet(pub(crate) u32); @@ -89,30 +99,50 @@ impl SemaTokenModifierSet { } } -define_semantic_token_kind! { - (SEMA_TOKENS_MODIFIERS: [lsp_types::SemanticTokenModifier] @ sema_token_modifiers) => - standard { - DECLARATION, - DEFINITION, - READONLY, - STATIC, - DEPRECATED, - ABSTRACT, - ASYNC, - MODIFICATION, - DOCUMENTATION, - DEFAULT_LIBRARY, - } - custom { - (READ, "read"), - (WRITE, "write"), - (REF, "ref") => MODIFICATION, - (DEF, "definition"), +pub(crate) mod sema_token_modifiers { + pub(crate) const DECLARATION: &str = "declaration"; + pub(crate) const DEFINITION: &str = "definition"; + pub(crate) const READONLY: &str = "readonly"; + pub(crate) const STATIC: &str = "static"; + pub(crate) const DEPRECATED: &str = "deprecated"; + pub(crate) const ABSTRACT: &str = "abstract"; + pub(crate) const ASYNC: &str = "async"; + pub(crate) const MODIFICATION: &str = "modification"; + pub(crate) const DOCUMENTATION: &str = "documentation"; + pub(crate) const DEFAULT_LIBRARY: &str = "defaultLibrary"; + + pub(crate) const READ: &str = "read"; + pub(crate) const WRITE: &str = "write"; + pub(crate) const REF: &str = "ref"; + pub(crate) const DEF: &str = "definition"; + + pub(crate) fn fallback(token: &'static str) -> Option<&'static str> { + match token { + REF => Some(MODIFICATION), + _ => Some(token), + } } } -impl ops::BitOrAssign for SemaTokenModifierSet { - fn bitor_assign(&mut self, rhs: lsp_types::SemanticTokenModifier) { +pub(crate) const SEMA_TOKENS_MODIFIERS: &[&str] = &[ + sema_token_modifiers::DECLARATION, + sema_token_modifiers::DEFINITION, + sema_token_modifiers::READONLY, + sema_token_modifiers::STATIC, + sema_token_modifiers::DEPRECATED, + sema_token_modifiers::ABSTRACT, + sema_token_modifiers::ASYNC, + sema_token_modifiers::MODIFICATION, + sema_token_modifiers::DOCUMENTATION, + sema_token_modifiers::DEFAULT_LIBRARY, + sema_token_modifiers::READ, + sema_token_modifiers::WRITE, + sema_token_modifiers::REF, + sema_token_modifiers::DEF, +]; + +impl std::ops::BitOrAssign<&'static str> for SemaTokenModifierSet { + fn bitor_assign(&mut self, rhs: &'static str) { let Some(idx) = SEMA_TOKENS_MODIFIERS.iter().position(|it| it == &rhs) else { tracing::debug!(?rhs, "unknown semantic token modifier"); return; @@ -124,7 +154,7 @@ impl ops::BitOrAssign for SemaTokenModifierSet #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct CodeActionData { - pub code_action_params: lsp_types::CodeActionParams, + pub code_action_params: lspt::CodeActionParams, pub id: String, #[serde(skip_serializing_if = "Option::is_none")] pub version: Option, @@ -146,7 +176,7 @@ pub const RELOAD_WORKSPACE_COMMAND: &str = "vizsla.server.reloadWorkspace"; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RunQiheAnalysisParams { - pub uri: lsp_types::Url, + pub uri: lspt::Uri, #[serde(default, skip_serializing_if = "Option::is_none")] pub cwd: Option, } @@ -197,8 +227,8 @@ pub enum ProjectStatusState { #[serde(rename_all = "camelCase")] pub struct ProjectStatusParams { pub state: ProjectStatusState, - pub manifest_uris: Vec, - pub unconfigured_root_uris: Vec, + pub manifest_uris: Vec, + pub unconfigured_root_uris: Vec, pub workspace_count: usize, pub errors: Vec, #[serde(skip_serializing_if = "Option::is_none")] diff --git a/src/lsp_ext/from_proto.rs b/src/lsp_ext/from_proto.rs index a1ac0706..26bf135a 100644 --- a/src/lsp_ext/from_proto.rs +++ b/src/lsp_ext/from_proto.rs @@ -10,14 +10,14 @@ use vfs::{FileId, VfsPath}; use super::ext; use crate::global_state::snapshot::GlobalStateSnapshot; -pub(crate) fn vfs_path(url: &lsp_types::Url) -> anyhow::Result { +pub(crate) fn vfs_path(url: &lspt::Uri) -> anyhow::Result { let path = url.to_file_path().map_err(|()| anyhow::format_err!("url is not a file"))?; let path = AbsPathBuf::try_from(path) .map_err(|path| anyhow::format_err!("file url path is not absolute UTF-8: {path:?}"))?; Ok(VfsPath::from(path)) } -pub(crate) fn abs_path(url: &lsp_types::Url) -> anyhow::Result { +pub(crate) fn abs_path(url: &lspt::Uri) -> anyhow::Result { let path = url.to_file_path().map_err(|()| anyhow::format_err!("url is not a file"))?; AbsPathBuf::try_from(path) .map_err(|path| anyhow::format_err!("file url path is not absolute UTF-8: {path:?}")) @@ -26,7 +26,7 @@ pub(crate) fn abs_path(url: &lsp_types::Url) -> anyhow::Result { // convert position (line, col) to Offset pub(crate) fn offset( LineInfo { index, encoding, .. }: &LineInfo, - pos: lsp_types::Position, + pos: lspt::Position, ) -> anyhow::Result { let line_col = match *encoding { PositionEncoding::Utf8 => LineCol { line: pos.line, col: pos.character }, @@ -43,7 +43,7 @@ pub(crate) fn offset( pub(crate) fn text_range( line_info: &LineInfo, - lsp_types::Range { start, end }: lsp_types::Range, + lspt::Range { start, end }: lspt::Range, ) -> anyhow::Result { let start = offset(line_info, start)?; let end = offset(line_info, end)?; @@ -57,18 +57,19 @@ pub(crate) fn text_range( pub(crate) fn file_position( snap: &GlobalStateSnapshot, - pos_params: lsp_types::TextDocumentPositionParams, + text_document: lspt::TextDocumentIdentifier, + position: lspt::Position, ) -> anyhow::Result { - let file_id = snap.file_id(&pos_params.text_document.uri)?; + let file_id = snap.file_id(&text_document.uri)?; let line_index = snap.line_info(file_id)?; - let offset = offset(&line_index, pos_params.position)?; + let offset = offset(&line_index, position)?; Ok(FilePosition { file_id, offset }) } pub(crate) fn file_range( snap: &GlobalStateSnapshot, - url: &lsp_types::Url, - range: lsp_types::Range, + url: &lspt::Uri, + range: lspt::Range, ) -> anyhow::Result { let file_id = snap.file_id(url)?; let line_index = snap.line_info(file_id)?; @@ -76,7 +77,7 @@ pub(crate) fn file_range( Ok(FileRange { file_id, range }) } -pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> anyhow::Result { +pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lspt::Uri) -> anyhow::Result { snap.file_id(url) } @@ -87,7 +88,7 @@ pub(crate) fn code_lens( let data = serde_json::from_value::(data)?; let (file_id, kind) = match data.kind { ext::CodeLensDataKind::Instantiation(pos_params) => { - let pos = self::file_position(snap, pos_params)?; + let pos = self::file_position(snap, pos_params.text_document, pos_params.position)?; let file_id = pos.file_id; (file_id, CodeLensKind::ModuleInstance { pos, data: None }) } diff --git a/src/lsp_ext/to_proto.rs b/src/lsp_ext/to_proto.rs index 3eafd92f..deb079a8 100644 --- a/src/lsp_ext/to_proto.rs +++ b/src/lsp_ext/to_proto.rs @@ -49,7 +49,7 @@ pub(crate) fn goto_definition_response( snap: &GlobalStateSnapshot, src: Option, targets: Vec, -) -> anyhow::Result { +) -> anyhow::Result<::Result> { let res = if snap.config.location_link() { let links = targets .into_iter() @@ -58,7 +58,7 @@ pub(crate) fn goto_definition_response( }) .map(|nav| location_link(snap, src, nav)) .collect::>>()?; - links.into() + lspt::Union3::B(links) } else { let locations = targets .into_iter() @@ -66,25 +66,24 @@ pub(crate) fn goto_definition_response( .unique() .map(|file_range| location(snap, file_range)) .collect::>>()?; - locations.into() + lspt::Union3::A(lspt::Union2::B(locations)) }; - Ok(res) + Ok(Some(res)) } #[allow(deprecated)] pub(crate) fn document_symbol( line_info: &LineInfo, symbol: ide::document_symbols::DocumentSymbol, -) -> lsp_types::DocumentSymbol { +) -> lspt::DocumentSymbol { let children = symbol.children.into_iter().map(|child| document_symbol(line_info, child)).collect_vec(); - lsp_types::DocumentSymbol { + lspt::DocumentSymbol { name: symbol.name, detail: symbol.detail, kind: symbol_kind(symbol.kind), tags: None, - deprecated: None, range: self::range(line_info, symbol.full_range), selection_range: self::range(line_info, symbol.focus_range), children: if children.is_empty() { None } else { Some(children) }, @@ -94,16 +93,18 @@ pub(crate) fn document_symbol( #[allow(deprecated)] pub(crate) fn document_symbol_information( symbol: ide::document_symbols::DocumentSymbol, - url: lsp_types::Url, + url: lspt::Uri, line_info: &LineInfo, - res: &mut Vec, + res: &mut Vec, ) { - res.push(lsp_types::SymbolInformation { + res.push(lspt::SymbolInformation { name: symbol.name, kind: symbol_kind(symbol.kind), tags: None, - deprecated: None, - location: lsp_types::Location::new(url.clone(), self::range(line_info, symbol.focus_range)), + location: lspt::Location { + uri: url.clone(), + range: self::range(line_info, symbol.focus_range), + }, container_name: symbol.container_name, }); @@ -115,16 +116,16 @@ pub(crate) fn document_symbol_information( pub(crate) fn document_highlight( line_info: &LineInfo, DocumentHighlight { range, category }: DocumentHighlight, -) -> lsp_types::DocumentHighlight { +) -> lspt::DocumentHighlight { let kind = if category.contains(ReferenceCategory::READ) { - Some(lsp_types::DocumentHighlightKind::READ) + Some(lspt::DocumentHighlightKind::Read) } else if category.contains(ReferenceCategory::WRITE) { - Some(lsp_types::DocumentHighlightKind::WRITE) + Some(lspt::DocumentHighlightKind::Write) } else { None }; - lsp_types::DocumentHighlight { range: self::range(line_info, range), kind } + lspt::DocumentHighlight { range: self::range(line_info, range), kind } } const SLANG_DIAGNOSTIC_SOURCE: &str = "slang"; @@ -133,13 +134,13 @@ pub(crate) fn diagnostic( i18n: I18n, line_info: &LineInfo, diag: ide_diagnostics::Diagnostic, -) -> lsp_types::Diagnostic { +) -> lspt::Diagnostic { let data = diagnostic_data(&diag); let message = diagnostic_message(i18n, &diag); - lsp_types::Diagnostic { + lspt::Diagnostic { range: self::range(line_info, diag.range), severity: diagnostic_severity(diag.severity), - code: Some(lsp_types::NumberOrString::String(format!("{}:{}", diag.subsystem, diag.code))), + code: Some(lspt::Union2::B(format!("{}:{}", diag.subsystem, diag.code))), code_description: None, source: Some( match diag.source { @@ -202,40 +203,40 @@ fn diagnostic_selector_hints(diag: &ide_diagnostics::Diagnostic) -> Vec selectors } -fn diagnostic_severity(severity: SlangDiagnosticSeverity) -> Option { - use lsp_types::DiagnosticSeverity as LspSeverity; +fn diagnostic_severity(severity: SlangDiagnosticSeverity) -> Option { + use lspt::DiagnosticSeverity as LspSeverity; match severity { SlangDiagnosticSeverity::Ignored => None, - SlangDiagnosticSeverity::Note => Some(LspSeverity::INFORMATION), - SlangDiagnosticSeverity::Warning => Some(LspSeverity::WARNING), - SlangDiagnosticSeverity::Error | SlangDiagnosticSeverity::Fatal => Some(LspSeverity::ERROR), + SlangDiagnosticSeverity::Note => Some(LspSeverity::Information), + SlangDiagnosticSeverity::Warning => Some(LspSeverity::Warning), + SlangDiagnosticSeverity::Error | SlangDiagnosticSeverity::Fatal => Some(LspSeverity::Error), } } -fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind { - use lsp_types::SymbolKind as LspSymbolKind; +fn symbol_kind(symbol_kind: SymbolKind) -> lspt::SymbolKind { + use lspt::SymbolKind as LspSymbolKind; match symbol_kind { - SymbolKind::Module => LspSymbolKind::MODULE, - SymbolKind::Config => LspSymbolKind::NAMESPACE, - SymbolKind::Primitive => LspSymbolKind::OBJECT, - SymbolKind::NonAnsiPortLabel => LspSymbolKind::FIELD, - SymbolKind::PortDecl => LspSymbolKind::FIELD, - SymbolKind::ParamDecl => LspSymbolKind::TYPE_PARAMETER, - SymbolKind::NetDecl => LspSymbolKind::PROPERTY, - SymbolKind::DataDecl => LspSymbolKind::VARIABLE, - SymbolKind::Genvar => LspSymbolKind::VARIABLE, - SymbolKind::Specparam => LspSymbolKind::TYPE_PARAMETER, - SymbolKind::Typedef => LspSymbolKind::TYPE_PARAMETER, - SymbolKind::Instance => LspSymbolKind::OBJECT, - SymbolKind::Block => LspSymbolKind::NAMESPACE, - SymbolKind::Stmt => LspSymbolKind::NAMESPACE, - SymbolKind::Fn => LspSymbolKind::FUNCTION, - SymbolKind::Generate => LspSymbolKind::NAMESPACE, - SymbolKind::Specify => LspSymbolKind::NAMESPACE, - SymbolKind::Interface => LspSymbolKind::INTERFACE, - SymbolKind::Library => LspSymbolKind::NAMESPACE, - SymbolKind::Region => LspSymbolKind::NAMESPACE, - SymbolKind::Unknown => LspSymbolKind::NAMESPACE, + SymbolKind::Module => LspSymbolKind::Module, + SymbolKind::Config => LspSymbolKind::Namespace, + SymbolKind::Primitive => LspSymbolKind::Object, + SymbolKind::NonAnsiPortLabel => LspSymbolKind::Field, + SymbolKind::PortDecl => LspSymbolKind::Field, + SymbolKind::ParamDecl => LspSymbolKind::TypeParameter, + SymbolKind::NetDecl => LspSymbolKind::Property, + SymbolKind::DataDecl => LspSymbolKind::Variable, + SymbolKind::Genvar => LspSymbolKind::Variable, + SymbolKind::Specparam => LspSymbolKind::TypeParameter, + SymbolKind::Typedef => LspSymbolKind::TypeParameter, + SymbolKind::Instance => LspSymbolKind::Object, + SymbolKind::Block => LspSymbolKind::Namespace, + SymbolKind::Stmt => LspSymbolKind::Namespace, + SymbolKind::Fn => LspSymbolKind::Function, + SymbolKind::Generate => LspSymbolKind::Namespace, + SymbolKind::Specify => LspSymbolKind::Namespace, + SymbolKind::Interface => LspSymbolKind::Interface, + SymbolKind::Library => LspSymbolKind::Namespace, + SymbolKind::Region => LspSymbolKind::Namespace, + SymbolKind::Unknown => LspSymbolKind::Namespace, } } @@ -243,7 +244,7 @@ fn location_link( snap: &GlobalStateSnapshot, src: Option, target: NavTarget, -) -> anyhow::Result { +) -> anyhow::Result { let origin_selection_range = try { let FileRange { file_id, range } = src?; let line_info = snap.line_info(file_id).ok()?; @@ -251,7 +252,7 @@ fn location_link( }; let (target_uri, target_range, target_selection_range) = location_info(snap, target)?; - let res = lsp_types::LocationLink { + let res = lspt::LocationLink { origin_selection_range, target_uri, target_range, @@ -263,7 +264,7 @@ fn location_link( fn location_info( snap: &GlobalStateSnapshot, NavTarget { file_id, full_range, focus_range, .. }: NavTarget, -) -> anyhow::Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { +) -> anyhow::Result<(lspt::Uri, lspt::Range, lspt::Range)> { let line_info = snap.line_info(file_id)?; let target_uri = url(snap, file_id)?; @@ -273,12 +274,12 @@ fn location_info( Ok((target_uri, target_range, target_selection_range)) } -pub(crate) fn url(snap: &GlobalStateSnapshot, file_id: FileId) -> anyhow::Result { +pub(crate) fn url(snap: &GlobalStateSnapshot, file_id: FileId) -> anyhow::Result { snap.url(file_id) } -pub(crate) fn url_from_abs_path(path: &AbsPath) -> anyhow::Result { - let url = lsp_types::Url::from_file_path(path) +pub(crate) fn url_from_abs_path(path: &AbsPath) -> anyhow::Result { + let url = lspt::Uri::from_file_path(path) .map_err(|()| anyhow::format_err!("failed to convert file path to URL: {path}"))?; let Some(Utf8Component::Prefix(prefix)) = path.components().next() else { @@ -300,37 +301,37 @@ pub(crate) fn url_from_abs_path(path: &AbsPath) -> anyhow::Result lsp_types::Range { +pub(crate) fn range(line_info: &LineInfo, range: TextRange) -> lspt::Range { let start = position(line_info, range.start()); let end = position(line_info, range.end()); - lsp_types::Range::new(start, end) + lspt::Range { start, end } } pub(crate) fn location( snap: &GlobalStateSnapshot, FileRange { file_id, range }: FileRange, -) -> anyhow::Result { +) -> anyhow::Result { let url = url(snap, file_id)?; let line_info = snap.line_info(file_id)?; let range = self::range(&line_info, range); - Ok(lsp_types::Location::new(url, range)) + Ok(lspt::Location { uri: url, range }) } pub(crate) fn position( LineInfo { index, encoding, .. }: &LineInfo, offset: TextSize, -) -> lsp_types::Position { +) -> lspt::Position { let line_col = line_col_for_position(index, offset); match *encoding { - PositionEncoding::Utf8 => lsp_types::Position::new(line_col.line, line_col.col), + PositionEncoding::Utf8 => lspt::Position { line: line_col.line, character: line_col.col }, PositionEncoding::Wide(enc) => match index.to_wide(enc, line_col) { - Some(line_col) => lsp_types::Position::new(line_col.line, line_col.col), + Some(line_col) => lspt::Position { line: line_col.line, character: line_col.col }, None => { tracing::debug!(?line_col, "failed to convert UTF-8 position to wide encoding"); - lsp_types::Position::new(line_col.line, line_col.col) + lspt::Position { line: line_col.line, character: line_col.col } } }, } @@ -379,20 +380,19 @@ pub(crate) fn code_action_resolve_error(i18n: I18n, err: CodeActionResolveError) pub(crate) fn workspace_edit( snap: &GlobalStateSnapshot, source_change: SourceChange, -) -> anyhow::Result { +) -> anyhow::Result { let mut document_changes = Vec::with_capacity(source_change.text_edits.len()); for (file_id, edit) in source_change.text_edits { let text_document = optional_versioned_text_document_identifier(snap, file_id)?; let line_info = snap.line_info(file_id)?; - let edits = - edit.into_iter().map(|it| lsp_types::OneOf::Left(text_edit(&line_info, it))).collect(); - document_changes.push(lsp_types::TextDocumentEdit { text_document, edits }); + let edits = edit.into_iter().map(|it| lspt::Union2::A(text_edit(&line_info, it))).collect(); + document_changes.push(lspt::TextDocumentEdit { text_document, edits }); } - let workspace_edit = lsp_types::WorkspaceEdit { + let workspace_edit = lspt::WorkspaceEdit { changes: None, - document_changes: Some(lsp_types::DocumentChanges::Edits(document_changes)), + document_changes: Some(document_changes.into_iter().map(lspt::Union4::A).collect()), change_annotations: None, }; @@ -402,31 +402,31 @@ pub(crate) fn workspace_edit( pub(crate) fn optional_versioned_text_document_identifier( snap: &GlobalStateSnapshot, file_id: FileId, -) -> anyhow::Result { +) -> anyhow::Result { let url = url(snap, file_id)?; let version = snap.url_file_version(&url); - Ok(lsp_types::OptionalVersionedTextDocumentIdentifier { uri: url, version }) + Ok(lspt::OptionalVersionedTextDocumentIdentifier { uri: url, version }) } -pub(crate) fn text_edit(line_info: &LineInfo, item: TextEditItem) -> lsp_types::TextEdit { +pub(crate) fn text_edit(line_info: &LineInfo, item: TextEditItem) -> lspt::TextEdit { let range = self::range(line_info, item.del); let new_text = match line_info.ending { LineEnding::Unix => item.ins, LineEnding::Dos => item.ins.replace('\n', "\r\n"), }; - lsp_types::TextEdit { range, new_text } + lspt::TextEdit { range, new_text } } -pub(crate) fn text_edits(line_info: &LineInfo, edit: TextEdit) -> Vec { +pub(crate) fn text_edits(line_info: &LineInfo, edit: TextEdit) -> Vec { edit.into_iter().map(|it| self::text_edit(line_info, it)).collect() } pub(crate) fn selection_ranges( line_info: &LineInfo, ranges: Vec, -) -> Option { +) -> Option { ranges.into_iter().rfold(None, |parent, range| { - Some(lsp_types::SelectionRange { + Some(lspt::SelectionRange { range: self::range(line_info, range), parent: parent.map(Box::new), }) @@ -438,16 +438,16 @@ pub(crate) fn folding_range( line_info: &LineInfo, FoldingConfig { line_fold_only }: &FoldingConfig, Fold { range, kind, collapsed_text }: Fold, -) -> lsp_types::FoldingRange { +) -> lspt::FoldingRange { use ide::folding_ranges::FoldKind; let kind = match kind { - FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment), - FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports), - FoldKind::Region => Some(lsp_types::FoldingRangeKind::Region), + FoldKind::Comment => Some(lspt::FoldingRangeKind::Comment), + FoldKind::Imports => Some(lspt::FoldingRangeKind::Imports), + FoldKind::Region => Some(lspt::FoldingRangeKind::Region), _ => None, }; - let lsp_types::Range { start, end } = self::range(line_info, range); + let lspt::Range { start, end } = self::range(line_info, range); if *line_fold_only { // Clients with `line_folding_only` will fold the whole end line even if @@ -460,7 +460,7 @@ pub(crate) fn folding_range( end.line.saturating_sub(1) }; - lsp_types::FoldingRange { + lspt::FoldingRange { start_line: start.line, start_character: None, end_line, @@ -469,7 +469,7 @@ pub(crate) fn folding_range( collapsed_text, } } else { - lsp_types::FoldingRange { + lspt::FoldingRange { start_line: start.line, start_character: Some(start.character), end_line: end.line, @@ -512,21 +512,24 @@ fn has_more_text_in_line(text: &str) -> bool { true } -pub(crate) fn hover_contents(markup: Markup, format: HoverFormat) -> lsp_types::HoverContents { +pub(crate) fn hover_contents( + markup: Markup, + format: HoverFormat, +) -> lspt::Union3> { let kind = match format { - HoverFormat::Markdown => lsp_types::MarkupKind::Markdown, - HoverFormat::PlainText => lsp_types::MarkupKind::PlainText, + HoverFormat::Markdown => lspt::MarkupKind::Markdown, + HoverFormat::PlainText => lspt::MarkupKind::PlainText, }; let value = markup.into(); - lsp_types::HoverContents::Markup(lsp_types::MarkupContent { kind, value }) + lspt::Union3::A(lspt::MarkupContent { kind, value }) } pub(crate) fn inlay_hint( snap: &GlobalStateSnapshot, line_info: &LineInfo, hint: InlayHint, -) -> lsp_types::InlayHint { +) -> lspt::InlayHint { let InlayHint { label, tooltip, @@ -538,11 +541,11 @@ pub(crate) fn inlay_hint( padding_right, } = hint; - let label = lsp_types::InlayHintLabelPart { + let label = lspt::InlayHintLabelPart { value: label, tooltip: tooltip.map(|tooltip| { - lsp_types::InlayHintLabelPartTooltip::MarkupContent(lsp_types::MarkupContent { - kind: lsp_types::MarkupKind::Markdown, + lspt::Union2::B(lspt::MarkupContent { + kind: lspt::MarkupKind::Markdown, value: tooltip.into(), }) }), @@ -555,15 +558,15 @@ pub(crate) fn inlay_hint( let position = self::position(line_info, position); let kind = match kind { - InlayKind::ParamAssign | InlayKind::Port => Some(lsp_types::InlayHintKind::PARAMETER), + InlayKind::ParamAssign | InlayKind::Port => Some(lspt::InlayHintKind::Parameter), InlayKind::EndStructure => None, }; let text_edits = text_edit.map(|it| self::text_edits(line_info, it)); - lsp_types::InlayHint { + lspt::InlayHint { position, - label: lsp_types::InlayHintLabel::LabelParts(vec![label]), + label: lspt::Union2::B(vec![label]), kind, text_edits, tooltip: None, @@ -578,10 +581,10 @@ pub(crate) fn code_lens( line_info: &LineInfo, file_id: FileId, CodeLens { range, kind }: CodeLens, -) -> Option { +) -> Option { let range = self::range(line_info, range); let (command, data) = self::code_lens_kind(snap, file_id, line_info, kind).ok()?; - Some(lsp_types::CodeLens { range, command, data }) + Some(lspt::CodeLens { range, command, data }) } pub(crate) fn code_lens_kind( @@ -589,7 +592,7 @@ pub(crate) fn code_lens_kind( file_id: FileId, line_info: &LineInfo, kind: CodeLensKind, -) -> anyhow::Result<(Option, Option)> { +) -> anyhow::Result<(Option, Option)> { let url = self::url(snap, file_id)?; let command = match kind { @@ -600,7 +603,7 @@ pub(crate) fn code_lens_kind( } else { keys::CODE_LENS_INSTANCES_MANY }; - lsp_types::Command { + lspt::Command { title: snap.config.i18n.format(key, [("count", count.to_string())]), command: String::new(), arguments: None, @@ -611,8 +614,8 @@ pub(crate) fn code_lens_kind( let data = match kind { CodeLensKind::ModuleInstance { pos: FilePosition { offset, .. }, .. } => { snap.url_file_version(&url).and_then(|version| { - let file_pos = lsp_types::TextDocumentPositionParams { - text_document: lsp_types::TextDocumentIdentifier { uri: url.clone() }, + let file_pos = ext::TextDocumentPositionParams { + text_document: lspt::TextDocumentIdentifier { uri: url.clone() }, position: self::position(line_info, offset), }; let data = @@ -629,7 +632,7 @@ pub(crate) struct SemanticTokensBuilder { id: String, prev_line: u32, prev_char: u32, - data: Vec, + data: Vec, } impl SemanticTokensBuilder { @@ -640,11 +643,11 @@ impl SemanticTokensBuilder { /// Push a new token onto the builder pub(crate) fn push( &mut self, - range: lsp_types::Range, + range: lspt::Range, token_type: u32, token_modifiers_bitset: u32, ) { - let lsp_types::Position { line: mut push_line, character: mut push_char } = range.start; + let lspt::Position { line: mut push_line, character: mut push_char } = range.start; if !self.data.is_empty() { if push_line < self.prev_line @@ -664,22 +667,20 @@ impl SemanticTokensBuilder { } } - let token = lsp_types::SemanticToken { - delta_line: push_line, - delta_start: push_char, - length: range.end.character.saturating_sub(range.start.character), + self.data.extend([ + push_line, + push_char, + range.end.character.saturating_sub(range.start.character), token_type, token_modifiers_bitset, - }; - - self.data.push(token); + ]); self.prev_line = range.start.line; self.prev_char = range.start.character; } - pub(crate) fn build(self) -> lsp_types::SemanticTokens { - lsp_types::SemanticTokens { result_id: Some(self.id), data: self.data } + pub(crate) fn build(self) -> lspt::SemanticTokens { + lspt::SemanticTokens { result_id: Some(self.id), data: self.data } } } @@ -687,7 +688,7 @@ pub(crate) fn semantic_tokens( text: &str, line_info: &LineInfo, sema_tokens: Vec, -) -> lsp_types::SemanticTokens { +) -> lspt::SemanticTokens { static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1); let id = TOKEN_RESULT_COUNTER.fetch_add(1, Ordering::SeqCst).to_string(); @@ -704,7 +705,7 @@ pub(crate) fn semantic_tokens( }; // Prefer standard tokens where we have an explicit fallback, otherwise // keep the token from the advertised legend. - let legend_ty = sema_token_types::fallback(ty.clone()).unwrap_or(ty); + let legend_ty = sema_token_types::fallback(ty).unwrap_or(ty); let Some(ty) = SEMA_TOKENS_TYPES.iter().position(|it| it == &legend_ty).map(|idx| idx as u32) else { @@ -727,7 +728,7 @@ pub(crate) fn semantic_tokens( }; // Prefer standard modifiers where we have an explicit fallback, // otherwise keep the modifier from the advertised legend. - mods_set |= sema_token_modifiers::fallback(modifier.clone()).unwrap_or(modifier); + mods_set |= sema_token_modifiers::fallback(modifier).unwrap_or(modifier); } let mods = mods_set.finish(); @@ -744,9 +745,9 @@ pub(crate) fn semantic_tokens( } pub(crate) fn semantic_token_delta( - lsp_types::SemanticTokens { data: old, .. }: &lsp_types::SemanticTokens, - lsp_types::SemanticTokens { data: new, result_id }: &lsp_types::SemanticTokens, -) -> lsp_types::SemanticTokensDelta { + lspt::SemanticTokens { data: old, .. }: &lspt::SemanticTokens, + lspt::SemanticTokens { data: new, result_id }: &lspt::SemanticTokens, +) -> lspt::SemanticTokensDelta { let old = old.as_slice(); let new = new.as_slice(); @@ -763,21 +764,20 @@ pub(crate) fn semantic_token_delta( let edits = if old.is_empty() && new.is_empty() { vec![] } else { - const TOKEN_SIZE: u32 = 5; - vec![lsp_types::SemanticTokensEdit { - start: TOKEN_SIZE * (offset as u32), - delete_count: TOKEN_SIZE * (old.len() as u32), - data: Some(new.into()), + vec![lspt::SemanticTokensEdit { + start: offset as u32, + delete_count: old.len() as u32, + data: Some(new.to_vec()), }] }; - lsp_types::SemanticTokensDelta { result_id: result_id.clone().clone(), edits } + lspt::SemanticTokensDelta { result_id: result_id.clone().clone(), edits } } pub(crate) fn signature_help( sig_help: SignatureHelp, support_label_offsets: bool, -) -> lsp_types::SignatureHelp { +) -> lspt::SignatureHelp { let parameters = if support_label_offsets { sig_help .param_ranges @@ -787,8 +787,8 @@ pub(crate) fn signature_help( let end = sig_help.label[..it.end().into()].chars().count() as u32; [start, end] }) - .map(|range| lsp_types::ParameterInformation { - label: lsp_types::ParameterLabel::LabelOffsets(range), + .map(|range| lspt::ParameterInformation { + label: lspt::Union2::B((range[0], range[1])), documentation: None, }) .collect() @@ -796,8 +796,8 @@ pub(crate) fn signature_help( sig_help .param_ranges .iter() - .map(|range| lsp_types::ParameterInformation { - label: lsp_types::ParameterLabel::Simple(sig_help.label[*range].to_owned()), + .map(|range| lspt::ParameterInformation { + label: lspt::Union2::A(sig_help.label[*range].to_owned()), documentation: None, }) .collect() @@ -805,39 +805,35 @@ pub(crate) fn signature_help( let active_parameter = sig_help.active_parameter.map(|it| it as u32); - let signature = lsp_types::SignatureInformation { + let signature = lspt::SignatureInformation { label: sig_help.label, documentation: None, parameters: Some(parameters), active_parameter, }; - lsp_types::SignatureHelp { - signatures: vec![signature], - active_signature: Some(0), - active_parameter, - } + lspt::SignatureHelp { signatures: vec![signature], active_signature: Some(0), active_parameter } } -pub(crate) fn code_action_kind(kind: CodeActionKind) -> lsp_types::CodeActionKind { +pub(crate) fn code_action_kind(kind: CodeActionKind) -> lspt::CodeActionKind { match kind { - CodeActionKind::Generate => lsp_types::CodeActionKind::EMPTY, - CodeActionKind::QuickFix => lsp_types::CodeActionKind::QUICKFIX, - CodeActionKind::Refactor => lsp_types::CodeActionKind::REFACTOR, - CodeActionKind::RefactorExtract => lsp_types::CodeActionKind::REFACTOR_EXTRACT, - CodeActionKind::RefactorInline => lsp_types::CodeActionKind::REFACTOR_INLINE, - CodeActionKind::RefactorRewrite => lsp_types::CodeActionKind::REFACTOR_REWRITE, + CodeActionKind::Generate => lspt::CodeActionKind::Empty, + CodeActionKind::QuickFix => lspt::CodeActionKind::QuickFix, + CodeActionKind::Refactor => lspt::CodeActionKind::Refactor, + CodeActionKind::RefactorExtract => lspt::CodeActionKind::RefactorExtract, + CodeActionKind::RefactorInline => lspt::CodeActionKind::RefactorInline, + CodeActionKind::RefactorRewrite => lspt::CodeActionKind::RefactorRewrite, } } pub(crate) fn code_action( snap: &GlobalStateSnapshot, CodeAction { id, label, source_change, .. }: CodeAction, - resolve_data: Option<(usize, lsp_types::CodeActionParams, Option)>, - diagnostics: Option>, -) -> anyhow::Result { + resolve_data: Option<(usize, lspt::CodeActionParams, Option)>, + diagnostics: Option>, +) -> anyhow::Result { let title = code_action_title(snap.config.i18n, id.name, &label); - let mut res = lsp_types::CodeAction { + let mut res = lspt::CodeAction { title, kind: Some(self::code_action_kind(id.kind)), edit: None, @@ -846,6 +842,7 @@ pub(crate) fn code_action( diagnostics, disabled: None, data: None, + tags: None, }; match (source_change, resolve_data) { diff --git a/src/main.rs b/src/main.rs index cf90022c..cb0ee87b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use config::Config; use const_format::formatcp; use itertools::Itertools; use lsp_server::Connection; -use lsp_types::{MessageType, ShowMessageParams}; +use lspt::{MessageType, ShowMessageParams, TraceValue}; use slang as _; use tracing_subscriber::{ Registry, filter::Targets, fmt::writer::BoxMakeWriter, layer::SubscriberExt, @@ -97,29 +97,18 @@ fn run_server(opt: Opt) -> anyhow::Result<()> { tracing::info!("Server initialized. InitializeParams: {}", &initialize_params); - let lsp_types::InitializeParams { - root_uri, + let lspt::InitializeParams { capabilities: client_caps, workspace_folders, initialization_options, trace, locale, .. - } = from_json::("InitializeParams", &initialize_params)?; - - let root_path = match root_uri - .and_then(|uri| uri.to_file_path().ok()) - .map(patch_path_prefix) - .and_then(|path| AbsPathBuf::try_from(path).ok()) - { - Some(path) => path, - None => AbsPathBuf::try_from(env::current_dir()?).map_err(|path| { - anyhow::format_err!( - "current directory is not an absolute UTF-8 path: {}", - path.display() - ) - })?, - }; + } = from_json::("InitializeParams", &initialize_params)?; + + let root_path = AbsPathBuf::try_from(env::current_dir()?).map_err(|path| { + anyhow::format_err!("current directory is not an absolute UTF-8 path: {}", path.display()) + })?; let workspace_roots = workspace_folders .map(|workspace| { @@ -138,10 +127,10 @@ fn run_server(opt: Opt) -> anyhow::Result<()> { let (user_config, snippets) = if let Some(options) = initialization_options { let (user_config, snippets, errors) = Config::parse_initialization_options(options); if !errors.is_empty() { - use lsp_types::notification::{Notification, ShowMessage}; + use lspt::notification::{Notification, ShowMessageNotification}; let noti = lsp_server::Notification::new( - ShowMessage::METHOD.to_string(), - ShowMessageParams { typ: MessageType::WARNING, message: errors.message(i18n) }, + ShowMessageNotification::METHOD.to_string(), + ShowMessageParams { ty: MessageType::Warning, message: errors.message(i18n) }, ); if connection.sender.send(lsp_server::Message::Notification(noti)).is_err() { tracing::debug!( @@ -157,9 +146,9 @@ fn run_server(opt: Opt) -> anyhow::Result<()> { let config = Config::new(opt, root_path, client_caps, workspace_roots, i18n, user_config, snippets); - let initialize_result = lsp_types::InitializeResult { + let initialize_result = lspt::InitializeResult { capabilities: config.server_caps(), - server_info: Some(lsp_types::ServerInfo { + server_info: Some(lspt::ServerInfo { name: config.opt.process_name.clone(), version: Some(VERSION.to_string()), }), @@ -174,7 +163,7 @@ fn run_server(opt: Opt) -> anyhow::Result<()> { return Err(e.into()); } - main_loop::main_loop(config, connection, trace.unwrap_or_default())?; + main_loop::main_loop(config, connection, trace.unwrap_or(TraceValue::Off))?; io_threads.join()?; tracing::info!("Server shut down. BYE!"); diff --git a/src/tests.rs b/src/tests.rs index 47620cd7..9d04ed2a 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -4,27 +4,29 @@ use std::{ }; use lsp_server::{Connection, Message, Notification, Request}; -use lsp_types::{ - ClientCapabilities, CodeActionCapabilityResolveSupport, CodeActionClientCapabilities, - CodeActionContext, CodeActionKind, CodeActionKindLiteralSupport, CodeActionLiteralSupport, - CodeActionOrCommand, CodeActionParams, DiagnosticClientCapabilities, - DidChangeTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams, - DocumentDiagnosticParams, DocumentDiagnosticReport, DocumentDiagnosticReportResult, - DocumentSymbolParams, DocumentSymbolResponse, FileChangeType, FileEvent, FoldingRange, - FoldingRangeParams, GotoDefinitionParams, GotoDefinitionResponse, Hover, HoverParams, Position, - ProgressParams, PublishDiagnosticsParams, Range, SemanticTokensParams, SemanticTokensResult, - TextDocumentClientCapabilities, TextDocumentContentChangeEvent, TextDocumentIdentifier, - TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, - WorkDoneProgressParams, WorkspaceClientCapabilities, WorkspaceDiagnosticParams, - WorkspaceDiagnosticReportResult, +use lspt::{ + ClientCapabilities, ClientCodeActionKindOptions, ClientCodeActionLiteralOptions, + ClientCodeActionResolveOptions, CodeActionClientCapabilities, CodeActionContext, + CodeActionKind, CodeActionParams, DiagnosticClientCapabilities, DidChangeTextDocumentParams, + DidOpenTextDocumentParams, DidSaveTextDocumentParams, DocumentDiagnosticParams, + DocumentSymbolParams, FileChangeType, FileEvent, FoldingRange, FoldingRangeParams, Hover, + HoverParams, Position, ProgressParams, PublishDiagnosticsParams, Range, SemanticTokensParams, + TextDocumentClientCapabilities, TextDocumentIdentifier, TextDocumentItem, Union2, Union3, + Uri as Url, VersionedTextDocumentIdentifier, WorkspaceClientCapabilities, + WorkspaceDiagnosticParams, notification::{ - DidChangeTextDocument, DidChangeWatchedFiles, DidOpenTextDocument, DidSaveTextDocument, - Exit, Notification as _, + DidChangeTextDocumentNotification as DidChangeTextDocument, + DidChangeWatchedFilesNotification as DidChangeWatchedFiles, + DidOpenTextDocumentNotification as DidOpenTextDocument, + DidSaveTextDocumentNotification as DidSaveTextDocument, ExitNotification as Exit, + Notification as _, }, request::{ - CodeActionRequest, CodeLensRequest, CodeLensResolve, DocumentDiagnosticRequest, - DocumentSymbolRequest, FoldingRangeRequest, GotoDefinition, HoverRequest, References, - Request as _, SemanticTokensFullRequest, Shutdown, WorkspaceDiagnosticRequest, + CodeActionRequest, CodeLensRequest, CodeLensResolveRequest as CodeLensResolve, + DefinitionRequest as GotoDefinition, DocumentDiagnosticRequest, DocumentSymbolRequest, + FoldingRangeRequest, HoverRequest, ReferencesRequest as References, Request as _, + SemanticTokensRequest as SemanticTokensFullRequest, ShutdownRequest as Shutdown, + WorkspaceDiagnosticRequest, }, }; use serde::de::DeserializeOwned; @@ -42,6 +44,14 @@ use crate::{ }; type TempDir = TestDir; +type CodeActionOrCommand = Union2; +type DocumentDiagnosticReportResult = ::Result; +type DocumentSymbolResponse = Union2, Vec>; +type GotoDefinitionResponse = + Union3, Vec>; +type SemanticTokensResult = Union2; +type WorkspaceDiagnosticReportResult = + ::Result; const LSP_TEST_TIMEOUT: Duration = Duration::from_secs(30); const DEFAULT_TEST_CONFIG: &str = "sources = [\"**\"]\ninclude_dirs = [\".\"]\n"; @@ -73,8 +83,8 @@ fn recv_lsp_message_until( } fn handle_test_server_request(client: &Connection, request: Request, context: &str) { - if request.method == lsp_types::request::WorkDoneProgressCreate::METHOD - || request.method == lsp_types::request::WorkspaceDiagnosticRefresh::METHOD + if request.method == lspt::request::WorkDoneProgressCreateRequest::METHOD + || request.method == lspt::request::DiagnosticRefreshRequest::METHOD { client .sender @@ -90,7 +100,7 @@ fn spawn_default_test_server( config: config::Config, server: Connection, ) -> thread::JoinHandle> { - thread::spawn(move || main_loop::main_loop(config, server, lsp_types::TraceValue::Off)) + thread::spawn(move || main_loop::main_loop(config, server, lspt::TraceValue::Off)) } fn test_server_config( @@ -142,7 +152,7 @@ fn open_test_document(client: &Connection, uri: Url, text: &str) { DidOpenTextDocumentParams { text_document: TextDocumentItem { uri, - language_id: "systemverilog".to_string(), + language_id: lspt::LanguageKind::Custom_("systemverilog".to_string()), version: 1, text: text.to_owned(), }, @@ -255,9 +265,10 @@ fn shutdown_test_server( match client.receiver.recv_timeout(LSP_TEST_TIMEOUT).unwrap() { Message::Response(response) if response.id == shutdown_id => break, Message::Notification(notification) - if notification.method == lsp_types::notification::Progress::METHOD => {} + if notification.method == lspt::notification::ProgressNotification::METHOD => {} Message::Notification(notification) - if notification.method == lsp_types::notification::PublishDiagnostics::METHOD => {} + if notification.method + == lspt::notification::PublishDiagnosticsNotification::METHOD => {} other => panic!("unexpected message while shutting down test server: {other:?}"), } } @@ -273,7 +284,7 @@ fn shutdown_test_server( fn recv_document_diagnostics( client: &Connection, request_id: lsp_server::RequestId, -) -> (Option, Vec) { +) -> (Option, Vec) { let deadline = Instant::now() + LSP_TEST_TIMEOUT; while let Some(message) = recv_lsp_message_until(client, deadline, "documentDiagnostic") { match message { @@ -284,22 +295,16 @@ fn recv_document_diagnostics( ) .unwrap(); return match result { - DocumentDiagnosticReportResult::Report(DocumentDiagnosticReport::Full( - report, - )) => ( - report.full_document_diagnostic_report.result_id, - report.full_document_diagnostic_report.items, - ), - DocumentDiagnosticReportResult::Report( - DocumentDiagnosticReport::Unchanged(report), - ) => (Some(report.unchanged_document_diagnostic_report.result_id), Vec::new()), + Union2::A(Union2::A(report)) => (report.result_id, report.items), + Union2::A(Union2::B(report)) => (Some(report.result_id), Vec::new()), other => panic!("unexpected diagnostic response: {other:?}"), }; } Message::Notification(notification) - if notification.method == lsp_types::notification::Progress::METHOD => {} + if notification.method == lspt::notification::ProgressNotification::METHOD => {} Message::Notification(notification) - if notification.method == lsp_types::notification::PublishDiagnostics::METHOD => {} + if notification.method + == lspt::notification::PublishDiagnosticsNotification::METHOD => {} Message::Request(request) => { handle_test_server_request(client, request, "documentDiagnostic diagnostics test") } @@ -314,7 +319,7 @@ fn request_document_diagnostics( client: &Connection, uri: Url, request_id: i32, -) -> (Option, Vec) { +) -> (Option, Vec) { let request_id = lsp_server::RequestId::from(request_id); client .sender @@ -325,8 +330,8 @@ fn request_document_diagnostics( text_document: TextDocumentIdentifier { uri }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -346,13 +351,11 @@ fn request_goto_definition_uris( .send(Message::Request(Request::new( request_id.clone(), GotoDefinition::METHOD.to_string(), - GotoDefinitionParams { - text_document_position_params: TextDocumentPositionParams { - text_document: TextDocumentIdentifier { uri }, - position: position_of(text, needle), - }, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + lspt::DefinitionParams { + text_document: TextDocumentIdentifier { uri }, + position: position_of(text, needle), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -375,28 +378,25 @@ fn request_reference_uris( .send(Message::Request(Request::new( request_id.clone(), References::METHOD.to_string(), - lsp_types::ReferenceParams { - text_document_position: TextDocumentPositionParams { - text_document: TextDocumentIdentifier { uri }, - position: position_of(text, needle), - }, - context: lsp_types::ReferenceContext { include_declaration: true }, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + lspt::ReferenceParams { + text_document: TextDocumentIdentifier { uri }, + position: position_of(text, needle), + context: lspt::ReferenceContext { include_declaration: true }, + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); - let references: Option> = - recv_response(client, request_id, "references"); + let references: Option> = recv_response(client, request_id, "references"); references.unwrap_or_default().into_iter().map(|location| location.uri).collect() } fn request_workspace_diagnostic_report( client: &Connection, request_id: i32, - previous_result_ids: Vec, -) -> lsp_types::WorkspaceDiagnosticReport { + previous_result_ids: Vec, +) -> lspt::WorkspaceDiagnosticReport { let request_id = lsp_server::RequestId::from(request_id); client .sender @@ -406,15 +406,15 @@ fn request_workspace_diagnostic_report( WorkspaceDiagnosticParams { identifier: None, previous_result_ids, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); let result: WorkspaceDiagnosticReportResult = recv_response(client, request_id, "workspaceDiagnostic"); - let WorkspaceDiagnosticReportResult::Report(report) = result else { + let Union2::A(report) = result else { panic!("unexpected workspaceDiagnostic response: {result:?}"); }; report @@ -425,18 +425,19 @@ fn request_workspace_diagnostic_uris(client: &Connection, request_id: i32) -> Ve .items .into_iter() .map(|item| match item { - lsp_types::WorkspaceDocumentDiagnosticReport::Full(full) => full.uri, - lsp_types::WorkspaceDocumentDiagnosticReport::Unchanged(unchanged) => unchanged.uri, + Union2::A(full) => full.uri, + Union2::B(unchanged) => unchanged.uri, }) .collect() } -fn recv_publish_diagnostics_for_uri(client: &Connection, uri: &Url) -> Vec { +fn recv_publish_diagnostics_for_uri(client: &Connection, uri: &Url) -> Vec { let deadline = Instant::now() + LSP_TEST_TIMEOUT; while let Some(message) = recv_lsp_message_until(client, deadline, "publishDiagnostics") { match message { Message::Notification(notification) - if notification.method == lsp_types::notification::PublishDiagnostics::METHOD => + if notification.method + == lspt::notification::PublishDiagnosticsNotification::METHOD => { let params = serde_json::from_value::(notification.params) @@ -446,7 +447,7 @@ fn recv_publish_diagnostics_for_uri(client: &Connection, uri: &Url) -> Vec {} + if notification.method == lspt::notification::ProgressNotification::METHOD => {} Message::Request(request) => { handle_test_server_request(client, request, "publishDiagnostics diagnostics test") } @@ -471,9 +472,10 @@ fn recv_response( .unwrap_or_else(|err| panic!("failed to decode {label} response: {err}")); } Message::Notification(notification) - if notification.method == lsp_types::notification::Progress::METHOD => {} + if notification.method == lspt::notification::ProgressNotification::METHOD => {} Message::Notification(notification) - if notification.method == lsp_types::notification::PublishDiagnostics::METHOD => {} + if notification.method + == lspt::notification::PublishDiagnosticsNotification::METHOD => {} Message::Request(request) => handle_test_server_request(client, request, label), _ => {} } @@ -484,13 +486,12 @@ fn recv_response( fn goto_definition_response_uris(response: GotoDefinitionResponse) -> Vec { match response { - GotoDefinitionResponse::Scalar(location) => vec![location.uri], - GotoDefinitionResponse::Array(locations) => { + Union3::A(Union2::A(location)) => vec![location.uri], + Union3::A(Union2::B(locations)) => { locations.into_iter().map(|location| location.uri).collect() } - GotoDefinitionResponse::Link(links) => { - links.into_iter().map(|location| location.target_uri).collect() - } + Union3::B(links) => links.into_iter().map(|location| location.target_uri).collect(), + Union3::C(locations) => locations.into_iter().map(|location| location.uri).collect(), } } @@ -505,20 +506,19 @@ fn code_action_client_caps() -> ClientCapabilities { ClientCapabilities { text_document: Some(TextDocumentClientCapabilities { code_action: Some(CodeActionClientCapabilities { - code_action_literal_support: Some(CodeActionLiteralSupport { - code_action_kind: CodeActionKindLiteralSupport { + code_action_literal_support: Some(ClientCodeActionLiteralOptions { + code_action_kind: ClientCodeActionKindOptions { value_set: [ - CodeActionKind::EMPTY, - CodeActionKind::QUICKFIX, - CodeActionKind::REFACTOR, - CodeActionKind::REFACTOR_REWRITE, + CodeActionKind::Empty, + CodeActionKind::QuickFix, + CodeActionKind::Refactor, + CodeActionKind::RefactorRewrite, ] .into_iter() - .map(|kind| kind.as_str().to_owned()) .collect(), }, }), - resolve_support: Some(CodeActionCapabilityResolveSupport { + resolve_support: Some(ClientCodeActionResolveOptions { properties: vec!["edit".to_owned()], }), ..Default::default() @@ -547,10 +547,10 @@ fn request_code_actions( CodeActionRequest::METHOD.to_string(), CodeActionParams { text_document: TextDocumentIdentifier { uri }, - range: Range::new(position, position), + range: Range { start: position, end: position }, context, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -558,17 +558,17 @@ fn request_code_actions( recv_response(client, request_id, "codeAction") } -fn request_code_lenses(client: &Connection, uri: Url, request_id: i32) -> Vec { +fn request_code_lenses(client: &Connection, uri: Url, request_id: i32) -> Vec { let request_id = lsp_server::RequestId::from(request_id); client .sender .send(Message::Request(Request::new( request_id.clone(), CodeLensRequest::METHOD.to_string(), - lsp_types::CodeLensParams { + lspt::CodeLensParams { text_document: TextDocumentIdentifier { uri }, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -576,11 +576,7 @@ fn request_code_lenses(client: &Connection, uri: Url, request_id: i32) -> Vec lsp_types::CodeLens { +fn resolve_code_lens(client: &Connection, lens: lspt::CodeLens, request_id: i32) -> lspt::CodeLens { let request_id = lsp_server::RequestId::from(request_id); client .sender @@ -598,8 +594,8 @@ fn code_action_titles(actions: &[CodeActionOrCommand]) -> Vec { actions .iter() .map(|action| match action { - CodeActionOrCommand::CodeAction(action) => action.title.clone(), - CodeActionOrCommand::Command(command) => command.title.clone(), + Union2::B(action) => action.title.clone(), + Union2::A(command) => command.title.clone(), }) .collect() } @@ -616,11 +612,9 @@ fn clearing_open_document_updates_analysis_state() { DidChangeTextDocument::METHOD.to_string(), DidChangeTextDocumentParams { text_document: VersionedTextDocumentIdentifier { uri: uri.clone(), version: 2 }, - content_changes: vec![TextDocumentContentChangeEvent { - range: None, - range_length: None, + content_changes: vec![Union2::B(lspt::TextDocumentContentChangeWholeDocument { text: String::new(), - }], + })], }, ))) .unwrap(); @@ -633,8 +627,8 @@ fn clearing_open_document_updates_analysis_state() { DocumentSymbolRequest::METHOD.to_string(), DocumentSymbolParams { text_document: TextDocumentIdentifier { uri }, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -642,8 +636,8 @@ fn clearing_open_document_updates_analysis_state() { let symbols: Option = recv_response(&client, symbols_id, "documentSymbol"); let symbol_count = match symbols { - Some(DocumentSymbolResponse::Nested(symbols)) => symbols.len(), - Some(DocumentSymbolResponse::Flat(symbols)) => symbols.len(), + Some(Union2::B(symbols)) => symbols.len(), + Some(Union2::A(symbols)) => symbols.len(), None => 0, }; @@ -675,8 +669,8 @@ endmodule text_document: TextDocumentIdentifier { uri: uri.clone() }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -689,7 +683,7 @@ endmodule "convert_ports_only (clk", CodeActionContext { diagnostics: Vec::new(), - only: Some(vec![CodeActionKind::REFACTOR_REWRITE]), + only: Some(vec![CodeActionKind::RefactorRewrite]), trigger_kind: None, }, 200, @@ -728,8 +722,8 @@ endmodule text_document: TextDocumentIdentifier { uri: uri.clone() }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -746,7 +740,7 @@ endmodule "clk, .rst_n", CodeActionContext { diagnostics, - only: Some(vec![CodeActionKind::QUICKFIX]), + only: Some(vec![CodeActionKind::QuickFix]), trigger_kind: None, }, 211, @@ -864,22 +858,16 @@ endconfig text_document: text_document.clone(), identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); let diagnostics: DocumentDiagnosticReportResult = recv_response(&client, diagnostics_id, "documentDiagnostic"); - if let DocumentDiagnosticReportResult::Report(DocumentDiagnosticReport::Full(report)) = - diagnostics - { + if let Union2::A(Union2::A(report)) = diagnostics { assert!( - report - .full_document_diagnostic_report - .items - .iter() - .all(|diag| diag.source.as_deref() != Some("vizsla")), + report.items.iter().all(|diag| diag.source.as_deref() != Some("vizsla")), "document diagnostics should not include removed Vizsla model diagnostics" ); } @@ -892,8 +880,8 @@ endconfig DocumentSymbolRequest::METHOD.to_string(), DocumentSymbolParams { text_document: text_document.clone(), - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -909,8 +897,8 @@ endconfig SemanticTokensFullRequest::METHOD.to_string(), SemanticTokensParams { text_document: text_document.clone(), - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -926,8 +914,8 @@ endconfig FoldingRangeRequest::METHOD.to_string(), FoldingRangeParams { text_document: text_document.clone(), - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -941,11 +929,9 @@ endconfig hover_id.clone(), HoverRequest::METHOD.to_string(), HoverParams { - text_document_position_params: TextDocumentPositionParams { - text_document: text_document.clone(), - position: position_of(file_text, "g_loop"), - }, - work_done_progress_params: WorkDoneProgressParams::default(), + text_document: text_document.clone(), + position: position_of(file_text, "g_loop"), + work_done_token: None, }, ))) .unwrap(); @@ -958,13 +944,11 @@ endconfig .send(Message::Request(Request::new( definition_id.clone(), GotoDefinition::METHOD.to_string(), - GotoDefinitionParams { - text_document_position_params: TextDocumentPositionParams { - text_document, - position: position_of(file_text, "sig), .y"), - }, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + lspt::DefinitionParams { + text_document, + position: position_of(file_text, "sig), .y"), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -994,8 +978,8 @@ fn pull_capable_client_does_not_receive_duplicate_publish_diagnostics() { text_document: TextDocumentIdentifier { uri: uri.clone() }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ); client.sender.send(Message::Request(request)).unwrap(); @@ -1016,15 +1000,14 @@ fn pull_capable_client_does_not_receive_duplicate_publish_diagnostics() { ) .unwrap(); let items = match result { - DocumentDiagnosticReportResult::Report(DocumentDiagnosticReport::Full( - report, - )) => report.full_document_diagnostic_report.items, + Union2::A(Union2::A(report)) => report.items, other => panic!("unexpected diagnostic response: {other:?}"), }; pull_diagnostics = Some(items); } Message::Notification(notification) - if notification.method == lsp_types::notification::PublishDiagnostics::METHOD => + if notification.method + == lspt::notification::PublishDiagnosticsNotification::METHOD => { let params = serde_json::from_value::(notification.params) @@ -1034,7 +1017,7 @@ fn pull_capable_client_does_not_receive_duplicate_publish_diagnostics() { } } Message::Notification(notification) - if notification.method == lsp_types::notification::Progress::METHOD => + if notification.method == lspt::notification::ProgressNotification::METHOD => { let _ = serde_json::from_value::(notification.params).unwrap(); } @@ -1058,7 +1041,8 @@ fn pull_capable_client_does_not_receive_duplicate_publish_diagnostics() { let timeout = quiet_until.saturating_duration_since(Instant::now()); match client.receiver.recv_timeout(timeout) { Ok(Message::Notification(notification)) - if notification.method == lsp_types::notification::PublishDiagnostics::METHOD => + if notification.method + == lspt::notification::PublishDiagnosticsNotification::METHOD => { let params = serde_json::from_value::(notification.params) @@ -1069,7 +1053,7 @@ fn pull_capable_client_does_not_receive_duplicate_publish_diagnostics() { ); } Ok(Message::Notification(notification)) - if notification.method == lsp_types::notification::Progress::METHOD => {} + if notification.method == lspt::notification::ProgressNotification::METHOD => {} Ok(other) => { panic!("unexpected message after pull diagnostics response: {other:?}"); } @@ -1096,7 +1080,8 @@ fn legacy_client_receives_publish_diagnostics() { let timeout = deadline.saturating_duration_since(Instant::now()); match client.receiver.recv_timeout(timeout).unwrap() { Message::Notification(notification) - if notification.method == lsp_types::notification::PublishDiagnostics::METHOD => + if notification.method + == lspt::notification::PublishDiagnosticsNotification::METHOD => { let params = serde_json::from_value::(notification.params) @@ -1108,7 +1093,7 @@ fn legacy_client_receives_publish_diagnostics() { } } Message::Notification(notification) - if notification.method == lsp_types::notification::Progress::METHOD => {} + if notification.method == lspt::notification::ProgressNotification::METHOD => {} Message::Request(request) => { panic!("unexpected server request during diagnostics test: {request:?}"); } @@ -1155,8 +1140,8 @@ endmodule text_document: TextDocumentIdentifier { uri }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ); client.sender.send(Message::Request(request)).unwrap(); @@ -1172,9 +1157,7 @@ endmodule ) .unwrap(); let items = match result { - DocumentDiagnosticReportResult::Report(DocumentDiagnosticReport::Full( - report, - )) => report.full_document_diagnostic_report.items, + Union2::A(Union2::A(report)) => report.items, other => panic!("unexpected diagnostic response: {other:?}"), }; assert!( @@ -1185,7 +1168,7 @@ endmodule return; } Message::Notification(notification) - if notification.method == lsp_types::notification::Progress::METHOD => {} + if notification.method == lspt::notification::ProgressNotification::METHOD => {} Message::Request(request) => { panic!("unexpected server request during diagnostics test: {request:?}"); } @@ -1227,8 +1210,8 @@ endmodule text_document: TextDocumentIdentifier { uri }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -1282,7 +1265,7 @@ fn unconfigured_workspace_diagnostics_skip_unopened_indexed_files() { ..Default::default() }), workspace: Some(WorkspaceClientCapabilities { - diagnostic: Some(lsp_types::DiagnosticWorkspaceClientCapabilities { + diagnostics: Some(lspt::DiagnosticWorkspaceClientCapabilities { refresh_support: Some(true), }), ..Default::default() @@ -1343,8 +1326,8 @@ endmodule text_document: TextDocumentIdentifier { uri }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -1389,8 +1372,8 @@ endmodule text_document: TextDocumentIdentifier { uri }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -1430,8 +1413,8 @@ endmodule text_document: TextDocumentIdentifier { uri }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -1474,8 +1457,8 @@ fn workspace_diagnostics_use_multi_file_semantic_context() { WorkspaceDiagnosticParams { identifier: None, previous_result_ids: Vec::new(), - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ); client.sender.send(Message::Request(request)).unwrap(); @@ -1491,20 +1474,20 @@ fn workspace_diagnostics_use_multi_file_semantic_context() { ) .unwrap(); let report = match result { - WorkspaceDiagnosticReportResult::Report(report) => report, + Union2::A(report) => report, other => panic!("unexpected workspace diagnostic response: {other:?}"), }; let mut child_diagnostics = None; let mut unused_diagnostics = None; let mut top_diagnostics = None; for item in report.items { - if let lsp_types::WorkspaceDocumentDiagnosticReport::Full(full) = item { + if let Union2::A(full) = item { if full.uri == child_uri { - child_diagnostics = Some(full.full_document_diagnostic_report.items); + child_diagnostics = Some(full.items); } else if full.uri == unused_uri { - unused_diagnostics = Some(full.full_document_diagnostic_report.items); + unused_diagnostics = Some(full.items); } else if full.uri == top_uri { - top_diagnostics = Some(full.full_document_diagnostic_report.items); + top_diagnostics = Some(full.items); } } } @@ -1544,7 +1527,7 @@ fn workspace_diagnostics_use_multi_file_semantic_context() { return; } Message::Notification(notification) - if notification.method == lsp_types::notification::Progress::METHOD => {} + if notification.method == lspt::notification::ProgressNotification::METHOD => {} Message::Request(request) => { panic!("unexpected server request during diagnostics test: {request:?}"); } @@ -1605,7 +1588,7 @@ fn configured_include_dirs_suppress_include_defined_macro_diagnostic() { DidOpenTextDocumentParams { text_document: TextDocumentItem { uri: top_uri.clone(), - language_id: "systemverilog".to_string(), + language_id: lspt::LanguageKind::Custom_("systemverilog".to_string()), version: 1, text: top_text.to_string(), }, @@ -1623,8 +1606,8 @@ fn configured_include_dirs_suppress_include_defined_macro_diagnostic() { text_document: TextDocumentIdentifier { uri: top_uri }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -1705,8 +1688,8 @@ fn unsaved_library_include_header_changes_are_used_for_dependent_diagnostics() { text_document: TextDocumentIdentifier { uri: top_uri.clone() }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -1723,7 +1706,7 @@ fn unsaved_library_include_header_changes_are_used_for_dependent_diagnostics() { DidOpenTextDocumentParams { text_document: TextDocumentItem { uri: header_uri, - language_id: "systemverilog".to_string(), + language_id: lspt::LanguageKind::Custom_("systemverilog".to_string()), version: 1, text: String::new(), }, @@ -1741,8 +1724,8 @@ fn unsaved_library_include_header_changes_are_used_for_dependent_diagnostics() { text_document: TextDocumentIdentifier { uri: top_uri }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -1818,8 +1801,8 @@ fn unsaved_include_header_changes_are_used_for_dependent_diagnostics() { text_document: TextDocumentIdentifier { uri: top_uri.clone() }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -1836,7 +1819,7 @@ fn unsaved_include_header_changes_are_used_for_dependent_diagnostics() { DidOpenTextDocumentParams { text_document: TextDocumentItem { uri: header_uri.clone(), - language_id: "systemverilog".to_string(), + language_id: lspt::LanguageKind::Custom_("systemverilog".to_string()), version: 1, text: String::new(), }, @@ -1854,8 +1837,8 @@ fn unsaved_include_header_changes_are_used_for_dependent_diagnostics() { text_document: TextDocumentIdentifier { uri: top_uri }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -1911,7 +1894,7 @@ fn project_manifest_is_not_diagnosed_as_systemverilog() { DidOpenTextDocumentParams { text_document: TextDocumentItem { uri: manifest_uri.clone(), - language_id: "toml".to_string(), + language_id: lspt::LanguageKind::Custom_("toml".to_string()), version: 1, text: manifest_text.to_string(), }, @@ -1928,11 +1911,9 @@ fn project_manifest_is_not_diagnosed_as_systemverilog() { uri: manifest_uri.clone(), version: 2, }, - content_changes: vec![TextDocumentContentChangeEvent { - range: None, - range_length: None, + content_changes: vec![Union2::B(lspt::TextDocumentContentChangeWholeDocument { text: String::new(), - }], + })], }, ))) .unwrap(); @@ -1946,11 +1927,9 @@ fn project_manifest_is_not_diagnosed_as_systemverilog() { uri: manifest_uri.clone(), version: 3, }, - content_changes: vec![TextDocumentContentChangeEvent { - range: None, - range_length: None, + content_changes: vec![Union2::B(lspt::TextDocumentContentChangeWholeDocument { text: manifest_text.to_string(), - }], + })], }, ))) .unwrap(); @@ -1965,8 +1944,8 @@ fn project_manifest_is_not_diagnosed_as_systemverilog() { text_document: TextDocumentIdentifier { uri: manifest_uri }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -2021,14 +2000,11 @@ fn restored_project_manifest_clears_diagnostics_for_excluded_files() { let first_report = request_workspace_diagnostic_report(&client, 1, Vec::new()); let mut saw_ignored_diagnostic = false; for item in first_report.items { - if let lsp_types::WorkspaceDocumentDiagnosticReport::Full(full) = item + if let Union2::A(full) = item && full.uri == ignored_uri { - saw_ignored_diagnostic = full - .full_document_diagnostic_report - .items - .iter() - .any(|diag| diag.message.contains("expected")); + saw_ignored_diagnostic = + full.items.iter().any(|diag| diag.message.contains("expected")); } } assert!(saw_ignored_diagnostic, "root-scanning config should diagnose ignored.sv"); @@ -2058,25 +2034,25 @@ fn restored_project_manifest_clears_diagnostics_for_excluded_files() { WorkspaceDiagnosticParams { identifier: None, previous_result_ids: Vec::new(), - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); let second: WorkspaceDiagnosticReportResult = recv_response(&client, second_id, "workspaceDiagnostic"); let second_report = match second { - WorkspaceDiagnosticReportResult::Report(report) => report, + Union2::A(report) => report, other => panic!("unexpected workspace diagnostic response: {other:?}"), }; for item in second_report.items { - if let lsp_types::WorkspaceDocumentDiagnosticReport::Full(full) = item + if let Union2::A(full) = item && full.uri == ignored_uri { assert!( - full.full_document_diagnostic_report.items.is_empty(), + full.items.is_empty(), "restored config should clear diagnostics for excluded file: {:?}", - full.full_document_diagnostic_report.items + full.items ); shutdown_test_server(&client, server_thread); return; @@ -2094,7 +2070,7 @@ fn workspace_scan_refreshes_diagnostics_for_unopened_systemverilog_dependency() ..Default::default() }), workspace: Some(WorkspaceClientCapabilities { - diagnostic: Some(lsp_types::DiagnosticWorkspaceClientCapabilities { + diagnostics: Some(lspt::DiagnosticWorkspaceClientCapabilities { refresh_support: Some(true), }), ..Default::default() @@ -2135,7 +2111,7 @@ fn workspace_scan_refreshes_diagnostics_for_unopened_systemverilog_dependency() DidOpenTextDocumentParams { text_document: TextDocumentItem { uri: top_uri.clone(), - language_id: "verilog".to_string(), + language_id: lspt::LanguageKind::Custom_("verilog".to_string()), version: 1, text: top_text.to_string(), }, @@ -2148,7 +2124,7 @@ fn workspace_scan_refreshes_diagnostics_for_unopened_systemverilog_dependency() let timeout = deadline.saturating_duration_since(Instant::now()); match client.receiver.recv_timeout(timeout).unwrap() { Message::Request(request) - if request.method == lsp_types::request::WorkspaceDiagnosticRefresh::METHOD => + if request.method == lspt::request::DiagnosticRefreshRequest::METHOD => { client .sender @@ -2157,7 +2133,7 @@ fn workspace_scan_refreshes_diagnostics_for_unopened_systemverilog_dependency() break; } Message::Request(request) - if request.method == lsp_types::request::WorkDoneProgressCreate::METHOD => + if request.method == lspt::request::WorkDoneProgressCreateRequest::METHOD => { client .sender @@ -2165,7 +2141,7 @@ fn workspace_scan_refreshes_diagnostics_for_unopened_systemverilog_dependency() .unwrap(); } Message::Notification(notification) - if notification.method == lsp_types::notification::Progress::METHOD => {} + if notification.method == lspt::notification::ProgressNotification::METHOD => {} Message::Request(request) => { panic!( "unexpected server request while waiting for diagnostic refresh: {request:?}" @@ -2184,8 +2160,8 @@ fn workspace_scan_refreshes_diagnostics_for_unopened_systemverilog_dependency() WorkspaceDiagnosticParams { identifier: None, previous_result_ids: Vec::new(), - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -2201,15 +2177,15 @@ fn workspace_scan_refreshes_diagnostics_for_unopened_systemverilog_dependency() ) .unwrap(); let report = match result { - WorkspaceDiagnosticReportResult::Report(report) => report, + Union2::A(report) => report, other => panic!("unexpected workspace diagnostic response: {other:?}"), }; let mut top_diagnostics = None; for item in report.items { - if let lsp_types::WorkspaceDocumentDiagnosticReport::Full(full) = item + if let Union2::A(full) = item && full.uri == top_uri { - top_diagnostics = Some(full.full_document_diagnostic_report.items); + top_diagnostics = Some(full.items); } } let top_diagnostics = top_diagnostics.expect("missing top diagnostics"); @@ -2229,9 +2205,9 @@ fn workspace_scan_refreshes_diagnostics_for_unopened_systemverilog_dependency() return; } Message::Notification(notification) - if notification.method == lsp_types::notification::Progress::METHOD => {} + if notification.method == lspt::notification::ProgressNotification::METHOD => {} Message::Request(request) - if request.method == lsp_types::request::WorkspaceDiagnosticRefresh::METHOD => + if request.method == lspt::request::DiagnosticRefreshRequest::METHOD => { client .sender @@ -2256,7 +2232,7 @@ fn deleted_workspace_file_requests_diagnostic_refresh() { ..Default::default() }), workspace: Some(WorkspaceClientCapabilities { - diagnostic: Some(lsp_types::DiagnosticWorkspaceClientCapabilities { + diagnostics: Some(lspt::DiagnosticWorkspaceClientCapabilities { refresh_support: Some(true), }), ..Default::default() @@ -2292,15 +2268,11 @@ fn deleted_workspace_file_requests_diagnostic_refresh() { let mut saw_broken_diagnostic = false; let mut broken_result_id = None; for item in first_report.items { - if let lsp_types::WorkspaceDocumentDiagnosticReport::Full(full) = item + if let Union2::A(full) = item && full.uri == broken_uri { - broken_result_id = full.full_document_diagnostic_report.result_id.clone(); - saw_broken_diagnostic = full - .full_document_diagnostic_report - .items - .iter() - .any(|diag| diag.message.contains("expected")); + broken_result_id = full.result_id.clone(); + saw_broken_diagnostic = full.items.iter().any(|diag| diag.message.contains("expected")); } } assert!(saw_broken_diagnostic, "expected broken.sv diagnostics before deletion"); @@ -2312,8 +2284,8 @@ fn deleted_workspace_file_requests_diagnostic_refresh() { .sender .send(Message::Notification(Notification::new( DidChangeWatchedFiles::METHOD.to_string(), - lsp_types::DidChangeWatchedFilesParams { - changes: vec![FileEvent::new(broken_uri.clone(), FileChangeType::DELETED)], + lspt::DidChangeWatchedFilesParams { + changes: vec![FileEvent { uri: broken_uri.clone(), ty: FileChangeType::Deleted }], }, ))) .unwrap(); @@ -2325,7 +2297,7 @@ fn deleted_workspace_file_requests_diagnostic_refresh() { { match message { Message::Request(request) - if request.method == lsp_types::request::WorkspaceDiagnosticRefresh::METHOD => + if request.method == lspt::request::DiagnosticRefreshRequest::METHOD => { client .sender @@ -2335,7 +2307,7 @@ fn deleted_workspace_file_requests_diagnostic_refresh() { break; } Message::Request(request) - if request.method == lsp_types::request::WorkDoneProgressCreate::METHOD => + if request.method == lspt::request::WorkDoneProgressCreateRequest::METHOD => { client .sender @@ -2343,7 +2315,7 @@ fn deleted_workspace_file_requests_diagnostic_refresh() { .unwrap(); } Message::Notification(notification) - if notification.method == lsp_types::notification::Progress::METHOD => {} + if notification.method == lspt::notification::ProgressNotification::METHOD => {} other => panic!("unexpected message while waiting for diagnostic refresh: {other:?}"), } } @@ -2352,16 +2324,16 @@ fn deleted_workspace_file_requests_diagnostic_refresh() { let second_report = request_workspace_diagnostic_report( &client, 2, - vec![lsp_types::PreviousResultId { uri: broken_uri.clone(), value: broken_result_id }], + vec![lspt::PreviousResultId { uri: broken_uri.clone(), value: broken_result_id }], ); for item in second_report.items { - if let lsp_types::WorkspaceDocumentDiagnosticReport::Full(full) = item + if let Union2::A(full) = item && full.uri == broken_uri { assert!( - full.full_document_diagnostic_report.items.is_empty(), + full.items.is_empty(), "deleted file diagnostics should be cleared: {:?}", - full.full_document_diagnostic_report.items + full.items ); shutdown_test_server(&client, server_thread); return; @@ -2401,8 +2373,8 @@ fn document_diagnostic_result_id_changes_when_dependency_changes() { text_document: TextDocumentIdentifier { uri: top_uri.clone() }, identifier: None, previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -2420,11 +2392,9 @@ fn document_diagnostic_result_id_changes_when_dependency_changes() { DidChangeTextDocument::METHOD.to_string(), DidChangeTextDocumentParams { text_document: VersionedTextDocumentIdentifier { uri: child_uri, version: 2 }, - content_changes: vec![TextDocumentContentChangeEvent { - range: None, - range_length: None, + content_changes: vec![Union2::B(lspt::TextDocumentContentChangeWholeDocument { text: "module child(input logic a);\nendmodule\n".to_string(), - }], + })], }, ))) .unwrap(); @@ -2439,8 +2409,8 @@ fn document_diagnostic_result_id_changes_when_dependency_changes() { text_document: TextDocumentIdentifier { uri: top_uri }, identifier: None, previous_result_id: Some(first_result_id.clone()), - work_done_progress_params: WorkDoneProgressParams::default(), - partial_result_params: Default::default(), + work_done_token: None, + partial_result_token: None, }, ))) .unwrap(); @@ -2486,11 +2456,9 @@ fn legacy_publish_diagnostics_refreshes_dependent_open_files() { DidChangeTextDocument::METHOD.to_string(), DidChangeTextDocumentParams { text_document: VersionedTextDocumentIdentifier { uri: child_uri, version: 2 }, - content_changes: vec![TextDocumentContentChangeEvent { - range: None, - range_length: None, + content_changes: vec![Union2::B(lspt::TextDocumentContentChangeWholeDocument { text: "module child(input logic a);\nendmodule\n".to_string(), - }], + })], }, ))) .unwrap(); From dd58df3a9687c02100f781a7c730d56f63574ad8 Mon Sep 17 00:00:00 2001 From: hongjr03 Date: Fri, 22 May 2026 23:00:00 +0800 Subject: [PATCH 2/2] fix(qihe): refresh diagnostics after analysis ^ Conflicts: ^ src/global_state/qihe.rs --- src/global_state/qihe.rs | 89 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/src/global_state/qihe.rs b/src/global_state/qihe.rs index bd59e988..4bd3674b 100644 --- a/src/global_state/qihe.rs +++ b/src/global_state/qihe.rs @@ -13,6 +13,7 @@ use anyhow::{Context, Result, anyhow, bail}; use base_db::compilation_plan::CompilationPlan; use lspt::{ Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, MessageType, ShowMessageParams, + request::DiagnosticRefreshRequest, }; use project_model::project_manifest::MANIFEST_FILE_NAME; use regex::Regex; @@ -34,7 +35,7 @@ use super::{ }; use crate::{ config::user_config::QiheConfig, - global_state::main_loop::Task, + global_state::{DEFAULT_REQ_HANDLER, main_loop::Task}, i18n::{I18n, keys}, lsp_ext::{ ext::{ @@ -123,7 +124,7 @@ impl GlobalState { QiheTask::Finished { update, progress_token } => { let summary = update.summary.clone(); let changed_files = self.replace_qihe_diagnostics(update.by_file); - self.publish_qihe_diagnostics(changed_files); + self.refresh_qihe_diagnostics(changed_files); self.end_qihe_progress(progress_token, "end", summary.clone(), summary); } QiheTask::Failed { message, progress_token } => { @@ -161,11 +162,18 @@ impl GlobalState { changed_files } - fn publish_qihe_diagnostics(&mut self, changed_files: FxHashSet) { + fn refresh_qihe_diagnostics(&mut self, changed_files: FxHashSet) { if changed_files.is_empty() { return; } + if self.config.cli_pull_diagnostics_support() { + if self.config.cli_workspace_diagnostic_refresh_support() { + self.send_request::((), DEFAULT_REQ_HANDLER); + } + return; + } + let snapshot = self.make_snapshot(); let mut publish_tasks = Vec::with_capacity(changed_files.len()); for file_id in changed_files { @@ -187,7 +195,7 @@ impl GlobalState { diagnostics: snapshot.lsp_diagnostics(file_id), }); } - self.publish_diagnostics_tasks(publish_tasks, true); + self.publish_diagnostics_tasks(publish_tasks, false); } fn begin_qihe_progress(&mut self, progress_token: &str, label: String) { @@ -779,7 +787,15 @@ mod tests { use base_db::compilation_plan::CompilationPlan; use crossbeam_channel::unbounded; + use lsp_server::{Connection, Message}; + use lspt::{ + ClientCapabilities, DiagnosticClientCapabilities, DiagnosticWorkspaceClientCapabilities, + TextDocumentClientCapabilities, WorkspaceClientCapabilities, + request::{DiagnosticRefreshRequest, Request as _}, + }; + use rustc_hash::FxHashSet; use utils::paths::AbsPathBuf; + use vfs::FileId; use super::{ QiheCompileInput, QiheLogSink, command_line, has_compile_mode, join_command_output, @@ -787,10 +803,54 @@ mod tests { qihe_working_directory, split_compile_args, stream_command_output, strip_ansi, }; use crate::{ - config::user_config::QiheConfig, - global_state::main_loop::{QiheTask, Task}, + Opt, + config::{ + Config, + user_config::{QiheConfig, UserConfig}, + }, + global_state::{ + GlobalState, + main_loop::{QiheTask, Task}, + }, + i18n::I18n, }; + fn test_state(client_caps: ClientCapabilities) -> (GlobalState, Connection) { + let root_path = AbsPathBuf::assert_utf8(std::env::current_dir().unwrap()); + let config = Config::new( + Opt { + process_name: "vizsla-test".to_string(), + log: "error".to_string(), + log_filename: None, + }, + root_path.clone(), + client_caps, + vec![root_path], + I18n::default(), + UserConfig::default(), + Vec::new(), + ); + + let (server, client) = Connection::memory(); + (GlobalState::new(server.sender, config, lspt::TraceValue::Off), client) + } + + fn pull_diagnostic_caps() -> ClientCapabilities { + ClientCapabilities { + text_document: Some(TextDocumentClientCapabilities { + diagnostic: Some(DiagnosticClientCapabilities::default()), + ..Default::default() + }), + workspace: Some(WorkspaceClientCapabilities { + diagnostics: Some(DiagnosticWorkspaceClientCapabilities { + refresh_support: Some(true), + }), + ..Default::default() + }), + ..Default::default() + } + } + #[test] fn parses_line_col_only_locations() { let loc = parse_source_loc("12:34").expect("location"); @@ -843,6 +903,23 @@ mod tests { } } + #[test] + fn qihe_refresh_requests_pull_diagnostics_refresh_without_publishing() { + let (mut state, client) = test_state(pull_diagnostic_caps()); + + state.refresh_qihe_diagnostics(FxHashSet::from_iter([FileId(0)])); + + let message = client.receiver.try_recv().expect("workspace diagnostic refresh request"); + match message { + Message::Request(request) => { + assert_eq!(request.method, DiagnosticRefreshRequest::METHOD); + } + other => panic!("expected workspace diagnostic refresh request, got {other:?}"), + } + + assert!(client.receiver.try_recv().is_err(), "pull diagnostics should not be published"); + } + #[test] fn command_output_streamer_strips_ansi_and_logs_lines() { let (sender, receiver) = unbounded();