diff options
author | Aleksey Kladov <[email protected]> | 2021-01-05 13:57:05 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-01-05 14:46:57 +0000 |
commit | 624eb1ee54e759c03d07c06e5e68dec7f36cb519 (patch) | |
tree | e7ee04b6a3cb030e4db0c3d118d723b8cf3704e0 /crates | |
parent | c8d3d5694be065ffb1d52bc33e098ff610693097 (diff) |
More maintainable caps config
The idea here is that we preserve client's config as is, without
changes. This gets rid of state!
Diffstat (limited to 'crates')
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 154 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 19 | ||||
-rw-r--r-- | crates/rust-analyzer/src/lsp_utils.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/reload.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 6 | ||||
-rw-r--r-- | crates/rust-analyzer/tests/rust-analyzer/support.rs | 24 |
6 files changed, 124 insertions, 83 deletions
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index a5b1d90b1..a80652e83 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -175,7 +175,7 @@ config_data! { | |||
175 | 175 | ||
176 | #[derive(Debug, Clone)] | 176 | #[derive(Debug, Clone)] |
177 | pub struct Config { | 177 | pub struct Config { |
178 | pub client_caps: ClientCapsConfig, | 178 | pub caps: lsp_types::ClientCapabilities, |
179 | 179 | ||
180 | pub publish_diagnostics: bool, | 180 | pub publish_diagnostics: bool, |
181 | pub diagnostics: DiagnosticsConfig, | 181 | pub diagnostics: DiagnosticsConfig, |
@@ -286,26 +286,12 @@ pub struct RunnablesConfig { | |||
286 | pub cargo_extra_args: Vec<String>, | 286 | pub cargo_extra_args: Vec<String>, |
287 | } | 287 | } |
288 | 288 | ||
289 | #[derive(Debug, Clone, Default)] | ||
290 | pub struct ClientCapsConfig { | ||
291 | pub location_link: bool, | ||
292 | pub line_folding_only: bool, | ||
293 | pub hierarchical_symbols: bool, | ||
294 | pub code_action_literals: bool, | ||
295 | pub work_done_progress: bool, | ||
296 | pub code_action_group: bool, | ||
297 | pub code_action_resolve: bool, | ||
298 | pub hover_actions: bool, | ||
299 | pub status_notification: bool, | ||
300 | pub signature_help_label_offsets: bool, | ||
301 | } | ||
302 | |||
303 | impl Config { | 289 | impl Config { |
304 | pub fn new(root_path: AbsPathBuf) -> Self { | 290 | pub fn new(root_path: AbsPathBuf) -> Self { |
305 | // Defaults here don't matter, we'll immediately re-write them with | 291 | // Defaults here don't matter, we'll immediately re-write them with |
306 | // ConfigData. | 292 | // ConfigData. |
307 | let mut res = Config { | 293 | let mut res = Config { |
308 | client_caps: ClientCapsConfig::default(), | 294 | caps: lsp_types::ClientCapabilities::default(), |
309 | 295 | ||
310 | publish_diagnostics: false, | 296 | publish_diagnostics: false, |
311 | diagnostics: DiagnosticsConfig::default(), | 297 | diagnostics: DiagnosticsConfig::default(), |
@@ -505,38 +491,11 @@ impl Config { | |||
505 | } | 491 | } |
506 | 492 | ||
507 | pub fn update_caps(&mut self, caps: &ClientCapabilities) { | 493 | pub fn update_caps(&mut self, caps: &ClientCapabilities) { |
494 | self.caps = caps.clone(); | ||
508 | if let Some(doc_caps) = caps.text_document.as_ref() { | 495 | if let Some(doc_caps) = caps.text_document.as_ref() { |
509 | if let Some(value) = doc_caps.hover.as_ref().and_then(|it| it.content_format.as_ref()) { | 496 | if let Some(value) = doc_caps.hover.as_ref().and_then(|it| it.content_format.as_ref()) { |
510 | self.hover.markdown = value.contains(&MarkupKind::Markdown) | 497 | self.hover.markdown = value.contains(&MarkupKind::Markdown) |
511 | } | 498 | } |
512 | if let Some(value) = doc_caps.definition.as_ref().and_then(|it| it.link_support) { | ||
513 | self.client_caps.location_link = value; | ||
514 | } | ||
515 | if let Some(value) = doc_caps.folding_range.as_ref().and_then(|it| it.line_folding_only) | ||
516 | { | ||
517 | self.client_caps.line_folding_only = value | ||
518 | } | ||
519 | if let Some(value) = doc_caps | ||
520 | .document_symbol | ||
521 | .as_ref() | ||
522 | .and_then(|it| it.hierarchical_document_symbol_support) | ||
523 | { | ||
524 | self.client_caps.hierarchical_symbols = value | ||
525 | } | ||
526 | if let Some(value) = | ||
527 | doc_caps.code_action.as_ref().map(|it| it.code_action_literal_support.is_some()) | ||
528 | { | ||
529 | self.client_caps.code_action_literals = value; | ||
530 | } | ||
531 | if let Some(value) = doc_caps | ||
532 | .signature_help | ||
533 | .as_ref() | ||
534 | .and_then(|it| it.signature_information.as_ref()) | ||
535 | .and_then(|it| it.parameter_information.as_ref()) | ||
536 | .and_then(|it| it.label_offset_support) | ||
537 | { | ||
538 | self.client_caps.signature_help_label_offsets = value; | ||
539 | } | ||
540 | 499 | ||
541 | self.completion.allow_snippets(false); | 500 | self.completion.allow_snippets(false); |
542 | self.completion.active_resolve_capabilities = | 501 | self.completion.active_resolve_capabilities = |
@@ -548,20 +507,6 @@ impl Config { | |||
548 | } | 507 | } |
549 | } | 508 | } |
550 | } | 509 | } |
551 | |||
552 | if let Some(code_action) = &doc_caps.code_action { | ||
553 | if let Some(resolve_support) = &code_action.resolve_support { | ||
554 | if resolve_support.properties.iter().any(|it| it == "edit") { | ||
555 | self.client_caps.code_action_resolve = true; | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | } | ||
560 | |||
561 | if let Some(window_caps) = caps.window.as_ref() { | ||
562 | if let Some(value) = window_caps.work_done_progress { | ||
563 | self.client_caps.work_done_progress = value; | ||
564 | } | ||
565 | } | 510 | } |
566 | 511 | ||
567 | self.assist.allow_snippets(false); | 512 | self.assist.allow_snippets(false); |
@@ -571,10 +516,6 @@ impl Config { | |||
571 | 516 | ||
572 | let snippet_text_edit = get_bool("snippetTextEdit"); | 517 | let snippet_text_edit = get_bool("snippetTextEdit"); |
573 | self.assist.allow_snippets(snippet_text_edit); | 518 | self.assist.allow_snippets(snippet_text_edit); |
574 | |||
575 | self.client_caps.code_action_group = get_bool("codeActionGroup"); | ||
576 | self.client_caps.hover_actions = get_bool("hoverActions"); | ||
577 | self.client_caps.status_notification = get_bool("statusNotification"); | ||
578 | } | 519 | } |
579 | 520 | ||
580 | if let Some(workspace_caps) = caps.workspace.as_ref() { | 521 | if let Some(workspace_caps) = caps.workspace.as_ref() { |
@@ -597,6 +538,95 @@ impl Config { | |||
597 | } | 538 | } |
598 | } | 539 | } |
599 | 540 | ||
541 | macro_rules! try_ { | ||
542 | ($expr:expr) => { | ||
543 | || -> _ { Some($expr) }() | ||
544 | }; | ||
545 | } | ||
546 | macro_rules! try_or { | ||
547 | ($expr:expr, $or:expr) => { | ||
548 | try_!($expr).unwrap_or($or) | ||
549 | }; | ||
550 | } | ||
551 | |||
552 | impl Config { | ||
553 | pub fn location_link(&self) -> bool { | ||
554 | try_or!(self.caps.text_document.as_ref()?.definition?.link_support?, false) | ||
555 | } | ||
556 | pub fn line_folding_only(&self) -> bool { | ||
557 | try_or!(self.caps.text_document.as_ref()?.folding_range.as_ref()?.line_folding_only?, false) | ||
558 | } | ||
559 | pub fn hierarchical_symbols(&self) -> bool { | ||
560 | try_or!( | ||
561 | self.caps | ||
562 | .text_document | ||
563 | .as_ref()? | ||
564 | .document_symbol | ||
565 | .as_ref()? | ||
566 | .hierarchical_document_symbol_support?, | ||
567 | false | ||
568 | ) | ||
569 | } | ||
570 | pub fn code_action_literals(&self) -> bool { | ||
571 | try_!(self | ||
572 | .caps | ||
573 | .text_document | ||
574 | .as_ref()? | ||
575 | .code_action | ||
576 | .as_ref()? | ||
577 | .code_action_literal_support | ||
578 | .as_ref()?) | ||
579 | .is_some() | ||
580 | } | ||
581 | pub fn work_done_progress(&self) -> bool { | ||
582 | try_or!(self.caps.window.as_ref()?.work_done_progress?, false) | ||
583 | } | ||
584 | pub fn code_action_resolve(&self) -> bool { | ||
585 | try_or!( | ||
586 | self.caps | ||
587 | .text_document | ||
588 | .as_ref()? | ||
589 | .code_action | ||
590 | .as_ref()? | ||
591 | .resolve_support | ||
592 | .as_ref()? | ||
593 | .properties | ||
594 | .as_slice(), | ||
595 | &[] | ||
596 | ) | ||
597 | .iter() | ||
598 | .any(|it| it == "edit") | ||
599 | } | ||
600 | pub fn signature_help_label_offsets(&self) -> bool { | ||
601 | try_or!( | ||
602 | self.caps | ||
603 | .text_document | ||
604 | .as_ref()? | ||
605 | .signature_help | ||
606 | .as_ref()? | ||
607 | .signature_information | ||
608 | .as_ref()? | ||
609 | .parameter_information | ||
610 | .as_ref()? | ||
611 | .label_offset_support?, | ||
612 | false | ||
613 | ) | ||
614 | } | ||
615 | |||
616 | fn experimental(&self, index: &'static str) -> bool { | ||
617 | try_or!(self.caps.experimental.as_ref()?.get(index)?.as_bool()?, false) | ||
618 | } | ||
619 | pub fn code_action_group(&self) -> bool { | ||
620 | self.experimental("codeActionGroup") | ||
621 | } | ||
622 | pub fn hover_actions(&self) -> bool { | ||
623 | self.experimental("hoverActions") | ||
624 | } | ||
625 | pub fn status_notification(&self) -> bool { | ||
626 | self.experimental("statusNotification") | ||
627 | } | ||
628 | } | ||
629 | |||
600 | #[derive(Deserialize)] | 630 | #[derive(Deserialize)] |
601 | #[serde(untagged)] | 631 | #[serde(untagged)] |
602 | enum ManifestOrProjectJson { | 632 | enum ManifestOrProjectJson { |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index c21ca044a..c13cdc4e3 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -320,7 +320,7 @@ pub(crate) fn handle_document_symbol( | |||
320 | acc | 320 | acc |
321 | }; | 321 | }; |
322 | 322 | ||
323 | let res = if snap.config.client_caps.hierarchical_symbols { | 323 | let res = if snap.config.hierarchical_symbols() { |
324 | document_symbols.into() | 324 | document_symbols.into() |
325 | } else { | 325 | } else { |
326 | let url = to_proto::url(&snap, file_id); | 326 | let url = to_proto::url(&snap, file_id); |
@@ -727,7 +727,7 @@ pub(crate) fn handle_folding_range( | |||
727 | let folds = snap.analysis.folding_ranges(file_id)?; | 727 | let folds = snap.analysis.folding_ranges(file_id)?; |
728 | let text = snap.analysis.file_text(file_id)?; | 728 | let text = snap.analysis.file_text(file_id)?; |
729 | let line_index = snap.analysis.file_line_index(file_id)?; | 729 | let line_index = snap.analysis.file_line_index(file_id)?; |
730 | let line_folding_only = snap.config.client_caps.line_folding_only; | 730 | let line_folding_only = snap.config.line_folding_only(); |
731 | let res = folds | 731 | let res = folds |
732 | .into_iter() | 732 | .into_iter() |
733 | .map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it)) | 733 | .map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it)) |
@@ -746,11 +746,8 @@ pub(crate) fn handle_signature_help( | |||
746 | None => return Ok(None), | 746 | None => return Ok(None), |
747 | }; | 747 | }; |
748 | let concise = !snap.config.call_info_full; | 748 | let concise = !snap.config.call_info_full; |
749 | let res = to_proto::signature_help( | 749 | let res = |
750 | call_info, | 750 | to_proto::signature_help(call_info, concise, snap.config.signature_help_label_offsets()); |
751 | concise, | ||
752 | snap.config.client_caps.signature_help_label_offsets, | ||
753 | ); | ||
754 | Ok(Some(res)) | 751 | Ok(Some(res)) |
755 | } | 752 | } |
756 | 753 | ||
@@ -929,7 +926,7 @@ pub(crate) fn handle_code_action( | |||
929 | // We intentionally don't support command-based actions, as those either | 926 | // We intentionally don't support command-based actions, as those either |
930 | // requires custom client-code anyway, or requires server-initiated edits. | 927 | // requires custom client-code anyway, or requires server-initiated edits. |
931 | // Server initiated edits break causality, so we avoid those as well. | 928 | // Server initiated edits break causality, so we avoid those as well. |
932 | if !snap.config.client_caps.code_action_literals { | 929 | if !snap.config.code_action_literals() { |
933 | return Ok(None); | 930 | return Ok(None); |
934 | } | 931 | } |
935 | 932 | ||
@@ -959,7 +956,7 @@ pub(crate) fn handle_code_action( | |||
959 | add_quick_fixes(&snap, frange, &line_index, &mut res)?; | 956 | add_quick_fixes(&snap, frange, &line_index, &mut res)?; |
960 | } | 957 | } |
961 | 958 | ||
962 | if snap.config.client_caps.code_action_resolve { | 959 | if snap.config.code_action_resolve() { |
963 | for (index, assist) in | 960 | for (index, assist) in |
964 | snap.analysis.assists(&assists_config, false, frange)?.into_iter().enumerate() | 961 | snap.analysis.assists(&assists_config, false, frange)?.into_iter().enumerate() |
965 | { | 962 | { |
@@ -1542,7 +1539,7 @@ fn debug_single_command(runnable: &lsp_ext::Runnable) -> Command { | |||
1542 | } | 1539 | } |
1543 | 1540 | ||
1544 | fn goto_location_command(snap: &GlobalStateSnapshot, nav: &NavigationTarget) -> Option<Command> { | 1541 | fn goto_location_command(snap: &GlobalStateSnapshot, nav: &NavigationTarget) -> Option<Command> { |
1545 | let value = if snap.config.client_caps.location_link { | 1542 | let value = if snap.config.location_link() { |
1546 | let link = to_proto::location_link(snap, None, nav.clone()).ok()?; | 1543 | let link = to_proto::location_link(snap, None, nav.clone()).ok()?; |
1547 | to_value(link).ok()? | 1544 | to_value(link).ok()? |
1548 | } else { | 1545 | } else { |
@@ -1641,7 +1638,7 @@ fn prepare_hover_actions( | |||
1641 | file_id: FileId, | 1638 | file_id: FileId, |
1642 | actions: &[HoverAction], | 1639 | actions: &[HoverAction], |
1643 | ) -> Vec<lsp_ext::CommandLinkGroup> { | 1640 | ) -> Vec<lsp_ext::CommandLinkGroup> { |
1644 | if snap.config.hover.none() || !snap.config.client_caps.hover_actions { | 1641 | if snap.config.hover.none() || !snap.config.hover_actions() { |
1645 | return Vec::new(); | 1642 | return Vec::new(); |
1646 | } | 1643 | } |
1647 | 1644 | ||
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index 60c12e4e2..40de56dad 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs | |||
@@ -46,7 +46,7 @@ impl GlobalState { | |||
46 | message: Option<String>, | 46 | message: Option<String>, |
47 | fraction: Option<f64>, | 47 | fraction: Option<f64>, |
48 | ) { | 48 | ) { |
49 | if !self.config.client_caps.work_done_progress { | 49 | if !self.config.work_done_progress() { |
50 | return; | 50 | return; |
51 | } | 51 | } |
52 | let percentage = fraction.map(|f| { | 52 | let percentage = fraction.map(|f| { |
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 79e39e3a5..ce5cedeb3 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs | |||
@@ -79,7 +79,7 @@ impl GlobalState { | |||
79 | } | 79 | } |
80 | pub(crate) fn transition(&mut self, new_status: Status) { | 80 | pub(crate) fn transition(&mut self, new_status: Status) { |
81 | self.status = new_status; | 81 | self.status = new_status; |
82 | if self.config.client_caps.status_notification { | 82 | if self.config.status_notification() { |
83 | let lsp_status = match new_status { | 83 | let lsp_status = match new_status { |
84 | Status::Loading => lsp_ext::Status::Loading, | 84 | Status::Loading => lsp_ext::Status::Loading, |
85 | Status::Ready => lsp_ext::Status::Ready, | 85 | Status::Ready => lsp_ext::Status::Ready, |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 999b18351..e0413ec06 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -605,7 +605,7 @@ pub(crate) fn goto_definition_response( | |||
605 | src: Option<FileRange>, | 605 | src: Option<FileRange>, |
606 | targets: Vec<NavigationTarget>, | 606 | targets: Vec<NavigationTarget>, |
607 | ) -> Result<lsp_types::GotoDefinitionResponse> { | 607 | ) -> Result<lsp_types::GotoDefinitionResponse> { |
608 | if snap.config.client_caps.location_link { | 608 | if snap.config.location_link() { |
609 | let links = targets | 609 | let links = targets |
610 | .into_iter() | 610 | .into_iter() |
611 | .map(|nav| location_link(snap, src, nav)) | 611 | .map(|nav| location_link(snap, src, nav)) |
@@ -785,7 +785,7 @@ pub(crate) fn unresolved_code_action( | |||
785 | assert!(assist.source_change.is_none()); | 785 | assert!(assist.source_change.is_none()); |
786 | let res = lsp_ext::CodeAction { | 786 | let res = lsp_ext::CodeAction { |
787 | title: assist.label.to_string(), | 787 | title: assist.label.to_string(), |
788 | group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0), | 788 | group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0), |
789 | kind: Some(code_action_kind(assist.id.1)), | 789 | kind: Some(code_action_kind(assist.id.1)), |
790 | edit: None, | 790 | edit: None, |
791 | is_preferred: None, | 791 | is_preferred: None, |
@@ -805,7 +805,7 @@ pub(crate) fn resolved_code_action( | |||
805 | let res = lsp_ext::CodeAction { | 805 | let res = lsp_ext::CodeAction { |
806 | edit: Some(snippet_workspace_edit(snap, change)?), | 806 | edit: Some(snippet_workspace_edit(snap, change)?), |
807 | title: assist.label.to_string(), | 807 | title: assist.label.to_string(), |
808 | group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0), | 808 | group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0), |
809 | kind: Some(code_action_kind(assist.id.1)), | 809 | kind: Some(code_action_kind(assist.id.1)), |
810 | is_preferred: None, | 810 | is_preferred: None, |
811 | data: None, | 811 | data: None, |
diff --git a/crates/rust-analyzer/tests/rust-analyzer/support.rs b/crates/rust-analyzer/tests/rust-analyzer/support.rs index 456125789..aac7dbcce 100644 --- a/crates/rust-analyzer/tests/rust-analyzer/support.rs +++ b/crates/rust-analyzer/tests/rust-analyzer/support.rs | |||
@@ -14,7 +14,7 @@ use lsp_types::{ | |||
14 | use lsp_types::{ProgressParams, ProgressParamsValue}; | 14 | use lsp_types::{ProgressParams, ProgressParamsValue}; |
15 | use project_model::{CargoConfig, ProjectManifest}; | 15 | use project_model::{CargoConfig, ProjectManifest}; |
16 | use rust_analyzer::{ | 16 | use rust_analyzer::{ |
17 | config::{ClientCapsConfig, Config, FilesConfig, FilesWatcher, LinkedProject}, | 17 | config::{Config, FilesConfig, FilesWatcher, LinkedProject}, |
18 | main_loop, | 18 | main_loop, |
19 | }; | 19 | }; |
20 | use serde::Serialize; | 20 | use serde::Serialize; |
@@ -84,10 +84,24 @@ impl<'a> Project<'a> { | |||
84 | .collect::<Vec<_>>(); | 84 | .collect::<Vec<_>>(); |
85 | 85 | ||
86 | let mut config = Config { | 86 | let mut config = Config { |
87 | client_caps: ClientCapsConfig { | 87 | caps: lsp_types::ClientCapabilities { |
88 | location_link: true, | 88 | text_document: Some(lsp_types::TextDocumentClientCapabilities { |
89 | code_action_literals: true, | 89 | definition: Some(lsp_types::GotoCapability { |
90 | work_done_progress: true, | 90 | link_support: Some(true), |
91 | ..Default::default() | ||
92 | }), | ||
93 | code_action: Some(lsp_types::CodeActionClientCapabilities { | ||
94 | code_action_literal_support: Some( | ||
95 | lsp_types::CodeActionLiteralSupport::default(), | ||
96 | ), | ||
97 | ..Default::default() | ||
98 | }), | ||
99 | ..Default::default() | ||
100 | }), | ||
101 | window: Some(lsp_types::WindowClientCapabilities { | ||
102 | work_done_progress: Some(true), | ||
103 | ..Default::default() | ||
104 | }), | ||
91 | ..Default::default() | 105 | ..Default::default() |
92 | }, | 106 | }, |
93 | cargo: CargoConfig { no_sysroot: !self.with_sysroot, ..Default::default() }, | 107 | cargo: CargoConfig { no_sysroot: !self.with_sysroot, ..Default::default() }, |