From 76ca5be56e4705ab9a7c9001ad54ad201127b784 Mon Sep 17 00:00:00 2001 From: EdenQwQ Date: Sun, 13 Feb 2022 18:22:09 +0800 Subject: [PATCH] [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)]