From ab7a237f05d4f0c67ca57a84e99cd89c51818f7e Mon Sep 17 00:00:00 2001 From: Vitaly Slobodin Date: Sun, 29 Sep 2024 20:19:41 +0200 Subject: [PATCH] fix(lsp): unify code actions capabilities The `biome` language server sends to a client specific code actions that the client can use later to send code actions: - `quickfix.biome` - `source.fixAll.biome` - `source.organizeImports.biome` But under the hood the language server accepts not announced code actions such as `quickfix.suppressRule` or `quickfix.suppressRule.biome.suspicious.noDoubleEquals`. Such code actions work in clients that do not rely on code actions capabilities sent before, VSCode for example. The LSP specification (^1) specifies that clients should not send unsupported requests (code actions). This pull request unified code actions and their announcements by applying the following changes: 1. Custom sub-categories like, e.g. `quickfix.*.suspicious.noDoubleEquals` are removed because they are dynamic and announcing them could be hard to maintain. Instead only the base category is used: `quickfix.suppressRule.biome.suspicious.noDoubleEquals` becomes `quickfix.suppressRule.biome`. The code action data already has all required information to handle it on the server side. 2. Adds additional code actions to the list of `code_action_kinds` capabilities. References: 1. https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#codeActionKind --- crates/biome_analyze/src/lib.rs | 2 +- crates/biome_lsp/src/capabilities.rs | 7 +++++++ crates/biome_lsp/src/utils.rs | 13 +------------ crates/biome_lsp/tests/server.rs | 24 ++++++------------------ 4 files changed, 15 insertions(+), 31 deletions(-) diff --git a/crates/biome_analyze/src/lib.rs b/crates/biome_analyze/src/lib.rs index ed5e3e2ad914..c6d4a0c8e4be 100644 --- a/crates/biome_analyze/src/lib.rs +++ b/crates/biome_analyze/src/lib.rs @@ -25,7 +25,7 @@ pub use biome_diagnostics::category_concat; pub use crate::categories::{ ActionCategory, RefactorKind, RuleCategories, RuleCategoriesBuilder, RuleCategory, - SourceActionKind, + SourceActionKind, SUPPRESSION_ACTION_CATEGORY, }; pub use crate::diagnostics::{AnalyzerDiagnostic, RuleError, SuppressionDiagnostic}; pub use crate::matcher::{InspectMatcher, MatchQueryParams, QueryMatcher, RuleKey, SignalEntry}; diff --git a/crates/biome_lsp/src/capabilities.rs b/crates/biome_lsp/src/capabilities.rs index 899f25ef68ba..e9c559d49a60 100644 --- a/crates/biome_lsp/src/capabilities.rs +++ b/crates/biome_lsp/src/capabilities.rs @@ -1,4 +1,5 @@ use crate::converters::{negotiated_encoding, PositionEncoding, WideEncoding}; +use biome_analyze::SUPPRESSION_ACTION_CATEGORY; use tower_lsp::lsp_types::{ ClientCapabilities, CodeActionKind, CodeActionOptions, CodeActionProviderCapability, DocumentOnTypeFormattingOptions, OneOf, PositionEncodingKind, ServerCapabilities, @@ -60,8 +61,14 @@ pub(crate) fn server_capabilities(capabilities: &ClientCapabilities) -> ServerCa CodeActionOptions { code_action_kinds: Some(vec![ CodeActionKind::from("quickfix.biome"), + // quickfix.suppressRule + CodeActionKind::from(SUPPRESSION_ACTION_CATEGORY), CodeActionKind::from("source.fixAll.biome"), CodeActionKind::from("source.organizeImports.biome"), + CodeActionKind::from("refactor.biome"), + CodeActionKind::from("refactor.extract.biome"), + CodeActionKind::from("refactor.inline.biome"), + CodeActionKind::from("refactor.rewrite.biome"), ]), ..Default::default() } diff --git a/crates/biome_lsp/src/utils.rs b/crates/biome_lsp/src/utils.rs index 76798529fa29..7d9fb52ce598 100644 --- a/crates/biome_lsp/src/utils.rs +++ b/crates/biome_lsp/src/utils.rs @@ -128,18 +128,7 @@ pub(crate) fn code_fix_to_lsp( }) .unwrap_or_default(); - let kind = action.category.to_str(); - let mut kind = kind.into_owned(); - - if !matches!(action.category, ActionCategory::Source(_)) { - if let Some((group, rule)) = action.rule_name { - kind.push('.'); - kind.push_str(group.as_ref()); - kind.push('.'); - kind.push_str(rule.as_ref()); - } - } - + let kind = action.category.to_str().into_owned(); let suggestion = action.suggestion; let mut changes = HashMap::new(); diff --git a/crates/biome_lsp/tests/server.rs b/crates/biome_lsp/tests/server.rs index efd4f9ebb7c3..8ed0acbd37c5 100644 --- a/crates/biome_lsp/tests/server.rs +++ b/crates/biome_lsp/tests/server.rs @@ -922,9 +922,7 @@ async fn pull_quick_fixes() -> Result<()> { let expected_code_action = lsp::CodeActionOrCommand::CodeAction(lsp::CodeAction { title: String::from("Replace -0 with 0"), - kind: Some(lsp::CodeActionKind::new( - "quickfix.biome.suspicious.noCompareNegZero", - )), + kind: Some(lsp::CodeActionKind::new("quickfix.biome")), diagnostics: Some(vec![fixable_diagnostic(0)?]), edit: Some(lsp::WorkspaceEdit { changes: Some(changes), @@ -959,9 +957,7 @@ async fn pull_quick_fixes() -> Result<()> { let expected_suppression_action = lsp::CodeActionOrCommand::CodeAction(lsp::CodeAction { title: String::from("Suppress rule lint/suspicious/noCompareNegZero"), - kind: Some(lsp::CodeActionKind::new( - "quickfix.suppressRule.biome.suspicious.noCompareNegZero", - )), + kind: Some(lsp::CodeActionKind::new("quickfix.suppressRule.biome")), diagnostics: Some(vec![fixable_diagnostic(0)?]), edit: Some(lsp::WorkspaceEdit { changes: Some(suppression_changes), @@ -1135,9 +1131,7 @@ async fn pull_biome_quick_fixes() -> Result<()> { let expected_code_action = lsp::CodeActionOrCommand::CodeAction(lsp::CodeAction { title: String::from("Replace -0 with 0"), - kind: Some(lsp::CodeActionKind::new( - "quickfix.biome.suspicious.noCompareNegZero", - )), + kind: Some(lsp::CodeActionKind::new("quickfix.biome")), diagnostics: Some(vec![fixable_diagnostic(0)?]), edit: Some(lsp::WorkspaceEdit { changes: Some(changes), @@ -1252,9 +1246,7 @@ async fn pull_quick_fixes_include_unsafe() -> Result<()> { let expected_code_action = lsp::CodeActionOrCommand::CodeAction(lsp::CodeAction { title: String::from("Use ==="), - kind: Some(lsp::CodeActionKind::new( - "quickfix.biome.suspicious.noDoubleEquals", - )), + kind: Some(lsp::CodeActionKind::new("quickfix.biome")), diagnostics: Some(vec![unsafe_fixable.clone()]), edit: Some(lsp::WorkspaceEdit { changes: Some(changes), @@ -1289,9 +1281,7 @@ async fn pull_quick_fixes_include_unsafe() -> Result<()> { let expected_suppression_action = lsp::CodeActionOrCommand::CodeAction(lsp::CodeAction { title: String::from("Suppress rule lint/suspicious/noDoubleEquals"), - kind: Some(lsp::CodeActionKind::new( - "quickfix.suppressRule.biome.suspicious.noDoubleEquals", - )), + kind: Some(lsp::CodeActionKind::new("quickfix.suppressRule.biome")), diagnostics: Some(vec![unsafe_fixable]), edit: Some(lsp::WorkspaceEdit { changes: Some(suppression_changes), @@ -1922,9 +1912,7 @@ async fn pull_refactors() -> Result<()> { let _expected_action = lsp::CodeActionOrCommand::CodeAction(lsp::CodeAction { title: String::from("Inline variable"), - kind: Some(lsp::CodeActionKind::new( - "refactor.inline.biome.correctness.inlineVariable", - )), + kind: Some(lsp::CodeActionKind::new("refactor.inline.biome")), diagnostics: None, edit: Some(lsp::WorkspaceEdit { changes: Some(changes),