From 5977776874d16febbf26d73e833b4e4d104aa359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Miedzi=C5=84ski?= Date: Thu, 25 May 2017 18:19:00 +0200 Subject: [PATCH] Add support for running commands on key press (#566) Based on option `command` in key binding section in config, e.g. - { key: N, mods: Control|Shift, command: alacritty } # or - { key: N, mods: Control|Shift, command: { program: "alacritty", args: ["-e", "vttest"], }} specified command will be run in the background on key press. Alacritty doesn't wait for its result nor block IO. --- src/config.rs | 49 +++++++++++++++++++++++++++++++++++++++---------- src/input.rs | 15 +++++++++++++++ 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/config.rs b/src/config.rs index 62e0ba49..ada6f8d1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -378,6 +378,17 @@ impl de::Deserialize for ActionWrapper { } } +#[derive(Debug, Deserialize)] +#[serde(untagged)] +enum CommandWrapper { + Just(String), + WithArgs { + program: String, + #[serde(default)] + args: Vec, + }, +} + use ::term::{mode, TermMode}; struct ModeWrapper { @@ -517,7 +528,8 @@ impl de::Deserialize for RawBinding { Mode, Action, Chars, - Mouse + Mouse, + Command, } impl de::Deserialize for Field { @@ -527,7 +539,7 @@ impl de::Deserialize for RawBinding { struct FieldVisitor; static FIELDS: &'static [&'static str] = &[ - "key", "mods", "mode", "action", "chars", "mouse" + "key", "mods", "mode", "action", "chars", "mouse", "command", ]; impl Visitor for FieldVisitor { @@ -547,6 +559,7 @@ impl de::Deserialize for RawBinding { "action" => Ok(Field::Action), "chars" => Ok(Field::Chars), "mouse" => Ok(Field::Mouse), + "command" => Ok(Field::Command), _ => Err(E::unknown_field(value, FIELDS)), } } @@ -577,6 +590,7 @@ impl de::Deserialize for RawBinding { let mut mode: Option = None; let mut not_mode: Option = None; let mut mouse: Option<::glutin::MouseButton> = None; + let mut command: Option = None; use ::serde::de::Error; @@ -626,17 +640,32 @@ impl de::Deserialize for RawBinding { } mouse = Some(visitor.visit_value::()?.into_inner()); - } + }, + Field::Command => { + if command.is_some() { + return Err(::duplicate_field("command")); + } + + command = Some(visitor.visit_value::()?); + }, } } - let action = match (action, chars) { - (Some(_), Some(_)) => { - return Err(V::Error::custom("must specify only chars or action")); + let action = match (action, chars, command) { + (Some(action), None, None) => action, + (None, Some(chars), None) => Action::Esc(chars), + (None, None, Some(cmd)) => { + match cmd { + CommandWrapper::Just(program) => { + Action::Command(program, vec![]) + }, + CommandWrapper::WithArgs { program, args } => { + Action::Command(program, args) + }, + } }, - (Some(action), _) => action, - (_, Some(chars)) => Action::Esc(chars), - _ => return Err(V::Error::custom("must specify chars or action")) + (None, None, None) => return Err(V::Error::custom("must specify chars, action or command")), + _ => return Err(V::Error::custom("must specify only chars, action or command")), }; let mode = mode.unwrap_or_else(TermMode::empty); @@ -659,7 +688,7 @@ impl de::Deserialize for RawBinding { } const FIELDS: &'static [&'static str] = &[ - "key", "mods", "mode", "action", "chars", "mouse" + "key", "mods", "mode", "action", "chars", "mouse", "command", ]; deserializer.deserialize_struct("RawBinding", FIELDS, RawBindingVisitor) diff --git a/src/input.rs b/src/input.rs index a1bd5c9a..47374e47 100644 --- a/src/input.rs +++ b/src/input.rs @@ -20,6 +20,7 @@ //! determine what to do when a non-modifier key is pressed. use std::borrow::Cow; use std::mem; +use std::process::Command; use std::time::Instant; use copypasta::{Clipboard, Load, Buffer}; @@ -144,6 +145,9 @@ pub enum Action { /// Paste contents of selection buffer PasteSelection, + /// Run given command + Command(String, Vec), + /// Quits Alacritty. Quit, } @@ -174,6 +178,17 @@ impl Action { warn!("Error loading data from clipboard. {}", Red(err)); }); }, + Action::Command(ref program, ref args) => { + trace!("running command: {} {:?}", program, args); + match Command::new(program).args(args).spawn() { + Ok(child) => { + debug!("spawned new proc with pid: {}", child.id()); + }, + Err(err) => { + warn!("couldn't run command: {}", err); + }, + } + }, Action::Quit => { // FIXME should do a more graceful shutdown ::std::process::exit(0);