pub(super) fn fix_single_brace_in_verify_blocks(toml_text: &str) -> (String, usize) {
let mut out = String::with_capacity(toml_text.len());
let mut in_verify = false;
let mut total = 0usize;
for line in toml_text.lines() {
let trimmed = line.trim_start();
if let Some(rest) = trimmed.strip_prefix('[') {
let header = rest.trim_end_matches(['\r', ' ', '\t']);
in_verify = header.starts_with("detector.verify")
|| header.starts_with("[detector.verify")
|| header == "detector.verify]"
|| header == "[detector.verify]]";
if !in_verify {
let stripped = header.trim_matches(['[', ']'].as_ref());
in_verify = stripped.starts_with("detector.verify");
}
}
if in_verify {
let (rewritten, count) = rewrite_braces_in_string_literals(line);
total += count;
out.push_str(&rewritten);
} else {
out.push_str(line);
}
out.push('\n');
}
if !toml_text.ends_with('\n') && out.ends_with('\n') {
out.pop();
}
(out, total)
}
pub(super) fn rewrite_braces_in_string_literals(line: &str) -> (String, usize) {
let mut out = String::with_capacity(line.len());
let mut count = 0usize;
let bytes = line.as_bytes();
let mut i = 0;
while i < bytes.len() {
let b = bytes[i];
if b == b'"' || b == b'\'' {
let quote = b;
out.push(quote as char);
let mut j = i + 1;
let mut literal = String::new();
while j < bytes.len() {
let c = bytes[j];
if quote == b'"' && c == b'\\' && j + 1 < bytes.len() {
literal.push(c as char);
literal.push(bytes[j + 1] as char);
j += 2;
continue;
}
if c == quote {
break;
}
literal.push(c as char);
j += 1;
}
let (rewritten_literal, c) = rewrite_braces(&literal);
count += c;
out.push_str(&rewritten_literal);
if j < bytes.len() {
out.push(quote as char);
i = j + 1;
} else {
i = j;
}
} else {
out.push(b as char);
i += 1;
}
}
(out, count)
}
pub(super) fn rewrite_braces(s: &str) -> (String, usize) {
let bytes = s.as_bytes();
let mut out = String::with_capacity(s.len());
let mut count = 0usize;
let mut i = 0;
while i < bytes.len() {
if bytes[i] == b'{' {
if i + 1 < bytes.len() && bytes[i + 1] == b'{' {
out.push('{');
out.push('{');
i += 2;
continue;
}
let start = i + 1;
if start < bytes.len() && (bytes[start].is_ascii_alphabetic() || bytes[start] == b'_') {
let mut end = start + 1;
while end < bytes.len()
&& (bytes[end].is_ascii_alphanumeric()
|| bytes[end] == b'_'
|| bytes[end] == b'.')
{
end += 1;
}
if end < bytes.len() && bytes[end] == b'}' {
out.push_str("{{");
out.push_str(&s[start..end]);
out.push_str("}}");
count += 1;
i = end + 1;
continue;
}
}
out.push('{');
i += 1;
} else {
out.push(bytes[i] as char);
i += 1;
}
}
(out, count)
}