//! Advertizes the capabilities of the LSP Server. use std::env; use ide::CompletionResolveCapability; use lsp_types::{ CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions, CodeActionProviderCapability, CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, HoverProviderCapability, ImplementationProviderCapability, OneOf, RenameOptions, SaveOptions, SelectionRangeProviderCapability, SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions, }; use rustc_hash::FxHashSet; use serde_json::json; use crate::semantic_tokens; pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabilities { ServerCapabilities { text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { open_close: Some(true), change: Some(if env::var("RA_NO_INCREMENTAL_SYNC").is_ok() { TextDocumentSyncKind::Full } else { TextDocumentSyncKind::Incremental }), will_save: None, will_save_wait_until: None, save: Some(SaveOptions::default().into()), })), hover_provider: Some(HoverProviderCapability::Simple(true)), completion_provider: Some(CompletionOptions { resolve_provider: completions_resolve_provider(client_caps), trigger_characters: Some(vec![":".to_string(), ".".to_string()]), work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, }), signature_help_provider: Some(SignatureHelpOptions { trigger_characters: Some(vec!["(".to_string(), ",".to_string()]), retrigger_characters: None, work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, }), declaration_provider: None, definition_provider: Some(OneOf::Left(true)), type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)), implementation_provider: Some(ImplementationProviderCapability::Simple(true)), references_provider: Some(OneOf::Left(true)), document_highlight_provider: Some(OneOf::Left(true)), document_symbol_provider: Some(OneOf::Left(true)), workspace_symbol_provider: Some(OneOf::Left(true)), code_action_provider: Some(code_action_capabilities(client_caps)), code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), document_formatting_provider: Some(OneOf::Left(true)), document_range_formatting_provider: None, document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { first_trigger_character: "=".to_string(), more_trigger_character: Some(vec![".".to_string(), ">".to_string()]), }), selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), semantic_highlighting: None, folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), rename_provider: Some(OneOf::Right(RenameOptions { prepare_provider: Some(true), work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, })), linked_editing_range_provider: None, document_link_provider: None, color_provider: None, execute_command_provider: None, workspace: None, call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)), semantic_tokens_provider: Some( SemanticTokensOptions { legend: SemanticTokensLegend { token_types: semantic_tokens::SUPPORTED_TYPES.to_vec(), token_modifiers: semantic_tokens::SUPPORTED_MODIFIERS.to_vec(), }, full: Some(SemanticTokensFullOptions::Delta { delta: Some(true) }), range: Some(true), work_done_progress_options: Default::default(), } .into(), ), moniker_provider: None, experimental: Some(json!({ "joinLines": true, "ssr": true, "onEnter": true, "parentModule": true, "runnables": { "kinds": [ "cargo" ], }, })), } } fn completions_resolve_provider(client_caps: &ClientCapabilities) -> Option { if enabled_completions_resolve_capabilities(client_caps)?.is_empty() { log::info!("No `additionalTextEdits` completion resolve capability was found in the client capabilities, autoimport completion is disabled"); None } else { Some(true) } } /// Parses client capabilities and returns all completion resolve capabilities rust-analyzer supports. pub(crate) fn enabled_completions_resolve_capabilities( caps: &ClientCapabilities, ) -> Option> { Some( caps.text_document .as_ref()? .completion .as_ref()? .completion_item .as_ref()? .resolve_support .as_ref()? .properties .iter() .filter_map(|cap_string| match cap_string.as_str() { "additionalTextEdits" => Some(CompletionResolveCapability::AdditionalTextEdits), "detail" => Some(CompletionResolveCapability::Detail), "documentation" => Some(CompletionResolveCapability::Documentation), _unsupported => None, }) .collect(), ) } fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProviderCapability { client_caps .text_document .as_ref() .and_then(|it| it.code_action.as_ref()) .and_then(|it| it.code_action_literal_support.as_ref()) .map_or(CodeActionProviderCapability::Simple(true), |_| { CodeActionProviderCapability::Options(CodeActionOptions { // Advertise support for all built-in CodeActionKinds. // Ideally we would base this off of the client capabilities // but the client is supposed to fall back gracefully for unknown values. code_action_kinds: Some(vec![ CodeActionKind::EMPTY, CodeActionKind::QUICKFIX, CodeActionKind::REFACTOR, CodeActionKind::REFACTOR_EXTRACT, CodeActionKind::REFACTOR_INLINE, CodeActionKind::REFACTOR_REWRITE, ]), resolve_provider: Some(true), work_done_progress_options: Default::default(), }) }) }