More maintainable caps config
The idea here is that we preserve client's config as is, without changes. This gets rid of state!
This commit is contained in:
parent
c8d3d5694b
commit
624eb1ee54
@ -175,7 +175,7 @@ config_data! {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub client_caps: ClientCapsConfig,
|
||||
pub caps: lsp_types::ClientCapabilities,
|
||||
|
||||
pub publish_diagnostics: bool,
|
||||
pub diagnostics: DiagnosticsConfig,
|
||||
@ -286,26 +286,12 @@ pub struct RunnablesConfig {
|
||||
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(),
|
||||
@ -505,38 +491,11 @@ impl Config {
|
||||
}
|
||||
|
||||
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 =
|
||||
@ -548,20 +507,6 @@ impl Config {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@ -571,10 +516,6 @@ impl Config {
|
||||
|
||||
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() {
|
||||
@ -597,6 +538,95 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -320,7 +320,7 @@ pub(crate) fn handle_document_symbol(
|
||||
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);
|
||||
@ -727,7 +727,7 @@ pub(crate) fn handle_folding_range(
|
||||
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))
|
||||
@ -746,11 +746,8 @@ pub(crate) fn handle_signature_help(
|
||||
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))
|
||||
}
|
||||
|
||||
@ -929,7 +926,7 @@ pub(crate) fn handle_code_action(
|
||||
// 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);
|
||||
}
|
||||
|
||||
@ -959,7 +956,7 @@ pub(crate) fn handle_code_action(
|
||||
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()
|
||||
{
|
||||
@ -1542,7 +1539,7 @@ fn debug_single_command(runnable: &lsp_ext::Runnable) -> Command {
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -1641,7 +1638,7 @@ fn prepare_hover_actions(
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ impl GlobalState {
|
||||
message: Option<String>,
|
||||
fraction: Option<f64>,
|
||||
) {
|
||||
if !self.config.client_caps.work_done_progress {
|
||||
if !self.config.work_done_progress() {
|
||||
return;
|
||||
}
|
||||
let percentage = fraction.map(|f| {
|
||||
|
@ -79,7 +79,7 @@ impl GlobalState {
|
||||
}
|
||||
pub(crate) fn transition(&mut self, new_status: Status) {
|
||||
self.status = new_status;
|
||||
if self.config.client_caps.status_notification {
|
||||
if self.config.status_notification() {
|
||||
let lsp_status = match new_status {
|
||||
Status::Loading => lsp_ext::Status::Loading,
|
||||
Status::Ready => lsp_ext::Status::Ready,
|
||||
|
@ -605,7 +605,7 @@ pub(crate) fn goto_definition_response(
|
||||
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))
|
||||
@ -785,7 +785,7 @@ pub(crate) fn unresolved_code_action(
|
||||
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,
|
||||
@ -805,7 +805,7 @@ pub(crate) fn resolved_code_action(
|
||||
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,
|
||||
|
@ -14,7 +14,7 @@ use lsp_types::{
|
||||
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;
|
||||
@ -84,10 +84,24 @@ impl<'a> Project<'a> {
|
||||
.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() },
|
||||
|
Loading…
x
Reference in New Issue
Block a user