mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-27 19:27:21 -06:00
Keep the denominator of DXF MTEXT stacked fractions written with ^
Found while testing crates/cad/src/import/text.rs:14-27 (mtext calls escapes at :14, which treats `^2` as a caret escape and drops it; the `\S` branch at :25 expects the `^`) Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
committed by
bflatastic
co-authored by
Claude Haiku 5.5
parent
aaf336ba31
commit
41c26c6997
@@ -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<String>) {
|
||||
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<String>) {
|
||||
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<std::str::Chars<'_>>) -> 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\\");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user