diff --git a/dsl/src/dsl_conv.rs b/dsl/src/dsl_conv.rs index 033e6eb..3d125a4 100644 --- a/dsl/src/dsl_conv.rs +++ b/dsl/src/dsl_conv.rs @@ -6,15 +6,15 @@ pub struct DslNs<'t, T: 't>(pub &'t [(&'t str, T)]); /// Namespace where keys are symbols. pub trait DslSymNs<'t, T: 't>: 't { const SYMS: DslNs<'t, fn (&'t Self)->T>; - fn from_sym (&'t self, dsl: D) -> Usually { + fn from_sym (&'t self, dsl: D) -> Perhaps { if let Some(dsl) = dsl.sym()? { for (sym, get) in Self::SYMS.0 { if dsl == *sym { - return Ok(get(self)) + return Ok(Some(get(self))) } } } - return Err(format!("not found: sym: {dsl:?}").into()) + return Ok(None) } } @@ -26,11 +26,21 @@ pub trait DslSymNs<'t, T: 't>: 't { pub trait DslExpNs<'t, T: 't>: 't { const EXPS: DslNs<'t, fn (&'t Self, &str)->T>; + fn from_exp (&'t self, dsl: D) -> Perhaps { + if let Some(exp) = dsl.exp()? { + for (key, value) in Self::EXPS.0.iter() { + if exp.head() == Ok(Some(key)) { + return Ok(Some(value(self, exp.tail()?.unwrap_or("")))) + } + } + } + return Ok(None) + } } #[macro_export] macro_rules! dsl_exp ( - (|$state:ident:$State:ty|->$type:ty { $( - [$key:literal $(/ $sub:ident: $Sub:ty)? $(, $arg:ident $(?)? :$argtype:ty)*] => $body:expr + (|$state:ident:$State:ty$(, $tail:ident)?|->$type:ty { $( + ($key:literal $(/ $sub:ident: $Sub:ty)? $(, $arg:ident $(?)? :$argtype:ty)*) => $body:expr ),* $(,)? }) => { impl<'t> DslExpNs<'t, $type> for $State { const EXPS: DslNs<'t, fn (&'t $State, &str)->$type> = diff --git a/tui/src/tui_content/tui_string.rs b/tui/src/tui_content/tui_string.rs index 92b91fc..57ae7f4 100644 --- a/tui/src/tui_content/tui_string.rs +++ b/tui/src/tui_content/tui_string.rs @@ -3,22 +3,37 @@ use crate::ratatui::prelude::Position; use unicode_width::{UnicodeWidthStr, UnicodeWidthChar}; impl_content_layout_render!(TuiOut: |self: &str, to| - layout = to.center_xy([self.chars().count() as u16, 1]); - render = {let [x, y, ..] = Content::layout(self, to.area()); - to.blit(self, x, y, None)}); + layout = to.center_xy([width_chars_max(to.w(), self), 1]); + render = {let [x, y, w, ..] = Content::layout(self, to.area()); + to.text(self, x, y, w)}); + impl_content_layout_render!(TuiOut: |self: String, to| - layout = to.center_xy([self.chars().count() as u16, 1]); - render = {let [x, y, ..] = Content::layout(self, to.area()); - to.blit(self, x, y, None)}); + layout = Content::::layout(&self.as_str(), to); + render = Content::::render(&self.as_str(), to)); + +impl_content_layout_render!(TuiOut: |self: Arc, to| + layout = Content::::layout(&self.as_ref(), to); + render = Content::::render(&self.as_ref(), to)); + impl_content_layout_render!(TuiOut: |self: std::sync::RwLock, to| layout = Content::::layout(&self.read().unwrap(), to); render = Content::::render(&self.read().unwrap(), to)); + impl_content_layout_render!(TuiOut: |self: std::sync::RwLockReadGuard<'_, String>, to| layout = Content::::layout(&**self, to); render = Content::::render(&**self, to)); -impl_content_layout_render!(TuiOut: |self: Arc, to| - layout = to.center_xy([self.chars().count() as u16, 1]); - render = to.blit(self, to.area.x(), to.area.y(), None)); + +fn width_chars_max (max: u16, text: impl AsRef) -> u16 { + let mut width: u16 = 0; + let mut chars = text.as_ref().chars(); + while let Some(c) = chars.next() { + width += c.width().unwrap_or(0) as u16; + if width > max { + break + } + } + return width +} /// Trim string with [unicode_width]. pub fn trim_string (max_width: usize, input: impl AsRef) -> String { diff --git a/tui/src/tui_engine/tui_output.rs b/tui/src/tui_engine/tui_output.rs index 04cbe94..9b35936 100644 --- a/tui/src/tui_engine/tui_output.rs +++ b/tui/src/tui_engine/tui_output.rs @@ -1,6 +1,7 @@ use crate::*; use std::time::Duration; use std::thread::{spawn, JoinHandle}; +use unicode_width::*; #[derive(Default)] pub struct TuiOut { pub buffer: Buffer, @@ -10,8 +11,12 @@ impl Output for TuiOut { type Unit = u16; type Size = [Self::Unit;2]; type Area = [Self::Unit;4]; - #[inline] fn area (&self) -> [u16;4] { self.area } - #[inline] fn area_mut (&mut self) -> &mut [u16;4] { &mut self.area } + #[inline] fn area (&self) -> [u16;4] { + self.area + } + #[inline] fn area_mut (&mut self) -> &mut [u16;4] { + &mut self.area + } #[inline] fn place <'t, T: Render + ?Sized> (&mut self, area: [u16;4], content: &'t T) { let last = self.area(); *self.area_mut() = area; @@ -63,10 +68,32 @@ impl TuiOut { pub fn blit ( &mut self, text: &impl AsRef, x: u16, y: u16, style: Option