#[derive(Debug, Clone)]
pub struct Config {
- pub client_caps: ClientCapsConfig,
+ pub caps: lsp_types::ClientCapabilities,
pub publish_diagnostics: bool,
pub diagnostics: DiagnosticsConfig,
pub cargo_extra_args: Vec<String>,
}
-#[derive(Debug, Clone, Default)]
-pub struct ClientCapsConfig {
- pub location_link: bool,
- pub line_folding_only: bool,
- pub hierarchical_symbols: bool,
- pub code_action_literals: bool,
- pub work_done_progress: bool,
- pub code_action_group: bool,
- pub code_action_resolve: bool,
- pub hover_actions: bool,
- pub status_notification: bool,
- pub signature_help_label_offsets: bool,
-}
-
impl Config {
pub fn new(root_path: AbsPathBuf) -> Self {
// Defaults here don't matter, we'll immediately re-write them with
// ConfigData.
let mut res = Config {
- client_caps: ClientCapsConfig::default(),
+ caps: lsp_types::ClientCapabilities::default(),
publish_diagnostics: false,
diagnostics: DiagnosticsConfig::default(),
}
pub fn update_caps(&mut self, caps: &ClientCapabilities) {
+ self.caps = caps.clone();
if let Some(doc_caps) = caps.text_document.as_ref() {
if let Some(value) = doc_caps.hover.as_ref().and_then(|it| it.content_format.as_ref()) {
self.hover.markdown = value.contains(&MarkupKind::Markdown)
}
- if let Some(value) = doc_caps.definition.as_ref().and_then(|it| it.link_support) {
- self.client_caps.location_link = value;
- }
- if let Some(value) = doc_caps.folding_range.as_ref().and_then(|it| it.line_folding_only)
- {
- self.client_caps.line_folding_only = value
- }
- if let Some(value) = doc_caps
- .document_symbol
- .as_ref()
- .and_then(|it| it.hierarchical_document_symbol_support)
- {
- self.client_caps.hierarchical_symbols = value
- }
- if let Some(value) =
- doc_caps.code_action.as_ref().map(|it| it.code_action_literal_support.is_some())
- {
- self.client_caps.code_action_literals = value;
- }
- if let Some(value) = doc_caps
- .signature_help
- .as_ref()
- .and_then(|it| it.signature_information.as_ref())
- .and_then(|it| it.parameter_information.as_ref())
- .and_then(|it| it.label_offset_support)
- {
- self.client_caps.signature_help_label_offsets = value;
- }
self.completion.allow_snippets(false);
self.completion.active_resolve_capabilities =
}
}
}
-
- if let Some(code_action) = &doc_caps.code_action {
- if let Some(resolve_support) = &code_action.resolve_support {
- if resolve_support.properties.iter().any(|it| it == "edit") {
- self.client_caps.code_action_resolve = true;
- }
- }
- }
- }
-
- if let Some(window_caps) = caps.window.as_ref() {
- if let Some(value) = window_caps.work_done_progress {
- self.client_caps.work_done_progress = value;
- }
}
self.assist.allow_snippets(false);
let snippet_text_edit = get_bool("snippetTextEdit");
self.assist.allow_snippets(snippet_text_edit);
-
- self.client_caps.code_action_group = get_bool("codeActionGroup");
- self.client_caps.hover_actions = get_bool("hoverActions");
- self.client_caps.status_notification = get_bool("statusNotification");
}
if let Some(workspace_caps) = caps.workspace.as_ref() {
}
}
+macro_rules! try_ {
+ ($expr:expr) => {
+ || -> _ { Some($expr) }()
+ };
+}
+macro_rules! try_or {
+ ($expr:expr, $or:expr) => {
+ try_!($expr).unwrap_or($or)
+ };
+}
+
+impl Config {
+ pub fn location_link(&self) -> bool {
+ try_or!(self.caps.text_document.as_ref()?.definition?.link_support?, false)
+ }
+ pub fn line_folding_only(&self) -> bool {
+ try_or!(self.caps.text_document.as_ref()?.folding_range.as_ref()?.line_folding_only?, false)
+ }
+ pub fn hierarchical_symbols(&self) -> bool {
+ try_or!(
+ self.caps
+ .text_document
+ .as_ref()?
+ .document_symbol
+ .as_ref()?
+ .hierarchical_document_symbol_support?,
+ false
+ )
+ }
+ pub fn code_action_literals(&self) -> bool {
+ try_!(self
+ .caps
+ .text_document
+ .as_ref()?
+ .code_action
+ .as_ref()?
+ .code_action_literal_support
+ .as_ref()?)
+ .is_some()
+ }
+ pub fn work_done_progress(&self) -> bool {
+ try_or!(self.caps.window.as_ref()?.work_done_progress?, false)
+ }
+ pub fn code_action_resolve(&self) -> bool {
+ try_or!(
+ self.caps
+ .text_document
+ .as_ref()?
+ .code_action
+ .as_ref()?
+ .resolve_support
+ .as_ref()?
+ .properties
+ .as_slice(),
+ &[]
+ )
+ .iter()
+ .any(|it| it == "edit")
+ }
+ pub fn signature_help_label_offsets(&self) -> bool {
+ try_or!(
+ self.caps
+ .text_document
+ .as_ref()?
+ .signature_help
+ .as_ref()?
+ .signature_information
+ .as_ref()?
+ .parameter_information
+ .as_ref()?
+ .label_offset_support?,
+ false
+ )
+ }
+
+ fn experimental(&self, index: &'static str) -> bool {
+ try_or!(self.caps.experimental.as_ref()?.get(index)?.as_bool()?, false)
+ }
+ pub fn code_action_group(&self) -> bool {
+ self.experimental("codeActionGroup")
+ }
+ pub fn hover_actions(&self) -> bool {
+ self.experimental("hoverActions")
+ }
+ pub fn status_notification(&self) -> bool {
+ self.experimental("statusNotification")
+ }
+}
+
#[derive(Deserialize)]
#[serde(untagged)]
enum ManifestOrProjectJson {
acc
};
- let res = if snap.config.client_caps.hierarchical_symbols {
+ let res = if snap.config.hierarchical_symbols() {
document_symbols.into()
} else {
let url = to_proto::url(&snap, file_id);
let folds = snap.analysis.folding_ranges(file_id)?;
let text = snap.analysis.file_text(file_id)?;
let line_index = snap.analysis.file_line_index(file_id)?;
- let line_folding_only = snap.config.client_caps.line_folding_only;
+ let line_folding_only = snap.config.line_folding_only();
let res = folds
.into_iter()
.map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it))
None => return Ok(None),
};
let concise = !snap.config.call_info_full;
- let res = to_proto::signature_help(
- call_info,
- concise,
- snap.config.client_caps.signature_help_label_offsets,
- );
+ let res =
+ to_proto::signature_help(call_info, concise, snap.config.signature_help_label_offsets());
Ok(Some(res))
}
// We intentionally don't support command-based actions, as those either
// requires custom client-code anyway, or requires server-initiated edits.
// Server initiated edits break causality, so we avoid those as well.
- if !snap.config.client_caps.code_action_literals {
+ if !snap.config.code_action_literals() {
return Ok(None);
}
add_quick_fixes(&snap, frange, &line_index, &mut res)?;
}
- if snap.config.client_caps.code_action_resolve {
+ if snap.config.code_action_resolve() {
for (index, assist) in
snap.analysis.assists(&assists_config, false, frange)?.into_iter().enumerate()
{
}
fn goto_location_command(snap: &GlobalStateSnapshot, nav: &NavigationTarget) -> Option<Command> {
- let value = if snap.config.client_caps.location_link {
+ let value = if snap.config.location_link() {
let link = to_proto::location_link(snap, None, nav.clone()).ok()?;
to_value(link).ok()?
} else {
file_id: FileId,
actions: &[HoverAction],
) -> Vec<lsp_ext::CommandLinkGroup> {
- if snap.config.hover.none() || !snap.config.client_caps.hover_actions {
+ if snap.config.hover.none() || !snap.config.hover_actions() {
return Vec::new();
}
src: Option<FileRange>,
targets: Vec<NavigationTarget>,
) -> Result<lsp_types::GotoDefinitionResponse> {
- if snap.config.client_caps.location_link {
+ if snap.config.location_link() {
let links = targets
.into_iter()
.map(|nav| location_link(snap, src, nav))
assert!(assist.source_change.is_none());
let res = lsp_ext::CodeAction {
title: assist.label.to_string(),
- group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0),
+ group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0),
kind: Some(code_action_kind(assist.id.1)),
edit: None,
is_preferred: None,
let res = lsp_ext::CodeAction {
edit: Some(snippet_workspace_edit(snap, change)?),
title: assist.label.to_string(),
- group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0),
+ group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0),
kind: Some(code_action_kind(assist.id.1)),
is_preferred: None,
data: None,
use lsp_types::{ProgressParams, ProgressParamsValue};
use project_model::{CargoConfig, ProjectManifest};
use rust_analyzer::{
- config::{ClientCapsConfig, Config, FilesConfig, FilesWatcher, LinkedProject},
+ config::{Config, FilesConfig, FilesWatcher, LinkedProject},
main_loop,
};
use serde::Serialize;
.collect::<Vec<_>>();
let mut config = Config {
- client_caps: ClientCapsConfig {
- location_link: true,
- code_action_literals: true,
- work_done_progress: true,
+ caps: lsp_types::ClientCapabilities {
+ text_document: Some(lsp_types::TextDocumentClientCapabilities {
+ definition: Some(lsp_types::GotoCapability {
+ link_support: Some(true),
+ ..Default::default()
+ }),
+ code_action: Some(lsp_types::CodeActionClientCapabilities {
+ code_action_literal_support: Some(
+ lsp_types::CodeActionLiteralSupport::default(),
+ ),
+ ..Default::default()
+ }),
+ ..Default::default()
+ }),
+ window: Some(lsp_types::WindowClientCapabilities {
+ work_done_progress: Some(true),
+ ..Default::default()
+ }),
..Default::default()
},
cargo: CargoConfig { no_sysroot: !self.with_sysroot, ..Default::default() },