diff --git a/src/config.rs b/src/config.rs index 55e34ed6..8875649d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -88,6 +88,12 @@ pub fn modes_add <'a> (modes: &Modes, expr: impl Language) -> UsuallyRef<'a, ()> Ok(()) } +impl AsMut for Mode { + fn as_mut (&mut self) -> &mut Self { + self + } +} + /// Add a definition to the mode. /// /// Supported definitions: @@ -99,10 +105,9 @@ pub fn modes_add <'a> (modes: &Modes, expr: impl Language) -> UsuallyRef<'a, ()> /// - ... -> view /// /// ``` -/// let mut mode: tek::Mode> = Default::default(); -/// mode.add("(name hello)").unwrap(); +/// let mut mode: tek::Mode = tek::mode_add(tek::Mode::default(), "(name hello)").unwrap(); /// ``` -pub fn mode_add (mut mode: Mode, dsl: impl Language) -> Usually { +pub fn mode_add > (mut mode: T, dsl: impl Language) -> Usually { 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(""); @@ -112,23 +117,23 @@ pub fn mode_add (mut mode: Mode, dsl: impl Language) -> Usually { let body = tail.tail()?.ok_or("submode: missing body")?; let submode = Mode::default(); let submode = body.each(submode, |c,s|mode_add(c,s))?; - let modes = mode.modes.clone(); + let modes = mode.as_mut().modes.clone(); modes.0.try_write().unwrap().insert(name.into(), Arc::new(submode)); mode }, "keys" => { - tail.each(mode, |mut mode: Mode, expr: &str|{ - mode.keys.push(expr.trim().into()); + tail.each(mode, |mut mode: T, expr: &str|{ + mode.as_mut().keys.push(expr.trim().into()); Ok(mode) })? }, - "name" => { mode.name.push(tail.into()); mode }, - "info" => { mode.info.push(tail.into()); mode }, - "view" => { mode.view.push(View::new(tail)?.into()); mode }, - _ => { mode.view.push(View::new(tail)?.into()); mode }, + "name" => { mode.as_mut().name.push(tail.into()); mode }, + "info" => { mode.as_mut().info.push(tail.into()); mode }, + "view" => { mode.as_mut().view.push(View::new(tail)?.into()); mode }, + _ => { mode.as_mut().view.push(View::new(tail)?.into()); mode }, } } else if let Ok(Some(word)) = dsl.word() { - mode.view.push(View::new(word)?.into()); + mode.as_mut().view.push(View::new(word)?.into()); mode } else { return Err(format!("Mode::add: unexpected: {dsl:?}").into()); @@ -141,7 +146,7 @@ pub fn load_bind <'a> (binds: &Binds, expr: impl Language) -> UsuallyRef<'a, ()> let body = expr.tail()?.unwrap_or(""); binds.try_write().unwrap().insert(name.into(), { let mut map = Bind::new(); - body.each((), |_, item: &str|if item.expr().head() == Ok(Some("see")) { + body.each((), |_, item: &str|if matches!(item.expr().head(), Ok(Some("see"))) { // TODO Ok(()) } else if let Ok(Some(_word)) = item.expr().head().word() { @@ -172,22 +177,15 @@ pub fn load_bind <'a> (binds: &Binds, expr: impl Language) -> UsuallyRef<'a, ()> /// Configuration: mode, view, and bind definitions. /// /// ``` -/// let config = tek::Config::default(); -/// ``` -/// -/// ``` -/// // Some dizzle. -/// // What indentation to use here lol? -/// let source = stringify!((mode :menu (name Menu) -/// (info Mode selector.) (keys :axis/y :confirm) -/// (view (bg (g 0) (bsp/s :ports/out -/// (bsp/n :ports/in -/// (bg (g 30) (bsp/s (fixed/y 7 :logo) -/// (fill :dialog/menu))))))))); -/// // Add this definition to the config and try to load it. -/// // A "mode" is basically a state machine -/// // with associated input and output definitions. -/// tek::Config::default().add(&source).unwrap().get_mode(":menu").unwrap(); +/// let source = stringify!( +/// (mode :menu (name Menu) +/// (info Mode selector.) (keys :axis/y :confirm) +/// (view (bg (g 0) (bsp/s :ports/out +/// (bsp/n :ports/in +/// (bg (g 30) (bsp/s (fixed/y 7 :logo) +/// (fill :dialog/menu))))))))); +/// let config: tek::Config = tek::modes_add(tek::Config::default(), source).unwrap(); +/// let mode: tek::Mode = config.get_mode(":menu").unwrap(); /// ``` #[derive(Default, Debug)] pub struct Config { @@ -221,7 +219,7 @@ pub struct Modes(Arc, Arc>>>); /// Group of view and keys definitions. /// /// ``` -/// let mode = tek::Mode::>::default(); +/// let mode = tek::Mode::default(); /// ``` #[derive(Default, Debug)] pub struct Mode { @@ -279,6 +277,7 @@ impl View { UsuallyDrawn + Send + Sync>>> { Ok(Arc::new(if let Some(head) = expr.head()? && let Some(ns) = head.split('/').next() { + match ns { "when" => { @@ -452,27 +451,31 @@ impl View { }, "fg" | "bg" => { - let color = expr.nth(1)?.ok_or_else(||Box::::from("{}: no arg1: color"))?; + let color = Arc::from(expr.nth(1)?.ok_or_else(||Box::::from("{}: no arg1: color"))?); + let color = move|state: &App|state.namespace(&color); let thunk = Self::compile(expr.nth(2)?.ok_or_else(||Box::::from("either: no arg2: thunk"))?)?; - todo!() + match ns { + "fg" => Self::boxed(move|state, screen|fg( + color(state)?.unwrap_or_default(), draw(|screen|thunk(state, screen)) + ).draw(screen)), + "bg" => Self::boxed(move|state, screen|bg( + color(state)?.unwrap_or_default(), draw(|screen|thunk(state, screen)) + ).draw(screen)), + _ => unreachable!() + } }, "text" => { - todo!() + let text: Arc = Arc::from(expr.tail()?.unwrap_or_default()); + Self::boxed(move|_state, screen|{ + text.draw(screen) + }) }, - //"align" => Self::boxed(move|state, screen|kw_align(state, screen, expr)), - //"full" => Self::boxed(move|state, screen|kw_full(state, screen, expr)), - //"exact" => Self::boxed(move|state, screen|kw_exact(state, screen, expr)), - //"min" => Self::boxed(move|state, screen|kw_min(state, screen, expr)), - //"max" => Self::boxed(move|state, screen|kw_max(state, screen, expr)), - //"push" => Self::boxed(move|state, screen|kw_push(state, screen, expr)), - //"pull" => Self::boxed(move|state, screen|kw_pull(state, screen, expr)), - //"text" => Self::boxed(move|state, screen|kw_tui_text(state, screen, expr)), - //"fg" => Self::boxed(move|state, screen|kw_tui_fg(state, screen, expr)), - //"bg" => Self::boxed(move|state, screen|kw_tui_bg(state, screen, expr)), _ => return Err(format!("compile_expr: unexpected: {expr:?}").into()) + } + } else { return Err(format!("compile_expr: invalid expression: {expr:?}").into()) })) @@ -503,13 +506,13 @@ impl View { }, Some(":dialog") => Self::boxed(move|state, to|draw_dialog(to, word.split("/").skip(1), state)), Some(":templates") => Self::boxed(move|state, to|view_templates(state).draw(to)), - Some(":sessions") => Self::boxed(move|state, to|view_sessions().draw(to)), + Some(":sessions") => Self::boxed(move|_, to|view_sessions().draw(to)), Some(":browse/title") => Self::boxed(move|state, to|view_browse_title(state).draw(to)), Some(":device") => Self::boxed(move|state, to|view_device(state).draw(to)), - Some(":status") => Self::boxed(move|state, to|"TODO: Status Bar".draw(to)), - Some(":editor") => Self::boxed(move|state, to|"TODO Editor".draw(to)), - Some(":transport") => Self::boxed(move|state, to|view_transport(true, "", "", "").draw(to)), - Some(":debug") => Self::boxed(move|state, to|format!("[{:?}]", to.area()).exact_h(1).draw(to)), + Some(":status") => Self::boxed(move|_, to|"TODO: Status Bar".draw(to)), + Some(":editor") => Self::boxed(move|_, to|"TODO Editor".draw(to)), + Some(":transport") => Self::boxed(move|_, to|view_transport(true, "", "", "").draw(to)), + Some(":debug") => Self::boxed(move|_, to|format!("[{:?}]", to.area()).exact_h(1).draw(to)), Some(_) => Self::boxed(move|state, to|if let Some(view) = state.config.get_view(word.as_ref()) { (view.render)(state, to) } else { @@ -632,7 +635,9 @@ mod bind { /// An map of input events (e.g. [TuiEvent]) to [Binding]s. /// /// ``` - /// let lang = "(@x (nop)) (@y (nop) (nop))"; + /// let lang = stringify!( + /// (@x (nop)) + /// (@y (nop) (nop))); /// let bind = tek::Bind::>::load(&lang).unwrap(); /// assert_eq!(bind.query(&'x'.into()).map(|x|x.len()), Some(1)); /// //assert_eq!(bind.query(&'y'.into()).map(|x|x.len()), Some(2)); diff --git a/src/tek.edn b/src/tek.edn index a2fd3dc2..b102b865 100644 --- a/src/tek.edn +++ b/src/tek.edn @@ -1,8 +1,8 @@ (view :logo (text tek)) (view :browse (bsp/s - (padding 3 1 :browse-title) - (enclose (fg (g 96)) browser))) + (pad 3 1 :browse-title) + (fg (g 96) browser)) (mode :transport (name Transport) diff --git a/src/tek.rs b/src/tek.rs index 5c64590c..ff6c27a7 100644 --- a/src/tek.rs +++ b/src/tek.rs @@ -26,11 +26,11 @@ fn main () -> Usually<()> { _guard }; tengri::Tui::setup_panic(); - #[cfg(feature = "cli")] { - Config::watched(crate::cli::run_with_config)?; - } - #[cfg(not(feature = "cli"))] { - Config::watched(run_new_plain)?; + #[cfg(feature = "cli")] let outcome = Config::watched(crate::cli::run_with_config); + #[cfg(not(feature = "cli"))] let outcome = Config::watched(run_new_plain); + if let Err(e) = outcome { + println!("{e:#?}"); + std::process::exit(1); } Ok(()) } @@ -334,16 +334,15 @@ mod app { /// /// ``` /// let mut proj = tek::Arrangement::default(); - /// proj.jack = tek::tengri::Jack::new(&"test_tek").expect("failed to connect to jack"); - /// let mut conf = std::sync::Arc::new(tek::Config::default()); - /// conf.add("(mode hello)"); - /// let tek = tek::App::new(None, proj, conf, "hello"); + /// proj.jack = tek::tengri::Jack::new(&"test_tek").expect("failed to connect to jack"); + /// let mut conf = tek::config_load(tek::Config::default(), "(mode hello)").unwrap(); + /// let tek = tek::App::new(None, proj, conf.into(), "hello"); /// ``` pub fn new ( - exit: Option, + exit: Option, project: Arrangement, - config: Arc, - mode: impl AsRef + config: Arc, + mode: impl AsRef ) -> Self { App { exit: exit.unwrap_or_default(), diff --git a/tengri b/tengri index 8e7286e4..7f067b84 160000 --- a/tengri +++ b/tengri @@ -1 +1 @@ -Subproject commit 8e7286e409ec6d4ac4382856ff93767a4758e11e +Subproject commit 7f067b848fb504feb312033bf0a485bb2ccacef6