Skip to content

Commit 1e5d6fd

Browse files
committed
add: config rw
1 parent db047ae commit 1e5d6fd

11 files changed

Lines changed: 364 additions & 32 deletions

File tree

Cargo.lock

Lines changed: 58 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members = ["xtask", "asteride", "pages", "elements"]
2+
members = ["xtask", "asteride", "pages", "elements", "config"]
33

44
default-members = ["asteride"]
55
resolver = "3"
@@ -14,19 +14,32 @@ authors = [
1414
]
1515

1616
[workspace.dependencies]
17+
pico-args = "0.5.0"
18+
tracing = "0.1.44"
1719
image = "0.25.10"
20+
toml = "1.1.2"
1821
rfd = "0.17.2"
1922

20-
[workspace.dependencies.lucide-icons]
21-
version = "1.24.0"
22-
features = ["iced"]
23-
2423
[workspace.dependencies.elements]
2524
path = "./elements"
2625

26+
[workspace.dependencies.config]
27+
path = "./config"
28+
2729
[workspace.dependencies.pages]
2830
path = "./pages"
2931

32+
[workspace.dependencies.serde]
33+
version = "1.0.228"
34+
features = ["derive"]
35+
36+
[workspace.dependencies.lucide-icons]
37+
version = "1.24.0"
38+
features = ["iced"]
39+
40+
[workspace.dependencies.logging_subscriber]
41+
git = "https://gitlab.com/invra/logging_subscriber"
42+
3043
[workspace.dependencies.tokio]
3144
version = "1.52.3"
3245
features = ["rt", "macros", "rt-multi-thread", "sync"]

asteride/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,9 @@ iced.workspace = true
1111
tokio.workspace = true
1212
image.workspace = true
1313
pages.workspace = true
14+
config.workspace = true
15+
tracing.workspace = true
1416
elements.workspace = true
17+
pico-args.workspace = true
1518
lucide-icons.workspace = true
19+
logging_subscriber.workspace = true

asteride/src/main.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
mod app_icon;
22
mod sidebar;
3+
use std::path::PathBuf;
4+
35
use elements::bottom_area;
46
use iced::{
5-
Element,
6-
Subscription,
7-
Task,
7+
Element, Subscription, Task,
88
theme::Theme,
9-
widget::{
10-
column,
11-
row,
12-
},
9+
widget::{column, row},
1310
window,
1411
};
12+
1513
use lucide_icons::LUCIDE_FONT_BYTES;
1614

1715
struct AsterIDE {
@@ -83,7 +81,36 @@ impl AsterIDE {
8381
}
8482
}
8583

84+
struct Args {
85+
config_path: Option<PathBuf>,
86+
version: bool,
87+
silent: bool,
88+
}
89+
90+
fn parse_args() -> Args {
91+
let mut args = pico_args::Arguments::from_env();
92+
93+
Args {
94+
config_path: args.opt_value_from_str(["-c", "--config"]).unwrap(),
95+
version: args.contains(["-v", "--version"]),
96+
silent: args.contains(["-s", "--silent"]),
97+
}
98+
}
99+
86100
pub fn main() -> iced::Result {
101+
let args = parse_args();
102+
103+
if args.version {
104+
print!("AsterIDE v{}", env!("CARGO_PKG_VERSION"));
105+
return iced::Result::Ok(());
106+
}
107+
108+
if !args.silent {
109+
tracing::subscriber::set_global_default(logging_subscriber::SimpleSubscriber).unwrap();
110+
}
111+
112+
let _config = config::init_ring(args.config_path);
113+
87114
let window_settings = window::Settings {
88115
// TODO: Create own titlebar later
89116
decorations: true,
@@ -97,6 +124,8 @@ pub fn main() -> iced::Result {
97124
..Default::default()
98125
};
99126

127+
tracing::info!("Init iced app");
128+
100129
iced::application(AsterIDE::new, AsterIDE::update, AsterIDE::view)
101130
.subscription(AsterIDE::subscription)
102131
.title("AsterIDE")

config/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "config"
3+
description = "Configuration management"
4+
authors.workspace = true
5+
edition.workspace = true
6+
license.workspace = true
7+
version.workspace = true
8+
9+
[dependencies]
10+
toml.workspace = true
11+
iced.workspace = true
12+
serde.workspace = true

config/src/lib.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
pub mod spec;
2+
mod theme;
3+
use std::{env, path::PathBuf, sync::OnceLock};
4+
5+
/// Configuration ring, holds all configuration that is in a config file.
6+
static INSTANCE: OnceLock<spec::Config> = OnceLock::new();
7+
8+
fn config_home() -> PathBuf {
9+
if cfg!(target_family = "unix") {
10+
std::env::var_os("XDG_CONFIG_HOME")
11+
.map(PathBuf::from)
12+
.unwrap_or_else(|| {
13+
let home_var: PathBuf = env::var("HOME").unwrap().into();
14+
home_var.join(".config")
15+
})
16+
.join("asteride")
17+
} else {
18+
let home_var: PathBuf = env::var("LOCALAPPDATA").unwrap().into();
19+
home_var.join("asteride")
20+
}
21+
}
22+
23+
/// Goes around and initializes vital stuff for config to
24+
/// be read and written
25+
pub fn init_ring(
26+
// used to override a path, e.g -c / --config
27+
override_default_path: Option<PathBuf>,
28+
) {
29+
let maybe_file = override_default_path.unwrap_or_else(config_home);
30+
let config_path = if maybe_file.is_dir() {
31+
maybe_file.join("config.toml")
32+
} else {
33+
maybe_file.to_path_buf()
34+
};
35+
36+
let inner_config = if config_path.is_file() {
37+
let raw = std::fs::read_to_string(&config_path)
38+
.unwrap_or_else(|e| panic!("failed to read config at {config_path:?}: {e}"));
39+
toml::from_str(&raw)
40+
.unwrap_or_else(|e| panic!("failed to parse config at {config_path:?}: {e}"))
41+
} else {
42+
if let Some(parent) = config_path.parent() {
43+
std::fs::create_dir_all(parent).expect("failed to create config directory");
44+
}
45+
46+
let default = spec::InnerConfig::default();
47+
let toml_str =
48+
toml::to_string_pretty(&default).expect("failed to serialize default config");
49+
std::fs::write(&config_path, toml_str).expect("failed to write default config");
50+
default
51+
};
52+
53+
let config: spec::Config = inner_config.into();
54+
55+
INSTANCE.set(config).unwrap();
56+
}
57+
58+
pub fn get() -> &'static spec::Config {
59+
INSTANCE
60+
.get()
61+
.expect("init_ring wasn't called before access")
62+
}

config/src/spec.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use serde::{Deserialize, Serialize};
2+
3+
/// Public surface for the config.
4+
#[derive(Debug, Clone, PartialEq)]
5+
pub struct Config {
6+
pub appearance: Appearance,
7+
}
8+
9+
impl Config {
10+
pub fn new() -> Self {
11+
Self {
12+
appearance: Appearance {
13+
theme: iced::Theme::GruvboxLight,
14+
scale: 1.0,
15+
},
16+
}
17+
}
18+
}
19+
20+
impl Default for Config {
21+
fn default() -> Self {
22+
Self::new()
23+
}
24+
}
25+
26+
/// Fills in any missing fields from `inner` using `Config::default()`.
27+
impl From<InnerConfig> for Config {
28+
fn from(inner: InnerConfig) -> Self {
29+
let defaults = Config::default();
30+
Self {
31+
appearance: inner
32+
.appearance
33+
.map(|a| Appearance {
34+
theme: a
35+
.theme
36+
.map(iced::Theme::from)
37+
.unwrap_or(defaults.appearance.theme.clone()),
38+
scale: a.scale.unwrap_or(defaults.appearance.scale.clone()),
39+
})
40+
.unwrap_or(defaults.appearance.clone()),
41+
}
42+
}
43+
}
44+
45+
/// For writing config back out to disk — only include what differs
46+
/// from defaults if you want a "sparse" file, or just mirror everything.
47+
impl From<&Config> for InnerConfig {
48+
fn from(config: &Config) -> Self {
49+
Self {
50+
appearance: Some(InnerAppearance {
51+
theme: crate::theme::ThemeSetting::try_from(&config.appearance.theme).ok(),
52+
scale: Some(config.appearance.scale),
53+
}),
54+
}
55+
}
56+
}
57+
58+
/// Reader to config file
59+
#[derive(Deserialize, Serialize, Default)]
60+
pub(crate) struct InnerConfig {
61+
appearance: Option<InnerAppearance>,
62+
}
63+
64+
#[derive(Debug, Clone, PartialEq)]
65+
pub struct Appearance {
66+
/// Inner to `iced::Theme` until I feel like adding custom themes
67+
pub theme: iced::Theme,
68+
pub scale: f32,
69+
}
70+
71+
#[derive(Deserialize, Serialize)]
72+
pub(crate) struct InnerAppearance {
73+
theme: Option<crate::theme::ThemeSetting>,
74+
scale: Option<f32>,
75+
}

0 commit comments

Comments
 (0)