Add TOML support to xremap (#404)

* Add TOML support to load_configs()

* Add TOML tests to config/tests.rs

* Add TOML to Cargo.toml

* Move toml tests in src/config/tests.rs to below yaml tests

* Add filename extension checker to config parser

---------

Co-authored-by: Matt Amend <matt.a.amend@gmail.com>
pull/410/head
mattamend 4 months ago committed by GitHub
parent fa6290e2ac
commit 3f1c85def6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

46
Cargo.lock generated

@ -1074,7 +1074,7 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
dependencies = [
"toml",
"toml 0.5.11",
]
[[package]]
@ -1084,7 +1084,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
dependencies = [
"once_cell",
"toml_edit",
"toml_edit 0.19.14",
]
[[package]]
@ -1272,6 +1272,15 @@ dependencies = [
"syn 2.0.28",
]
[[package]]
name = "serde_spanned"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
dependencies = [
"serde",
]
[[package]]
name = "serde_with"
version = "3.4.0"
@ -1529,11 +1538,26 @@ dependencies = [
"serde",
]
[[package]]
name = "toml"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit 0.21.0",
]
[[package]]
name = "toml_datetime"
version = "0.6.3"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
@ -1546,6 +1570,19 @@ dependencies = [
"winnow",
]
[[package]]
name = "toml_edit"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
dependencies = [
"indexmap 2.0.0",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]]
name = "unicode-ident"
version = "1.0.11"
@ -1867,6 +1904,7 @@ dependencies = [
"serde_with",
"serde_yaml",
"swayipc",
"toml 0.8.8",
"wayland-client",
"wayland-protocols-wlr",
"x11rb",

@ -30,6 +30,7 @@ wayland-protocols-wlr = { version = "0.1", features = ["client"], optional = tru
x11rb = { version = "0.13.0", optional = true }
zbus = { version = "1.9.2", optional = true }
hyprland = { version = "0.3.12", optional = true }
toml = "0.8.8"
[features]
gnome = ["zbus"]

@ -12,6 +12,7 @@ pub mod remap;
mod tests;
extern crate serde_yaml;
extern crate toml;
use evdev::Key;
use keymap::Keymap;
@ -52,14 +53,40 @@ pub struct Config {
pub keymap_table: HashMap<Key, Vec<KeymapEntry>>,
}
enum ConfigFiletype {
Yaml,
Toml,
}
fn get_file_ext(filename: &PathBuf) -> ConfigFiletype {
match filename.extension() {
Some(f) => {
if f.to_str().unwrap_or("").to_lowercase() == "toml" {
ConfigFiletype::Toml
} else {
ConfigFiletype::Yaml
}
},
_ => ConfigFiletype::Yaml,
}
}
pub fn load_configs(filenames: &Vec<PathBuf>) -> Result<Config, Box<dyn error::Error>> {
// Assumes filenames is non-empty
let yaml = fs::read_to_string(&filenames[0])?;
let mut config: Config = serde_yaml::from_str(&yaml)?;
let config_contents = fs::read_to_string(&filenames[0])?;
let mut config: Config = match get_file_ext(&filenames[0]) {
ConfigFiletype::Yaml => serde_yaml::from_str(&config_contents)?,
ConfigFiletype::Toml => toml::from_str(&config_contents)?,
};
for filename in &filenames[1..] {
let yaml = fs::read_to_string(&filename)?;
let c: Config = serde_yaml::from_str(&yaml)?;
let config_contents = fs::read_to_string(&filename)?;
let c: Config = match get_file_ext(&filename) {
ConfigFiletype::Yaml => serde_yaml::from_str(&config_contents)?,
ConfigFiletype::Toml => serde_yaml::from_str(&config_contents)?,
};
config.modmap.extend(c.modmap);
config.keymap.extend(c.keymap);
config.virtual_modifiers.extend(c.virtual_modifiers);

@ -1,10 +1,12 @@
use crate::Config;
use indoc::indoc;
use serde_yaml::Error;
extern crate serde_yaml;
extern crate toml;
#[test]
fn test_modmap_basic() {
assert_parse(indoc! {"
fn test_yaml_modmap_basic() {
yaml_assert_parse(indoc! {"
modmap:
- name: Global
remap:
@ -17,8 +19,8 @@ fn test_modmap_basic() {
}
#[test]
fn test_modmap_application() {
assert_parse(indoc! {"
fn test_yaml_modmap_application() {
yaml_assert_parse(indoc! {"
modmap:
- remap:
Alt_L: Ctrl_L
@ -33,8 +35,8 @@ fn test_modmap_application() {
}
#[test]
fn test_modmap_application_regex() {
assert_parse(indoc! {r"
fn test_yaml_modmap_application_regex() {
yaml_assert_parse(indoc! {r"
modmap:
- remap:
Alt_L: Ctrl_L
@ -51,8 +53,8 @@ fn test_modmap_application_regex() {
}
#[test]
fn test_modmap_multi_purpose_key() {
assert_parse(indoc! {"
fn test_yaml_modmap_multi_purpose_key() {
yaml_assert_parse(indoc! {"
modmap:
- remap:
Space:
@ -66,8 +68,8 @@ fn test_modmap_multi_purpose_key() {
"})
}
#[test]
fn test_modmap_multi_purpose_key_multi_key() {
assert_parse(indoc! {"
fn test_yaml_modmap_multi_purpose_key_multi_key() {
yaml_assert_parse(indoc! {"
modmap:
- remap:
Space:
@ -81,16 +83,16 @@ fn test_modmap_multi_purpose_key_multi_key() {
"})
}
#[test]
fn test_virtual_modifiers() {
assert_parse(indoc! {"
fn test_yaml_virtual_modifiers() {
yaml_assert_parse(indoc! {"
virtual_modifiers:
- CapsLock
"})
}
#[test]
fn test_modmap_press_release_key() {
assert_parse(indoc! {r#"
fn test_yaml_modmap_press_release_key() {
yaml_assert_parse(indoc! {r#"
modmap:
- remap:
Space:
@ -100,8 +102,8 @@ fn test_modmap_press_release_key() {
}
#[test]
fn test_keymap_basic() {
assert_parse(indoc! {"
fn test_yaml_keymap_basic() {
yaml_assert_parse(indoc! {"
keymap:
- name: Global
remap:
@ -112,8 +114,8 @@ fn test_keymap_basic() {
}
#[test]
fn test_keymap_lr_modifiers() {
assert_parse(indoc! {"
fn test_yaml_keymap_lr_modifiers() {
yaml_assert_parse(indoc! {"
keymap:
- name: Global
remap:
@ -124,8 +126,8 @@ fn test_keymap_lr_modifiers() {
}
#[test]
fn test_keymap_application() {
assert_parse(indoc! {"
fn test_yaml_keymap_application() {
yaml_assert_parse(indoc! {"
keymap:
- remap:
Alt-Enter: Ctrl-Enter
@ -140,8 +142,8 @@ fn test_keymap_application() {
}
#[test]
fn test_keymap_array() {
assert_parse(indoc! {"
fn test_yaml_keymap_array() {
yaml_assert_parse(indoc! {"
keymap:
- remap:
C-w:
@ -151,8 +153,8 @@ fn test_keymap_array() {
}
#[test]
fn test_keymap_remap() {
assert_parse(indoc! {"
fn test_yaml_keymap_remap() {
yaml_assert_parse(indoc! {"
keymap:
- remap:
C-x:
@ -167,8 +169,8 @@ fn test_keymap_remap() {
}
#[test]
fn test_keymap_launch() {
assert_parse(indoc! {r#"
fn test_yaml_keymap_launch() {
yaml_assert_parse(indoc! {r#"
keymap:
- remap:
KEY_GRAVE:
@ -180,8 +182,8 @@ fn test_keymap_launch() {
}
#[test]
fn test_keymap_mode() {
assert_parse(indoc! {"
fn test_yaml_keymap_mode() {
yaml_assert_parse(indoc! {"
default_mode: insert
keymap:
- mode: insert
@ -198,8 +200,8 @@ fn test_keymap_mode() {
}
#[test]
fn test_keymap_mark() {
assert_parse(indoc! {"
fn test_yaml_keymap_mark() {
yaml_assert_parse(indoc! {"
keymap:
- remap:
C-space: { set_mark: true }
@ -210,8 +212,8 @@ fn test_keymap_mark() {
}
#[test]
fn test_shared_data_anchor() {
assert_parse(indoc! {"
fn test_yaml_shared_data_anchor() {
yaml_assert_parse(indoc! {"
shared:
terminals: &terminals
- Gnome-terminal
@ -231,8 +233,8 @@ fn test_shared_data_anchor() {
#[test]
#[should_panic]
fn test_fail_on_data_outside_of_config_model() {
assert_parse(indoc! {"
fn test_yaml_fail_on_data_outside_of_config_model() {
yaml_assert_parse(indoc! {"
terminals: &terminals
- Gnome-terminal
- Kitty
@ -249,8 +251,287 @@ fn test_fail_on_data_outside_of_config_model() {
"})
}
fn assert_parse(yaml: &str) {
let result: Result<Config, Error> = serde_yaml::from_str(yaml);
#[test]
fn test_toml_modmap_basic() {
toml_assert_parse(indoc! {"
[[modmap]]
name = \"Global\"
[modmap.remap]
Alt_L = \"Ctrl_L\"
[[modmap]]
[modmap.remap]
Shift_R = \"Win_R\"
[modmap.application]
only = \"Google-chrome\"
"})
}
#[test]
fn test_toml_modmap_application() {
toml_assert_parse(indoc! {"
[[modmap]]
[modmap.remap]
Alt_L = \"Ctrl_L\"
[modmap.application]
not = [ \"Gnome-terminal\" ]
[[modmap]]
[modmap.remap]
Shift_R = \"Win_R\"
[modmap.application]
only = \"Google-chrome\"
"})
}
#[test]
fn test_toml_modmap_application_regex() {
toml_assert_parse(indoc! {r#"
[[modmap]]
[modmap.remap]
Alt_L = "Ctrl_L"
[modmap.application]
not = [ "/^Minecraft/", "/^Minecraft\\//", "/^Minecraft\\d/" ]
[[modmap]]
[modmap.remap]
Shift_R = "Win_R"
[modmap.application]
only = "/^Miencraft\\\\/"
"#})
}
#[test]
fn test_toml_modmap_multi_purpose_key() {
toml_assert_parse(indoc! {"
[[modmap]]
[modmap.remap.Space]
held = [ \"Shift_L\" ]
alone = \"Space\"
[[modmap]]
[modmap.remap.Muhenkan]
held = [ \"Alt_L\", \"Shift_L\" ]
alone = [ \"Muhenkan\" ]
alone_timeout_millis = 500
"})
}
#[test]
fn test_toml_modmap_multi_purpose_key_multi_key() {
toml_assert_parse(indoc! {"
[[modmap]]
[modmap.remap.Space]
held = [ \"Shift_L\" ]
alone = [ \"Shift_L\", \"A\" ]
[[modmap]]
[modmap.remap.Muhenkan]
held = [ \"Alt_L\", \"Shift_L\" ]
alone = [ \"Muhenkan\" ]
alone_timeout_millis = 500
"})
}
#[test]
fn test_toml_virtual_modifiers() {
toml_assert_parse(indoc! {"
virtual_modifiers = [ \"CapsLock\" ]
"})
}
#[test]
fn test_toml_modmap_press_release_key() {
toml_assert_parse(indoc! {r#"
[[modmap]]
[modmap.remap.Space.press]
launch = [ "wmctrl", "-x", "-a", "code.Code" ]
[modmap.remap.Space.release]
launch = ["wmctrl", "-x", "-a", "nocturn.Nocturn"]
"#})
}
#[test]
fn test_toml_keymap_basic() {
toml_assert_parse(indoc! {"
[[keymap]]
name = \"Global\"
[keymap.remap]
Alt-Enter = \"Ctrl-Enter\"
[[keymap]]
[keymap.remap]
M-S = \"C-S\"
"})
}
#[test]
fn test_toml_keymap_lr_modifiers() {
toml_assert_parse(indoc! {"
[[keymap]]
name = \"Global\"
[keymap.remap]
Alt_L-Enter = \"Ctrl_L-Enter\"
[[keymap]]
[keymap.remap]
M_R-S = \"C_L-S\"
"})
}
#[test]
fn test_toml_keymap_application() {
toml_assert_parse(indoc! {"
[[keymap]]
[keymap.remap]
Alt-Enter = \"Ctrl-Enter\"
[keymap.application]
not = \"Gnome-terminal\"
[[keymap]]
[keymap.remap]
Alt-S = \"Ctrl-S\"
[keymap.application]
only = \"Gnome-terminal\"
"})
}
#[test]
fn test_toml_keymap_array() {
toml_assert_parse(indoc! {"
[[keymap]]
[keymap.remap]
C-w = [\"Shift-C-w\", \"C-x\"]
"})
}
#[test]
fn test_toml_keymap_remap() {
toml_assert_parse(indoc! {"
[[keymap]]
[keymap.remap.C-x]
timeout_key = \"Down\"
timeout_millis = 1_000
[keymap.remap.C-x.remap]
s = \"C-w\"
[keymap.remap.C-x.remap.C-s.remap]
x = \"C-z\"
"})
}
#[test]
fn test_toml_keymap_launch() {
toml_assert_parse(indoc! {r#"
[[keymap]]
[keymap.remap.KEY_GRAVE]
launch = [ "/bin/sh", "-c", "date > /tmp/hotkey_test" ]
"#})
}
#[test]
fn test_toml_keymap_mode() {
toml_assert_parse(indoc! {"
default_mode = \"insert\"
[[keymap]]
mode = \"instert\"
[keymap.remap.Esc]
set_mode = \"normal\"
[[keymap]]
mode = \"normal\"
[keymap.remap]
h = \"Left\"
j = \"Down\"
k = \"Up\"
l = \"Right\"
[keymap.remap.i]
set_mode = \"insert\"
"})
}
#[test]
fn test_toml_keymap_mark() {
toml_assert_parse(indoc! {"
[[keymap]]
[keymap.remap]
C-g = [ \"esc\", { set_mark = false } ]
[keymap.remap.C-space]
set_mark = true
[keymap.remap.C-b]
with_mark = \"left\"
[keymap.remap.M-b]
with_mark = \"C-left\"
"})
}
#[test]
fn test_toml_shared_data_anchor() {
toml_assert_parse(indoc! {"
[shared]
terminals = [ \"Gnome-terminal\", \"Kitty\" ]
[[shared.modmap]]
[shared.modmap.remap]
Alt_L = \"Ctrl_L\"
[shared.modmap.application]
not = \"terminals\"
[[shared.modmap]]
[shared.modmap.remap]
Shift_R = \"Win_R\"
[shared.modmap.application]
only = \"Google-chrome\"
"})
}
#[test]
#[should_panic]
fn test_toml_fail_on_data_outside_of_config_model() {
toml_assert_parse(indoc! {"
terminals = [ \"Gnome-terminal\", \"Kitty\" ]
[[modmap]]
[modmap.remap]
Alt_L = \"Ctrl_L\"
[modmap.application]
not = [ \"Gnome-terminal\", \"Kitty\" ]
[[modmap]]
[modmap.remap]
Shift_R = \"Win_R\"
[modmap.application]
only = \"Google-chrome\"
"})
}
fn toml_assert_parse(toml: &str) {
let result: Result<Config, toml::de::Error> = toml::from_str(toml);
if let Err(e) = result {
panic!("{}", e)
}
}
fn yaml_assert_parse(yaml: &str) {
let result: Result<Config, serde_yaml::Error> = serde_yaml::from_str(yaml);
if let Err(e) = result {
panic!("{}", e)
}

Loading…
Cancel
Save