diff --git a/src/config.rs b/src/config.rs index d7770db..27d2c37 100644 --- a/src/config.rs +++ b/src/config.rs @@ -93,125 +93,6 @@ fn load_file_contents(path: path::PathBuf) -> Result { Ok(contents) } -fn extract_curly_brace(line: &str) -> Vec { - if !line.is_ascii() { - return vec![line.to_string()]; - } - let mut output: Vec = Vec::new(); - - let index_open_brace = line.chars().position(|c| c == '{'); - let index_close_brace = line.chars().position(|c| c == '}'); - - if index_open_brace.is_none() || index_close_brace.is_none() { - return vec![line.to_string()]; - } - - let start_index = index_open_brace.unwrap(); - let end_index = index_close_brace.unwrap(); - - // There are no expansions to build if } is earlier than { - if start_index >= end_index { - return vec![line.to_string()]; - } - - let str_before_braces = line[..start_index].to_string(); - let str_after_braces = line[end_index + 1..].to_string(); - - let comma_separated_items = line[start_index + 1..end_index].split(','); - - for item in comma_separated_items { - let mut push_one_item = || { - output.push(format!("{}{}{}", str_before_braces, item.trim(), str_after_braces)); - }; - - if !item.contains('-') { - push_one_item(); - continue; - } - - // Parse dash ranges like {1-5} and {a-f} - - let mut range = item.split('-').map(|s| s.trim()); - let begin_char: &str; - let end_char: &str; - - if let Some(b) = range.next() { - begin_char = b; - } else { - push_one_item(); - continue; - } - - if let Some(e) = range.next() { - end_char = e; - } else { - push_one_item(); - continue; - } - - // Do not accept range values that are longer than one char - // Example invalid: {ef,p} {3,56} - // Beginning of the range cannot be greater than end - // Example invalid: {9,4} {3,2} - if begin_char.len() != 1 || end_char.len() != 1 || begin_char > end_char { - push_one_item(); - continue; - } - - // In swhkd we will parse the full range using ASCII values. - - let begin_ascii_val = begin_char.parse::().unwrap() as u8; - let end_ascii_val = end_char.parse::().unwrap() as u8; - - for ascii_number in begin_ascii_val..=end_ascii_val { - output - .push(format!("{}{}{}", str_before_braces, ascii_number as char, str_after_braces)); - } - } - output -} - -// We need to get the reference to key_to_evdev_key -// and mod_to_mod enum instead of recreating them -// after each function call because it's too expensive -fn parse_keybind( - line: &str, - line_nr: u32, - key_to_evdev_key: &HashMap<&str, evdev::Key>, - 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 last_token = tokens.last().unwrap().trim(); - - // Check if each token is valid - for token in &tokens { - if key_to_evdev_key.contains_key(token.as_str()) { - // Can't have a key that's like a modifier - if token != last_token { - return Err(Error::InvalidConfig(ParseError::InvalidModifier(line_nr))); - } - } else if mod_to_mod_enum.contains_key(token.as_str()) { - // Can't have a modifier that's like a modifier - if token == last_token { - return Err(Error::InvalidConfig(ParseError::InvalidKeysym(line_nr))); - } - } else { - return Err(Error::InvalidConfig(ParseError::UnknownSymbol(line_nr))); - } - } - - // Translate keypress into evdev key - let keysym = key_to_evdev_key.get(last_token).unwrap(); - - let modifiers: Vec = tokens[0..(tokens.len() - 1)] - .iter() - .map(|token| *mod_to_mod_enum.get(token.as_str()).unwrap()) - .collect(); - - Ok((*keysym, modifiers)) -} - fn parse_contents(contents: String) -> Result, Error> { let key_to_evdev_key: HashMap<&str, evdev::Key> = HashMap::from([ ("q", evdev::Key::KEY_Q), @@ -410,6 +291,125 @@ fn parse_contents(contents: String) -> Result, Error> { Ok(hotkeys) } +// We need to get the reference to key_to_evdev_key +// and mod_to_mod enum instead of recreating them +// after each function call because it's too expensive +fn parse_keybind( + line: &str, + line_nr: u32, + key_to_evdev_key: &HashMap<&str, evdev::Key>, + 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 last_token = tokens.last().unwrap().trim(); + + // Check if each token is valid + for token in &tokens { + if key_to_evdev_key.contains_key(token.as_str()) { + // Can't have a key that's like a modifier + if token != last_token { + return Err(Error::InvalidConfig(ParseError::InvalidModifier(line_nr))); + } + } else if mod_to_mod_enum.contains_key(token.as_str()) { + // Can't have a modifier that's like a modifier + if token == last_token { + return Err(Error::InvalidConfig(ParseError::InvalidKeysym(line_nr))); + } + } else { + return Err(Error::InvalidConfig(ParseError::UnknownSymbol(line_nr))); + } + } + + // Translate keypress into evdev key + let keysym = key_to_evdev_key.get(last_token).unwrap(); + + let modifiers: Vec = tokens[0..(tokens.len() - 1)] + .iter() + .map(|token| *mod_to_mod_enum.get(token.as_str()).unwrap()) + .collect(); + + Ok((*keysym, modifiers)) +} + +fn extract_curly_brace(line: &str) -> Vec { + if !line.is_ascii() { + return vec![line.to_string()]; + } + let mut output: Vec = Vec::new(); + + let index_open_brace = line.chars().position(|c| c == '{'); + let index_close_brace = line.chars().position(|c| c == '}'); + + if index_open_brace.is_none() || index_close_brace.is_none() { + return vec![line.to_string()]; + } + + let start_index = index_open_brace.unwrap(); + let end_index = index_close_brace.unwrap(); + + // There are no expansions to build if } is earlier than { + if start_index >= end_index { + return vec![line.to_string()]; + } + + let str_before_braces = line[..start_index].to_string(); + let str_after_braces = line[end_index + 1..].to_string(); + + let comma_separated_items = line[start_index + 1..end_index].split(','); + + for item in comma_separated_items { + let mut push_one_item = || { + output.push(format!("{}{}{}", str_before_braces, item.trim(), str_after_braces)); + }; + + if !item.contains('-') { + push_one_item(); + continue; + } + + // Parse dash ranges like {1-5} and {a-f} + + let mut range = item.split('-').map(|s| s.trim()); + let begin_char: &str; + let end_char: &str; + + if let Some(b) = range.next() { + begin_char = b; + } else { + push_one_item(); + continue; + } + + if let Some(e) = range.next() { + end_char = e; + } else { + push_one_item(); + continue; + } + + // Do not accept range values that are longer than one char + // Example invalid: {ef,p} {3,56} + // Beginning of the range cannot be greater than end + // Example invalid: {9,4} {3,2} + if begin_char.len() != 1 || end_char.len() != 1 || begin_char > end_char { + push_one_item(); + continue; + } + + // In swhkd we will parse the full range using ASCII values. + + let begin_ascii_val = begin_char.parse::().unwrap() as u8; + let end_ascii_val = end_char.parse::().unwrap() as u8; + + for ascii_number in begin_ascii_val..=end_ascii_val { + output + .push(format!("{}{}{}", str_before_braces, ascii_number as char, str_after_braces)); + } + } + output +} + #[cfg(test)] mod tests { use super::*;