use regex::Regex;
use std::sync::LazyLock;
static JINJA_EXPRESSION_REGEX: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"\{\{.*?\}\}").expect("Failed to compile Jinja expression regex"));
static JINJA_STATEMENT_REGEX: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"\{%.*?%\}").expect("Failed to compile Jinja statement regex"));
pub fn find_jinja_ranges(content: &str) -> Vec<(usize, usize)> {
let mut ranges = Vec::new();
for mat in JINJA_EXPRESSION_REGEX.find_iter(content) {
ranges.push((mat.start(), mat.end()));
}
for mat in JINJA_STATEMENT_REGEX.find_iter(content) {
ranges.push((mat.start(), mat.end()));
}
ranges.sort_by_key(|r| r.0);
ranges
}
pub fn is_in_jinja_template(content: &str, pos: usize) -> bool {
for mat in JINJA_EXPRESSION_REGEX.find_iter(content) {
if pos >= mat.start() && pos < mat.end() {
return true;
}
}
for mat in JINJA_STATEMENT_REGEX.find_iter(content) {
if pos >= mat.start() && pos < mat.end() {
return true;
}
}
false
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_jinja_expression_detection() {
let content = "Some text {{ variable }} more text";
assert!(!is_in_jinja_template(content, 5));
assert!(is_in_jinja_template(content, 15));
assert!(!is_in_jinja_template(content, 30));
}
#[test]
fn test_jinja_statement_detection() {
let content = "{% if condition %} text {% endif %}";
assert!(is_in_jinja_template(content, 5));
assert!(!is_in_jinja_template(content, 20));
assert!(is_in_jinja_template(content, 28));
}
#[test]
fn test_complex_jinja_expression() {
let content = "{{ pd_read_csv()[index] | filter }}";
assert!(is_in_jinja_template(content, 10));
assert!(is_in_jinja_template(content, 20));
}
}