Parse remap action

This commit is contained in:
Takashi Kokubun 2021-12-17 22:41:29 -08:00
parent 689ad59163
commit db1c9f5600
No known key found for this signature in database
GPG Key ID: 6FFC433B12EE23DD
6 changed files with 136 additions and 19 deletions

View File

@ -33,6 +33,10 @@ keymap:
# SKK hack for Chrome
C-j: C-m
C-m:
remap:
C-j: a
- name: Default (Nocturn, etc.)
wm_class:
not: [Google-chrome, Slack, Gnome-terminal, jetbrains-idea]

View File

@ -1,18 +1,78 @@
use crate::config::keypress::KeyPress;
use crate::config::keypress::{parse_keypress, KeyPress};
use std::collections::HashMap;
use serde::Deserialize;
use crate::config::actions::Actions;
use serde::de;
use serde::de::{MapAccess, Visitor};
use serde::{Deserialize, Deserializer};
use std::fmt::{Debug, Formatter};
#[derive(Deserialize)]
#[serde(untagged)]
#[derive(Debug)]
pub enum Action {
KeyPress(KeyPress),
Remap(HashMap<KeyPress, Vec<Action>>),
}
impl Debug for Action {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Action::KeyPress(key_press) => key_press.fmt(f),
impl<'de> Deserialize<'de> for Action {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct ActionVisitor;
impl<'de> Visitor<'de> for ActionVisitor {
type Value = Action;
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("string or map")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let keypress = parse_keypress(value).map_err(de::Error::custom)?;
Ok(Action::KeyPress(keypress))
}
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let key = map.next_key::<String>()?;
let action = match key.as_deref() {
Some("remap") => {
let mut action: HashMap<KeyPress, Vec<Action>> = HashMap::new();
let remap = map.next_value::<HashMap<KeyPress, Actions>>()?;
for (keypress, actions) in remap.into_iter() {
let actions = match actions {
Actions::Action(action) => vec![action],
Actions::Actions(actions) => actions,
};
action.insert(keypress, actions);
}
Action::Remap(action)
}
Some(action) => {
return serde_error::<Self::Value, M>(&format!(
"unexpected action '{}'",
action
))
}
None => return serde_error::<Self::Value, M>("missing action"),
};
Ok(action)
}
}
deserializer.deserialize_any(ActionVisitor)
}
}
fn serde_error<'de, V, M>(message: &str) -> Result<V, M::Error>
where
M: MapAccess<'de>,
{
let error: Box<dyn std::error::Error> = message.into();
Err(error).map_err(de::Error::custom)
}

57
src/config/actions.rs Normal file
View File

@ -0,0 +1,57 @@
use crate::config::action::Action;
use crate::config::keypress::parse_keypress;
use serde::de;
use serde::de::{value, MapAccess, SeqAccess, Visitor};
use serde::{Deserialize, Deserializer};
use std::fmt::Formatter;
// Used only for deserializing Vec<Action>
pub enum Actions {
Action(Action),
Actions(Vec<Action>),
}
impl<'de> Deserialize<'de> for Actions {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct ActionsVisitor;
impl<'de> Visitor<'de> for ActionsVisitor {
type Value = Actions;
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("strings or maps")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let keypress = parse_keypress(value).map_err(de::Error::custom)?;
Ok(Actions::Action(Action::KeyPress(keypress)))
}
fn visit_seq<S>(self, seq: S) -> Result<Self::Value, S::Error>
where
S: SeqAccess<'de>,
{
let actions: Vec<Action> =
Deserialize::deserialize(value::SeqAccessDeserializer::new(seq))?;
Ok(Actions::Actions(actions))
}
fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let action: Action =
Deserialize::deserialize(value::MapAccessDeserializer::new(map))?;
Ok(Actions::Action(action))
}
}
deserializer.deserialize_any(ActionsVisitor)
}
}

View File

@ -1,10 +1,12 @@
use crate::config::action::Action;
use crate::config::actions::Actions;
use crate::config::keypress::KeyPress;
use crate::config::wm_class::WMClass;
use serde::de::{MapAccess, Visitor};
use serde::{Deserialize, Deserializer};
use std::collections::HashMap;
use std::fmt;
use std::fmt::Formatter;
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
@ -21,17 +23,10 @@ where
{
struct KeymapRemap;
#[derive(Deserialize)]
#[serde(untagged)]
enum Actions {
Action(Action),
Actions(Vec<Action>),
}
impl<'de> Visitor<'de> for KeymapRemap {
type Value = HashMap<KeyPress, Vec<Action>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("map from string to strings or maps")
}

View File

@ -33,10 +33,10 @@ impl<'de> Deserialize<'de> for KeyPress {
type Value = KeyPress;
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("string or map")
formatter.write_str("string")
}
fn visit_str<E>(self, value: &str) -> Result<KeyPress, E>
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
@ -48,7 +48,7 @@ impl<'de> Deserialize<'de> for KeyPress {
}
}
fn parse_keypress(input: &str) -> Result<KeyPress, Box<dyn error::Error>> {
pub fn parse_keypress(input: &str) -> Result<KeyPress, Box<dyn error::Error>> {
let keys: Vec<&str> = input.split("-").collect();
if let Some((key, modifiers)) = keys.split_last() {
let mut shift = false;

View File

@ -1,4 +1,5 @@
mod action;
mod actions;
mod key;
mod keymap;
mod keypress;