11use djls_semantic:: ValidationError ;
22use djls_source:: File ;
33use djls_source:: LineIndex ;
4+ use djls_source:: Offset ;
45use djls_source:: Span ;
56use djls_templates:: TemplateError ;
67use djls_templates:: TemplateErrorAccumulator ;
@@ -13,6 +14,30 @@ trait DiagnosticError: std::fmt::Display {
1314 fn message ( & self ) -> String {
1415 self . to_string ( )
1516 }
17+
18+ fn as_diagnostic ( & self , line_index : & LineIndex ) -> lsp_types:: Diagnostic {
19+ let range = self
20+ . span ( )
21+ . map ( |( start, length) | {
22+ let span = Span :: new ( start, length) ;
23+ LspRange :: from ( ( & span, line_index) ) . into ( )
24+ } )
25+ . unwrap_or_default ( ) ;
26+
27+ lsp_types:: Diagnostic {
28+ range,
29+ severity : Some ( lsp_types:: DiagnosticSeverity :: ERROR ) ,
30+ code : Some ( lsp_types:: NumberOrString :: String (
31+ self . diagnostic_code ( ) . to_string ( ) ,
32+ ) ) ,
33+ code_description : None ,
34+ source : Some ( "Django Language Server" . to_string ( ) ) ,
35+ message : self . message ( ) ,
36+ related_information : None ,
37+ tags : None ,
38+ data : None ,
39+ }
40+ }
1641}
1742
1843impl DiagnosticError for TemplateError {
@@ -32,14 +57,12 @@ impl DiagnosticError for TemplateError {
3257impl DiagnosticError for ValidationError {
3358 fn span ( & self ) -> Option < ( u32 , u32 ) > {
3459 match self {
35- ValidationError :: UnbalancedStructure { opening_span, .. } => {
36- Some ( opening_span. as_tuple ( ) )
37- }
60+ ValidationError :: UnbalancedStructure { opening_span, .. } => Some ( opening_span. into ( ) ) ,
3861 ValidationError :: UnclosedTag { span, .. }
3962 | ValidationError :: OrphanedTag { span, .. }
4063 | ValidationError :: UnmatchedBlockName { span, .. }
4164 | ValidationError :: MissingRequiredArguments { span, .. }
42- | ValidationError :: TooManyArguments { span, .. } => Some ( span. as_tuple ( ) ) ,
65+ | ValidationError :: TooManyArguments { span, .. } => Some ( span. into ( ) ) ,
4366 }
4467 }
4568
@@ -55,47 +78,43 @@ impl DiagnosticError for ValidationError {
5578 }
5679}
5780
58- /// Convert a Span to an LSP Range using line offsets.
59- fn span_to_lsp_range ( span : Span , line_index : & LineIndex ) -> lsp_types:: Range {
60- let ( start_pos, end_pos) = span. to_line_col ( line_index) ;
61-
62- lsp_types:: Range {
63- start : lsp_types:: Position {
64- line : start_pos. line ( ) ,
65- character : start_pos. column ( ) ,
66- } ,
67- end : lsp_types:: Position {
68- line : end_pos. line ( ) ,
69- character : end_pos. column ( ) ,
70- } ,
81+ #[ derive( Debug , Clone , Copy , PartialEq ) ]
82+ #[ repr( transparent) ]
83+ pub struct LspRange ( pub lsp_types:: Range ) ;
84+
85+ impl From < ( & Span , & LineIndex ) > for LspRange {
86+ #[ inline]
87+ fn from ( ( s, line_index) : ( & Span , & LineIndex ) ) -> Self {
88+ let start = LspPosition :: from ( ( s. start_offset ( ) , line_index) ) . into ( ) ;
89+ let end = LspPosition :: from ( ( s. end_offset ( ) , line_index) ) . into ( ) ;
90+
91+ LspRange ( lsp_types:: Range { start, end } )
92+ }
93+ }
94+
95+ impl From < LspRange > for lsp_types:: Range {
96+ #[ inline]
97+ fn from ( value : LspRange ) -> Self {
98+ value. 0
99+ }
100+ }
101+
102+ #[ derive( Debug , Clone , Copy , PartialEq ) ]
103+ #[ repr( transparent) ]
104+ pub struct LspPosition ( pub lsp_types:: Position ) ;
105+
106+ impl From < ( Offset , & LineIndex ) > for LspPosition {
107+ #[ inline]
108+ fn from ( ( offset, line_index) : ( Offset , & LineIndex ) ) -> Self {
109+ let ( line, character) = line_index. to_line_col ( offset) . into ( ) ;
110+ Self ( lsp_types:: Position { line, character } )
71111 }
72112}
73113
74- /// Convert any error implementing `DiagnosticError` to an LSP diagnostic.
75- fn error_to_diagnostic (
76- error : & impl DiagnosticError ,
77- line_index : & LineIndex ,
78- ) -> lsp_types:: Diagnostic {
79- let range = error
80- . span ( )
81- . map ( |( start, length) | {
82- let span = Span :: new ( start, length) ;
83- span_to_lsp_range ( span, line_index)
84- } )
85- . unwrap_or_default ( ) ;
86-
87- lsp_types:: Diagnostic {
88- range,
89- severity : Some ( lsp_types:: DiagnosticSeverity :: ERROR ) ,
90- code : Some ( lsp_types:: NumberOrString :: String (
91- error. diagnostic_code ( ) . to_string ( ) ,
92- ) ) ,
93- code_description : None ,
94- source : Some ( "Django Language Server" . to_string ( ) ) ,
95- message : error. message ( ) ,
96- related_information : None ,
97- tags : None ,
98- data : None ,
114+ impl From < LspPosition > for lsp_types:: Position {
115+ #[ inline]
116+ fn from ( value : LspPosition ) -> Self {
117+ value. 0
99118 }
100119}
101120
@@ -133,7 +152,7 @@ pub fn collect_diagnostics(
133152 let line_index = file. line_index ( db) ;
134153
135154 for error_acc in template_errors {
136- diagnostics. push ( error_to_diagnostic ( & error_acc. 0 , line_index) ) ;
155+ diagnostics. push ( error_acc. 0 . as_diagnostic ( line_index) ) ;
137156 }
138157
139158 if let Some ( nodelist) = nodelist {
@@ -142,7 +161,7 @@ pub fn collect_diagnostics(
142161 > ( db, nodelist) ;
143162
144163 for error_acc in validation_errors {
145- diagnostics. push ( error_to_diagnostic ( & error_acc. 0 , line_index) ) ;
164+ diagnostics. push ( error_acc. 0 . as_diagnostic ( line_index) ) ;
146165 }
147166 }
148167
0 commit comments