From 76ca5be56e4705ab9a7c9001ad54ad201127b784 Mon Sep 17 00:00:00 2001 From: EdenQwQ Date: Sun, 13 Feb 2022 18:22:09 +0800 Subject: [PATCH 1/4] [feat] config: support for aliases --- src/config.rs | 85 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 3 deletions(-) diff --git a/src/config.rs b/src/config.rs index 27d2c37..6c3a7ae 100644 --- a/src/config.rs +++ b/src/config.rs @@ -207,12 +207,20 @@ fn parse_contents(contents: String) -> Result, Error> { // as commands, and mark the other lines as keysyms. Mark means storing a line's type and the // line number in a vector. let mut lines_with_types: Vec<(&str, u32)> = Vec::new(); + let mut aliases: Vec<(&str, &str)> = Vec::new(); for (line_number, line) in lines.iter().enumerate() { if line.trim().starts_with('#') || line.trim().is_empty() { continue; } if line.starts_with(' ') || line.starts_with('\t') { lines_with_types.push(("command", line_number as u32)); + } else if line.starts_with("alias ") && line.contains('=') { + // things behind the alias and before the first equal sign are the alias name + // everything behind the first equal sign is the alias value + // store each name and value in aliases + let alias_name = &line[6..line.find('=').unwrap()].trim(); + let alias_value = &line[line.find('=').unwrap() + 1..]; + aliases.push((alias_name, alias_value)); } else { lines_with_types.push(("keysym", line_number as u32)); } @@ -253,7 +261,21 @@ fn parse_contents(contents: String) -> Result, Error> { for (i, item) in actual_lines.iter().enumerate() { let line_type = item.0; let line_number = item.1; - let line = &item.2; + let line = item.2.to_owned(); + // match all the aliases for the line + let match_aliases = |mut line: String| { + for alias in aliases.iter().rev() { + if line.contains(alias.0) { + line.replace_range( + line.find(alias.0).unwrap()..line.find(alias.0).unwrap() + alias.0.len(), + alias.1, + ); + } + } + line + }; + + let line = match_aliases(line.to_owned()); if line_type != "keysym" { continue; @@ -263,13 +285,14 @@ fn parse_contents(contents: String) -> Result, Error> { if next_line.is_none() { break; } - let next_line = next_line.unwrap(); + let mut next_line = next_line.unwrap().to_owned(); + next_line.2 = match_aliases(next_line.2.to_owned()); if next_line.0 != "command" { continue; // this should ignore keysyms that are not followed by a command } - let extracted_keys = extract_curly_brace(line); + let extracted_keys = extract_curly_brace(&line); let extracted_commands = extract_curly_brace(&next_line.2); 'hotkey_parse: for (key, command) in extracted_keys.iter().zip(extracted_commands.iter()) { @@ -1293,6 +1316,62 @@ super + {a-} {firefox, brave}"; eval_invalid_config_test(contents, ParseError::UnknownSymbol(2)) } + + #[test] + fn test_alias() -> std::io::Result<()> { + let contents = " +alias ctal = control + alt +alias pls =doas +ctal + t + pls firefox # why always firefox +alias ctals = ctal + shift +ctals + t + brave"; + eval_config_test( + contents, + vec![ + Hotkey::new( + evdev::Key::KEY_T, + vec![Modifier::Control, Modifier::Alt], + "doas firefox # why always firefox".to_string(), + ), + Hotkey::new( + evdev::Key::KEY_T, + vec![Modifier::Control, Modifier::Alt, Modifier::Shift], + "brave".to_string(), + ), + ], + ) + } + + #[test] + fn test_invalid_alias() -> std::io::Result<()> { + let contents = " +alias ctal = control + alt = +ctal +t + firefox"; + eval_invalid_config_test(contents, ParseError::UnknownSymbol(3)) + } + + #[test] + fn test_not_an_alias() -> std::io::Result<()> { + let contents = " +alias ctal # nothing here +ctal + t + firefox"; + eval_invalid_config_test(contents, ParseError::UnknownSymbol(2)) + } + + #[test] + fn test_alias_comment() -> std::io::Result<()> { + let contents = " +alias ctal = # no inline comment support for alias statement yet. + +# will be '# no inline comment support for alias statement yet. + t' here +ctal + t + firefox"; + eval_invalid_config_test(contents, ParseError::UnknownSymbol(5)) + } } #[cfg(test)] From 467067459c97496adfc2d8fda939875351f49fc2 Mon Sep 17 00:00:00 2001 From: EdenQwQ Date: Sun, 13 Feb 2022 18:40:17 +0800 Subject: [PATCH 2/4] [test] config: test for should work aliases (just to make sure) --- src/config.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/config.rs b/src/config.rs index 88eb9ac..e6d4702 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1372,6 +1372,35 @@ ctal + t firefox"; eval_invalid_config_test(contents, ParseError::UnknownSymbol(5)) } + + #[test] + fn test_longer_alias_example() -> std::io::Result<()> { + let contents = " +# Longer example +alias pls=doas +alias ctal = control + alt +alias ctals = ctal + shift +alias hello = #hello +ctal + f hello + firefox +ctals + b + brave hello"; + eval_config_test( + contents, + vec![ + Hotkey::new( + evdev::Key::KEY_F, + vec![Modifier::Control, Modifier::Alt], + "firefox".to_string(), + ), + Hotkey::new( + evdev::Key::KEY_B, + vec![Modifier::Control, Modifier::Alt, Modifier::Shift], + "brave #hello".to_string(), + ), + ], + ) + } } #[cfg(test)] From ca68cc6cb11f8318198059fd0ccaab8909ca990a Mon Sep 17 00:00:00 2001 From: EdenQwQ Date: Sun, 13 Feb 2022 22:29:46 +0800 Subject: [PATCH 3/4] [update] config: add space key; add support for using '_' as a 'None' --- src/config.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index e6d4702..67bea7b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -137,6 +137,7 @@ fn parse_contents(contents: String) -> Result, Error> { ("return", evdev::Key::KEY_ENTER), ("enter", evdev::Key::KEY_ENTER), ("tab", evdev::Key::KEY_TAB), + ("space", evdev::Key::KEY_SPACE), ("minus", evdev::Key::KEY_MINUS), ("-", evdev::Key::KEY_MINUS), ("equal", evdev::Key::KEY_EQUAL), @@ -324,11 +325,15 @@ fn parse_keybind( mod_to_mod_enum: &HashMap<&str, Modifier>, ) -> Result<(evdev::Key, Vec), Error> { let line = line.split('#').next().unwrap(); - let tokens: Vec = line.split('+').map(|s| s.trim().to_lowercase()).collect(); + let tokens: Vec = + line.split('+').map(|s| s.trim().to_lowercase()).filter(|s| s != "_").collect(); let last_token = tokens.last().unwrap().trim(); // Check if each token is valid for token in &tokens { + if token == "_" { + continue; + } if key_to_evdev_key.contains_key(token.as_str()) { // Can't have a key that's like a modifier if token != last_token { @@ -1401,6 +1406,24 @@ ctals + b ], ) } + + #[test] + fn test_none() -> std::io::Result<()> { + let contents = " +super + {_, shift} + b + {firefox, brave}"; + eval_config_test( + contents, + vec![ + Hotkey::new(evdev::Key::KEY_B, vec![Modifier::Super], "firefox".to_string()), + Hotkey::new( + evdev::Key::KEY_B, + vec![Modifier::Super, Modifier::Shift], + "brave".to_string(), + ), + ], + ) + } } #[cfg(test)] From 53eca2d556652023f5aafd3905e07efe823e66e3 Mon Sep 17 00:00:00 2001 From: Eden <62473844+EdenQwQ@users.noreply.github.com> Date: Sun, 13 Feb 2022 22:49:56 +0800 Subject: [PATCH 4/4] [remove] config: remove unnecessary check I'm literally pushing this commit on my phone lol --- src/config.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/config.rs b/src/config.rs index 67bea7b..5886ef4 100644 --- a/src/config.rs +++ b/src/config.rs @@ -331,9 +331,6 @@ fn parse_keybind( // Check if each token is valid for token in &tokens { - if token == "_" { - continue; - } if key_to_evdev_key.contains_key(token.as_str()) { // Can't have a key that's like a modifier if token != last_token {