Skip to content

Commit a080e18

Browse files
Add BlockTree prototype with TagIndex grammar (#241)
1 parent 3d140e5 commit a080e18

33 files changed

+2054
-299
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/djls-ide/src/completions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ fn generate_tag_name_completions(
390390
let specs = tag_specs.unwrap();
391391

392392
// Add all end tags that match the partial
393-
for (opener_name, spec) in specs.iter() {
393+
for (opener_name, spec) in specs {
394394
if let Some(end_tag) = &spec.end_tag {
395395
if end_tag.name.starts_with(partial) {
396396
// Create a completion for the end tag

crates/djls-ide/src/diagnostics.rs

Lines changed: 63 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use djls_semantic::ValidationError;
22
use djls_source::File;
33
use djls_source::LineIndex;
4+
use djls_source::Offset;
45
use djls_source::Span;
56
use djls_templates::TemplateError;
67
use 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

1843
impl DiagnosticError for TemplateError {
@@ -32,14 +57,12 @@ impl DiagnosticError for TemplateError {
3257
impl 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

crates/djls-semantic/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ serde = { workspace = true }
1616
thiserror = { workspace = true }
1717

1818
[dev-dependencies]
19+
insta = { workspace = true }
1920
tempfile = { workspace = true }
2021

2122
[lints]

crates/djls-semantic/src/blocks.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
mod builder;
2+
mod grammar;
3+
mod nodes;
4+
mod snapshot;
5+
mod tree;

0 commit comments

Comments
 (0)