From c5f0b58c6027305f6cff119f695fea252ad090d4 Mon Sep 17 00:00:00 2001 From: Eden Date: Mon, 14 Aug 2023 12:56:25 +0800 Subject: [PATCH 1/2] feat: added @pend, refactor send_command --- swhkd/src/config.rs | 1 + swhkd/src/daemon.rs | 90 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/swhkd/src/config.rs b/swhkd/src/config.rs index a2dac65..7f59cf1 100644 --- a/swhkd/src/config.rs +++ b/swhkd/src/config.rs @@ -65,6 +65,7 @@ pub const MODE_STATEMENT: &str = "mode"; pub const MODE_END_STATEMENT: &str = "endmode"; pub const MODE_ENTER_STATEMENT: &str = "@enter"; pub const MODE_ESCAPE_STATEMENT: &str = "@escape"; +pub const MODE_PEND_STATEMENT: &str = "@pend"; pub const MODE_SWALLOW_STATEMENT: &str = "swallow"; pub const MODE_ONEOFF_STATEMENT: &str = "oneoff"; diff --git a/swhkd/src/daemon.rs b/swhkd/src/daemon.rs index 108f175..71440ed 100644 --- a/swhkd/src/daemon.rs +++ b/swhkd/src/daemon.rs @@ -97,44 +97,101 @@ async fn main() -> Result<(), Box> { let mut modes = load_config(); let mut mode_stack: Vec = vec![0]; + let mut command_stack: Vec = Vec::new(); + let mut pending_mode_stack: Vec = Vec::new(); macro_rules! send_command { - ($hotkey: expr, $socket_path: expr) => { - log::info!("Hotkey pressed: {:#?}", $hotkey); - let command = $hotkey.command; + ($command: expr, $socket_path: expr) => { + let mut command = $command; let mut commands_to_send = String::new(); if modes[mode_stack[mode_stack.len() - 1]].options.oneoff { + if pending_mode_stack[pending_mode_stack.len() - 1] + != mode_stack[mode_stack.len() - 1] + { + mode_stack.pop(); + continue; + } + command = format!("{} && {}", command, command_stack.pop().unwrap()); mode_stack.pop(); + pending_mode_stack.pop(); + command_stack.pop(); } if command.contains('@') { - let commands = command.split("&&").map(|s| s.trim()).collect::>(); - for cmd in commands { + let mut commands = command.split("&&").map(|s| s.trim()).collect::>(); + let mut pending: bool = false; + let mut i: usize = 0; + let mut len: usize = commands.len(); + let mut pending_command = String::new(); + let mut commands_to_push = String::new(); + if !command_stack.is_empty() { + pending_command = command_stack[command_stack.len() - 1].clone(); + } + + while i < len { + let cmd = commands[i]; + if pending { + commands_to_push.push_str(format!("{cmd} && ").as_str()); + i += 1; + continue; + } match cmd.split(' ').next().unwrap() { config::MODE_ENTER_STATEMENT => { let enter_mode = cmd.split(' ').nth(1).unwrap(); - for (i, mode) in modes.iter().enumerate() { - if mode.name == enter_mode { - mode_stack.push(i); - break; - } - } + let index = modes.iter().position(|m| m.name == enter_mode).unwrap(); + mode_stack.push(index); + log::info!( + "Entering mode: {}", + modes[mode_stack[mode_stack.len() - 1]].name + ); + } + config::MODE_PEND_STATEMENT => { + let enter_mode = cmd.split(' ').nth(1).unwrap(); + let index = modes.iter().position(|m| m.name == enter_mode).unwrap(); + mode_stack.push(index); log::info!( "Entering mode: {}", modes[mode_stack[mode_stack.len() - 1]].name ); + pending = true; + pending_mode_stack.push(index); } config::MODE_ESCAPE_STATEMENT => { + if pending_mode_stack[pending_mode_stack.len() - 1] + != mode_stack[mode_stack.len() - 1] + { + mode_stack.pop(); + i += 1; + continue; + } + let pending_commands: Vec<&str> = + pending_command.split("&&").map(|s| s.trim()).collect(); + commands.extend(pending_commands); + len = commands.len(); mode_stack.pop(); + pending_mode_stack.pop(); + command_stack.pop(); } - _ => commands_to_send.push_str(format!("{cmd} &&").as_str()), + _ => commands_to_send.push_str(format!("{cmd} && ").as_str()), + } + i += 1; + } + if pending { + commands_to_push = commands_to_push.trim().to_string(); + if commands_to_push.ends_with(" &&") { + commands_to_push = + commands_to_push.strip_suffix(" &&").unwrap().to_string(); } + log::info!("pending command: {}", commands_to_push); + command_stack.push(commands_to_push); } } else { commands_to_send = command; } + commands_to_send = commands_to_send.trim().to_string(); if commands_to_send.ends_with(" &&") { commands_to_send = commands_to_send.strip_suffix(" &&").unwrap().to_string(); } + log::info!("commands_to_send: {}", commands_to_send); if let Err(e) = socket_write(&commands_to_send, $socket_path.to_path_buf()) { log::error!("Failed to send command to swhks through IPC."); log::error!("Please make sure that swhks is running."); @@ -239,7 +296,8 @@ async fn main() -> Result<(), Box> { if hotkey.keybinding.on_release { continue; } - send_command!(hotkey.clone(), &socket_file_path); + log::info!("Hotkey pressed: {:#?}", hotkey); + send_command!(hotkey.clone().command, &socket_file_path); hotkey_repeat_timer.as_mut().reset(Instant::now() + Duration::from_millis(repeat_cooldown_duration)); } @@ -359,7 +417,8 @@ async fn main() -> Result<(), Box> { 0 => { if last_hotkey.is_some() && pending_release { pending_release = false; - send_command!(last_hotkey.clone().unwrap(), &socket_file_path); + log::info!("Hotkey pressed: {:#?}", last_hotkey.clone().unwrap()); + send_command!(last_hotkey.clone().unwrap().command, &socket_file_path); last_hotkey = None; } if let Some(modifier) = modifiers_map.get(&key) { @@ -422,7 +481,8 @@ async fn main() -> Result<(), Box> { pending_release = true; break; } - send_command!(hotkey.clone(), &socket_file_path); + log::info!("Hotkey pressed: {:#?}", hotkey); + send_command!(hotkey.clone().command, &socket_file_path); hotkey_repeat_timer.as_mut().reset(Instant::now() + Duration::from_millis(repeat_cooldown_duration)); continue; } From 2b072d8a2be13a12f73e97d53ca028e7c82f8699 Mon Sep 17 00:00:00 2001 From: Eden Date: Fri, 18 Aug 2023 15:25:52 +0800 Subject: [PATCH 2/2] [fix] check if pending_mode_stack is empty --- swhkd/src/daemon.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/swhkd/src/daemon.rs b/swhkd/src/daemon.rs index 71440ed..6ed849e 100644 --- a/swhkd/src/daemon.rs +++ b/swhkd/src/daemon.rs @@ -105,8 +105,9 @@ async fn main() -> Result<(), Box> { let mut command = $command; let mut commands_to_send = String::new(); if modes[mode_stack[mode_stack.len() - 1]].options.oneoff { - if pending_mode_stack[pending_mode_stack.len() - 1] - != mode_stack[mode_stack.len() - 1] + if !pending_mode_stack.is_empty() + && pending_mode_stack[pending_mode_stack.len() - 1] + != mode_stack[mode_stack.len() - 1] { mode_stack.pop(); continue; @@ -156,8 +157,9 @@ async fn main() -> Result<(), Box> { pending_mode_stack.push(index); } config::MODE_ESCAPE_STATEMENT => { - if pending_mode_stack[pending_mode_stack.len() - 1] - != mode_stack[mode_stack.len() - 1] + if !pending_mode_stack.is_empty() + && pending_mode_stack[pending_mode_stack.len() - 1] + != mode_stack[mode_stack.len() - 1] { mode_stack.pop(); i += 1;