ability to set suggestions on lints (#6535)
* fix the lint tests which were not compiling Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * apply sugggestions for offsetplanes Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * diagnostics and suggestions for offset planes Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
@ -17,30 +17,31 @@ use tokio::sync::RwLock;
|
||||
use tower_lsp::{
|
||||
jsonrpc::Result as RpcResult,
|
||||
lsp_types::{
|
||||
CodeAction, CodeActionKind, CodeActionOrCommand, CodeActionParams, CodeActionResponse, CompletionItem,
|
||||
CompletionItemKind, CompletionOptions, CompletionParams, CompletionResponse, CreateFilesParams,
|
||||
DeleteFilesParams, Diagnostic, DiagnosticOptions, DiagnosticServerCapabilities, DiagnosticSeverity,
|
||||
DidChangeConfigurationParams, DidChangeTextDocumentParams, DidChangeWatchedFilesParams,
|
||||
DidChangeWorkspaceFoldersParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams,
|
||||
DidSaveTextDocumentParams, DocumentDiagnosticParams, DocumentDiagnosticReport, DocumentDiagnosticReportResult,
|
||||
DocumentFilter, DocumentFormattingParams, DocumentSymbol, DocumentSymbolParams, DocumentSymbolResponse,
|
||||
Documentation, FoldingRange, FoldingRangeParams, FoldingRangeProviderCapability, FullDocumentDiagnosticReport,
|
||||
Hover as LspHover, HoverContents, HoverParams, HoverProviderCapability, InitializeParams, InitializeResult,
|
||||
InitializedParams, InlayHint, InlayHintParams, InsertTextFormat, MarkupContent, MarkupKind, MessageType, OneOf,
|
||||
Position, RelatedFullDocumentDiagnosticReport, RenameFilesParams, RenameParams, SemanticToken,
|
||||
SemanticTokenModifier, SemanticTokenType, SemanticTokens, SemanticTokensFullOptions, SemanticTokensLegend,
|
||||
SemanticTokensOptions, SemanticTokensParams, SemanticTokensRegistrationOptions, SemanticTokensResult,
|
||||
SemanticTokensServerCapabilities, ServerCapabilities, SignatureHelp, SignatureHelpOptions, SignatureHelpParams,
|
||||
StaticRegistrationOptions, TextDocumentItem, TextDocumentRegistrationOptions, TextDocumentSyncCapability,
|
||||
TextDocumentSyncKind, TextDocumentSyncOptions, TextEdit, WorkDoneProgressOptions, WorkspaceEdit,
|
||||
WorkspaceFolder, WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities,
|
||||
CodeAction, CodeActionKind, CodeActionOptions, CodeActionOrCommand, CodeActionParams,
|
||||
CodeActionProviderCapability, CodeActionResponse, CompletionItem, CompletionItemKind, CompletionOptions,
|
||||
CompletionParams, CompletionResponse, CreateFilesParams, DeleteFilesParams, Diagnostic, DiagnosticOptions,
|
||||
DiagnosticServerCapabilities, DiagnosticSeverity, DidChangeConfigurationParams, DidChangeTextDocumentParams,
|
||||
DidChangeWatchedFilesParams, DidChangeWorkspaceFoldersParams, DidCloseTextDocumentParams,
|
||||
DidOpenTextDocumentParams, DidSaveTextDocumentParams, DocumentDiagnosticParams, DocumentDiagnosticReport,
|
||||
DocumentDiagnosticReportResult, DocumentFilter, DocumentFormattingParams, DocumentSymbol, DocumentSymbolParams,
|
||||
DocumentSymbolResponse, Documentation, FoldingRange, FoldingRangeParams, FoldingRangeProviderCapability,
|
||||
FullDocumentDiagnosticReport, Hover as LspHover, HoverContents, HoverParams, HoverProviderCapability,
|
||||
InitializeParams, InitializeResult, InitializedParams, InlayHint, InlayHintParams, InsertTextFormat,
|
||||
MarkupContent, MarkupKind, MessageType, OneOf, Position, RelatedFullDocumentDiagnosticReport,
|
||||
RenameFilesParams, RenameParams, SemanticToken, SemanticTokenModifier, SemanticTokenType, SemanticTokens,
|
||||
SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions, SemanticTokensParams,
|
||||
SemanticTokensRegistrationOptions, SemanticTokensResult, SemanticTokensServerCapabilities, ServerCapabilities,
|
||||
SignatureHelp, SignatureHelpOptions, SignatureHelpParams, StaticRegistrationOptions, TextDocumentItem,
|
||||
TextDocumentRegistrationOptions, TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions,
|
||||
TextEdit, WorkDoneProgressOptions, WorkspaceEdit, WorkspaceFolder, WorkspaceFoldersServerCapabilities,
|
||||
WorkspaceServerCapabilities,
|
||||
},
|
||||
Client, LanguageServer,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
docs::kcl_doc::DocData,
|
||||
errors::Suggestion,
|
||||
errors::LspSuggestion,
|
||||
exec::KclValue,
|
||||
execution::{cache, kcl_value::FunctionSource},
|
||||
lsp::{
|
||||
@ -837,6 +838,11 @@ impl LanguageServer for Backend {
|
||||
|
||||
Ok(InitializeResult {
|
||||
capabilities: ServerCapabilities {
|
||||
code_action_provider: Some(CodeActionProviderCapability::Options(CodeActionOptions {
|
||||
code_action_kinds: Some(vec![CodeActionKind::QUICKFIX]),
|
||||
resolve_provider: Some(false),
|
||||
work_done_progress_options: WorkDoneProgressOptions::default(),
|
||||
})),
|
||||
completion_provider: Some(CompletionOptions {
|
||||
resolve_provider: Some(false),
|
||||
trigger_characters: Some(vec![".".to_string()]),
|
||||
@ -1452,14 +1458,18 @@ impl LanguageServer for Backend {
|
||||
.diagnostics
|
||||
.into_iter()
|
||||
.filter_map(|diagnostic| {
|
||||
let (suggestion, range) = diagnostic.data.as_ref().and_then(|data| {
|
||||
serde_json::from_value::<(Suggestion, tower_lsp::lsp_types::Range)>(data.clone()).ok()
|
||||
})?;
|
||||
let (suggestion, range) = diagnostic
|
||||
.data
|
||||
.as_ref()
|
||||
.and_then(|data| serde_json::from_value::<LspSuggestion>(data.clone()).ok())?;
|
||||
let edit = TextEdit {
|
||||
range,
|
||||
new_text: suggestion.insert,
|
||||
};
|
||||
let changes = HashMap::from([(params.text_document.uri.clone(), vec![edit])]);
|
||||
|
||||
// If you add more code action kinds, make sure you add it to the server
|
||||
// capabilities on initialization!
|
||||
Some(CodeActionOrCommand::CodeAction(CodeAction {
|
||||
title: suggestion.title,
|
||||
kind: Some(CodeActionKind::QUICKFIX),
|
||||
|
@ -19,10 +19,7 @@ use crate::{
|
||||
|
||||
impl IntoDiagnostic for CompilationError {
|
||||
fn to_lsp_diagnostics(&self, code: &str) -> Vec<Diagnostic> {
|
||||
let edit = self.suggestion.as_ref().map(|s| {
|
||||
let range = s.source_range.to_lsp_range(code);
|
||||
serde_json::to_value((s, range)).unwrap()
|
||||
});
|
||||
let edit = self.suggestion.as_ref().map(|s| s.to_lsp_edit(code));
|
||||
|
||||
vec![Diagnostic {
|
||||
range: self.source_range.to_lsp_range(code),
|
||||
@ -33,7 +30,7 @@ impl IntoDiagnostic for CompilationError {
|
||||
message: self.message.clone(),
|
||||
related_information: None,
|
||||
tags: self.tag.to_lsp_tags(),
|
||||
data: edit,
|
||||
data: edit.map(|e| serde_json::to_value(e).unwrap()),
|
||||
}]
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,19 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use tower_lsp::{
|
||||
lsp_types::{Diagnostic, SemanticTokenModifier, SemanticTokenType},
|
||||
lsp_types::{
|
||||
CodeActionKind, CodeActionOrCommand, Diagnostic, SemanticTokenModifier, SemanticTokenType, TextEdit,
|
||||
WorkspaceEdit,
|
||||
},
|
||||
LanguageServer,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
errors::{LspSuggestion, Suggestion},
|
||||
lsp::test_util::{copilot_lsp_server, kcl_lsp_server},
|
||||
parsing::ast::types::{Node, Program},
|
||||
SourceRange,
|
||||
};
|
||||
|
||||
#[track_caller]
|
||||
@ -3549,3 +3554,129 @@ startSketchOn(XY)
|
||||
|
||||
server.executor_ctx().await.clone().unwrap().close().await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_kcl_lsp_code_actions_lint_offset_planes() {
|
||||
let server = kcl_lsp_server(false).await.unwrap();
|
||||
|
||||
// Send open file.
|
||||
server
|
||||
.did_open(tower_lsp::lsp_types::DidOpenTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentItem {
|
||||
uri: "file:///testlint.kcl".try_into().unwrap(),
|
||||
language_id: "kcl".to_string(),
|
||||
version: 1,
|
||||
text: r#"startSketchOn({
|
||||
origin = { x = 0, y = -14.3, z = 0 },
|
||||
xAxis = { x = 1, y = 0, z = 0 },
|
||||
yAxis = { x = 0, y = 0, z = 1 },
|
||||
})
|
||||
|> startProfile(at = [0, 0])"#
|
||||
.to_string(),
|
||||
},
|
||||
})
|
||||
.await;
|
||||
|
||||
// Send diagnostics request.
|
||||
let diagnostics = server
|
||||
.diagnostic(tower_lsp::lsp_types::DocumentDiagnosticParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentIdentifier {
|
||||
uri: "file:///testlint.kcl".try_into().unwrap(),
|
||||
},
|
||||
partial_result_params: Default::default(),
|
||||
work_done_progress_params: Default::default(),
|
||||
identifier: None,
|
||||
previous_result_id: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Check the diagnostics.
|
||||
let tower_lsp::lsp_types::DocumentDiagnosticReportResult::Report(diagnostics) = diagnostics else {
|
||||
panic!("Expected diagnostics");
|
||||
};
|
||||
|
||||
let tower_lsp::lsp_types::DocumentDiagnosticReport::Full(diagnostics) = diagnostics else {
|
||||
panic!("Expected full diagnostics");
|
||||
};
|
||||
assert_eq!(diagnostics.full_document_diagnostic_report.items.len(), 1);
|
||||
assert_eq!(
|
||||
diagnostics.full_document_diagnostic_report.items[0].message,
|
||||
"offsetPlane should be used to define a new plane offset from the origin"
|
||||
);
|
||||
|
||||
// Make sure we get the suggestion data.
|
||||
assert_eq!(
|
||||
diagnostics.full_document_diagnostic_report.items[0]
|
||||
.data
|
||||
.clone()
|
||||
.map(|d| serde_json::from_value::<LspSuggestion>(d).unwrap()),
|
||||
Some((
|
||||
Suggestion {
|
||||
insert: "offsetPlane(XZ, offset = -14.3)".to_string(),
|
||||
source_range: SourceRange::new(14, 133, Default::default()),
|
||||
title: "use offsetPlane instead".to_string(),
|
||||
},
|
||||
tower_lsp::lsp_types::Range {
|
||||
start: tower_lsp::lsp_types::Position { line: 0, character: 14 },
|
||||
end: tower_lsp::lsp_types::Position { line: 4, character: 1 },
|
||||
}
|
||||
))
|
||||
);
|
||||
|
||||
let diagnostic = diagnostics.full_document_diagnostic_report.items[0].clone();
|
||||
|
||||
// Run a code action.
|
||||
let code_action = server
|
||||
.code_action(tower_lsp::lsp_types::CodeActionParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentIdentifier {
|
||||
uri: "file:///testlint.kcl".try_into().unwrap(),
|
||||
},
|
||||
range: tower_lsp::lsp_types::Range {
|
||||
start: tower_lsp::lsp_types::Position { line: 0, character: 14 },
|
||||
end: tower_lsp::lsp_types::Position { line: 4, character: 1 },
|
||||
},
|
||||
context: tower_lsp::lsp_types::CodeActionContext {
|
||||
diagnostics: vec![diagnostic.clone()],
|
||||
only: None,
|
||||
trigger_kind: Default::default(),
|
||||
},
|
||||
work_done_progress_params: Default::default(),
|
||||
partial_result_params: Default::default(),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(code_action.is_some());
|
||||
|
||||
let code_action = code_action.unwrap();
|
||||
|
||||
assert_eq!(code_action.len(), 1);
|
||||
|
||||
assert_eq!(
|
||||
code_action[0],
|
||||
CodeActionOrCommand::CodeAction(tower_lsp::lsp_types::CodeAction {
|
||||
title: "use offsetPlane instead".to_string(),
|
||||
kind: Some(CodeActionKind::QUICKFIX),
|
||||
diagnostics: Some(vec![diagnostic]),
|
||||
edit: Some(WorkspaceEdit {
|
||||
changes: Some(HashMap::from_iter(vec![(
|
||||
"file:///testlint.kcl".try_into().unwrap(),
|
||||
vec![TextEdit {
|
||||
range: tower_lsp::lsp_types::Range {
|
||||
start: tower_lsp::lsp_types::Position { line: 0, character: 14 },
|
||||
end: tower_lsp::lsp_types::Position { line: 4, character: 1 },
|
||||
},
|
||||
new_text: "offsetPlane(XZ, offset = -14.3)".to_string(),
|
||||
}],
|
||||
)])),
|
||||
document_changes: None,
|
||||
change_annotations: None,
|
||||
}),
|
||||
command: None,
|
||||
is_preferred: Some(true),
|
||||
disabled: None,
|
||||
data: None,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user