mirror of
https://github.com/joshuadavidthomas/django-language-server.git
synced 2025-09-10 12:26:50 +00:00
fix tagspecs
This commit is contained in:
parent
a078faabf7
commit
17f3fb43f7
3 changed files with 61 additions and 72 deletions
|
@ -125,7 +125,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
// If we get here, either there was no expected closing tag or it didn't match
|
// If we get here, either there was no expected closing tag or it didn't match
|
||||||
if let Some(branches) = &spec.branches {
|
if let Some(branches) = &spec.branches {
|
||||||
if branches.iter().any(|b| b.name == tag.name) {
|
if branches.iter().any(|b| b == &tag.name) {
|
||||||
let mut branch_tag = tag.clone();
|
let mut branch_tag = tag.clone();
|
||||||
let mut branch_nodes = Vec::new();
|
let mut branch_nodes = Vec::new();
|
||||||
let mut found_closing = false;
|
let mut found_closing = false;
|
||||||
|
@ -147,8 +147,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check if this is another branch tag
|
// Check if this is another branch tag
|
||||||
if branches.iter().any(|b| b.name == next_tag.name)
|
if branches.iter().any(|b| b == &next_tag.name) {
|
||||||
{
|
|
||||||
// Push the current branch and start a new one
|
// Push the current branch and start a new one
|
||||||
nodes.push(Node::Block(Block::Branch {
|
nodes.push(Node::Block(Block::Branch {
|
||||||
tag: branch_tag.clone(),
|
tag: branch_tag.clone(),
|
||||||
|
|
|
@ -10,63 +10,15 @@ pub struct TagSpec {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub tag_type: TagType,
|
pub tag_type: TagType,
|
||||||
pub closing: Option<String>,
|
pub closing: Option<String>,
|
||||||
pub branches: Option<Vec<BranchSpec>>,
|
#[serde(default)]
|
||||||
|
pub branches: Option<Vec<String>>,
|
||||||
pub args: Option<Vec<ArgSpec>>,
|
pub args: Option<Vec<ArgSpec>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
|
||||||
pub struct BranchSpec {
|
|
||||||
pub name: String,
|
|
||||||
pub args: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TagSpec {
|
impl TagSpec {
|
||||||
pub fn load_builtin_specs() -> Result<HashMap<String, TagSpec>> {
|
pub fn load_builtin_specs() -> Result<HashMap<String, TagSpec>> {
|
||||||
let mut specs = HashMap::new();
|
let mut specs = HashMap::new();
|
||||||
|
|
||||||
// Add built-in tag specs
|
|
||||||
specs.insert(
|
|
||||||
"if".to_string(),
|
|
||||||
TagSpec {
|
|
||||||
tag_type: TagType::Block,
|
|
||||||
closing: Some("endif".to_string()),
|
|
||||||
branches: Some(vec![
|
|
||||||
BranchSpec {
|
|
||||||
name: "elif".to_string(),
|
|
||||||
args: true,
|
|
||||||
},
|
|
||||||
BranchSpec {
|
|
||||||
name: "else".to_string(),
|
|
||||||
args: false,
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
args: None,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
specs.insert(
|
|
||||||
"for".to_string(),
|
|
||||||
TagSpec {
|
|
||||||
tag_type: TagType::Block,
|
|
||||||
closing: Some("endfor".to_string()),
|
|
||||||
branches: Some(vec![BranchSpec {
|
|
||||||
name: "empty".to_string(),
|
|
||||||
args: false,
|
|
||||||
}]),
|
|
||||||
args: None,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
specs.insert(
|
|
||||||
"block".to_string(),
|
|
||||||
TagSpec {
|
|
||||||
tag_type: TagType::Block,
|
|
||||||
closing: Some("endblock".to_string()),
|
|
||||||
branches: None,
|
|
||||||
args: None,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let specs_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("tagspecs");
|
let specs_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("tagspecs");
|
||||||
|
|
||||||
for entry in fs::read_dir(&specs_dir)? {
|
for entry in fs::read_dir(&specs_dir)? {
|
||||||
|
@ -80,36 +32,39 @@ impl TagSpec {
|
||||||
let value: Value = toml::from_str(&content)
|
let value: Value = toml::from_str(&content)
|
||||||
.with_context(|| format!("Failed to parse {:?}", path))?;
|
.with_context(|| format!("Failed to parse {:?}", path))?;
|
||||||
|
|
||||||
Self::extract_specs(&value, "", &mut specs)?;
|
Self::extract_specs(&value, None, &mut specs)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eprintln!("specs: {:?}", specs);
|
||||||
|
|
||||||
Ok(specs)
|
Ok(specs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_specs(
|
fn extract_specs(
|
||||||
value: &Value,
|
value: &Value,
|
||||||
prefix: &str,
|
prefix: Option<&str>,
|
||||||
specs: &mut HashMap<String, TagSpec>,
|
specs: &mut HashMap<String, TagSpec>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if let Value::Table(table) = value {
|
// Try to deserialize as a tag spec first
|
||||||
// If this table has a 'type' field, try to parse it as a TagSpec
|
match TagSpec::deserialize(value.clone()) {
|
||||||
if table.contains_key("type") {
|
Ok(tag_spec) => {
|
||||||
if let Ok(tag_spec) = TagSpec::deserialize(value.clone()) {
|
let name = prefix.map_or_else(String::new, |p| {
|
||||||
let name = prefix.split('.').last().unwrap_or(prefix);
|
p.split('.').last().unwrap_or(p).to_string()
|
||||||
specs.insert(name.to_string(), tag_spec);
|
});
|
||||||
return Ok(());
|
eprintln!("Found tag spec at '{}', using name '{}'", prefix.unwrap_or(""), name);
|
||||||
}
|
specs.insert(name, tag_spec);
|
||||||
}
|
}
|
||||||
|
Err(_) => {
|
||||||
// Otherwise, recursively process each field
|
// Not a tag spec, try recursing into any table values
|
||||||
for (key, value) in table {
|
for (key, value) in value.as_table().iter().flat_map(|t| t.iter()) {
|
||||||
let new_prefix = if prefix.is_empty() {
|
let new_prefix = match prefix {
|
||||||
key.clone()
|
None => key.clone(),
|
||||||
} else {
|
Some(p) => format!("{}.{}", p, key),
|
||||||
format!("{}.{}", prefix, key)
|
};
|
||||||
};
|
eprintln!("Recursing into prefix: {}", new_prefix);
|
||||||
Self::extract_specs(value, &new_prefix, specs)?;
|
Self::extract_specs(value, Some(&new_prefix), specs)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -162,4 +117,34 @@ mod tests {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_builtin_django_tags() -> Result<()> {
|
||||||
|
let specs = TagSpec::load_builtin_specs()?;
|
||||||
|
|
||||||
|
let if_tag = specs.get("if").expect("if tag should be present");
|
||||||
|
assert_eq!(if_tag.tag_type, TagType::Block);
|
||||||
|
assert_eq!(if_tag.closing, Some("endif".to_string()));
|
||||||
|
let if_branches = if_tag
|
||||||
|
.branches
|
||||||
|
.as_ref()
|
||||||
|
.expect("if tag should have branches");
|
||||||
|
assert!(if_branches.iter().any(|b| b == "elif"));
|
||||||
|
assert!(if_branches.iter().any(|b| b == "else"));
|
||||||
|
|
||||||
|
let for_tag = specs.get("for").expect("for tag should be present");
|
||||||
|
assert_eq!(for_tag.tag_type, TagType::Block);
|
||||||
|
assert_eq!(for_tag.closing, Some("endfor".to_string()));
|
||||||
|
let for_branches = for_tag
|
||||||
|
.branches
|
||||||
|
.as_ref()
|
||||||
|
.expect("for tag should have branches");
|
||||||
|
assert!(for_branches.iter().any(|b| b == "empty"));
|
||||||
|
|
||||||
|
let block_tag = specs.get("block").expect("block tag should be present");
|
||||||
|
assert_eq!(block_tag.tag_type, TagType::Block);
|
||||||
|
assert_eq!(block_tag.closing, Some("endblock".to_string()));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# Django built-in template tags
|
||||||
[django.template.defaulttags.if]
|
[django.template.defaulttags.if]
|
||||||
branches = ["elif", "else"]
|
branches = ["elif", "else"]
|
||||||
closing = "endif"
|
closing = "endif"
|
||||||
|
@ -23,3 +24,7 @@ required = true
|
||||||
[[django.template.defaulttags.for.args]]
|
[[django.template.defaulttags.for.args]]
|
||||||
name = "{iterable}"
|
name = "{iterable}"
|
||||||
required = true
|
required = true
|
||||||
|
|
||||||
|
[django.template.defaulttags.block]
|
||||||
|
closing = "endblock"
|
||||||
|
type = "block"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue