Skip to content

Commit 7196eb8

Browse files
finish migrating to tagspec v0.6.0
1 parent 213734b commit 7196eb8

File tree

8 files changed

+267
-164
lines changed

8 files changed

+267
-164
lines changed

crates/djls-ide/src/completions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ fn generate_argument_completions(
579579
}
580580
}
581581
}
582-
TagArg::Var { name, .. } => {
582+
TagArg::Variable { name, .. } => {
583583
// For variables, we could offer variable completions from context
584584
// For now, just provide a hint
585585
if partial.is_empty() {

crates/djls-ide/src/snippets.rs

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub fn generate_snippet_from_args(args: &[TagArg]) -> String {
2525
// At this point, we know it's required (optional literals were skipped above)
2626
lit.to_string()
2727
}
28-
TagArg::Var { name, .. } | TagArg::Expr { name, .. } => {
28+
TagArg::Variable { name, .. } | TagArg::Any { name, .. } => {
2929
// Variables and expressions become placeholders
3030
let result = format!("${{{}:{}}}", placeholder_index, name.as_ref());
3131
placeholder_index += 1;
@@ -125,22 +125,10 @@ mod tests {
125125
#[test]
126126
fn test_snippet_for_for_tag() {
127127
let args = vec![
128-
TagArg::Var {
129-
name: "item".into(),
130-
required: true,
131-
},
132-
TagArg::Literal {
133-
lit: "in".into(),
134-
required: true,
135-
},
136-
TagArg::Var {
137-
name: "items".into(),
138-
required: true,
139-
},
140-
TagArg::Literal {
141-
lit: "reversed".into(),
142-
required: false,
143-
},
128+
TagArg::var("item", true),
129+
TagArg::syntax("in", true),
130+
TagArg::var("items", true),
131+
TagArg::modifier("reversed", false),
144132
];
145133

146134
let snippet = generate_snippet_from_args(&args);
@@ -149,10 +137,7 @@ mod tests {
149137

150138
#[test]
151139
fn test_snippet_for_if_tag() {
152-
let args = vec![TagArg::Expr {
153-
name: "condition".into(),
154-
required: true,
155-
}];
140+
let args = vec![TagArg::expr("condition", true)];
156141

157142
let snippet = generate_snippet_from_args(&args);
158143
assert_eq!(snippet, "${1:condition}");
@@ -198,17 +183,11 @@ mod tests {
198183
end_tag: Some(EndTag {
199184
name: "endblock".into(),
200185
required: true,
201-
args: vec![TagArg::Var {
202-
name: "name".into(),
203-
required: false,
204-
}]
186+
args: vec![TagArg::var("name", false)]
205187
.into(),
206188
}),
207189
intermediate_tags: Cow::Borrowed(&[]),
208-
args: vec![TagArg::Var {
209-
name: "name".into(),
210-
required: true,
211-
}]
190+
args: vec![TagArg::var("name", true)]
212191
.into(),
213192
};
214193

@@ -254,14 +233,8 @@ mod tests {
254233
name: "args".into(),
255234
required: false,
256235
},
257-
TagArg::Literal {
258-
lit: "as".into(),
259-
required: false,
260-
},
261-
TagArg::Var {
262-
name: "varname".into(),
263-
required: false,
264-
},
236+
TagArg::syntax("as", false),
237+
TagArg::var("varname", false),
265238
];
266239

267240
let snippet = generate_snippet_from_args(&args);

crates/djls-semantic/src/arguments.rs

Lines changed: 20 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ fn validate_argument_order(
143143
}
144144

145145
match arg {
146-
TagArg::Literal { lit, required } => {
146+
TagArg::Literal { lit, required, .. } => {
147+
// kind field is ignored for validation - it's only for semantic hints
147148
let matches_literal = bits[bit_index] == lit.as_ref();
148149
if *required {
149150
if matches_literal {
@@ -234,6 +235,11 @@ fn validate_argument_order(
234235
if token.contains('=') {
235236
break;
236237
}
238+
crate::templatetags::TokenCount::Greedy => {
239+
// Assignment arguments can appear as:
240+
// 1. Single token: var=value
241+
// 2. Multi-token: expr as varname
242+
// Consume until we find = or "as", or hit next literal
237243

238244
// If we hit "as", consume the variable name after it
239245
if token == "as" && bit_index < bits.len() {
@@ -403,16 +409,13 @@ mod tests {
403409
fn test_if_tag_with_comparison_operator() {
404410
// Issue #1: {% if message.input_tokens > 0 %}
405411
// Parser tokenizes as: ["message.input_tokens", ">", "0"]
406-
// Spec expects: [Expr{name="condition"}]
412+
// Spec expects: [Any{name="condition", count=Greedy}]
407413
let bits = vec![
408414
"message.input_tokens".to_string(),
409415
">".to_string(),
410416
"0".to_string(),
411417
];
412-
let args = vec![TagArg::Expr {
413-
name: "condition".into(),
414-
required: true,
415-
}];
418+
let args = vec![TagArg::expr("condition", true)];
416419

417420
let errors = check_validation_errors("if", &bits, &args);
418421
assert!(
@@ -448,22 +451,10 @@ mod tests {
448451
"reversed".to_string(),
449452
];
450453
let args = vec![
451-
TagArg::Var {
452-
name: "item".into(),
453-
required: true,
454-
},
455-
TagArg::Literal {
456-
lit: "in".into(),
457-
required: true,
458-
},
459-
TagArg::Var {
460-
name: "items".into(),
461-
required: true,
462-
},
463-
TagArg::Literal {
464-
lit: "reversed".into(),
465-
required: false,
466-
},
454+
TagArg::var("item", true),
455+
TagArg::syntax("in", true),
456+
TagArg::var("items", true),
457+
TagArg::modifier("reversed", false),
467458
];
468459

469460
let errors = check_validation_errors("for", &bits, &args);
@@ -481,10 +472,7 @@ mod tests {
481472
"and".to_string(),
482473
"user.is_staff".to_string(),
483474
];
484-
let args = vec![TagArg::Expr {
485-
name: "condition".into(),
486-
required: true,
487-
}];
475+
let args = vec![TagArg::expr("condition", true)];
488476

489477
let errors = check_validation_errors("if", &bits, &args);
490478
assert!(
@@ -521,10 +509,7 @@ mod tests {
521509
fn test_with_assignment() {
522510
// {% with total=items|length %}
523511
let bits = vec!["total=items|length".to_string()];
524-
let args = vec![TagArg::Assignment {
525-
name: "bindings".into(),
526-
required: true,
527-
}];
512+
let args = vec![TagArg::assignment("bindings", true)];
528513

529514
let errors = check_validation_errors("with", &bits, &args);
530515
assert!(
@@ -556,14 +541,8 @@ mod tests {
556541
"reversed".to_string(),
557542
];
558543
let args = vec![
559-
TagArg::Expr {
560-
name: "condition".into(),
561-
required: true,
562-
},
563-
TagArg::Literal {
564-
lit: "reversed".into(),
565-
required: false,
566-
},
544+
TagArg::expr("condition", true),
545+
TagArg::modifier("reversed", false),
567546
];
568547

569548
let errors = check_validation_errors("if", &bits, &args);
@@ -675,18 +654,9 @@ mod tests {
675654
"library".to_string(),
676655
];
677656
let args = vec![
678-
TagArg::VarArgs {
679-
name: "tags".into(),
680-
required: false,
681-
},
682-
TagArg::Literal {
683-
lit: "from".into(),
684-
required: false,
685-
},
686-
TagArg::Var {
687-
name: "library".into(),
688-
required: false,
689-
},
657+
TagArg::varargs("tags", false),
658+
TagArg::syntax("from", false),
659+
TagArg::var("library", false),
690660
];
691661

692662
let errors = check_validation_errors("load", &bits, &args);

crates/djls-semantic/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ pub use resolution::TemplateReference;
2424
pub use semantic::build_semantic_forest;
2525
pub use templatetags::django_builtin_specs;
2626
pub use templatetags::EndTag;
27+
pub use templatetags::LiteralKind;
2728
pub use templatetags::TagArg;
2829
pub use templatetags::TagSpec;
2930
pub use templatetags::TagSpecs;
31+
pub use templatetags::TokenCount;
3032

3133
/// Validate a Django template node list and return validation errors.
3234
///

crates/djls-semantic/src/templatetags.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ pub use specs::TagArg;
77
pub(crate) use specs::TagArgSliceExt;
88
pub use specs::TagSpec;
99
pub use specs::TagSpecs;
10+
pub use specs::TokenCount;

0 commit comments

Comments
 (0)