Deserialize and eval Action

This commit is contained in:
Yash Karandikar 2022-07-06 21:47:37 +05:30
parent 1e00746636
commit 296c807c72
3 changed files with 56 additions and 16 deletions

View file

@ -15,6 +15,7 @@
#![allow(dead_code, clippy::module_name_repetitions)]
use crate::msg_listener::Action;
use crate::Result;
use breadx::auto::xproto::KeyButMask;
use serde::{
@ -32,8 +33,9 @@ pub struct XcrabConfig {
gap_size: Option<u16>,
outer_gap_size: Option<u16>,
pub msg: Option<XcrabMsgConfig>,
#[allow(clippy::zero_sized_map_values)] // TODO: Action will be expanded in the future
#[serde(default)]
pub binds: HashMap<Keybind, String>,
pub binds: HashMap<Keybind, Action>,
}
#[derive(Clone, Debug, Deserialize)]
@ -105,6 +107,25 @@ fn get_home() -> Result<String> {
Ok(std::env::var("HOME")?)
}
struct ActionVisitor;
impl<'de> Visitor<'de> for ActionVisitor {
type Value = Action;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid WM action")
}
fn visit_str<E: serde::de::Error>(self, value: &str) -> std::result::Result<Self::Value, E> {
value.parse().map_err(|s| E::custom(s))
}
}
impl<'de> Deserialize<'de> for Action {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
deserializer.deserialize_str(ActionVisitor)
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub struct Keybind {
pub key: char,

View file

@ -41,6 +41,7 @@ pub enum XcrabError {
Io(std::io::Error),
Toml(toml::de::Error),
Var(std::env::VarError),
FromStr(String),
ClientDoesntExist,
}
@ -68,6 +69,12 @@ impl From<std::env::VarError> for XcrabError {
}
}
impl From<String> for XcrabError {
fn from(v: String) -> Self {
Self::FromStr(v)
}
}
lazy_static! {
pub static ref CONFIG: config::XcrabConfig = config::load_file().unwrap_or_default();
}
@ -75,10 +82,11 @@ lazy_static! {
impl Display for XcrabError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Bread(be) => Display::fmt(&be, f)?,
Self::Io(ie) => Display::fmt(&ie, f)?,
Self::Toml(te) => Display::fmt(&te, f)?,
Self::Var(ve) => Display::fmt(&ve, f)?,
Self::Bread(be) => Display::fmt(be, f)?,
Self::Io(ie) => Display::fmt(ie, f)?,
Self::Toml(te) => Display::fmt(te, f)?,
Self::Var(ve) => Display::fmt(ve, f)?,
Self::FromStr(fe) => Display::fmt(fe, f)?,
Self::ClientDoesntExist => Display::fmt("client didn't exist", f)?,
}
@ -212,11 +220,7 @@ async fn process_event<Dpy: AsyncDisplay + ?Sized>(
{
for (&bind, action) in &CONFIG.binds {
if bind.key == c && bind.mods == ev.state {
// TODO: parse action into an enum & match it
if action == "close" {
manager.destroy_focused_client(conn).await?;
return Ok(());
}
action.eval(manager, conn).await?;
}
}
}

View file

@ -55,10 +55,9 @@ pub async fn on_recv<Dpy: AsyncDisplay + ?Sized>(
manager: &mut XcrabWindowManager,
conn: &mut Dpy,
) -> Result<()> {
match &*data {
"close" => manager.destroy_focused_client(conn).await?,
_ => println!("{}", data),
}
let a: Action = data.parse()?;
a.eval(manager, conn).await?;
Ok(())
}
@ -68,18 +67,34 @@ pub enum Action {
Close,
}
impl FromStr for Action {
impl std::str::FromStr for Action {
type Err = String;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
#[allow(clippy::enum_glob_use)]
use Action::*;
let v: Vec<String> = s.split(' ').map(str::to_ascii_lowercase).collect();
let a = match v[0].as_str() {
"close" => Close,
_ => return format!("Unknown action: {}", v[0]),
_ => return Err(format!("Unknown action: {}", v[0])),
};
Ok(a)
}
}
impl Action {
pub async fn eval<Dpy: AsyncDisplay + ?Sized>(
&self,
manager: &mut XcrabWindowManager,
conn: &mut Dpy,
) -> Result<()> {
#[allow(clippy::enum_glob_use)]
use Action::*;
match self {
Close => manager.destroy_focused_client(conn).await?,
}
Ok(())
}
}