1use crate::Result;
3pub use colors::Colors;
4use directories::ProjectDirs;
5pub use icons::Icons;
6pub use main::Main;
7use mlua::{FromLuaMulti, Lua};
8use std::fs;
9use std::path::{Path, PathBuf};
10
11mod colors;
12mod icons;
13mod main;
14
15pub struct ConfigDir {
17 project_dirs: ProjectDirs,
19}
20
21impl ConfigDir {
22 const QUALIFIER: &str = "";
24 const ORGANIZATION: &str = "";
26 const APPLICATION: &str = env!("CARGO_PKG_NAME");
28
29 pub fn new() -> Result<Self, &'static str> {
31 ProjectDirs::from(Self::QUALIFIER, Self::ORGANIZATION, Self::APPLICATION)
32 .map(|project_dirs| Self { project_dirs })
33 .ok_or("Missing home directory")
34 }
35
36 pub fn create_dir(&self) -> Result {
38 let dir = self.path();
39 fs::create_dir_all(dir)?;
40 Ok(())
41 }
42
43 #[inline]
45 pub fn load_main(&self, lua: &Lua) -> mlua::Result<Option<Main>> {
46 self.load_file(lua)
47 }
48
49 #[inline]
51 pub fn load_icons(&self, lua: &Lua) -> mlua::Result<Option<Icons>> {
52 self.load_file(lua)
53 }
54
55 #[inline]
57 pub fn load_colors(&self, lua: &Lua) -> mlua::Result<Option<Colors>> {
58 self.load_file(lua)
59 }
60
61 fn load_file<T>(&self, lua: &Lua) -> mlua::Result<Option<T>>
63 where
64 T: ConfigFile + FromLuaMulti,
65 {
66 let path = self.path().join(T::FILENAME);
67 path.exists()
68 .then(|| {
69 let chunk = lua.load(path);
70 chunk.call::<T>(())
71 })
72 .transpose()
73 }
74
75 #[inline]
77 pub fn path(&self) -> &Path {
78 self.project_dirs.config_dir()
79 }
80
81 fn file_name<T>(&self) -> PathBuf
83 where
84 T: ConfigFile,
85 {
86 self.path().join(T::FILENAME)
87 }
88
89 #[inline]
91 pub fn main_path(&self) -> PathBuf {
92 self.file_name::<Main>()
93 }
94
95 #[inline]
97 pub fn icons_path(&self) -> PathBuf {
98 self.file_name::<Icons>()
99 }
100
101 #[inline]
103 pub fn colors_path(&self) -> PathBuf {
104 self.file_name::<Colors>()
105 }
106}
107
108pub trait ConfigFile {
110 const FILENAME: &'static str;
112 const DEFAULT_MODULE: &'static str;
114}