style: format config.rs using rust-analyzer

main
Angelo Fallaria 2 years ago
parent b47904b3f3
commit cffd1694d1

@ -1,14 +1,14 @@
use std::{path, fs};
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::collections::HashMap;
use std::{fs, path};
#[derive(Debug)]
pub enum Error {
ConfigNotFound,
Io(std::io::Error),
InvalidConfig(ParseError)
InvalidConfig(ParseError),
}
#[derive(Debug)]
@ -16,7 +16,7 @@ pub enum ParseError {
// u32 is the line number where an error occured
UnknownSymbol(u32),
MissingCommand(u32),
CommandWithoutWhitespace(u32)
CommandWithoutWhitespace(u32),
}
impl From<std::io::Error> for Error {
@ -32,15 +32,12 @@ impl From<std::io::Error> for Error {
#[derive(Debug)]
pub struct Hotkey {
keysyms: Vec<evdev::Key>,
command: String
command: String,
}
impl Hotkey {
fn new(keysyms: Vec<evdev::Key>, command: String) -> Self {
Hotkey {
keysyms,
command
}
Hotkey { keysyms, command }
}
}
@ -49,8 +46,7 @@ pub fn load(path: path::PathBuf) -> Result<Vec<Hotkey>, Error> {
parse_contents(file_contents)
}
fn load_file_contents(path: path::PathBuf)
-> Result<String, Error> {
fn load_file_contents(path: path::PathBuf) -> Result<String, Error> {
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
@ -59,28 +55,42 @@ fn load_file_contents(path: path::PathBuf)
fn parse_contents(contents: String) -> Result<Vec<Hotkey>, Error> {
let key_to_evdev_key: HashMap<&str, evdev::Key> = HashMap::from([
("q", evdev::Key::KEY_Q), ("w", evdev::Key::KEY_W),
("e", evdev::Key::KEY_E), ("r", evdev::Key::KEY_R),
("t", evdev::Key::KEY_T), ("y", evdev::Key::KEY_Y),
("u", evdev::Key::KEY_U), ("i", evdev::Key::KEY_I),
("o", evdev::Key::KEY_O), ("p", evdev::Key::KEY_P),
("a", evdev::Key::KEY_A), ("s", evdev::Key::KEY_S),
("d", evdev::Key::KEY_D), ("f", evdev::Key::KEY_F),
("g", evdev::Key::KEY_G), ("h", evdev::Key::KEY_H),
("j", evdev::Key::KEY_J), ("k", evdev::Key::KEY_K),
("q", evdev::Key::KEY_Q),
("w", evdev::Key::KEY_W),
("e", evdev::Key::KEY_E),
("r", evdev::Key::KEY_R),
("t", evdev::Key::KEY_T),
("y", evdev::Key::KEY_Y),
("u", evdev::Key::KEY_U),
("i", evdev::Key::KEY_I),
("o", evdev::Key::KEY_O),
("p", evdev::Key::KEY_P),
("a", evdev::Key::KEY_A),
("s", evdev::Key::KEY_S),
("d", evdev::Key::KEY_D),
("f", evdev::Key::KEY_F),
("g", evdev::Key::KEY_G),
("h", evdev::Key::KEY_H),
("j", evdev::Key::KEY_J),
("k", evdev::Key::KEY_K),
("l", evdev::Key::KEY_L),
("z", evdev::Key::KEY_Z), ("x", evdev::Key::KEY_X),
("c", evdev::Key::KEY_C), ("v", evdev::Key::KEY_V),
("b", evdev::Key::KEY_B), ("n", evdev::Key::KEY_N),
("z", evdev::Key::KEY_Z),
("x", evdev::Key::KEY_X),
("c", evdev::Key::KEY_C),
("v", evdev::Key::KEY_V),
("b", evdev::Key::KEY_B),
("n", evdev::Key::KEY_N),
("m", evdev::Key::KEY_M),
("1", evdev::Key::KEY_1), ("2", evdev::Key::KEY_2),
("3", evdev::Key::KEY_3), ("4", evdev::Key::KEY_4),
("5", evdev::Key::KEY_5), ("6", evdev::Key::KEY_6),
("7", evdev::Key::KEY_7), ("8", evdev::Key::KEY_8),
("9", evdev::Key::KEY_9), ("0", evdev::Key::KEY_0),
("1", evdev::Key::KEY_1),
("2", evdev::Key::KEY_2),
("3", evdev::Key::KEY_3),
("4", evdev::Key::KEY_4),
("5", evdev::Key::KEY_5),
("6", evdev::Key::KEY_6),
("7", evdev::Key::KEY_7),
("8", evdev::Key::KEY_8),
("9", evdev::Key::KEY_9),
("0", evdev::Key::KEY_0),
]);
let lines: Vec<&str> = contents.split("\n").collect();
@ -96,9 +106,7 @@ fn parse_contents(contents: String) -> Result<Vec<Hotkey>, Error> {
}
// Ignore blank lines and comments starting with #
if lines[i].trim().is_empty() ||
lines[i].trim().starts_with("#")
{
if lines[i].trim().is_empty() || lines[i].trim().starts_with("#") {
continue;
}
@ -110,12 +118,10 @@ fn parse_contents(contents: String) -> Result<Vec<Hotkey>, Error> {
let mut key_presses: Vec<evdev::Key> = Vec::new();
if key_to_evdev_key.contains_key(lines[i].trim()) {
// If the keybind line is at the very last line,
// it's impossible for there to be a command
if i >= lines.len() - 1 {
return Err(Error::InvalidConfig(
ParseError::MissingCommand(real_line_no)));
return Err(Error::InvalidConfig(ParseError::MissingCommand(real_line_no)));
}
// Translate keypress into evdev key
@ -125,8 +131,7 @@ fn parse_contents(contents: String) -> Result<Vec<Hotkey>, Error> {
//// Find the command
if lines[i + 1].trim().is_empty() {
return Err(Error::InvalidConfig(
ParseError::MissingCommand(real_line_no)));
return Err(Error::InvalidConfig(ParseError::MissingCommand(real_line_no)));
}
let command = lines[i + 1].trim();
@ -137,14 +142,11 @@ fn parse_contents(contents: String) -> Result<Vec<Hotkey>, Error> {
// Skip trying to parse the next line (command)
// because we already dealt with it
lines_to_skip += 1;
} else {
return Err(Error::InvalidConfig(
ParseError::UnknownSymbol(real_line_no)));
return Err(Error::InvalidConfig(ParseError::UnknownSymbol(real_line_no)));
}
}
// If all is ok, return Vec<Hotkeys>
return Ok(hotkeys);
}
@ -157,14 +159,12 @@ mod tests {
// so that the test file will be automatically removed
// no matter how the test goes
struct TestPath {
path: path::PathBuf
path: path::PathBuf,
}
impl TestPath {
fn new(path: &str) -> Self {
TestPath {
path: path::PathBuf::from(path)
}
TestPath { path: path::PathBuf::from(path) }
}
// Create a path method for a more succinct way
@ -191,7 +191,7 @@ mod tests {
match result.unwrap_err() {
Error::ConfigNotFound => {
return;
},
}
_ => {
panic!("Error type for nonexistent file is wrong.");
}
@ -203,12 +203,14 @@ mod tests {
let setup = TestPath::new("/tmp/swhkd-test-file1");
// Build a dummy file in /tmp
let mut f = File::create(setup.path())?;
f.write_all(b"
f.write_all(
b"
x
dmenu_run
q
bspc node -q")?;
bspc node -q",
)?;
let result = load_file_contents(setup.path());
assert!(result.is_ok());
@ -223,8 +225,7 @@ r
alacritty
";
let expected_hotkey = Hotkey::new(vec![evdev::Key::KEY_R],
String::from("alacritty"));
let expected_hotkey = Hotkey::new(vec![evdev::Key::KEY_R], String::from("alacritty"));
let parse_result = parse_contents(contents.to_string());
@ -232,11 +233,9 @@ r
let parse_result = parse_result.unwrap();
assert_eq!(parse_result[0].keysyms,
expected_hotkey.keysyms);
assert_eq!(parse_result[0].keysyms, expected_hotkey.keysyms);
assert_eq!(parse_result[0].command,
expected_hotkey.command);
assert_eq!(parse_result[0].command, expected_hotkey.command);
Ok(())
}
@ -254,12 +253,9 @@ t
/bin/firefox
";
let hotkey_1 = Hotkey::new(vec![evdev::Key::KEY_R],
String::from("alacritty"));
let hotkey_2 = Hotkey::new(vec![evdev::Key::KEY_W],
String::from("kitty"));
let hotkey_3 = Hotkey::new(vec![evdev::Key::KEY_T],
String::from("/bin/firefox"));
let hotkey_1 = Hotkey::new(vec![evdev::Key::KEY_R], String::from("alacritty"));
let hotkey_2 = Hotkey::new(vec![evdev::Key::KEY_W], String::from("kitty"));
let hotkey_3 = Hotkey::new(vec![evdev::Key::KEY_T], String::from("/bin/firefox"));
let result = parse_contents(contents.to_string());
assert!(result.is_ok());
@ -289,10 +285,8 @@ w
";
let expected_keybinds = vec![
Hotkey::new(vec![evdev::Key::KEY_R],
String::from("alacritty")),
Hotkey::new(vec![evdev::Key::KEY_W],
String::from("kitty")),
Hotkey::new(vec![evdev::Key::KEY_R], String::from("alacritty")),
Hotkey::new(vec![evdev::Key::KEY_W], String::from("kitty")),
];
let result = parse_contents(contents.to_string());
@ -317,11 +311,9 @@ super + 5
";
let expected_keybinds = vec![
// I don't know if the super key is macro or not,
// please check
Hotkey::new(vec![evdev::Key::KEY_MACRO, evdev::Key::KEY_5],
String::from("alacritty")),
Hotkey::new(vec![evdev::Key::KEY_MACRO, evdev::Key::KEY_5], String::from("alacritty")),
];
let result = parse_contents(contents.to_string());
@ -341,10 +333,10 @@ p
xbacklight -inc 10 -fps 30 -time 200
";
let expected_keybinds = vec![
Hotkey::new(vec![evdev::Key::KEY_P],
String::from("xbacklight -inc 10 -fps 30 -time 200")),
];
let expected_keybinds = vec![Hotkey::new(
vec![evdev::Key::KEY_P],
String::from("xbacklight -inc 10 -fps 30 -time 200"),
)];
let result = parse_contents(contents.to_string());
assert!(result.is_ok());
@ -378,10 +370,12 @@ pesto
if line_nr == 5 {
return Ok(());
} else {
panic!("{}", format!("Error line is wrong, expected 4 but actual: {}",
line_nr));
panic!(
"{}",
format!("Error line is wrong, expected 4 but actual: {}", line_nr)
);
}
},
}
_ => {
panic!("Error type is not Unknown Symbol");
}
@ -404,41 +398,49 @@ brave
let config_error = match result {
Ok(_) => panic!(
" Commands without whitespaces at the start are invalid.
" Commands without whitespaces at the start are invalid.
But the config parser still accepts commands without whitespaces.
The invalid file:
```
{}
``` ", contents),
Err(config_error) => {
config_error
}
``` ",
contents
),
Err(config_error) => config_error,
};
let parse_error = match config_error {
Error::InvalidConfig(parse_error) => parse_error,
other_error => panic!("The Error enum type for a command without starting whitespace
is expected to be InvalidConfig, but it is instead {:?}", other_error)
other_error => panic!(
"The Error enum type for a command without starting whitespace
is expected to be InvalidConfig, but it is instead {:?}",
other_error
),
};
let line_number = match parse_error {
ParseError::CommandWithoutWhitespace(line_nr) => line_nr,
other_error => panic!("The ParseError enum type for a command without starting whitespaces
is expected to be CommandWithoutWhitespace, but it is instead {:?}", other_error)
other_error => panic!(
"The ParseError enum type for a command without starting whitespaces
is expected to be CommandWithoutWhitespace, but it is instead {:?}",
other_error
),
};
if line_number == 5 {
Ok(())
} else {
panic!("The line number returned for the no-whitespace error is expected to be 5,
panic!(
"The line number returned for the no-whitespace error is expected to be 5,
but what was returned was {}.
Invalid config file:
```
{}
```", line_number, contents)
```",
line_number, contents
)
}
}
@ -472,24 +474,49 @@ w
#[test]
fn test_all_alphanumeric() -> std::io::Result<()> {
let symbols: [&str; 36] = ["a", "b", "c", "d", "e", "f", "g",
"h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
"s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2",
"3", "4", "5", "6", "7", "8", "9"];
let symbols: [&str; 36] = [
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q",
"r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7",
"8", "9",
];
let keysyms: [evdev::Key; 36] = [
evdev::Key::KEY_A, evdev::Key::KEY_B, evdev::Key::KEY_C,
evdev::Key::KEY_D, evdev::Key::KEY_E, evdev::Key::KEY_F,
evdev::Key::KEY_G, evdev::Key::KEY_H, evdev::Key::KEY_I,
evdev::Key::KEY_J, evdev::Key::KEY_K, evdev::Key::KEY_L,
evdev::Key::KEY_M, evdev::Key::KEY_N, evdev::Key::KEY_O,
evdev::Key::KEY_P, evdev::Key::KEY_Q, evdev::Key::KEY_R,
evdev::Key::KEY_S, evdev::Key::KEY_T, evdev::Key::KEY_U,
evdev::Key::KEY_V, evdev::Key::KEY_W, evdev::Key::KEY_X,
evdev::Key::KEY_Y, evdev::Key::KEY_Z, evdev::Key::KEY_0,
evdev::Key::KEY_1, evdev::Key::KEY_2, evdev::Key::KEY_3,
evdev::Key::KEY_4, evdev::Key::KEY_5, evdev::Key::KEY_6,
evdev::Key::KEY_7, evdev::Key::KEY_8, evdev::Key::KEY_9,
evdev::Key::KEY_A,
evdev::Key::KEY_B,
evdev::Key::KEY_C,
evdev::Key::KEY_D,
evdev::Key::KEY_E,
evdev::Key::KEY_F,
evdev::Key::KEY_G,
evdev::Key::KEY_H,
evdev::Key::KEY_I,
evdev::Key::KEY_J,
evdev::Key::KEY_K,
evdev::Key::KEY_L,
evdev::Key::KEY_M,
evdev::Key::KEY_N,
evdev::Key::KEY_O,
evdev::Key::KEY_P,
evdev::Key::KEY_Q,
evdev::Key::KEY_R,
evdev::Key::KEY_S,
evdev::Key::KEY_T,
evdev::Key::KEY_U,
evdev::Key::KEY_V,
evdev::Key::KEY_W,
evdev::Key::KEY_X,
evdev::Key::KEY_Y,
evdev::Key::KEY_Z,
evdev::Key::KEY_0,
evdev::Key::KEY_1,
evdev::Key::KEY_2,
evdev::Key::KEY_3,
evdev::Key::KEY_4,
evdev::Key::KEY_5,
evdev::Key::KEY_6,
evdev::Key::KEY_7,
evdev::Key::KEY_8,
evdev::Key::KEY_9,
];
let mut contents = String::new();
@ -570,30 +597,31 @@ super + minus
let expected_result: Vec<Hotkey> = vec![
Hotkey::new(
vec![evdev::Key::KEY_LEFTMETA,
evdev::Key::KEY_ESC],
String::from("pkill -USR1 -x sxhkd ; sxhkd &")),
vec![evdev::Key::KEY_LEFTMETA, evdev::Key::KEY_ESC],
String::from("pkill -USR1 -x sxhkd ; sxhkd &"),
),
Hotkey::new(
vec![evdev::Key::KEY_LEFTMETA,
evdev::Key::KEY_ENTER],
String::from("alacritty -t \"Terminal\" -e \"$HOME/.config/sxhkd/new_tmux_terminal.sh\"")),
vec![evdev::Key::KEY_LEFTMETA, evdev::Key::KEY_ENTER],
String::from(
"alacritty -t \"Terminal\" -e \"$HOME/.config/sxhkd/new_tmux_terminal.sh\"",
),
),
Hotkey::new(
vec![evdev::Key::KEY_LEFTMETA,
evdev::Key::KEY_LEFTSHIFT,
evdev::Key::KEY_ENTER],
String::from("alacritty -t \"Terminal\"")),
vec![evdev::Key::KEY_LEFTMETA, evdev::Key::KEY_LEFTSHIFT, evdev::Key::KEY_ENTER],
String::from("alacritty -t \"Terminal\""),
),
Hotkey::new(
vec![evdev::Key::KEY_LEFTALT,
evdev::Key::KEY_ENTER],
String::from("alacritty -t \"Terminal\" -e \"tmux\"")),
vec![evdev::Key::KEY_LEFTALT, evdev::Key::KEY_ENTER],
String::from("alacritty -t \"Terminal\" -e \"tmux\""),
),
Hotkey::new(
vec![evdev::Key::KEY_LEFTCTRL,
evdev::Key::KEY_0],
String::from("play-song.sh")),
vec![evdev::Key::KEY_LEFTCTRL, evdev::Key::KEY_0],
String::from("play-song.sh"),
),
Hotkey::new(
vec![evdev::Key::KEY_LEFTMETA,
evdev::Key::KEY_MINUS],
String::from("play-song.sh album")),
vec![evdev::Key::KEY_LEFTMETA, evdev::Key::KEY_MINUS],
String::from("play-song.sh album"),
),
];
let real_result = parse_contents(contents.to_string());
@ -605,10 +633,8 @@ super + minus
assert_eq!(real_result.len(), expected_result.len());
for i in 0..real_result.len() {
assert_eq!(real_result[i].keysyms,
expected_result[i].keysyms);
assert_eq!(real_result[i].command,
expected_result[i].command);
assert_eq!(real_result[i].keysyms, expected_result[i].keysyms);
assert_eq!(real_result[i].command, expected_result[i].command);
}
Ok(())
@ -624,8 +650,8 @@ k
let expected_keybind = Hotkey::new(
vec![evdev::Key::KEY_K],
String::from("mpc ls | dmenu | sed -i 's/foo/bar/g'")
);
String::from("mpc ls | dmenu | sed -i 's/foo/bar/g'"),
);
let real_keybind = parse_contents(contents.to_string());
@ -656,45 +682,67 @@ k
// TODO: Write these tests as needed.
#[ignore]
fn test_homerow_special_keys() -> std::io::Result<()> {Ok(())}
fn test_homerow_special_keys() -> std::io::Result<()> {
Ok(())
}
#[ignore]
fn test_numrow_special_keys() -> std::io::Result<()> {Ok(())}
fn test_numrow_special_keys() -> std::io::Result<()> {
Ok(())
}
#[ignore]
fn test_all_modifier_keys() -> std::io::Result<()> {Ok(())}
fn test_all_modifier_keys() -> std::io::Result<()> {
Ok(())
}
#[ignore]
fn test_mod_keys_after_normal_keys() -> std::io::Result<()> {Ok(())}
fn test_mod_keys_after_normal_keys() -> std::io::Result<()> {
Ok(())
}
#[ignore]
fn test_plus_at_start_and_end_of_keybind() -> std::io::Result<()> {Ok(())}
fn test_plus_at_start_and_end_of_keybind() -> std::io::Result<()> {
Ok(())
}
// Bracket expansion example:
// `super + ctrl + {h,j,k,l}`
// ` bspc node -p {westh,south,north,west}`
#[ignore]
fn test_bracket_expansion() -> std::io::Result<()> {Ok(())}
fn test_bracket_expansion() -> std::io::Result<()> {
Ok(())
}
// `super + {1-9}`
// ` bspc desktop -f '^{1-9}'`
#[ignore]
fn test_bracket_expansion_numbers() -> std::io::Result<()> {Ok(())}
fn test_bracket_expansion_numbers() -> std::io::Result<()> {
Ok(())
}
#[ignore]
fn test_unclosed_bracket_in_binding() -> std::io::Result<()> {Ok(())}
fn test_unclosed_bracket_in_binding() -> std::io::Result<()> {
Ok(())
}
#[ignore]
fn test_bracket_in_binding_but_not_in_command()
-> std::io::Result<()> {Ok(())}
fn test_bracket_in_binding_but_not_in_command() -> std::io::Result<()> {
Ok(())
}
#[ignore]
fn test_bracket_non_matching_counts() -> std::io::Result<()> {Ok(())}
fn test_bracket_non_matching_counts() -> std::io::Result<()> {
Ok(())
}
#[ignore]
fn test_multiple_brackets() -> std::io::Result<()> {Ok(())}
fn test_multiple_brackets() -> std::io::Result<()> {
Ok(())
}
#[ignore]
fn test_multiple_brackets_only_one_in_command()
-> std::io::Result<()> {Ok(())}
fn test_multiple_brackets_only_one_in_command() -> std::io::Result<()> {
Ok(())
}
}

Loading…
Cancel
Save