Skip to content

Commit e87cb37

Browse files
finish migrating to tagspec v0.6.0
1 parent 26847c2 commit e87cb37

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/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ use semantic::validate_block_tags;
2424
use semantic::validate_non_block_tags;
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/semantic/args.rs

Lines changed: 20 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,8 @@ fn validate_choices_and_order(
163163
args_consumed = arg_index + 1;
164164

165165
match arg {
166-
TagArg::Literal { lit, required } => {
166+
TagArg::Literal { lit, required, .. } => {
167+
// kind field is ignored for validation - it's only for semantic hints
167168
let matches_literal = bits[bit_index] == lit.as_ref();
168169
if *required {
169170
if matches_literal {
@@ -257,6 +258,11 @@ fn validate_choices_and_order(
257258
if token.contains('=') {
258259
break;
259260
}
261+
crate::templatetags::TokenCount::Greedy => {
262+
// Assignment arguments can appear as:
263+
// 1. Single token: var=value
264+
// 2. Multi-token: expr as varname
265+
// Consume until we find = or "as", or hit next literal
260266

261267
// If we hit "as", consume one more token (the variable name)
262268
if token == "as" {
@@ -449,16 +455,13 @@ mod tests {
449455
fn test_if_tag_with_comparison_operator() {
450456
// Issue #1: {% if message.input_tokens > 0 %}
451457
// Parser tokenizes as: ["message.input_tokens", ">", "0"]
452-
// Spec expects: [Expr{name="condition"}]
458+
// Spec expects: [Any{name="condition", count=Greedy}]
453459
let bits = vec![
454460
"message.input_tokens".to_string(),
455461
">".to_string(),
456462
"0".to_string(),
457463
];
458-
let args = vec![TagArg::Expr {
459-
name: "condition".into(),
460-
required: true,
461-
}];
464+
let args = vec![TagArg::expr("condition", true)];
462465

463466
let errors = check_validation_errors("if", &bits, &args);
464467
assert!(
@@ -494,22 +497,10 @@ mod tests {
494497
"reversed".to_string(),
495498
];
496499
let args = vec![
497-
TagArg::Var {
498-
name: "item".into(),
499-
required: true,
500-
},
501-
TagArg::Literal {
502-
lit: "in".into(),
503-
required: true,
504-
},
505-
TagArg::Var {
506-
name: "items".into(),
507-
required: true,
508-
},
509-
TagArg::Literal {
510-
lit: "reversed".into(),
511-
required: false,
512-
},
500+
TagArg::var("item", true),
501+
TagArg::syntax("in", true),
502+
TagArg::var("items", true),
503+
TagArg::modifier("reversed", false),
513504
];
514505

515506
let errors = check_validation_errors("for", &bits, &args);
@@ -527,10 +518,7 @@ mod tests {
527518
"and".to_string(),
528519
"user.is_staff".to_string(),
529520
];
530-
let args = vec![TagArg::Expr {
531-
name: "condition".into(),
532-
required: true,
533-
}];
521+
let args = vec![TagArg::expr("condition", true)];
534522

535523
let errors = check_validation_errors("if", &bits, &args);
536524
assert!(
@@ -567,10 +555,7 @@ mod tests {
567555
fn test_with_assignment() {
568556
// {% with total=items|length %}
569557
let bits = vec!["total=items|length".to_string()];
570-
let args = vec![TagArg::Assignment {
571-
name: "bindings".into(),
572-
required: true,
573-
}];
558+
let args = vec![TagArg::assignment("bindings", true)];
574559

575560
let errors = check_validation_errors("with", &bits, &args);
576561
assert!(
@@ -602,14 +587,8 @@ mod tests {
602587
"reversed".to_string(),
603588
];
604589
let args = vec![
605-
TagArg::Expr {
606-
name: "condition".into(),
607-
required: true,
608-
},
609-
TagArg::Literal {
610-
lit: "reversed".into(),
611-
required: false,
612-
},
590+
TagArg::expr("condition", true),
591+
TagArg::modifier("reversed", false),
613592
];
614593

615594
let errors = check_validation_errors("if", &bits, &args);
@@ -769,18 +748,9 @@ mod tests {
769748
"library".to_string(),
770749
];
771750
let args = vec![
772-
TagArg::VarArgs {
773-
name: "tags".into(),
774-
required: false,
775-
},
776-
TagArg::Literal {
777-
lit: "from".into(),
778-
required: false,
779-
},
780-
TagArg::Var {
781-
name: "library".into(),
782-
required: false,
783-
},
751+
TagArg::varargs("tags", false),
752+
TagArg::syntax("from", false),
753+
TagArg::var("library", false),
784754
];
785755

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

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(crate) use specs::IntermediateTag;
77
pub use specs::TagArg;
88
pub use specs::TagSpec;
99
pub use specs::TagSpecs;
10+
pub use specs::TokenCount;

0 commit comments

Comments
 (0)