mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-27 11:57:36 -06:00
Fields: several capitalization switches apply in the order they appear
A field with \* Lower \* Caps applied only \* Lower, so a title of WEEKLY REPORT showed as weekly report. Every capitalization switch in a field code now applies in turn, and the example shows Weekly Report.
This commit is contained in:
@@ -1145,14 +1145,14 @@ fn new_property_value(instr: &str) -> Option<String> {
|
||||
}
|
||||
|
||||
/// A count (NUMWORDS, NUMCHARS, REVNUM) in the field's `\*` number format, digits without one,
|
||||
/// with the field's capitalization switch.
|
||||
/// 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);
|
||||
wordcraft_layout::fields::field_number(instr, fmt, u32::try_from(n).unwrap_or(u32::MAX))
|
||||
}
|
||||
|
||||
/// A field's computed text with its capitalization switch (`\* Upper`, `\* Lower`, `\* Caps`,
|
||||
/// `\* FirstCap`) applied.
|
||||
/// A field's computed text with its capitalization switches (`\* Upper`, `\* Lower`, `\* Caps`,
|
||||
/// `\* FirstCap`) applied in order.
|
||||
fn text_result(instr: &str, text: String) -> String {
|
||||
wordcraft_layout::fields::apply_case_switch(instr, text)
|
||||
}
|
||||
|
||||
@@ -109,8 +109,8 @@ pub fn evaluate_field_with(
|
||||
/// with the `\#` picture, or in the cell's language when there is no picture. A number format such
|
||||
/// as `\* CardText`, `\* OrdText` or `\* roman` writes a whole number the format covers (up to
|
||||
/// 999,999 for CardText and OrdText, 1 to 50,000 for roman, 1 to 780 for alphabetic), in lowercase
|
||||
/// for CardText and OrdText. Any other result keeps its digits. A capitalization switch
|
||||
/// (`\* Upper`, `\* Lower`, `\* Caps`, `\* FirstCap`) then applies to the text. Other `\*` switches
|
||||
/// for CardText and OrdText. Any other result keeps its digits. The capitalization switches
|
||||
/// (`\* Upper`, `\* Lower`, `\* Caps`, `\* FirstCap`) then apply to the text in order. Other `\*` switches
|
||||
/// leave the text as it is. Quoted text, such as a `\#` picture, is not a switch.
|
||||
fn format_switches(switches: &str, value: f64, text: String) -> String {
|
||||
use wordcraft_doc::section::NumFormat;
|
||||
|
||||
+29
-11
@@ -162,10 +162,12 @@ enum CaseSwitch {
|
||||
FirstCap,
|
||||
}
|
||||
|
||||
/// The first capitalization switch in a field code. Quoted text in the code is not a switch.
|
||||
fn case_switch(instr: &str) -> Option<CaseSwitch> {
|
||||
/// The capitalization switches in a field code, in the order they appear. Quoted text in the code
|
||||
/// is not a switch.
|
||||
fn case_switches(instr: &str) -> Vec<CaseSwitch> {
|
||||
let mut chars = instr.chars().peekable();
|
||||
let mut quoted = false;
|
||||
let mut cases = Vec::new();
|
||||
while let Some(c) = chars.next() {
|
||||
match c {
|
||||
'\\' if quoted => {
|
||||
@@ -186,21 +188,26 @@ fn case_switch(instr: &str) -> Option<CaseSwitch> {
|
||||
"firstcap" => CaseSwitch::FirstCap,
|
||||
_ => continue,
|
||||
};
|
||||
return Some(case);
|
||||
cases.push(case);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
None
|
||||
cases
|
||||
}
|
||||
|
||||
/// `text` with the field's capitalization switch applied. `\* Upper` capitalizes every letter,
|
||||
/// `\* Lower` makes every letter lowercase, `\* Caps` capitalizes the first letter of each word,
|
||||
/// and `\* FirstCap` capitalizes the first letter of the first word. A word's first letter is its
|
||||
/// first letter or digit, after any leading quote, bracket or other punctuation. Without a switch,
|
||||
/// the function returns `text` unchanged.
|
||||
/// `text` with the field's capitalization switches applied in the order they appear, so
|
||||
/// `\* Lower \* Caps` shows "WEEKLY REPORT" as "Weekly Report". `\* Upper` capitalizes every
|
||||
/// letter, `\* Lower` makes every letter lowercase, `\* Caps` capitalizes the first letter of each
|
||||
/// word, and `\* FirstCap` capitalizes the first letter of the first word. A word's first letter is
|
||||
/// its first letter or digit, after any leading quote, bracket or other punctuation. Without a
|
||||
/// switch, the function returns `text` unchanged.
|
||||
pub fn apply_case_switch(instr: &str, text: String) -> String {
|
||||
let Some(case) = case_switch(instr) else { return text };
|
||||
case_switches(instr).into_iter().fold(text, apply_case)
|
||||
}
|
||||
|
||||
/// `text` with one capitalization switch applied (see [`apply_case_switch`]).
|
||||
fn apply_case(text: String, case: CaseSwitch) -> String {
|
||||
match case {
|
||||
CaseSwitch::Upper => text.to_uppercase(),
|
||||
CaseSwitch::Lower => text.to_lowercase(),
|
||||
@@ -229,7 +236,7 @@ pub fn apply_case_switch(instr: &str, text: String) -> String {
|
||||
}
|
||||
|
||||
/// Formats `n` in `fmt` as a field shows it. Cardinal and ordinal text is lowercase
|
||||
/// (`\* CardText` shows "twenty-one"), and the field's capitalization switch applies after that
|
||||
/// (`\* CardText` shows "twenty-one"), and the field's capitalization switches apply after that
|
||||
/// (`\* CardText \* Caps` shows "Twenty-one").
|
||||
pub fn field_number(instr: &str, fmt: NumFormat, n: u32) -> String {
|
||||
let text = match fmt {
|
||||
@@ -404,6 +411,17 @@ mod tests {
|
||||
assert_eq!(field_text(r"REF mark \* Upper", "stored", &ctx).0, "stored", "a stored result shows as it is");
|
||||
}
|
||||
|
||||
/// Several capitalization switches apply in the order they appear.
|
||||
#[test]
|
||||
fn capitalization_switches_apply_in_order() {
|
||||
let ctx = FieldCtx { title: "WEEKLY REPORT".into(), ..Default::default() };
|
||||
let text = |instr: &str| field_text(instr, "", &ctx).0;
|
||||
assert_eq!(text(r"TITLE \* Lower \* Caps"), "Weekly Report");
|
||||
assert_eq!(text(r"TITLE \* Lower \* FirstCap"), "Weekly report");
|
||||
assert_eq!(text(r"TITLE \* Caps \* Lower"), "weekly report");
|
||||
assert_eq!(text(r"TITLE \* Lower \* MERGEFORMAT \* Upper"), "WEEKLY REPORT");
|
||||
}
|
||||
|
||||
/// #1765: ASK and SET only assign text to a bookmark; they show nothing, whatever result is stored.
|
||||
#[test]
|
||||
fn ask_and_set_show_nothing() {
|
||||
|
||||
Reference in New Issue
Block a user