diff --git a/Cargo.lock b/Cargo.lock index c062366923dd..5ce35c5b1dc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -658,9 +658,9 @@ dependencies = [ [[package]] name = "lsp-server" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5383e043329615624bbf45e1ba27bd75c176762b2592855c659bc28ac580a06b" +checksum = "dccec31bfd027ac0dd288a78e19005fd89624d9099456e284b5241316a6c3072" dependencies = [ "crossbeam-channel", "log", diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 09908458dba7..e82fd57de84d 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -74,12 +74,25 @@ fn run_server() -> Result<()> { log::info!("lifecycle: server started"); let (connection, io_threads) = Connection::stdio(); - let server_capabilities = serde_json::to_value(rust_analyzer::server_capabilities()).unwrap(); - let initialize_params = connection.initialize(server_capabilities)?; + let (initialize_id, initialize_params) = connection.initialize_start()?; let initialize_params = from_json::("InitializeParams", initialize_params)?; + let server_capabilities = rust_analyzer::server_capabilities(&initialize_params.capabilities); + + let initialize_result = lsp_types::InitializeResult { + capabilities: server_capabilities, + server_info: Some(lsp_types::ServerInfo { + name: String::from("rust-analyzer"), + version: Some(String::from(env!("REV"))), + }), + }; + + let initialize_result = serde_json::to_value(initialize_result).unwrap(); + + connection.initialize_finish(initialize_id, initialize_result)?; + if let Some(client_info) = initialize_params.client_info { log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); } diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index 13af75469d69..780fc93174fa 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs @@ -2,19 +2,22 @@ use std::env; use lsp_types::{ - CallHierarchyServerCapability, CodeActionOptions, CodeActionProviderCapability, - CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, - FoldingRangeProviderCapability, ImplementationProviderCapability, RenameOptions, - RenameProviderCapability, SaveOptions, SelectionRangeProviderCapability, - SemanticTokensDocumentProvider, SemanticTokensLegend, SemanticTokensOptions, - ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, - TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions, + CallHierarchyServerCapability, ClientCapabilities, CodeActionOptions, + CodeActionProviderCapability, CodeLensOptions, CompletionOptions, + DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, + ImplementationProviderCapability, RenameOptions, RenameProviderCapability, SaveOptions, + SelectionRangeProviderCapability, SemanticTokensDocumentProvider, SemanticTokensLegend, + SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, + TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability, + WorkDoneProgressOptions, }; use serde_json::json; use crate::semantic_tokens; -pub fn server_capabilities() -> ServerCapabilities { +pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabilities { + let code_action_provider = code_action_capabilities(client_caps); + ServerCapabilities { text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { open_close: Some(true), @@ -46,20 +49,7 @@ pub fn server_capabilities() -> ServerCapabilities { document_highlight_provider: Some(true), document_symbol_provider: Some(true), workspace_symbol_provider: Some(true), - code_action_provider: Some(CodeActionProviderCapability::Options(CodeActionOptions { - // Advertise support for all built-in CodeActionKinds - code_action_kinds: Some(vec![ - lsp_types::code_action_kind::EMPTY.to_string(), - lsp_types::code_action_kind::QUICKFIX.to_string(), - lsp_types::code_action_kind::REFACTOR.to_string(), - lsp_types::code_action_kind::REFACTOR_EXTRACT.to_string(), - lsp_types::code_action_kind::REFACTOR_INLINE.to_string(), - lsp_types::code_action_kind::REFACTOR_REWRITE.to_string(), - lsp_types::code_action_kind::SOURCE.to_string(), - lsp_types::code_action_kind::SOURCE_ORGANIZE_IMPORTS.to_string(), - ]), - work_done_progress_options: Default::default(), - })), + code_action_provider: Some(code_action_provider), code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), document_formatting_provider: Some(true), document_range_formatting_provider: None, @@ -98,3 +88,29 @@ pub fn server_capabilities() -> ServerCapabilities { })), } } + +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![ + lsp_types::code_action_kind::EMPTY.to_string(), + lsp_types::code_action_kind::QUICKFIX.to_string(), + lsp_types::code_action_kind::REFACTOR.to_string(), + lsp_types::code_action_kind::REFACTOR_EXTRACT.to_string(), + lsp_types::code_action_kind::REFACTOR_INLINE.to_string(), + lsp_types::code_action_kind::REFACTOR_REWRITE.to_string(), + lsp_types::code_action_kind::SOURCE.to_string(), + lsp_types::code_action_kind::SOURCE_ORGANIZE_IMPORTS.to_string(), + ]), + work_done_progress_options: Default::default(), + }) + }) +}