diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index e22ab8402ec6..c0d3209262c9 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs @@ -3,13 +3,13 @@ use crate::semantic_tokens; use lsp_types::{ - CallHierarchyServerCapability, CodeActionProviderCapability, CodeLensOptions, - CompletionOptions, DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, - ImplementationProviderCapability, RenameOptions, RenameProviderCapability, SaveOptions, - SelectionRangeProviderCapability, SemanticTokensDocumentProvider, SemanticTokensLegend, - SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, - TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability, - WorkDoneProgressOptions, + CallHierarchyServerCapability, CodeActionOptions, CodeActionProviderCapability, + CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, + FoldingRangeProviderCapability, ImplementationProviderCapability, RenameOptions, + RenameProviderCapability, SaveOptions, SelectionRangeProviderCapability, + SemanticTokensDocumentProvider, SemanticTokensLegend, SemanticTokensOptions, + ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, + TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions, }; pub fn server_capabilities() -> ServerCapabilities { @@ -40,7 +40,20 @@ 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::Simple(true)), + code_action_provider: Some(CodeActionProviderCapability::Options(CodeActionOptions { + // Advertise support for all built-in CodeActionKinds + code_action_kinds: Some(vec![ + String::new(), + 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_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), document_formatting_provider: Some(true), document_range_formatting_provider: None, diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 74a63e32a302..177da94cc9b6 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -70,6 +70,7 @@ pub struct ClientCapsConfig { pub location_link: bool, pub line_folding_only: bool, pub hierarchical_symbols: bool, + pub code_action_literals: bool, } impl Default for Config { @@ -221,6 +222,11 @@ impl Config { { self.client_caps.hierarchical_symbols = value } + if let Some(value) = + caps.code_action.as_ref().and_then(|it| Some(it.code_action_literal_support.is_some())) + { + self.client_caps.code_action_literals = value; + } self.completion.allow_snippets(false); if let Some(completion) = &caps.completion { if let Some(completion_item) = &completion.completion_item { diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 8db2dfa0c861..0f623949ecb8 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -19,8 +19,7 @@ use lsp_types::{ TextEdit, Url, WorkspaceEdit, }; use ra_ide::{ - Assist, AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, - SearchScope, + Assist, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, SearchScope, }; use ra_prof::profile; use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize}; @@ -702,15 +701,9 @@ fn create_single_code_action(assist: Assist, world: &WorldSnapshot) -> Result Some("refactor.extract.variable".to_string()), - AssistId("add_custom_impl") => Some("refactor.rewrite.add_custom_impl".to_string()), - _ => None, - }; - Ok(CodeAction { title, - kind, + kind: Some(String::new()), diagnostics: None, edit: None, command: Some(command), @@ -812,6 +805,23 @@ pub fn handle_code_action( } } + // If the client only supports commands then filter the list + // and remove and actions that depend on edits. + if !world.config.client_caps.code_action_literals { + // FIXME: use drain_filter once it hits stable. + res = res + .into_iter() + .filter_map(|it| match it { + cmd @ lsp_types::CodeActionOrCommand::Command(_) => Some(cmd), + lsp_types::CodeActionOrCommand::CodeAction(action) => match action.command { + Some(cmd) if action.edit.is_none() => { + Some(lsp_types::CodeActionOrCommand::Command(cmd)) + } + _ => None, + }, + }) + .collect(); + } Ok(Some(res)) } diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs index e4fe3411aa63..8d47ee4f64c4 100644 --- a/crates/rust-analyzer/tests/heavy_tests/support.rs +++ b/crates/rust-analyzer/tests/heavy_tests/support.rs @@ -77,7 +77,11 @@ impl<'a> Project<'a> { let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect(); let mut config = Config { - client_caps: ClientCapsConfig { location_link: true, ..Default::default() }, + client_caps: ClientCapsConfig { + location_link: true, + code_action_literals: true, + ..Default::default() + }, with_sysroot: self.with_sysroot, ..Config::default() };