merman_editor_core/
diagnostics.rs1use crate::types::Range;
2use merman_analysis::{
3 AnalysisDiagnostic, AnalysisPayload, DiagnosticCategory, DiagnosticFix, DiagnosticSeverity,
4 DiagnosticSpan,
5};
6use serde::{Deserialize, Serialize};
7
8pub fn analysis_payload_to_diagnostics(payload: &AnalysisPayload) -> Vec<EditorDiagnostic> {
9 payload
10 .diagnostics
11 .iter()
12 .map(analysis_diagnostic_to_editor)
13 .collect()
14}
15
16pub fn analysis_diagnostic_to_editor(diagnostic: &AnalysisDiagnostic) -> EditorDiagnostic {
17 EditorDiagnostic {
18 range: diagnostic
19 .span
20 .as_ref()
21 .map(range_from_span)
22 .unwrap_or_default(),
23 severity: diagnostic.severity,
24 code: diagnostic.id.clone(),
25 source: "merman".to_string(),
26 message: diagnostic.message.clone(),
27 related: diagnostic
28 .related
29 .iter()
30 .filter_map(|related| {
31 Some(EditorDiagnosticRelated {
32 message: related.message.clone(),
33 range: related.span.as_ref().map(range_from_span)?,
34 })
35 })
36 .collect(),
37 data: diagnostic_data(diagnostic),
38 }
39}
40
41pub fn diagnostic_data(diagnostic: &AnalysisDiagnostic) -> Option<DiagnosticCodeActionData> {
42 Some(DiagnosticCodeActionData {
43 id: diagnostic.id.clone(),
44 code: diagnostic.code,
45 code_name: diagnostic.code_name.clone(),
46 category: diagnostic.category,
47 diagram_type: diagnostic.diagram_type.clone(),
48 help: diagnostic.help.clone(),
49 fixes: diagnostic.fixes.clone(),
50 })
51}
52
53fn range_from_span(span: &DiagnosticSpan) -> Range {
54 Range::new(
55 crate::types::Position::new(span.lsp_range.start.line, span.lsp_range.start.character),
56 crate::types::Position::new(span.lsp_range.end.line, span.lsp_range.end.character),
57 )
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
61pub struct EditorDiagnostic {
62 pub range: Range,
63 pub severity: DiagnosticSeverity,
64 pub code: String,
65 pub source: String,
66 pub message: String,
67 pub related: Vec<EditorDiagnosticRelated>,
68 pub data: Option<DiagnosticCodeActionData>,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
72pub struct EditorDiagnosticRelated {
73 pub message: String,
74 pub range: Range,
75}
76
77#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
78#[serde(rename_all = "camelCase")]
79pub struct DiagnosticCodeActionData {
80 pub id: String,
81 #[serde(default, skip_serializing_if = "Option::is_none")]
82 pub code: Option<i32>,
83 #[serde(default, skip_serializing_if = "Option::is_none")]
84 pub code_name: Option<String>,
85 #[serde(default = "default_diagnostic_category")]
86 pub category: DiagnosticCategory,
87 #[serde(default, skip_serializing_if = "Option::is_none")]
88 pub diagram_type: Option<String>,
89 #[serde(default, skip_serializing_if = "Option::is_none")]
90 pub help: Option<String>,
91 #[serde(default, skip_serializing_if = "Vec::is_empty")]
92 pub fixes: Vec<DiagnosticFix>,
93}
94
95fn default_diagnostic_category() -> DiagnosticCategory {
96 DiagnosticCategory::Internal
97}