Prepare server capabilities based on client ones.

This commit is contained in:
vsrs 2020-07-20 22:04:59 +03:00
parent 6ddcdb8b29
commit 594ce72d1e

View file

@ -7,16 +7,18 @@ use lsp_types::{
DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, HoverProviderCapability, DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, HoverProviderCapability,
ImplementationProviderCapability, RenameOptions, RenameProviderCapability, SaveOptions, ImplementationProviderCapability, RenameOptions, RenameProviderCapability, SaveOptions,
SelectionRangeProviderCapability, SemanticTokensDocumentProvider, SemanticTokensLegend, SelectionRangeProviderCapability, SemanticTokensDocumentProvider, SemanticTokensLegend,
SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, SemanticTokensOptions, SemanticTokensServerCapabilities, ServerCapabilities,
TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind,
WorkDoneProgressOptions, TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions,
}; };
use serde_json::json; use serde_json::{json, Value};
use crate::semantic_tokens; use crate::semantic_tokens;
pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabilities { pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabilities {
let code_action_provider = code_action_capabilities(client_caps); let code_action_provider = code_action_capabilities(client_caps);
let semantic_tokens_provider = semantic_tokens_capabilities(client_caps);
let experimental = experimental_capabilities(client_caps);
ServerCapabilities { ServerCapabilities {
text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions {
@ -69,50 +71,84 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
execute_command_provider: None, execute_command_provider: None,
workspace: None, workspace: None,
call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)), call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)),
semantic_tokens_provider: Some( semantic_tokens_provider,
SemanticTokensOptions { experimental,
legend: SemanticTokensLegend {
token_types: semantic_tokens::SUPPORTED_TYPES.to_vec(),
token_modifiers: semantic_tokens::SUPPORTED_MODIFIERS.to_vec(),
},
document_provider: Some(SemanticTokensDocumentProvider::Bool(true)),
range_provider: Some(true),
work_done_progress_options: Default::default(),
}
.into(),
),
experimental: Some(json!({
"joinLines": true,
"ssr": true,
"onEnter": true,
"parentModule": true,
"runnables": {
"kinds": [ "cargo" ],
},
})),
} }
} }
fn experimental_capabilities(client_caps: &ClientCapabilities) -> Option<Value> {
client_caps.experimental.as_ref().and_then(|it| {
it.as_object().map(|map| {
let mut obj = json!({});
let result = obj.as_object_mut().unwrap();
if map.contains_key("joinLines") {
result.insert("joinLines".into(), true.into());
}
if map.contains_key("ssr") {
result.insert("ssr".into(), true.into());
}
if map.contains_key("onEnter") {
result.insert("onEnter".into(), true.into());
}
if map.contains_key("parentModule") {
result.insert("parentModule".into(), true.into());
}
if map.contains_key("runnables") {
result.insert("runnables".into(), json!({ "kinds": [ "cargo" ] }));
}
obj
})
})
}
fn semantic_tokens_capabilities(
client_caps: &ClientCapabilities,
) -> Option<SemanticTokensServerCapabilities> {
client_caps.text_document.as_ref().and_then(|it| it.semantic_tokens.as_ref()).map(|_|
// client supports semanticTokens
SemanticTokensOptions {
legend: SemanticTokensLegend {
token_types: semantic_tokens::SUPPORTED_TYPES.to_vec(),
token_modifiers: semantic_tokens::SUPPORTED_MODIFIERS.to_vec(),
},
document_provider: Some(SemanticTokensDocumentProvider::Bool(true)),
range_provider: Some(true),
work_done_progress_options: Default::default(),
}
.into())
}
fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProviderCapability { fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProviderCapability {
client_caps client_caps
.text_document .text_document
.as_ref() .as_ref()
.and_then(|it| it.code_action.as_ref()) .and_then(|it| it.code_action.as_ref())
.and_then(|it| it.code_action_literal_support.as_ref()) .and_then(|it| it.code_action_literal_support.as_ref())
.map_or(CodeActionProviderCapability::Simple(true), |_| { .map_or(CodeActionProviderCapability::Simple(true), |caps| {
let mut action_kinds = vec![
CodeActionKind::EMPTY,
CodeActionKind::QUICKFIX,
CodeActionKind::REFACTOR,
CodeActionKind::REFACTOR_EXTRACT,
CodeActionKind::REFACTOR_INLINE,
CodeActionKind::REFACTOR_REWRITE,
];
// Not all clients can fall back gracefully for unknown values.
// Microsoft.VisualStudio.LanguageServer.Protocol.CodeActionKind does not support CodeActionKind::EMPTY
// So have to filter out.
action_kinds
.retain(|it| caps.code_action_kind.value_set.contains(&it.as_str().to_owned()));
CodeActionProviderCapability::Options(CodeActionOptions { CodeActionProviderCapability::Options(CodeActionOptions {
// Advertise support for all built-in CodeActionKinds. code_action_kinds: Some(action_kinds),
// 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,
]),
work_done_progress_options: Default::default(), work_done_progress_options: Default::default(),
}) })
}) })