Added endpoint selector, reworked config.toml structure, added movent features for text input
This commit is contained in:
@@ -3,9 +3,21 @@ use anyhow::Result;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct Endpoint {
|
||||
pub name: String,
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct Config {
|
||||
pub server_url: String,
|
||||
// Legacy field — present only in old configs; migrated to endpoints on load.
|
||||
#[serde(default, skip_serializing)]
|
||||
server_url: Option<String>,
|
||||
#[serde(default)]
|
||||
pub endpoints: Vec<Endpoint>,
|
||||
#[serde(default)]
|
||||
pub active_endpoint: String,
|
||||
pub timeout_sec: u64,
|
||||
#[serde(default = "default_theme")]
|
||||
pub theme: Theme,
|
||||
@@ -30,7 +42,6 @@ fn default_theme() -> Theme {
|
||||
}
|
||||
|
||||
pub fn config_path() -> PathBuf {
|
||||
// Respect XDG_CONFIG_HOME; fall back to ~/.config on all platforms.
|
||||
let base = std::env::var("XDG_CONFIG_HOME")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| {
|
||||
@@ -42,41 +53,85 @@ pub fn config_path() -> PathBuf {
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Returns true when a config file already exists.
|
||||
pub fn exists() -> bool {
|
||||
config_path().exists()
|
||||
}
|
||||
|
||||
/// Load config from disk. Panics-safe: returns error if file is missing or malformed.
|
||||
pub fn active_url(&self) -> &str {
|
||||
&self.active_endpoint
|
||||
}
|
||||
|
||||
pub fn load() -> Result<Self> {
|
||||
let path = config_path();
|
||||
let content = fs::read_to_string(&path)?;
|
||||
Ok(toml::from_str(&content)?)
|
||||
let mut cfg: Config = toml::from_str(&content)?;
|
||||
// Migrate old single server_url format to endpoints list.
|
||||
if cfg.endpoints.is_empty() {
|
||||
if let Some(url) = cfg.server_url.take() {
|
||||
cfg.active_endpoint = url.clone();
|
||||
cfg.endpoints.push(Endpoint {
|
||||
name: "Default".to_string(),
|
||||
url,
|
||||
});
|
||||
}
|
||||
}
|
||||
if cfg.active_endpoint.is_empty() {
|
||||
if let Some(ep) = cfg.endpoints.first() {
|
||||
cfg.active_endpoint = ep.url.clone();
|
||||
}
|
||||
}
|
||||
Ok(cfg)
|
||||
}
|
||||
|
||||
/// Create and persist a new config with the given server URL.
|
||||
pub fn create_with_url(server_url: &str) -> Result<Self> {
|
||||
pub fn create_with_endpoint(url: &str, name: &str) -> Result<Self> {
|
||||
let path = config_path();
|
||||
let config = Config {
|
||||
server_url: server_url.to_string(),
|
||||
server_url: None,
|
||||
endpoints: vec![Endpoint {
|
||||
name: name.to_string(),
|
||||
url: url.to_string(),
|
||||
}],
|
||||
active_endpoint: url.to_string(),
|
||||
timeout_sec: 10,
|
||||
theme: default_theme(),
|
||||
update_api: Some("https://git.vainend.com/api/v1/repos/admin/ostiary".to_string()),
|
||||
};
|
||||
let contents = format!(
|
||||
r#"server_url = "{}"
|
||||
timeout_sec = {}
|
||||
update_api = "https://git.vainend.com/api/v1/repos/admin/ostiary"
|
||||
|
||||
[theme]
|
||||
selected_bg = "{}"
|
||||
"#,
|
||||
config.server_url,
|
||||
config.timeout_sec,
|
||||
config.theme.selected_bg,
|
||||
);
|
||||
fs::create_dir_all(path.parent().unwrap())?;
|
||||
fs::write(&path, contents)?;
|
||||
fs::write(&path, config.to_toml())?;
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn save(&self) -> Result<()> {
|
||||
let path = config_path();
|
||||
fs::create_dir_all(path.parent().unwrap())?;
|
||||
fs::write(&path, self.to_toml())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_toml(&self) -> String {
|
||||
let mut s = format!(
|
||||
"active_endpoint = \"{}\"\ntimeout_sec = {}\n",
|
||||
escape_toml(&self.active_endpoint),
|
||||
self.timeout_sec,
|
||||
);
|
||||
if let Some(api) = &self.update_api {
|
||||
s.push_str(&format!("update_api = \"{}\"\n", escape_toml(api)));
|
||||
}
|
||||
s.push_str(&format!(
|
||||
"\n[theme]\nselected_bg = \"{}\"\n",
|
||||
escape_toml(&self.theme.selected_bg),
|
||||
));
|
||||
for ep in &self.endpoints {
|
||||
s.push_str(&format!(
|
||||
"\n[[endpoints]]\nname = \"{}\"\nurl = \"{}\"\n",
|
||||
escape_toml(&ep.name),
|
||||
escape_toml(&ep.url),
|
||||
));
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
fn escape_toml(s: &str) -> String {
|
||||
s.replace('\\', "\\\\").replace('"', "\\\"")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user