1use std::path::PathBuf;
16
17#[derive(Debug, Default, Clone, PartialEq, Eq)]
19pub struct Settings {
20 pub open_in_edit_mode: bool,
22}
23
24const OPEN_IN_EDIT_MODE: &str = "open-in-edit-mode";
25
26impl Settings {
27 pub fn load() -> Self {
31 path()
32 .and_then(|path| std::fs::read_to_string(path).ok())
33 .map_or_else(Self::default, |text| Self::parse(&text))
34 }
35
36 pub fn save(&self) -> std::io::Result<()> {
43 let path = path().ok_or_else(|| {
44 std::io::Error::new(std::io::ErrorKind::NotFound, "no configuration directory")
45 })?;
46 if let Some(directory) = path.parent() {
47 std::fs::create_dir_all(directory)?;
48 }
49 std::fs::write(path, self.to_string())
50 }
51
52 fn parse(text: &str) -> Self {
53 let mut settings = Self::default();
54 for line in text.lines() {
55 let Some((key, value)) = line.split_once('=') else {
56 continue;
57 };
58 if key.trim() == OPEN_IN_EDIT_MODE {
59 settings.open_in_edit_mode = value.trim() == "true";
60 }
61 }
62 settings
63 }
64}
65
66impl std::fmt::Display for Settings {
67 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68 writeln!(f, "{OPEN_IN_EDIT_MODE} = {}", self.open_in_edit_mode)
69 }
70}
71
72pub fn path() -> Option<PathBuf> {
80 let base = if cfg!(target_os = "windows") {
81 std::env::var_os("APPDATA").map(PathBuf::from)?
82 } else if cfg!(target_os = "macos") {
83 std::env::home_dir()?.join("Library/Application Support")
84 } else {
85 match std::env::var_os("XDG_CONFIG_HOME") {
86 Some(config) if !config.is_empty() => PathBuf::from(config),
87 _ => std::env::home_dir()?.join(".config"),
88 }
89 };
90 Some(base.join("odox").join("settings.toml"))
91}
92
93#[cfg(test)]
94mod tests {
95 use super::Settings;
96
97 #[test]
98 fn what_is_written_is_what_is_read() {
99 let on = Settings {
100 open_in_edit_mode: true,
101 };
102 assert_eq!(Settings::parse(&on.to_string()), on);
103 assert_eq!(
104 Settings::parse(&Settings::default().to_string()),
105 Settings::default()
106 );
107 }
108
109 #[test]
110 fn a_file_from_a_later_version_is_read_for_what_this_one_knows() {
111 let text = "# a comment\nopen-in-edit-mode = true\nsomething-newer = 3\n\n";
112 assert!(Settings::parse(text).open_in_edit_mode);
113 assert!(!Settings::parse("").open_in_edit_mode);
114 assert!(!Settings::parse("open-in-edit-mode = yes").open_in_edit_mode);
115 }
116}