diff --git a/crates/cad/src/import/text.rs b/crates/cad/src/import/text.rs index 8800aa270..5d2797d61 100644 --- a/crates/cad/src/import/text.rs +++ b/crates/cad/src/import/text.rs @@ -4,13 +4,13 @@ /// A single-line text value (TEXT, ATTRIB) as plain text. pub(crate) fn plain(s: &str) -> String { - percent_codes(&escapes(s)) + percent_codes(&escapes(s, false)) } /// A multiline text value (MTEXT) as plain text with `\n` between paragraphs, and the font family /// its first font change names. pub(crate) fn mtext(s: &str) -> (String, Option) { - let s = escapes(s); + let s = escapes(s, true); let mut out = String::with_capacity(s.len()); let mut family = None; let mut chars = s.chars().peekable(); @@ -25,7 +25,7 @@ pub(crate) fn mtext(s: &str) -> (String, Option) { Some('S') => { // A stacked fraction `\Snum^den;` (or / or #): written as num/den. let arg = until_semicolon(&mut chars); - out.push_str(&arg.replace(['^', '#'], "/")); + out.push_str(&arg.replace("^ ", "^").replace(['^', '#'], "/")); } Some(f @ ('f' | 'F')) => { let arg = until_semicolon(&mut chars); @@ -63,8 +63,9 @@ fn until_semicolon(chars: &mut std::iter::Peekable>) -> Stri } /// `\U+XXXX` Unicode escapes (how files before DXF 2007 hold characters outside their code page) -/// and caret escapes: `^ ` is a caret, `^I` a tab; other control characters are dropped. -fn escapes(s: &str) -> String { +/// and caret escapes: `^ ` is a caret, `^I` a tab; other control characters are dropped. With +/// `keep_stacks`, the `^` in an MTEXT stacked fraction `\Snum^den;` is left for the caller. +fn escapes(s: &str, keep_stacks: bool) -> String { let mut out = String::with_capacity(s.len()); let mut rest = s; while let Some(c) = rest.chars().next() { @@ -78,6 +79,16 @@ fn escapes(s: &str) -> String { rest = after.get(6..).unwrap_or(""); continue; } + if keep_stacks + && c == '\\' + && let Some(tail) = after.strip_prefix('S') + { + let end = tail.find(';').map_or(tail.len(), |i| i + 1); + out.push_str("\\S"); + out.push_str(tail.get(..end).unwrap_or("")); + rest = tail.get(end..).unwrap_or(""); + continue; + } if c == '^' && let Some(next) = after.chars().next() { @@ -161,6 +172,8 @@ mod tests { // Carets are written "^ " (a caret before another character is a control character). assert_eq!(mtext("x\\S3^ 4;").0, "x3/4"); assert_eq!(mtext("x\\S3#4;").0, "x3/4"); + assert_eq!(mtext("\\S1^2;").0, "1/2"); + assert_eq!(mtext("\\S+1^-2;^I").0, "+1/-2\t"); assert_eq!(mtext("trailing\\").0, "trailing\\"); } }