mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-29 12:57:09 -06:00
Fields: a count past its number format's range keeps its digits
NUMWORDS, NUMCHARS and REVNUM wrote a count past what the field's \* number format covers as the format's last value, so a revision number of 1,000,000 under \* ROMAN showed 50 M's. Such a count now keeps its digits, as a table formula result does.
This commit is contained in:
@@ -1144,10 +1144,13 @@ fn new_property_value(instr: &str) -> Option<String> {
|
||||
FieldCode::parse(instr).args.first().map(|a| a.chars().take(255).collect())
|
||||
}
|
||||
|
||||
/// A count (NUMWORDS, NUMCHARS, REVNUM) in the field's `\*` number format, digits without one,
|
||||
/// A count (NUMWORDS, NUMCHARS, REVNUM) in the field's `\*` number format, digits without one or
|
||||
/// when the format does not cover the count (see [`super::table_formula::number_format_covers`]),
|
||||
/// with the field's capitalization switches.
|
||||
fn count_text(instr: &str, n: usize) -> String {
|
||||
let fmt = wordcraft_layout::fields::format_switch(instr).unwrap_or(NumFormat::Decimal);
|
||||
let fmt = wordcraft_layout::fields::format_switch(instr)
|
||||
.filter(|f| super::table_formula::number_format_covers(*f, n as f64))
|
||||
.unwrap_or(NumFormat::Decimal);
|
||||
wordcraft_layout::fields::field_number(instr, fmt, u32::try_from(n).unwrap_or(u32::MAX))
|
||||
}
|
||||
|
||||
@@ -1647,6 +1650,18 @@ mod tests {
|
||||
assert_eq!((s.doc.core.subject.as_str(), s.doc.core.creator.as_str()), ("Old", "Grace"));
|
||||
}
|
||||
|
||||
/// A count the field's number format does not cover keeps its digits.
|
||||
#[test]
|
||||
fn counts_past_the_number_format_keep_their_digits() {
|
||||
let mut doc = wordcraft_doc::Document::from_text("one two three");
|
||||
doc.core.revision = 1_000_000;
|
||||
let codes = [r"REVNUM \* ROMAN", r"REVNUM \* CardText", r"REVNUM \* alphabetic", r"NUMWORDS \* ROMAN"];
|
||||
let (mut s, hdr) = header_fields_session(doc, &codes);
|
||||
s.run("references.updateFields", &json!({})).unwrap();
|
||||
let got: Vec<String> = story_fields(&s, StoryRef::Part(hdr)).into_iter().map(|(_, r)| r).collect();
|
||||
assert_eq!(got, ["1000000", "1000000", "1000000", "III"]);
|
||||
}
|
||||
|
||||
/// #1706: `all: true` (printing) updates the whole document even with the caret in a header.
|
||||
#[test]
|
||||
fn update_fields_all_covers_every_story() {
|
||||
|
||||
@@ -116,16 +116,23 @@ fn format_switches(switches: &str, value: f64, text: String) -> String {
|
||||
use wordcraft_doc::section::NumFormat;
|
||||
let unquoted = switches.split('"').step_by(2).collect::<Vec<_>>().join(" ");
|
||||
let fmt = wordcraft_layout::fields::format_switch(&unquoted).filter(|f| *f != NumFormat::Decimal);
|
||||
let covers = |fmt: NumFormat| match fmt {
|
||||
match fmt {
|
||||
Some(fmt) if number_format_covers(fmt, value) => wordcraft_layout::fields::field_number(switches, fmt, value as u32),
|
||||
_ => wordcraft_layout::fields::apply_case_switch(switches, text),
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the `\*` number format `fmt` writes `value`: a whole number up to 999,999 for CardText
|
||||
/// and OrdText, 1 to 50,000 for roman, 1 to 780 for alphabetic, and 0 to `u32::MAX` otherwise.
|
||||
pub(crate) fn number_format_covers(fmt: wordcraft_doc::section::NumFormat, value: f64) -> bool {
|
||||
use wordcraft_doc::section::NumFormat;
|
||||
let range = match fmt {
|
||||
NumFormat::CardinalText | NumFormat::OrdinalText => 0.0..=999_999.0,
|
||||
NumFormat::LowerRoman | NumFormat::UpperRoman => 1.0..=50_000.0,
|
||||
NumFormat::LowerLetter | NumFormat::UpperLetter => 1.0..=780.0,
|
||||
_ => 0.0..=f64::from(u32::MAX),
|
||||
};
|
||||
match fmt {
|
||||
Some(fmt) if value.fract() == 0.0 && covers(fmt).contains(&value) => wordcraft_layout::fields::field_number(switches, fmt, value as u32),
|
||||
_ => wordcraft_layout::fields::apply_case_switch(switches, text),
|
||||
}
|
||||
value.fract() == 0.0 && range.contains(&value)
|
||||
}
|
||||
|
||||
/// Splits a field's switches (`\#` and `\*`) off its formula: `=SUM(ABOVE) \# "0.00"` gives the
|
||||
|
||||
Reference in New Issue
Block a user