mirror of
https://github.com/storytold/wordcraft.git
synced 2026-11-08 03:32:19 +00:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
134 lines
6.3 KiB
Rust
134 lines
6.3 KiB
Rust
use serde::{Deserialize, Serialize};
|
||
|
||
/// Editing preferences that persist between runs (the front end saves and restores them).
|
||
/// File › Options sets most of them (`file.options`).
|
||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||
#[serde(default, rename_all = "camelCase")]
|
||
pub struct Prefs {
|
||
/// Word Count includes text boxes, footnotes and endnotes (Word's default).
|
||
pub count_notes: bool,
|
||
/// Track Changes Options: what markup shows and how revisions are drawn (per user, as in
|
||
/// Word).
|
||
pub markup: wordcraft_layout::display::MarkupOptions,
|
||
/// File › Print / Export: Print Markup. PDFs, prints and page images show comments in
|
||
/// balloons beside each page and tracked changes as marked up; HTML, Markdown and text
|
||
/// copies end with the comments (`file.printMarkup`).
|
||
pub print_markup: bool,
|
||
/// Language › Detect language automatically (per user, as in Word).
|
||
pub detect_language: bool,
|
||
/// Set Proofing Language › Set As Default: overrides the interface language for future
|
||
/// blank documents and plain text. Older preferences keep following the interface.
|
||
#[serde(deserialize_with = "lenient_default_language")]
|
||
pub default_language: Option<String>,
|
||
/// Typing over a selection replaces it; off, the typed text goes in front of it.
|
||
pub typing_replaces_selection: bool,
|
||
/// The Insert key switches overtype on and off.
|
||
pub insert_key_overtype: bool,
|
||
/// Overtype: typed characters replace the ones after the caret.
|
||
pub overtype: bool,
|
||
/// The unit rulers and dialogs show lengths in, when the user chose one (File › Options ›
|
||
/// Advanced › Measurement units); `None` follows the region ([`Session::units`]). Saved under
|
||
/// a new key; an older `units` value other than inches (the old default) carries over on load.
|
||
#[serde(rename = "measurementUnits")]
|
||
pub units: Option<wordcraft_geom::Unit>,
|
||
/// The region the user chose for new documents, units and the decimal separator (a locale
|
||
/// tag like `pl-PL`, File › Options › Advanced › Region); `None` follows the system.
|
||
pub region: Option<String>,
|
||
/// A folder searched for Hunspell dictionaries before the system locations (File › Options ›
|
||
/// Language, #1063): an app started from Finder or the Dock doesn't see
|
||
/// `WORDCRAFT_DICTIONARIES`. `None` searches the system locations only.
|
||
pub dictionaries_folder: Option<String>,
|
||
/// The user templates folder File › New lists personal templates from and Save as Word
|
||
/// Template starts in (File › Options › Advanced › File locations, #2852). `None`: the app's
|
||
/// own `Templates` folder in its settings folder.
|
||
pub user_templates_folder: Option<String>,
|
||
/// Formatting marks shown even while Show/Hide ¶ is off.
|
||
pub marks: wordcraft_layout::display::FormattingMarks,
|
||
/// Mark grammar errors as you type (with Check spelling as you type on).
|
||
pub mark_grammar: bool,
|
||
/// Check spelling as you type (File › Options › Proofing). The live value is
|
||
/// `ViewState::proofing`; this is the copy that is saved and restored (#1792).
|
||
pub check_spelling: bool,
|
||
/// Read Mode's Page Color. The live value is `ViewState::read_page_color`.
|
||
#[serde(deserialize_with = "lenient_read_page_color")]
|
||
pub read_page_color: crate::cmd::view::ReadPageColor,
|
||
pub ignore_uppercase: bool,
|
||
pub ignore_numbers: bool,
|
||
pub ignore_internet: bool,
|
||
/// AutoCorrect Options: replacements, capitalization and AutoFormat As You Type (per user, as
|
||
/// in Word). A damaged saved value reads as the defaults.
|
||
#[serde(deserialize_with = "crate::cmd::tools::lenient_autocorrect")]
|
||
pub autocorrect: crate::cmd::tools::AutoCorrectPrefs,
|
||
}
|
||
|
||
impl Default for Prefs {
|
||
fn default() -> Self {
|
||
Prefs {
|
||
count_notes: true,
|
||
markup: Default::default(),
|
||
print_markup: false,
|
||
typing_replaces_selection: true,
|
||
insert_key_overtype: false,
|
||
overtype: false,
|
||
units: Default::default(),
|
||
region: None,
|
||
dictionaries_folder: None,
|
||
user_templates_folder: None,
|
||
marks: Default::default(),
|
||
mark_grammar: true,
|
||
check_spelling: true,
|
||
read_page_color: Default::default(),
|
||
ignore_uppercase: true,
|
||
ignore_numbers: true,
|
||
ignore_internet: true,
|
||
detect_language: true,
|
||
default_language: None,
|
||
autocorrect: Default::default(),
|
||
}
|
||
}
|
||
}
|
||
|
||
impl Prefs {
|
||
/// What the spelling check skips.
|
||
pub fn spelling(&self) -> wordcraft_proof::Options {
|
||
wordcraft_proof::Options {
|
||
ignore_uppercase: self.ignore_uppercase,
|
||
ignore_numbers: self.ignore_numbers,
|
||
ignore_internet: self.ignore_internet,
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Ignore malformed saved language tags without discarding the other preferences.
|
||
fn lenient_default_language<'de, D: serde::Deserializer<'de>>(d: D) -> Result<Option<String>, D::Error> {
|
||
let value = serde_json::Value::deserialize(d)?;
|
||
Ok(value.as_str().and_then(wordcraft_proof::lang::normalize_tag))
|
||
}
|
||
|
||
/// Ignore an invalid saved Page Color without discarding other preferences.
|
||
fn lenient_read_page_color<'de, D: serde::Deserializer<'de>>(d: D) -> Result<crate::cmd::view::ReadPageColor, D::Error> {
|
||
let value = serde_json::Value::deserialize(d)?;
|
||
Ok(serde_json::from_value(value).unwrap_or_default())
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::Prefs;
|
||
use crate::cmd::view::ReadPageColor;
|
||
|
||
#[test]
|
||
fn read_page_color_loads_from_old_and_damaged_prefs() {
|
||
let old: Prefs = serde_json::from_str(r#"{"checkSpelling":false}"#).unwrap();
|
||
assert_eq!(old.read_page_color, ReadPageColor::None);
|
||
assert!(!old.check_spelling);
|
||
for bad in [r#"{"readPageColor":"unknown","checkSpelling":false}"#, r#"{"readPageColor":42,"checkSpelling":false}"#] {
|
||
let prefs: Prefs = serde_json::from_str(bad).unwrap();
|
||
assert_eq!(prefs.read_page_color, ReadPageColor::None);
|
||
assert!(!prefs.check_spelling);
|
||
}
|
||
let saved: Prefs = serde_json::from_str(r#"{"readPageColor":"sepia"}"#).unwrap();
|
||
assert_eq!(saved.read_page_color, ReadPageColor::Sepia);
|
||
assert_eq!(serde_json::to_value(saved).unwrap()["readPageColor"], "sepia");
|
||
}
|
||
}
|