diff --git a/crates/doc/src/lib.rs b/crates/doc/src/lib.rs index 9c2670329..8742330bc 100644 --- a/crates/doc/src/lib.rs +++ b/crates/doc/src/lib.rs @@ -273,7 +273,10 @@ fn parse_measure(s: &str, default: Unit) -> Option { for op in ['+', '-', '*', '/'] { // Past the first character, so a leading sign isn't an operator. let skip = s.chars().next().map_or(0, char::len_utf8); - if let Some(i) = s[skip..].rfind(op).map(|i| i + skip) { + // A `+` or `-` right after another operator is the sign of its operand (`10*-2`, `5--3`). + let is_sign = |i: usize| matches!(op, '+' | '-') && s.get(..i).and_then(|l| l.trim_end().chars().last()).is_some_and(|c| "+-*/".contains(c)); + let found = s.char_indices().rev().find(|&(i, c)| i >= skip && c == op && !is_sign(i)); + if let Some(i) = found.map(|(i, _)| i) { let (l, r) = (&s[..i], &s[i + 1..]); if l.trim().is_empty() { continue; diff --git a/crates/doc/src/tests_units.rs b/crates/doc/src/tests_units.rs index bad63f23d..80a0dee21 100644 --- a/crates/doc/src/tests_units.rs +++ b/crates/doc/src/tests_units.rs @@ -66,3 +66,14 @@ fn readouts_show_two_decimals() { assert_eq!((Unit::Inches.number(595.2756), Unit::Points.number(595.2756)), ("8.2677".into(), "595.276".into())); assert_eq!(Unit::Points.number(-0.00001), "0"); } + +#[test] +fn a_negative_operand_after_an_operator_is_a_sign() { + assert_eq!(Unit::Points.parse("10*-2"), Some(-20.0)); + assert_eq!(Unit::Points.parse("-10/-2"), Some(5.0)); + assert_eq!(Unit::Points.parse("5--3"), Some(8.0)); + assert_eq!(Unit::Points.parse("5 - -3"), Some(8.0)); + assert_eq!(Unit::Points.parse("5+-3"), Some(2.0)); + assert_eq!(Unit::Points.parse("10-2"), Some(8.0)); + assert_eq!(super::parse_number("90*-1"), Some(-90.0)); +}