4167: Filter out code actions if unsupported by the client and advertise our capabilities r=matklad a=kjeremy

This PR does three things:
1. If the client does not support `CodeActionKind` this will filter the results and only send `Command[]` back.
2. Correctly advertises to the client that the server supports `CodeActionKind`. This may cause clients to not request code actions if they are checking for the provider to be `true` (or implement LSP < 3.8) in the caps but I will fix that in a followup PR.
3. Marks most CodeActions as <strike>"refactor" so that they show up in the menu in vscode.</strike>`""`.

Part of #144
#4147 
#2833  

Co-authored-by: kjeremy <kjeremy@gmail.com>
This commit is contained in:
bors[bot] 2020-05-01 18:57:55 +00:00 committed by GitHub
commit 26079c7f2c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 18 deletions

View file

@ -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,

View file

@ -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 {

View file

@ -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<Co
arguments: Some(vec![arg]),
};
let kind = match assist.id {
AssistId("introduce_variable") => 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))
}

View file

@ -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()
};