Skip to content

Commit faf4520

Browse files
authored
server: add quick fix to open documentation for rule violation (#610)
also fix filtering of diagnostics so we exclude diagnostics made by other language servers / extensions
1 parent 9408978 commit faf4520

File tree

1 file changed

+40
-4
lines changed
  • crates/squawk_server/src

1 file changed

+40
-4
lines changed

crates/squawk_server/src/lib.rs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use log::info;
44
use lsp_server::{Connection, Message, Notification, Response};
55
use lsp_types::{
66
CodeAction, CodeActionKind, CodeActionOptions, CodeActionOrCommand, CodeActionParams,
7-
CodeActionProviderCapability, CodeActionResponse, CodeDescription, Diagnostic,
7+
CodeActionProviderCapability, CodeActionResponse, CodeDescription, Command, Diagnostic,
88
DiagnosticSeverity, DidChangeTextDocumentParams, DidCloseTextDocumentParams,
99
DidOpenTextDocumentParams, GotoDefinitionParams, GotoDefinitionResponse, InitializeParams,
1010
Location, Position, PublishDiagnosticsParams, Range, ServerCapabilities,
@@ -142,6 +142,8 @@ fn handle_goto_definition(connection: &Connection, req: lsp_server::Request) ->
142142
Ok(())
143143
}
144144

145+
const DIAGNOSTIC_NAME: &str = "squawk";
146+
145147
fn handle_code_action(
146148
connection: &Connection,
147149
req: lsp_server::Request,
@@ -152,7 +154,41 @@ fn handle_code_action(
152154

153155
let mut actions = Vec::new();
154156

155-
for mut diagnostic in params.context.diagnostics {
157+
for mut diagnostic in params
158+
.context
159+
.diagnostics
160+
.into_iter()
161+
.filter(|diagnostic| diagnostic.source.as_deref() == Some(DIAGNOSTIC_NAME))
162+
{
163+
if let Some(code) = diagnostic.code.as_ref() {
164+
let rule_name = match code {
165+
lsp_types::NumberOrString::String(s) => s.clone(),
166+
lsp_types::NumberOrString::Number(n) => n.to_string(),
167+
};
168+
169+
let title = format!("Show documentation for {}", rule_name);
170+
171+
let documentation_action = CodeAction {
172+
title: title.clone(),
173+
kind: Some(CodeActionKind::QUICKFIX),
174+
diagnostics: Some(vec![diagnostic.clone()]),
175+
edit: None,
176+
command: Some(Command {
177+
title,
178+
command: "vscode.open".to_string(),
179+
arguments: Some(vec![serde_json::to_value(format!(
180+
"https://squawkhq.com/docs/{}",
181+
rule_name
182+
))?]),
183+
}),
184+
is_preferred: Some(false),
185+
disabled: None,
186+
data: None,
187+
};
188+
189+
actions.push(CodeActionOrCommand::CodeAction(documentation_action));
190+
}
191+
156192
if let Some(data) = diagnostic.data.take() {
157193
let associated_data: AssociatedDiagnosticData =
158194
serde_json::from_value(data).context("deserializing diagnostic data")?;
@@ -328,7 +364,7 @@ fn lint(content: &str) -> Vec<Diagnostic> {
328364
code_description: Some(CodeDescription {
329365
href: Url::parse("https://squawkhq.com/docs/syntax-error").unwrap(),
330366
}),
331-
source: Some("squawk".to_string()),
367+
source: Some(DIAGNOSTIC_NAME.to_string()),
332368
message: error.message().to_string(),
333369
..Default::default()
334370
};
@@ -378,7 +414,7 @@ fn lint(content: &str) -> Vec<Diagnostic> {
378414
code_description: Some(CodeDescription {
379415
href: Url::parse(&format!("https://squawkhq.com/docs/{}", violation.code)).unwrap(),
380416
}),
381-
source: Some("squawk".to_string()),
417+
source: Some(DIAGNOSTIC_NAME.to_string()),
382418
message: violation.message,
383419
data: data.map(|d| serde_json::to_value(d).unwrap()),
384420
..Default::default()

0 commit comments

Comments
 (0)