use std::path::Path;
use crate::binding::ContextualBindings;
use crate::json::LoadJsonError;
pub use crate::binding::Binding;
pub use crate::matcher::InputMatcher;
pub trait Action:
for<'text, 'raw> TryFrom<nojson::RawJsonValue<'text, 'raw>, Error = nojson::JsonParseError>
{
}
#[derive(Debug)]
pub struct BindingConfig<A> {
initial_context: BindingContextName,
setup_action: Option<A>,
contextual_bindings: ContextualBindings<A>,
}
impl<A: Action> BindingConfig<A> {
pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<Self, LoadJsonError> {
crate::json::load_jsonc_file(path, |v| Self::try_from(v))
}
pub fn load_from_str(name: &str, text: &str) -> Result<Self, LoadJsonError> {
crate::json::load_jsonc_str(name, text, |v| Self::try_from(v))
}
pub fn initial_context(&self) -> &BindingContextName {
&self.initial_context
}
pub fn setup_action(&self) -> Option<&A> {
self.setup_action.as_ref()
}
pub fn get_bindings(&self, context: &BindingContextName) -> Option<&[Binding<A>]> {
self.contextual_bindings
.bindings
.get(context)
.map(|bindings| &bindings[..])
}
pub fn all_bindings(&self) -> impl Iterator<Item = (&BindingContextName, &[Binding<A>])> {
self.contextual_bindings
.bindings
.iter()
.map(|(k, v)| (k, &v[..]))
}
}
impl<'text, 'raw, A: Action> TryFrom<nojson::RawJsonValue<'text, 'raw>> for BindingConfig<A> {
type Error = nojson::JsonParseError;
fn try_from(value: nojson::RawJsonValue<'text, 'raw>) -> Result<Self, Self::Error> {
let setup = value.to_member("setup")?.required()?;
Ok(Self {
initial_context: setup.to_member("context")?.required()?.try_into()?,
setup_action: setup.to_member("action")?.map(A::try_from)?,
contextual_bindings: value.to_member("bindings")?.required()?.try_into()?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct BindingContextName(String);
impl BindingContextName {
pub fn new(name: &str) -> Self {
Self(name.to_owned())
}
pub fn get(&self) -> &str {
&self.0
}
}
impl<'text, 'raw> TryFrom<nojson::RawJsonValue<'text, 'raw>> for BindingContextName {
type Error = nojson::JsonParseError;
fn try_from(value: nojson::RawJsonValue<'text, 'raw>) -> Result<Self, Self::Error> {
let name: String = value.try_into()?;
let bindings = value.root().to_member("bindings")?.required()?;
if !bindings
.to_object()?
.any(|(k, _)| k.to_unquoted_string_str().is_ok_and(|k| k == name))
{
return Err(value.invalid("undefined context"));
}
Ok(Self(name))
}
}