This commit is contained in:
🪞👃🪞 2025-07-14 22:22:45 +03:00
parent 6c3a0964ec
commit 7271081fc9
10 changed files with 119 additions and 296 deletions

200
]
View file

@ -1,200 +0,0 @@
use crate::*;
/// A collection of input bind.
///
/// Each contained layer defines a mapping from input event to command invocation
/// over a given state. Furthermore, each layer may have an associated cond,
/// so that only certain layers are active at a given time depending on state.
#[derive(Debug, Default)] pub struct InputMap<I, T: Dsl>(std::collections::BTreeMap<I, T>);
impl<I, T: Dsl> InputMap<I, T> {
/// Create input layer collection from path to text file.
pub fn from_path <P: Debug + AsRef<Path>> (path: P) -> Usually<Self> {
if !exists(path.as_ref())? {
return Err(format!("(e5) not found: {path:?}").into())
}
Self::from_source(read_and_leak(path)?)
}
/// Create input layer collection from string.
pub fn from_source <S: AsRef<str>> (source: S) -> Usually<Self> {
Self::from_dsl(CstIter::from(source.as_ref()))
}
/// Create input layer collection from DSL.
pub fn from_dsl (dsl: impl Dsl) -> Usually<Self> {
use DslVal::*;
let mut input_map: Self = Self(Default::default());
while let Exp(_, mut exp) = dsl.val() {
match exp.nth(0).map(|x|x.val()) {
Some(Str(path)) => {
let path = PathBuf::from(path.as_ref());
let module = InputMap::<I, T>::from_path(&path)?;
for (key, val) in module.0.into_iter() {
}
},
Some(Exp(_, expr)) if let Some(Sym(sym)) = expr.nth(0) => {
//input_map.unconditional.push(expr);
todo!("binding");
},
Some(Exp(_, expr)) if expr.nth(0).map(|x|x.val()) == Some(Key("if")) => {
todo!("conditional binding");
},
_ => return Result::Err("invalid token in keymap".into()),
}
}
Ok(input_map)
}
/// Evaluate the active layers for a given state,
/// returning the command to be executed, if any.
pub fn handle <S, O> (&self, state: &mut S, input: I) -> Perhaps<O> where
S: DslInto<bool> + DslInto<O>,
O: Command<S>
{
todo!();
//let layers = self.0.as_slice();
//for InputLayer { cond, bind } in layers.iter() {
//let mut matches = true;
//if let Some(cond) = cond {
//matches = state.dsl_into(cond, ||format!("input: no cond").into())?;
//}
//if matches
//&& let Some(exp) = bind.val().exp_head()
//&& input.dsl_into(exp, ||format!("InputMap: input.eval(binding) failed").into())?
//&& let Some(command) = state.try_dsl_into(exp)? {
//return Ok(Some(command))
//}
//}
Ok(None)
}
/*
/// Create an input map with a single non-condal layer.
/// (Use [Default::default] to get an empty map.)
pub fn new (layer: DslVal<T::Str, T::Exp>) -> Self {
Self::default().layer(layer)
}
/// Add layer, return `Self`.
pub fn layer (mut self, layer: DslVal<T::Str, T::Exp>) -> Self {
self.add_layer(layer); self
}
/// Add condal layer, return `Self`.
pub fn layer_if (mut self, cond: DslVal<T::Str, T::Exp>, layer: DslVal<T::Str, T::Exp>) -> Self {
self.add_layer_if(Some(cond), layer); self
}
/// Add layer, return `&mut Self`.
pub fn add_layer (&mut self, layer: DslVal<T::Str, T::Exp>) -> &mut Self {
self.add_layer_if(None, layer.into()); self
}
/// Add condal layer, return `&mut Self`.
pub fn add_layer_if (&mut self, cond: Option<DslVal<T::Str, T::Exp>>, bind: DslVal<T::Str, T::Exp>) -> &mut Self {
self.0.push(InputLayer { cond, bind });
self
}
*/
}
//let mut keys = iter.unwrap();
//let mut map = InputMap::default();
//while let Some(token) = keys.next() {
//if let Value::Exp(_, mut exp) = token.value {
//let next = exp.next();
//if let Some(Token { value: Value::Key(sym), .. }) = next {
//match sym {
//"layer" => {
//if let Some(Token { value: Value::Str(path), .. }) = exp.peek() {
//let path = base.as_ref().parent().unwrap().join(unquote(path));
//if !std::fs::exists(&path)? {
//return Err(format!("(e5) not found: {path:?}").into())
//}
//map.add_layer(read_and_leak(path)?.into());
//print!("layer:\n path: {:?}...", exp.0.0.trim());
//println!("ok");
//} else {
//return Err(format!("(e4) unexpected non-string {next:?}").into())
//}
//},
//"layer-if" => {
//let mut cond = None;
//if let Some(Token { value: Value::Sym(sym), .. }) = exp.next() {
//cond = Some(leak(sym));
//} else {
//return Err(format!("(e4) unexpected non-symbol {next:?}").into())
//};
//if let Some(Token { value: Value::Str(path), .. }) = exp.peek() {
//let path = base.as_ref().parent().unwrap().join(unquote(path));
//if !std::fs::exists(&path)? {
//return Err(format!("(e5) not found: {path:?}").into())
//}
//print!("layer-if:\n cond: {}\n path: {path:?}...",
//cond.unwrap_or_default());
//let keys = read_and_leak(path)?.into();
//let cond = cond.unwrap();
//println!("ok");
//map.add_layer_if(
//Box::new(move |state: &App|Take::take_or_fail(
//state, exp, ||"missing input layer conditional"
//)), keys
//);
//} else {
//return Err(format!("(e4) unexpected non-symbol {next:?}").into())
//}
//},
//_ => return Err(format!("(e3) unexpected symbol {sym:?}").into())
//}
//} else {
//return Err(format!("(e2) unexpected exp {:?}", next.map(|x|x.value)).into())
//}
//} else {
//return Err(format!("(e1) unexpected token {token:?}").into())
//}
//}
//Ok(map)
//}
//{
//}
//fn from (source: &'s str) -> Self {
//// this should be for single layer:
//use DslVal::*;
//let mut layers = vec![];
//let mut source = CstIter::from(source);
//while let Some(Exp(_, mut iter)) = source.next().map(|x|x.value) {
//let mut iter = iter.clone();
//layers.push(match iter.next().map(|x|x.value) {
//Some(Sym(sym)) if sym.starts_with("@") => InputLayer {
//cond: None,
//bind: vec![[
//dsl_val(source.nth(1).unwrap()),
//dsl_val(source.nth(2).unwrap()),
//]],
//},
//Some(Str(layer)) => InputLayer {
//cond: None,
//bind: dsl_val(source.nth(1).unwrap()),
//},
//Some(Key("if")) => InputLayer {
//cond: Some(dsl_val(source.nth(1).unwrap())),
//bind: dsl_val(source.nth(2).unwrap()),
//},
//_ => panic!("invalid token in keymap"),
//})
//}
//Self(layers)
//}
//}
fn unquote (x: &str) -> &str {
let mut chars = x.chars();
chars.next();
//chars.next_back();
chars.as_str()
}
fn read_and_leak (path: impl AsRef<Path>) -> Usually<&'static str> {
Ok(leak(String::from_utf8(std::fs::read(path.as_ref())?)?))
}
fn leak (x: impl AsRef<str>) -> &'static str {
Box::leak(x.as_ref().into())
}

View file

@ -5,10 +5,10 @@ use crate::*;
/// CST stores strings as source references and expressions as [CstIter] instances. /// CST stores strings as source references and expressions as [CstIter] instances.
#[derive(Debug, Clone, Default, PartialEq)] #[derive(Debug, Clone, Default, PartialEq)]
pub struct Cst<'src>(pub CstIter<'src>); pub struct Cst<'s>(pub CstIter<'s>);
impl<'src> Dsl for Cst<'src> { impl<'s> Dsl for Cst<'s> {
type Str = &'src str; type Str = &'s str;
type Exp = CstIter<'src>; type Exp = CstIter<'s>;
fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>> { fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>> {
self.0.nth(index) self.0.nth(index)
} }
@ -16,49 +16,49 @@ impl<'src> Dsl for Cst<'src> {
/// Parsed substring with range and value. /// Parsed substring with range and value.
#[derive(Debug, Copy, Clone, Default, PartialEq)] #[derive(Debug, Copy, Clone, Default, PartialEq)]
pub struct CstVal<'src> { pub struct CstVal<'s> {
/// Meaning of token. /// Meaning of token.
pub value: DslVal<&'src str, CstIter<'src>>, pub value: DslVal<&'s str, CstIter<'s>>,
/// Reference to source text. /// Reference to source text.
pub source: &'src str, pub source: &'s str,
/// Index of 1st character of token. /// Index of 1st character of token.
pub start: usize, pub start: usize,
/// Length of token. /// Length of token.
pub length: usize, pub length: usize,
} }
impl<'src> Dsl for CstVal<'src> { impl<'s> Dsl for CstVal<'s> {
type Str = &'src str; type Str = &'s str;
type Exp = CstIter<'src>; type Exp = CstIter<'s>;
fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>> { fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>> {
todo!() todo!()
} }
} }
impl<'src> CstVal<'src> { impl<'s> CstVal<'s> {
pub const fn new ( pub const fn new (
source: &'src str, source: &'s str,
start: usize, start: usize,
length: usize, length: usize,
value: DslVal<&'src str, CstIter<'src>> value: DslVal<&'s str, CstIter<'s>>
) -> Self { ) -> Self {
Self { source, start, length, value } Self { source, start, length, value }
} }
pub const fn end (&self) -> usize { pub const fn end (&self) -> usize {
self.start.saturating_add(self.length) self.start.saturating_add(self.length)
} }
pub const fn slice (&'src self) -> &'src str { pub const fn slice (&'s self) -> &'s str {
self.slice_source(self.source) self.slice_source(self.source)
} }
pub const fn slice_source <'range> (&'src self, source: &'range str) -> &'range str { pub const fn slice_source <'range> (&'s self, source: &'range str) -> &'range str {
str_range(source, self.start, self.end()) str_range(source, self.start, self.end())
} }
pub const fn slice_source_exp <'range> (&'src self, source: &'range str) -> &'range str { pub const fn slice_source_exp <'range> (&'s self, source: &'range str) -> &'range str {
str_range(source, self.start.saturating_add(1), self.end()) str_range(source, self.start.saturating_add(1), self.end())
} }
pub const fn with_value (self, value: DslVal<&'src str, CstIter<'src>>) -> Self { pub const fn with_value (self, value: DslVal<&'s str, CstIter<'s>>) -> Self {
Self { value, ..self } Self { value, ..self }
} }
pub const fn value (&self) -> DslVal<&'src str, CstIter<'src>> { pub const fn value (&self) -> DslVal<&'s str, CstIter<'s>> {
self.value self.value
} }
pub const fn error (self, error: DslErr) -> Self { pub const fn error (self, error: DslErr) -> Self {
@ -121,46 +121,37 @@ impl<'src> CstVal<'src> {
/// [Cst::next] returns just the [Cst] and mutates `self`, /// [Cst::next] returns just the [Cst] and mutates `self`,
/// instead of returning an updated version of the struct as [CstConstIter::next] does. /// instead of returning an updated version of the struct as [CstConstIter::next] does.
#[derive(Copy, Clone, Debug, Default, PartialEq)] #[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct CstIter<'src>(pub CstConstIter<'src>); pub struct CstIter<'s>(pub CstConstIter<'s>);
impl<'src> Dsl for CstIter<'src> { impl<'s> Dsl for CstIter<'s> {
type Str = &'src str; type Str = &'s str;
type Exp = Self; type Exp = Self;
fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>> { fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>> {
use DslVal::*; self.0.nth(index).map(|x|dsl_val(x))
self.0.nth(index).map(|x|match x {
Nil => Nil,
Err(e) => Err(e),
Num(u) => Num(u),
Sym(s) => Sym(s),
Key(s) => Sym(s),
Str(s) => Sym(s),
Exp(d, x) => DslVal::Exp(d, CstIter(x)),
})
} }
} }
impl<'src> CstIter<'src> { impl<'s> CstIter<'s> {
pub const fn new (source: &'src str) -> Self { pub const fn new (source: &'s str) -> Self {
Self(CstConstIter::new(source)) Self(CstConstIter::new(source))
} }
pub const fn peek (&self) -> Option<CstVal<'src>> { pub const fn peek (&self) -> Option<CstVal<'s>> {
self.0.peek() self.0.peek()
} }
} }
impl<'src> Iterator for CstIter<'src> { impl<'s> Iterator for CstIter<'s> {
type Item = CstVal<'src>; type Item = CstVal<'s>;
fn next (&mut self) -> Option<CstVal<'src>> { fn next (&mut self) -> Option<CstVal<'s>> {
self.0.next().map(|(item, rest)|{ self.0.next().map(|(item, rest)|{
self.0 = rest; self.0 = rest;
item item
}) })
} }
} }
impl<'src> Into<Vec<CstVal<'src>>> for CstIter<'src> { impl<'s> Into<Vec<CstVal<'s>>> for CstIter<'s> {
fn into (self) -> Vec<CstVal<'src>> { fn into (self) -> Vec<CstVal<'s>> {
self.collect() self.collect()
} }
} }
impl<'src> Into<Vec<Ast>> for CstIter<'src> { impl<'s> Into<Vec<Ast>> for CstIter<'s> {
fn into (self) -> Vec<Ast> { fn into (self) -> Vec<Ast> {
self.map(Into::into).collect() self.map(Into::into).collect()
} }
@ -172,9 +163,9 @@ impl<'src> Into<Vec<Ast>> for CstIter<'src> {
/// * the source text remaining /// * the source text remaining
/// * [ ] TODO: maybe [CstConstIter::next] should wrap the remaining source in `Self` ? /// * [ ] TODO: maybe [CstConstIter::next] should wrap the remaining source in `Self` ?
#[derive(Copy, Clone, Debug, Default, PartialEq)] #[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct CstConstIter<'src>(pub &'src str); pub struct CstConstIter<'s>(pub &'s str);
impl<'src> Dsl for CstConstIter<'src> { impl<'s> Dsl for CstConstIter<'s> {
type Str = &'src str; type Str = &'s str;
type Exp = Self; type Exp = Self;
fn nth (&self, mut index: usize) -> Option<DslVal<Self::Str, Self::Exp>> { fn nth (&self, mut index: usize) -> Option<DslVal<Self::Str, Self::Exp>> {
use DslVal::*; use DslVal::*;
@ -182,37 +173,39 @@ impl<'src> Dsl for CstConstIter<'src> {
for i in 0..index { for i in 0..index {
iter = iter.next()?.1 iter = iter.next()?.1
} }
iter.next().map(|(x, _)|match x.value { iter.next().map(|(x, _)|dsl_val(x.value))
Nil => Nil,
Err(e) => Err(e),
Num(u) => Num(u),
Sym(s) => Sym(s),
Key(s) => Sym(s),
Str(s) => Sym(s),
Exp(d, x) => DslVal::Exp(d, x.0),
})
} }
} }
impl<'src> CstConstIter<'src> { impl<'s> CstConstIter<'s> {
pub const fn new (source: &'src str) -> Self { pub const fn new (source: &'s str) -> Self {
Self(source) Self(source)
} }
pub const fn chomp (&self, index: usize) -> Self { pub const fn chomp (&self, index: usize) -> Self {
Self(split_at(self.0, index).1) Self(split_at(self.0, index).1)
} }
pub const fn next (mut self) -> Option<(CstVal<'src>, Self)> { pub const fn next (mut self) -> Option<(CstVal<'s>, Self)> {
Self::next_mut(&mut self) Self::next_mut(&mut self)
} }
pub const fn peek (&self) -> Option<CstVal<'src>> { pub const fn peek (&self) -> Option<CstVal<'s>> {
peek_src(self.0) peek_src(self.0)
} }
pub const fn next_mut (&mut self) -> Option<(CstVal<'src>, Self)> { pub const fn next_mut (&mut self) -> Option<(CstVal<'s>, Self)> {
match self.peek() { match self.peek() {
Some(token) => Some((token, self.chomp(token.end()))), Some(token) => Some((token, self.chomp(token.end()))),
None => None None => None
} }
} }
} }
impl<'s> From<CstConstIter<'s>> for CstIter<'s> {
fn from (iter: CstConstIter<'s>) -> Self {
Self(iter)
}
}
impl<'s> From<CstIter<'s>> for CstConstIter<'s> {
fn from (iter: CstIter<'s>) -> Self {
iter.0
}
}
/// Implement the const iterator pattern. /// Implement the const iterator pattern.
macro_rules! const_iter { macro_rules! const_iter {
@ -229,8 +222,8 @@ macro_rules! const_iter {
} }
} }
const_iter!(<'src>|self: CstConstIter<'src>| const_iter!(<'s>|self: CstConstIter<'s>|
=> CstVal<'src> => CstVal<'s>
=> self.next_mut().map(|(result, _)|result)); => self.next_mut().map(|(result, _)|result));
/// Static iteration helper used by [cst]. /// Static iteration helper used by [cst].
@ -244,9 +237,9 @@ macro_rules! iterate {
} }
} }
pub const fn peek_src <'src> (source: &'src str) -> Option<CstVal<'src>> { pub const fn peek_src <'s> (source: &'s str) -> Option<CstVal<'s>> {
use DslVal::*; use DslVal::*;
let mut token: CstVal<'src> = CstVal::new(source, 0, 0, Nil); let mut token: CstVal<'s> = CstVal::new(source, 0, 0, Nil);
iterate!(char_indices(source) => (start, c) => token = match token.value() { iterate!(char_indices(source) => (start, c) => token = match token.value() {
Err(_) => return Some(token), Err(_) => return Some(token),
Nil => match c { Nil => match c {

View file

@ -42,7 +42,20 @@ pub enum DslVal<Str, Exp> {
Exp(usize, Exp), Exp(usize, Exp),
} }
pub trait Dsl { pub fn dsl_val <A: Into<X>, B: Into<Y>, X, Y> (val: DslVal<A, B>) -> DslVal<X, Y> {
use DslVal::*;
match val {
Nil => Nil,
Err(e) => Err(e),
Num(u) => Num(u),
Sym(s) => Sym(s.into()),
Key(s) => Key(s.into()),
Str(s) => Str(s.into()),
Exp(d, x) => Exp(d, x.into()),
}
}
pub trait Dsl: Debug {
type Str: PartialEq + Clone + Default + Debug + AsRef<str>; type Str: PartialEq + Clone + Default + Debug + AsRef<str>;
type Exp: PartialEq + Clone + Default + Debug + Dsl; type Exp: PartialEq + Clone + Default + Debug + Dsl;
fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>>; fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>>;
@ -61,7 +74,7 @@ impl<
fn val (&self) -> DslVal<Str, Exp> { fn val (&self) -> DslVal<Str, Exp> {
self.clone() self.clone()
} }
fn nth (&self, index: usize) -> Option<DslVal<Str, Exp>> { fn nth (&self, _index: usize) -> Option<DslVal<Str, Exp>> {
todo!() todo!()
} }
} }
@ -163,16 +176,3 @@ from_str!(Ast|source|Self::from(CstIter::from(source)));
from_str!(Cst<'s>|source|Self(CstIter(CstConstIter(source)))); from_str!(Cst<'s>|source|Self(CstIter(CstConstIter(source))));
from_str!(CstIter<'s>|source|Self(CstConstIter(source))); from_str!(CstIter<'s>|source|Self(CstConstIter(source)));
from_str!(CstConstIter<'s>|source|Self::new(source)); from_str!(CstConstIter<'s>|source|Self::new(source));
pub fn dsl_val <A: Into<X>, B: Into<Y>, X, Y> (val: DslVal<A, B>) -> DslVal<X, Y> {
use DslVal::*;
match val {
Nil => Nil,
Err(e) => Err(e),
Num(u) => Num(u),
Sym(s) => Sym(s.into()),
Key(s) => Key(s.into()),
Str(s) => Str(s.into()),
Exp(d, x) => Exp(d, x.into()),
}
}

View file

@ -5,8 +5,6 @@ pub(crate) use ::tengri_core::*;
pub(crate) use std::fmt::Debug; pub(crate) use std::fmt::Debug;
pub(crate) use std::sync::Arc; pub(crate) use std::sync::Arc;
pub(crate) use std::collections::VecDeque; pub(crate) use std::collections::VecDeque;
pub(crate) use std::path::Path;
pub(crate) use std::fs::exists;
pub(crate) use konst::iter::{ConstIntoIter, IsIteratorKind}; pub(crate) use konst::iter::{ConstIntoIter, IsIteratorKind};
pub(crate) use konst::string::{split_at, str_range, char_indices}; pub(crate) use konst::string::{split_at, str_range, char_indices};
pub(crate) use thiserror::Error; pub(crate) use thiserror::Error;

5
editor/Cargo.toml Normal file
View file

@ -0,0 +1,5 @@
[package]
name = "tengri_editor"
description = "Embeddable editor for Tengri DSL."
version = { workspace = true }
edition = { workspace = true }

View file

@ -1,11 +1,22 @@
use crate::*; use crate::*;
/// A collection of input bind. /// A collection of input bindings.
/// ///
/// Each contained layer defines a mapping from input event to command invocation /// Each contained layer defines a mapping from input event to command invocation
/// over a given state. Furthermore, each layer may have an associated cond, /// over a given state. Furthermore, each layer may have an associated cond,
/// so that only certain layers are active at a given time depending on state. /// so that only certain layers are active at a given time depending on state.
#[derive(Debug, Default)] pub struct InputMap<I, T: Dsl>(std::collections::BTreeMap<I, T>); #[derive(Debug, Default)] pub struct InputMap<I, T: Dsl>(
impl<I, T: Dsl> InputMap<I, T> { /// Map of input event (key combination) to
/// all command expressions bound to it by
/// all loaded input layers.
pub BTreeMap<I, Vec<InputBinding<T>>>
);
#[derive(Debug, Default)] pub struct InputBinding<T: Dsl> {
condition: Option<T>,
command: T,
description: Option<Arc<str>>,
source: Option<Arc<PathBuf>>,
}
impl<I: Debug + Ord, T: Dsl> InputMap<I, T> {
/// Create input layer collection from path to text file. /// Create input layer collection from path to text file.
pub fn from_path <P: Debug + AsRef<Path>> (path: P) -> Usually<Self> { pub fn from_path <P: Debug + AsRef<Path>> (path: P) -> Usually<Self> {
if !exists(path.as_ref())? { if !exists(path.as_ref())? {
@ -18,29 +29,38 @@ impl<I, T: Dsl> InputMap<I, T> {
Self::from_dsl(CstIter::from(source.as_ref())) Self::from_dsl(CstIter::from(source.as_ref()))
} }
/// Create input layer collection from DSL. /// Create input layer collection from DSL.
pub fn from_dsl (dsl: impl Dsl) -> Usually<Self> { pub fn from_dsl <D: Dsl> (dsl: D) -> Usually<Self> {
use DslVal::*; use DslVal::*;
let mut input_map: Self = Self(Default::default()); let mut input_map: BTreeMap<I, Vec<InputBinding<T>>> = Default::default();
while let Exp(_, mut exp) = dsl.val() { let mut index = 0;
while let Some(Exp(_, mut exp)) = dsl.nth(index) {
let val = exp.nth(0).map(|x|x.val()); let val = exp.nth(0).map(|x|x.val());
match val { match val {
Some(Str(path)) => { Some(Str(path)) => {
let path = PathBuf::from(path.as_ref()); let path = PathBuf::from(path.as_ref());
let module = InputMap::<I, T>::from_path(&path)?; let module = InputMap::<I, T>::from_path(&path)?;
for (key, val) in module.0.into_iter() { for (key, val) in module.0.into_iter() {
todo!("import {exp:?} {key:?} {val:?} {path:?}");
if !input_map.contains_key(&key) {
input_map.insert(key, vec![]);
}
} }
}, },
Some(Exp(_, expr)) if let Some(Sym(sym)) = expr.nth(0) => { Some(Sym(sym)) => {
//input_map.unconditional.push(expr); //let key: I = sym.into();
todo!("binding"); //if !input_map.contains_key(&key) {
//input_map.insert(key, vec![]);
//}
todo!("binding {exp:?} {sym:?}");
}, },
Some(Exp(_, expr)) if let Some(Key(key)) = expr.nth(0) && key.as_ref() == "if" => { Some(Key(key)) if key.as_ref() == "if" => {
todo!("conditional binding"); todo!("conditional binding {exp:?} {key:?}");
}, },
_ => return Result::Err(format!("invalid token in keymap: {val:?}").into()), _ => return Result::Err(format!("invalid token in keymap: {val:?}").into()),
} }
index += 1;
} }
Ok(input_map) Ok(Self(input_map))
} }
/// Evaluate the active layers for a given state, /// Evaluate the active layers for a given state,
/// returning the command to be executed, if any. /// returning the command to be executed, if any.

View file

@ -2,7 +2,8 @@
#![feature(if_let_guard)] #![feature(if_let_guard)]
pub(crate) use std::fmt::Debug; pub(crate) use std::fmt::Debug;
pub(crate) use std::collections::BTreeMap; pub(crate) use std::sync::Arc;
pub(crate) use std::collections::{BTreeMap, HashMap};
pub(crate) use std::path::{Path, PathBuf}; pub(crate) use std::path::{Path, PathBuf};
pub(crate) use std::fs::exists; pub(crate) use std::fs::exists;
pub(crate) use tengri_core::*; pub(crate) use tengri_core::*;

View file

@ -1,9 +1,15 @@
use crate::*; use crate::*;
use crate::{dsl::*, input::*, tui::TuiIn}; use crate::{dsl::*, input::*, tui::TuiIn};
use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState}; use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState};
use std::cmp::Ordering;
#[test] fn test_subcommand () -> Usually<()> { #[test] fn test_subcommand () -> Usually<()> {
struct Test { keys: InputMap<(), Ast> } #[derive(Debug)] struct Event(crossterm::event::Event);
impl Eq for Event {}
impl PartialEq for Event { fn eq (&self, other: &Self) -> bool { todo!() } }
impl Ord for Event { fn cmp (&self, other: &Self) -> Ordering { todo!() } }
impl PartialOrd for Event { fn partial_cmp (&self, other: &Self) -> Option<Ordering> { None } }
struct Test { keys: InputMap<Event, Ast> }
handle!(TuiIn: |self: Test, input|Ok(None));/*if let Some(command) = self.keys.command(self, input) { handle!(TuiIn: |self: Test, input|Ok(None));/*if let Some(command) = self.keys.command(self, input) {
Ok(Some(true)) Ok(Some(true))

View file

@ -8,13 +8,13 @@ pub struct TuiIn(
/// Exit flag /// Exit flag
pub Arc<AtomicBool>, pub Arc<AtomicBool>,
/// Input event /// Input event
pub Event, pub crossterm::event::Event,
); );
impl Input for TuiIn { impl Input for TuiIn {
type Event = Event; type Event = crossterm::event::Event;
type Handled = bool; type Handled = bool;
fn event (&self) -> &Event { &self.1 } fn event (&self) -> &crossterm::event::Event { &self.1 }
fn is_done (&self) -> bool { self.0.fetch_and(true, Relaxed) } fn is_done (&self) -> bool { self.0.fetch_and(true, Relaxed) }
fn done (&self) { self.0.store(true, Relaxed); } fn done (&self) { self.0.store(true, Relaxed); }
} }