-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
117 additions
and
146 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,149 +1,43 @@ | ||
mod keymap; | ||
mod main_config; | ||
mod utils; | ||
|
||
use std::{collections::HashMap, path::PathBuf, sync::OnceLock}; | ||
use std::{collections::HashMap, path::PathBuf}; | ||
|
||
use anyhow::{bail, Context, Result}; | ||
use anyhow::Result; | ||
use crossterm::event::{KeyCode, KeyModifiers}; | ||
use ratatui::style::Color; | ||
use rm_shared::action::Action; | ||
use serde::{Deserialize, Serialize}; | ||
use toml::Table; | ||
use xdg::BaseDirectories; | ||
use keymap::KeymapConfig; | ||
use main_config::MainConfig; | ||
|
||
use crate::utils::put_config; | ||
use keymap::Keymap; | ||
use rm_shared::action::Action; | ||
|
||
#[derive(Serialize, Deserialize)] | ||
pub struct Config { | ||
pub connection: Connection, | ||
pub general: General, | ||
#[serde(skip)] | ||
pub keymap: Option<HashMap<(KeyCode, KeyModifiers), Action>>, | ||
} | ||
|
||
#[derive(Debug, Serialize, Deserialize)] | ||
pub struct General { | ||
#[serde(default)] | ||
pub auto_hide: bool, | ||
#[serde(default = "default_accent_color")] | ||
pub accent_color: Color, | ||
#[serde(default = "default_beginner_mode")] | ||
pub beginner_mode: bool, | ||
} | ||
|
||
fn default_accent_color() -> Color { | ||
Color::LightMagenta | ||
} | ||
|
||
fn default_beginner_mode() -> bool { | ||
true | ||
pub general: main_config::General, | ||
pub connection: main_config::Connection, | ||
pub keymap: HashMap<(KeyCode, KeyModifiers), Action>, | ||
pub directories: Directories, | ||
} | ||
|
||
#[derive(Debug, Serialize, Deserialize)] | ||
pub struct Connection { | ||
pub username: Option<String>, | ||
pub password: Option<String>, | ||
pub url: String, | ||
} | ||
|
||
const DEFAULT_CONFIG: &str = include_str!("../defaults/config.toml"); | ||
static XDG_DIRS: OnceLock<BaseDirectories> = OnceLock::new(); | ||
static CONFIG_PATH: OnceLock<PathBuf> = OnceLock::new(); | ||
pub const MAIN_CONFIG_FILENAME: &str = "config.toml"; | ||
pub const KEYMAP_CONFIG_FILENAME: &str = "keymap.toml"; | ||
|
||
pub fn xdg_dirs() -> &'static BaseDirectories { | ||
XDG_DIRS.get_or_init(|| xdg::BaseDirectories::with_prefix("rustmission").unwrap()) | ||
} | ||
|
||
pub fn get_config_path(filename: &str) -> &'static PathBuf { | ||
CONFIG_PATH.get_or_init(|| xdg_dirs().place_config_file(filename).unwrap()) | ||
pub struct Directories { | ||
pub main_path: &'static PathBuf, | ||
pub keymap_path: &'static PathBuf, | ||
} | ||
|
||
impl Config { | ||
pub fn init() -> Result<Self> { | ||
let Ok(table) = utils::fetch_config_table(MAIN_CONFIG_FILENAME) else { | ||
put_config(DEFAULT_CONFIG, MAIN_CONFIG_FILENAME)?; | ||
// TODO: check if the user really changed the config. | ||
println!( | ||
"Update {:?} and start rustmission again", | ||
get_config_path(MAIN_CONFIG_FILENAME) | ||
); | ||
std::process::exit(0); | ||
}; | ||
let main_config = MainConfig::init()?; | ||
let keybindings = KeymapConfig::init()?; | ||
|
||
Self::table_config_verify(&table)?; | ||
|
||
let mut config = Self::table_to_config(&table)?; | ||
config.keymap = Some(Keymap::init().unwrap().to_hashmap()); | ||
Ok(config) | ||
} | ||
|
||
fn table_to_config(table: &Table) -> Result<Self> { | ||
let config_string = table.to_string(); | ||
let config: Self = toml::from_str(&config_string)?; | ||
Ok(config) | ||
} | ||
|
||
fn table_config_verify(table: &Table) -> Result<()> { | ||
let Some(connection_table) = table.get("connection").unwrap().as_table() else { | ||
bail!("expected connection table") | ||
let directories = Directories { | ||
main_path: MainConfig::path(), | ||
keymap_path: KeymapConfig::path(), | ||
}; | ||
|
||
let url = connection_table | ||
.get("url") | ||
.and_then(|url| url.as_str()) | ||
.with_context(|| { | ||
format!( | ||
"no url given in: {}", | ||
get_config_path(MAIN_CONFIG_FILENAME).to_str().unwrap() | ||
) | ||
})?; | ||
|
||
url::Url::parse(url).with_context(|| { | ||
format!( | ||
"invalid url '{url}' in {}", | ||
get_config_path(MAIN_CONFIG_FILENAME).to_str().unwrap() | ||
) | ||
})?; | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
fn invalid_config() -> Table { | ||
toml::toml! { | ||
[connection] | ||
username = "username" | ||
password = "password" | ||
auto_hide = "dfgoij" | ||
url = "bad_url" | ||
} | ||
} | ||
|
||
fn valid_config() -> Table { | ||
toml::toml! { | ||
[connection] | ||
username = "username" | ||
password = "password" | ||
url = "http://192.168.1.1/transmission/rpc" | ||
} | ||
} | ||
|
||
#[test] | ||
fn validates_properly() { | ||
let valid_config = valid_config(); | ||
assert!(Config::table_config_verify(&valid_config).is_ok()); | ||
} | ||
|
||
#[test] | ||
fn invalidates_properly() { | ||
let invalid_config = invalid_config(); | ||
assert!(Config::table_config_verify(&invalid_config).is_err()); | ||
Ok(Self { | ||
general: main_config.general, | ||
connection: main_config.connection, | ||
keymap: keybindings.to_hashmap(), | ||
directories, | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
use std::{path::PathBuf, sync::OnceLock}; | ||
|
||
use anyhow::Result; | ||
use ratatui::style::Color; | ||
use serde::{Deserialize, Serialize}; | ||
use url::Url; | ||
|
||
use crate::utils::{self, put_config}; | ||
|
||
#[derive(Serialize, Deserialize)] | ||
pub struct MainConfig { | ||
pub general: General, | ||
pub connection: Connection, | ||
} | ||
|
||
#[derive(Debug, Serialize, Deserialize)] | ||
pub struct General { | ||
#[serde(default)] | ||
pub auto_hide: bool, | ||
#[serde(default = "default_accent_color")] | ||
pub accent_color: Color, | ||
#[serde(default = "default_beginner_mode")] | ||
pub beginner_mode: bool, | ||
} | ||
|
||
fn default_accent_color() -> Color { | ||
Color::LightMagenta | ||
} | ||
|
||
fn default_beginner_mode() -> bool { | ||
true | ||
} | ||
|
||
#[derive(Debug, Serialize, Deserialize)] | ||
pub struct Connection { | ||
pub username: Option<String>, | ||
pub password: Option<String>, | ||
pub url: Url, | ||
} | ||
|
||
impl MainConfig { | ||
pub(crate) const FILENAME: &'static str = "config.toml"; | ||
const DEFAULT_CONFIG: &'static str = include_str!("../defaults/config.toml"); | ||
|
||
pub(crate) fn init() -> Result<Self> { | ||
let Ok(config) = utils::fetch_config(Self::FILENAME) else { | ||
put_config(Self::DEFAULT_CONFIG, Self::FILENAME)?; | ||
// TODO: check if the user really changed the config. | ||
println!("Update {:?} and start rustmission again", Self::path()); | ||
std::process::exit(0); | ||
}; | ||
|
||
Ok(config) | ||
} | ||
|
||
pub(crate) fn path() -> &'static PathBuf { | ||
static PATH: OnceLock<PathBuf> = OnceLock::new(); | ||
PATH.get_or_init(|| utils::get_config_path(Self::FILENAME)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters