mirror of
https://codeberg.org/unspeaker/tek.git
synced 2026-08-28 12:56:57 +02:00
fix config loading
This commit is contained in:
parent
a126d98f3c
commit
9e25564abb
4 changed files with 116 additions and 123 deletions
167
src/config.rs
167
src/config.rs
|
|
@ -2,55 +2,88 @@ use crate::*;
|
|||
use std::path::PathBuf;
|
||||
use notify_debouncer_full::notify::{RecursiveMode, PollWatcher, Config as NotifyConfig, Watcher};
|
||||
|
||||
/// Write initial contents of configuration.
|
||||
pub fn config_init (config: &Config) -> UsuallyRef<'static, ()> {
|
||||
//println!("\r\ninit {}", quanta::Clock::new().raw());
|
||||
config.clear();
|
||||
let path = Config::CONFIG;
|
||||
let defaults = Config::DEFAULTS;
|
||||
config.stamp.store(quanta::Clock::new().raw(), Relaxed);
|
||||
if config.find_file().is_none() {
|
||||
//println!("Creating {path:?}");
|
||||
std::fs::write(config.place_file()?, defaults)?;
|
||||
impl AsRef<Config> for Config {
|
||||
fn as_ref (&self) -> &Config {
|
||||
self
|
||||
}
|
||||
Ok(if let Some(path) = config.find_file() {
|
||||
//println!("Loading {path:?}");
|
||||
let src = std::fs::read_to_string(&path)?;
|
||||
src.as_str().each((), &mut move|ctx, item: &str|{
|
||||
config_add(config, item);
|
||||
Ok(ctx)
|
||||
});
|
||||
}
|
||||
|
||||
/// Write initial contents of configuration.
|
||||
pub fn config_init <C: AsRef<Config>> (config: C) -> Usually<C> {
|
||||
if config.as_ref().find_file().is_none() {
|
||||
std::fs::write(config.as_ref().place_file()?, Config::DEFAULTS)?;
|
||||
}
|
||||
Ok(if let Some(path) = config.as_ref().find_file() {
|
||||
config_load(config, std::fs::read_to_string(&path)?)?
|
||||
} else {
|
||||
return Err(format!("{path}: not found").into())
|
||||
return Err(format!("config_init: not found").into())
|
||||
})
|
||||
}
|
||||
|
||||
/// Add statements to configuration from [Dsl] source.
|
||||
pub fn config_add <'a> (config: &'a Config, dsl: &'a str) -> UsuallyRef<'a, &'a Config> {
|
||||
dsl.each(config, &mut move|ctx: &'a Config, item: &'a str|if let Some(expr) = item.expr()? {
|
||||
//if let (Some(name), Some(body)) = (expr.tail()?.head()?, expr.tail()?.tail()?,) {
|
||||
match expr.head()? {
|
||||
Some("mode") => expr.tail()?.map(|tail|modes_add(&config.modes, tail)),
|
||||
Some("keys") => expr.tail()?.map(|tail|load_bind(&config.binds, tail)),
|
||||
Some("view") => expr.tail()?.map(|tail|load_view(&config.views, tail)),
|
||||
_ => return Err(format!("Config::load: expected view/keys/mode expr, got: {item:?}").into())
|
||||
}.transpose()?;
|
||||
//}
|
||||
Ok(config)
|
||||
pub fn config_load <C: AsRef<Config>, L: Language> (config: C, src: L) -> Usually<C> {
|
||||
config.as_ref().clear();
|
||||
config.as_ref().stamp.store(quanta::Clock::new().raw(), Relaxed);
|
||||
src.each(config, |c, s|config_load_item(c, s))
|
||||
}
|
||||
|
||||
pub fn config_load_item <C: AsRef<Config>, L: Language> (config: C, src: L) -> Usually<C> {
|
||||
if let Some(expr) = src.expr()? {
|
||||
config_load_kind(config, expr)
|
||||
} else {
|
||||
Err(format!("Config::add_one: tried to add empty item").into())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn config_load_kind <C: AsRef<Config>, L: Language> (config: C, src: L) -> Usually<C> {
|
||||
//if let Some(tail) = src.tail()? {
|
||||
match src.head()? {
|
||||
Some("mode") => modes_add(&config.as_ref().modes, src.tail()),
|
||||
Some("keys") => load_bind(&config.as_ref().binds, src.tail()),
|
||||
Some("view") => load_view(&config.as_ref().views, src.tail()),
|
||||
_ => return Err(format!("Config::load: expected view/keys/mode expr, got: {src:?}").into())
|
||||
}?;
|
||||
//}
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
/// Watch a config's file for changes.
|
||||
pub fn config_watch (
|
||||
config: Arc<Config>, poll: Option<Duration>
|
||||
) -> Usually<()> {
|
||||
let poll = poll.unwrap_or(Duration::from_millis(250));
|
||||
let opts = NotifyConfig::default().with_poll_interval(poll);
|
||||
let mut watcher = ::notify_debouncer_full::notify::poll::PollWatcher::new({
|
||||
let config = config.clone();
|
||||
move|result|{
|
||||
match result {
|
||||
Ok(_events) => if let Err(e) = config_init(config.as_ref()) {
|
||||
*config.as_ref().error.write().unwrap() = Some(format!("{e:?}").into());
|
||||
panic!("{e:?}");
|
||||
} else {
|
||||
//println!("config updated");
|
||||
},
|
||||
Err(errors) => {
|
||||
panic!("{errors:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}, opts)?;
|
||||
if let Some(path) = config.as_ref().get_file() {
|
||||
//println!("watching: {path:?}");
|
||||
watcher.watch(&path, RecursiveMode::NonRecursive)?;
|
||||
*config.as_ref().watch.write().unwrap() = Some(watcher);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("no config path").into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a mode.
|
||||
pub fn modes_add <'a> (modes: &Modes, expr: &'a str) -> UsuallyRef<'a, ()> {
|
||||
pub fn modes_add <'a> (modes: &Modes, expr: impl Language) -> UsuallyRef<'a, ()> {
|
||||
let name = expr.head()?.ok_or("mode: missing name")?;
|
||||
let body = expr.tail()?.ok_or("mode: missing body")?;
|
||||
let mode = Mode::default();
|
||||
let mode = body.each(mode, move|mut submode: Mode, item: &str|{
|
||||
mode_add(&mut submode, &item);
|
||||
Ok(submode)
|
||||
})?;
|
||||
let mode = body.each(mode, |c,s|mode_add(c,s))?;
|
||||
modes.0.write().unwrap().insert(name.into(), Arc::new(mode));
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -69,8 +102,8 @@ pub fn modes_add <'a> (modes: &Modes, expr: &'a str) -> UsuallyRef<'a, ()> {
|
|||
/// let mut mode: tek::Mode<std::sync::Arc<str>> = Default::default();
|
||||
/// mode.add("(name hello)").unwrap();
|
||||
/// ```
|
||||
pub fn mode_add <'a> (mode: &'a mut Mode, dsl: &'a str) -> PerhapsRef<'a, &'a mut Mode> {
|
||||
Ok(Some(if let Ok(Some(expr)) = dsl.expr() && let Ok(Some(head)) = expr.head() {
|
||||
pub fn mode_add (mut mode: Mode, dsl: impl Language) -> Usually<Mode> {
|
||||
Ok(if let Ok(Some(expr)) = dsl.expr() && let Ok(Some(head)) = expr.head() {
|
||||
//println!("Mode::add: {head} {:?}", expr.tail());
|
||||
let tail = expr.tail()?.map(|x|x.trim()).unwrap_or("");
|
||||
match head {
|
||||
|
|
@ -78,16 +111,13 @@ pub fn mode_add <'a> (mode: &'a mut Mode, dsl: &'a str) -> PerhapsRef<'a, &'a mu
|
|||
let name = tail.head()?.ok_or("submode: missing name")?;
|
||||
let body = tail.tail()?.ok_or("submode: missing body")?;
|
||||
let submode = Mode::default();
|
||||
let submode = body.each(submode, move|mut submode: Mode, item: &str|{
|
||||
mode_add(&mut submode, &item);
|
||||
Ok(submode)
|
||||
})?;
|
||||
let submode = body.each(submode, |c,s|mode_add(c,s))?;
|
||||
let modes = mode.modes.clone();
|
||||
modes.0.write().unwrap().insert(name.into(), Arc::new(submode));
|
||||
mode
|
||||
},
|
||||
"keys" => {
|
||||
dsl.each(mode, &mut |mode: &'a mut Mode, expr: &'a str|{
|
||||
dsl.each(mode, |mut mode: Mode, expr: &str|{
|
||||
mode.keys.push(expr.trim().into());
|
||||
Ok(mode)
|
||||
})?
|
||||
|
|
@ -102,11 +132,11 @@ pub fn mode_add <'a> (mode: &'a mut Mode, dsl: &'a str) -> PerhapsRef<'a, &'a mu
|
|||
mode
|
||||
} else {
|
||||
return Err(format!("Mode::add: unexpected: {dsl:?}").into());
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
/// Load custom view definition.
|
||||
pub fn load_view <'a> (views: &Views, expr: &'a str,) -> UsuallyRef<'a, ()> {
|
||||
pub fn load_view <'a> (views: &Views, expr: impl Language) -> UsuallyRef<'a, ()> {
|
||||
let name = expr.head()?.ok_or("view: missing name")?;
|
||||
let body = expr.tail()?.ok_or("view: missing body")?;
|
||||
views.write().unwrap().insert(
|
||||
|
|
@ -116,12 +146,12 @@ pub fn load_view <'a> (views: &Views, expr: &'a str,) -> UsuallyRef<'a, ()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_bind <'a> (binds: &Binds, expr: &'a str) -> UsuallyRef<'a, ()> {
|
||||
pub fn load_bind <'a> (binds: &Binds, expr: impl Language) -> UsuallyRef<'a, ()> {
|
||||
let name = expr.head()?.ok_or("bind: missing name")?;
|
||||
let body = expr.tail()?.ok_or("bind: missing body")?;
|
||||
binds.write().unwrap().insert(name.into(), {
|
||||
let mut map = Bind::new();
|
||||
body.each((), &mut |_, item: &str|if item.expr().head() == Ok(Some("see")) {
|
||||
body.each((), |_, item: &str|if item.expr().head() == Ok(Some("see")) {
|
||||
// TODO
|
||||
Ok(())
|
||||
} else if let Ok(Some(_word)) = item.expr().head().word() {
|
||||
|
|
@ -241,47 +271,14 @@ impl Config {
|
|||
/// Create, initialize, and watch a new configuration.
|
||||
pub fn watched <T: 'static> (callback: impl FnOnce(Arc<Config>)->T) -> Usually<T> {
|
||||
let config = Self::init_new(None)?;
|
||||
Self::watch(config.clone(), None)?;
|
||||
config_watch(config.clone(), None)?;
|
||||
let result = callback(config);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Create and initialize a new configuration.
|
||||
pub fn init_new (_dirs: Option<BaseDirectories>) -> UsuallyRef<'static, Arc<Self>> {
|
||||
let config = Arc::new(Self::new(None));
|
||||
config_init(&config)?;
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
/// Watch a config's file for changes.
|
||||
pub fn watch (config: Arc<Config>, poll: Option<Duration>) -> UsuallyRef<'static, ()> {
|
||||
let handler = {
|
||||
let config = config.clone();
|
||||
move |result|match result {
|
||||
Ok(_events) => if let Err(e) = config_init(&config) {
|
||||
*config.error.write().unwrap() = Some(format!("{e:?}").into());
|
||||
panic!("{e:?}");
|
||||
} else {
|
||||
//println!("config updated");
|
||||
},
|
||||
Err(errors) => {
|
||||
panic!("{errors:?}");
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut watcher = ::notify_debouncer_full::notify::poll::PollWatcher::new(
|
||||
handler,
|
||||
NotifyConfig::default()
|
||||
.with_poll_interval(poll.unwrap_or(Duration::from_millis(250)))
|
||||
)?;
|
||||
if let Some(path) = config.get_file() {
|
||||
//println!("watching: {path:?}");
|
||||
watcher.watch(&path, RecursiveMode::NonRecursive)?;
|
||||
*config.watch.write().unwrap() = Some(watcher);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("no config path").into())
|
||||
}
|
||||
pub fn init_new (_dirs: Option<BaseDirectories>) -> Usually<Arc<Self>> {
|
||||
config_init(Arc::new(Self::new(None)))
|
||||
}
|
||||
|
||||
/// Find the config file.
|
||||
|
|
@ -316,6 +313,10 @@ impl Config {
|
|||
*self.binds.write().unwrap() = Default::default();
|
||||
}
|
||||
|
||||
pub fn get_view (&self, name: impl AsRef<str>) -> Option<Arc<str>> {
|
||||
self.views.read().unwrap().get(name.as_ref()).cloned()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub use self::view::*;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue