1use std::io::Write;
2use std::path::{Path, PathBuf};
3use std::{env, fs, io};
4
5use clap::Parser;
6use color_eyre::Help;
7use directories_next::ProjectDirs;
8
9use crate::errors::LostTheWay;
10use crate::utils::{get_default_copy_cmd, NAME};
11
12#[derive(Parser, Debug)]
13pub enum ConfigCommand {
14 Default {
17 file: Option<PathBuf>,
19 },
20 Get,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct TheWayConfig {
26 pub(crate) theme: String,
28 pub(crate) db_dir: PathBuf,
30 pub(crate) themes_dir: PathBuf,
32 #[serde(default = "get_default_copy_cmd")]
33 pub(crate) copy_cmd: Option<String>,
34 pub(crate) github_access_token: Option<String>,
36 pub gist_id: Option<String>,
38}
39
40fn get_project_dir() -> color_eyre::Result<ProjectDirs> {
42 Ok(ProjectDirs::from("rs", "", NAME).ok_or(LostTheWay::Homeless)?)
43}
44
45impl Default for TheWayConfig {
46 fn default() -> Self {
47 let (db_dir, themes_dir, theme, copy_cmd) = {
48 let dir = get_project_dir().expect("Couldn't get project dir");
49 let data_dir = dir.data_dir();
50 if !data_dir.exists() {
51 fs::create_dir_all(data_dir).expect("Couldn't create data dir");
52 }
53 (
54 data_dir.join("the_way_db"),
55 data_dir.join("themes"),
56 String::from("base16-ocean.dark"),
57 get_default_copy_cmd(),
58 )
59 };
60 let config = Self {
61 theme,
62 db_dir,
63 themes_dir,
64 copy_cmd,
65 github_access_token: None,
66 gist_id: None,
67 };
68 config.make_dirs().unwrap();
69 config
70 }
71}
72
73impl TheWayConfig {
74 pub(crate) fn default_config(file: Option<&Path>) -> color_eyre::Result<()> {
76 let writer: Box<dyn Write> = match file {
77 Some(file) => Box::new(fs::File::create(file)?),
78 None => Box::new(io::stdout()),
79 };
80 let mut buffered = io::BufWriter::new(writer);
81 let copy_cmd = get_default_copy_cmd().ok_or(LostTheWay::NoDefaultCopyCommand)?;
82 let contents =
83 format!(
84 "theme = 'base16-ocean.dark'\ndb_dir = 'the_way_db'\nthemes_dir = 'the_way_themes'\ncopy_cmd = '{}'",
85 copy_cmd
86 );
87 write!(&mut buffered, "{contents}")?;
88 Ok(())
89 }
90
91 pub(crate) fn print_config_location() -> color_eyre::Result<()> {
93 println!("{}", Self::get()?.to_string_lossy());
94 Ok(())
95 }
96
97 fn make_dirs(&self) -> color_eyre::Result<()> {
99 if !self.db_dir.exists() {
100 fs::create_dir_all(&self.db_dir).map_err(|e: io::Error| LostTheWay::ConfigError {
101 message: format!("Couldn't create db dir {:?}, {e}", self.db_dir),
102 })?;
103 }
104 if !self.themes_dir.exists() {
105 fs::create_dir_all(&self.themes_dir).map_err(|e: io::Error| {
106 LostTheWay::ConfigError {
107 message: format!("Couldn't create themes dir {:?}, {e}", self.themes_dir),
108 }
109 })?;
110 }
111 Ok(())
112 }
113
114 fn get_default_config_file() -> color_eyre::Result<PathBuf> {
116 Ok(confy::get_configuration_file_path(NAME, None)?)
117 }
118
119 fn get() -> color_eyre::Result<PathBuf> {
121 let config_file = env::var("THE_WAY_CONFIG").ok();
122 match config_file {
123 Some(file) => {
124 let path = Path::new(&file).to_owned();
125 if path.exists() {
126 Ok(path)
127 } else {
128 let error: color_eyre::Result<PathBuf> = Err(LostTheWay::ConfigError {
129 message: format!("No such file {file}"),
130 }
131 .into());
132 error.suggestion(format!(
133 "Use `the-way config default {file}` to write out the default configuration",
134 ))
135 }
136 }
137 None => Self::get_default_config_file(),
138 }
139 }
140
141 pub fn load() -> color_eyre::Result<Self> {
143 let config_file = env::var("THE_WAY_CONFIG").ok();
145 match config_file {
146 Some(file) => {
147 let path = Path::new(&file).to_owned();
148 if path.exists() {
149 let config: Self = confy::load_path(Path::new(&file))?;
150 config.make_dirs()?;
151 Ok(config)
152 } else {
153 let error: color_eyre::Result<Self> = Err(LostTheWay::ConfigError {
154 message: format!("No such file {file}"),
155 }
156 .into());
157 error.suggestion(format!(
158 "Use `the-way config default {file}` to write out the default configuration",
159 ))
160 }
161 }
162 None => {
163 Ok(confy::load(NAME, None).suggestion(LostTheWay::ConfigError {
164 message: "Couldn't load from the default config location, maybe you don't have access? \
165 Try running `the-way config default config_file.toml`, modify the generated file if necessary, \
166 then `export THE_WAY_CONFIG=<full/path/to/config_file.toml>`".into()
167 })?)
168 },
169 }
170 }
171
172 pub(crate) fn store(&self) -> color_eyre::Result<()> {
174 let config_file = env::var("THE_WAY_CONFIG").ok();
176 match config_file {
177 Some(file) => confy::store_path(Path::new(&file), (*self).clone()).suggestion(LostTheWay::ConfigError {
178 message: "The current config_file location does not seem to have write access. \
179 Use `export THE_WAY_CONFIG=<full/path/to/config_file.toml>` to set a new location".into()
180 })?,
181 None => confy::store(NAME, None, (*self).clone()).suggestion(LostTheWay::ConfigError {
182 message: "The current config_file location does not seem to have write access. \
183 Use `export THE_WAY_CONFIG=<full/path/to/config_file.toml>` to set a new location".into()
184 })?,
185 };
186 Ok(())
187 }
188}