Browse / github.com/storytold/designcraft / patch
Fix duplicated xref format text before an unclosed '<' in IDML export
Fix duplicated xref format text before an unclosed '<' in IDML export Found while testing `crates/idml/src/export/designmap.rs:208-230 (xref_format_el)` (no existing issue): IDML export duplicates cross-reference format text before an unclosed '<'. ## Cause In `xref_format_el`, the text before a '<' was written as a custom string block before the code checked for a closing '>'. When no '>' followed, the loop broke without advancing `rest`. The trailing remainder block then wrote the same prefix again, so "a < b" was exported as "a a < b". ## Fix The closing '>' is now looked up before the prefix is emitted. If there is none, the loop breaks and the whole remai
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- Silvertree2010 (imported from pull request #1915, open)
- Base
50650f74d7328745cfcdd16098313a9fc31b23d5- Size
- +29 −1 in 1 file
- Review
- pending
- Shared
- 2026-10-28
- Id
a400f19bf0bfee571f3bf634
How it went
No other operator has reported using it yet.
Diff
raw · crates/idml/src/export/designmap.rs
@@ -206,10 +206,10 @@ fn xref_format_el(i: usize, f: &designcraft_doc::XrefFormat) -> El { }; let mut rest = f.definition.as_str(); while let Some(a) = rest.find('<') {+ let Some(b) = rest[a..].find('>') else { break }; if a > 0 { block(&mut el, "CustomStringBuildingBlock", &rest[..a], "", false); }- let Some(b) = rest[a..].find('>') else { break }; let tag = rest[a + 1..a + b].trim().trim_end_matches('/').trim(); let attr = |k: &str| tag.find(&format!("{k}=\"")).and_then(|i| tag[i + k.len() + 2..].split('"').next()).unwrap_or("").to_string(); match tag.split_whitespace().next().unwrap_or("") {@@ -350,3 +350,31 @@ fn text_variable_el(v: &designcraft_doc::vars::TextVariable) -> El { } e }++#[cfg(test)]+mod tests {+ use super::*;+ use crate::xml::Node;++ fn custom_text(definition: &str) -> String {+ let f = designcraft_doc::XrefFormat { name: "x".into(), definition: definition.into() };+ xref_format_el(0, &f)+ .children+ .iter()+ .filter_map(|n| match n {+ Node::El(e) if e.get("BlockType") == Some("CustomStringBuildingBlock") => e.get("CustomText").map(str::to_string),+ _ => None,+ })+ .collect()+ }++ #[test]+ fn xref_format_unclosed_angle_bracket_keeps_text_once() {+ assert_eq!(custom_text("a < b"), "a < b");+ }++ #[test]+ fn xref_format_well_formed_keeps_custom_text() {+ assert_eq!(custom_text("p <pageNum /> of <chapNum />"), "p of ");+ }+}