From e4dc43e87c5330c1f22dc2e7570d7e66881ef647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Tu=C3=B1=C3=B3n?= Date: Sat, 5 Jan 2019 15:47:12 -0500 Subject: [PATCH] Add key/mouse action for spawning new Alacritty instances --- CHANGELOG.md | 1 + alacritty.yml | 5 ++--- alacritty_macos.yml | 3 ++- alacritty_windows.yml | 5 ++--- src/config.rs | 3 ++- src/event.rs | 26 ++++++++++++++++++++++++-- src/input.rs | 42 +++++++++++++++++++++--------------------- src/tty/unix.rs | 2 +- src/util.rs | 13 +++++++++++-- 9 files changed, 66 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a1d152b..5c724939 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Crashes on Windows are now also reported with a popup in addition to stderr - Windows: New configuration field `enable_experimental_conpty_backend` which enables support for the Pseudoconsole API (ConPTY) added in Windows 10 October 2018 (1809) update +- New mouse and key action `SpawnNewInstance` for launching another instance of Alacritty ### Changed diff --git a/alacritty.yml b/alacritty.yml index 2978f1dc..b1cfa9f8 100644 --- a/alacritty.yml +++ b/alacritty.yml @@ -319,7 +319,7 @@ live_config_reload: true # arguments (`command`). # # Example: -# `- { key: V, mods: Command, action: Paste }` +# `- { key: V, mods: Control|Shift, action: Paste }` # # Available fields: # - key @@ -374,6 +374,7 @@ live_config_reload: true # - Hide # - Quit # - ClearLogNotice +# - SpawnNewInstance # # Values for `command`: # The `command` field must be a map containing a `program` string and @@ -392,8 +393,6 @@ key_bindings: - { key: C, mods: Control|Shift, action: Copy } - { key: Paste, action: Paste } - { key: Copy, action: Copy } - - { key: Q, mods: Command, action: Quit } - - { key: W, mods: Command, action: Quit } - { key: Insert, mods: Shift, action: PasteSelection } - { key: Key0, mods: Control, action: ResetFontSize } - { key: Equals, mods: Control, action: IncreaseFontSize } diff --git a/alacritty_macos.yml b/alacritty_macos.yml index 4c8e26ed..f0448511 100644 --- a/alacritty_macos.yml +++ b/alacritty_macos.yml @@ -326,7 +326,7 @@ live_config_reload: true # arguments (`command`). # # Example: -# `- { key: V, mods: Command, action: Paste }` +# `- { key: V, mods: Control|Shift, action: Paste }` # # Available fields: # - key @@ -381,6 +381,7 @@ live_config_reload: true # - Hide # - Quit # - ClearLogNotice +# - SpawnNewInstance # # Values for `command`: # The `command` field must be a map containing a `program` string and diff --git a/alacritty_windows.yml b/alacritty_windows.yml index cdca685e..0d08b1e8 100644 --- a/alacritty_windows.yml +++ b/alacritty_windows.yml @@ -303,7 +303,7 @@ enable_experimental_conpty_backend: false # arguments (`command`). # # Example: -# `- { key: V, mods: Command, action: Paste }` +# `- { key: V, mods: Control|Shift, action: Paste }` # # Available fields: # - key @@ -358,6 +358,7 @@ enable_experimental_conpty_backend: false # - Hide # - Quit # - ClearLogNotice +# - SpawnNewInstance # # Values for `command`: # The `command` field must be a map containing a `program` string and @@ -374,8 +375,6 @@ enable_experimental_conpty_backend: false key_bindings: - { key: V, mods: Control|Shift, action: Paste } - { key: C, mods: Control|Shift, action: Copy } - - { key: Q, mods: Command, action: Quit } - - { key: W, mods: Command, action: Quit } - { key: Insert, mods: Shift, action: PasteSelection } - { key: Key0, mods: Control, action: ResetFontSize } - { key: Equals, mods: Control, action: IncreaseFontSize } diff --git a/src/config.rs b/src/config.rs index 547bce1f..95989cb0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -771,7 +771,7 @@ impl<'a> de::Deserialize<'a> for ActionWrapper { fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Paste, Copy, PasteSelection, IncreaseFontSize, DecreaseFontSize, \ ResetFontSize, ScrollPageUp, ScrollPageDown, ScrollToTop, \ - ScrollToBottom, ClearHistory, Hide, ClearLogNotice or Quit") + ScrollToBottom, ClearHistory, Hide, ClearLogNotice, SpawnNewInstance or Quit") } fn visit_str(self, value: &str) -> ::std::result::Result @@ -792,6 +792,7 @@ impl<'a> de::Deserialize<'a> for ActionWrapper { "Hide" => Action::Hide, "Quit" => Action::Quit, "ClearLogNotice" => Action::ClearLogNotice, + "SpawnNewInstance" => Action::SpawnNewInstance, _ => return Err(E::invalid_value(Unexpected::Str(value), &self)), })) } diff --git a/src/event.rs b/src/event.rs index 39ed25f6..4f7f1a76 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,15 +1,21 @@ //! Process window events +#[cfg(unix)] +use std::fs; use std::borrow::Cow; use std::fs::File; use std::io::Write; use std::sync::mpsc; use std::time::{Instant}; +use std::env; use serde_json as json; use parking_lot::MutexGuard; use glutin::{self, ModifiersState, Event, ElementState}; use copypasta::{Clipboard, Load, Store, Buffer as ClipboardBuffer}; +use glutin::dpi::PhysicalSize; +#[cfg(unix)] +use crate::tty; use crate::ansi::{Handler, ClearMode}; use crate::grid::Scroll; use crate::config::{self, Config}; @@ -21,10 +27,9 @@ use crate::selection::Selection; use crate::sync::FairMutex; use crate::term::{Term, SizeInfo, TermMode, Search}; use crate::term::cell::Cell; -use crate::util::limit; +use crate::util::{limit, start_daemon}; use crate::util::fmt::Red; use crate::window::Window; -use glutin::dpi::PhysicalSize; /// Byte sequences are sent to a `Notify` in response to some events pub trait Notify { @@ -177,6 +182,23 @@ impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> { fn clear_log(&mut self) { self.terminal.clear_log(); } + + fn spawn_new_instance(&mut self) { + let alacritty = env::args().next().unwrap(); + #[cfg(unix)] + let args = [ + "--working-directory".into(), + fs::read_link(format!("/proc/{}/cwd", unsafe { tty::PID })) + .expect("shell working directory"), + ]; + #[cfg(not(unix))] + let args: [&str; 0] = []; + + match start_daemon(&alacritty, &args) { + Ok(_) => debug!("Started new Alacritty process: {} {:?}", alacritty, args), + Err(_) => warn!("Unable to start new Alacritty process: {} {:?}", alacritty, args), + } + } } /// The ActionContext can't really have direct access to the Window diff --git a/src/input.rs b/src/input.rs index be5dc264..2e949d64 100644 --- a/src/input.rs +++ b/src/input.rs @@ -75,6 +75,7 @@ pub trait ActionContext { fn hide_window(&mut self); fn url(&self, _: Point) -> Option; fn clear_log(&mut self); + fn spawn_new_instance(&mut self); } /// Describes a state and action to take in that state @@ -202,6 +203,9 @@ pub enum Action { /// Clears warning and error notices. ClearLogNotice, + + /// Spawn a new instance of Alacritty. + SpawnNewInstance, } impl Action { @@ -279,7 +283,10 @@ impl Action { }, Action::ClearLogNotice => { ctx.clear_log(); - } + }, + Action::SpawnNewInstance => { + ctx.spawn_new_instance(); + }, } } @@ -793,9 +800,17 @@ mod tests { } impl <'a>super::ActionContext for ActionContext<'a> { - fn write_to_pty>>(&mut self, _val: B) { - // STUBBED - } + fn write_to_pty>>(&mut self, _val: B) {} + fn update_selection(&mut self, _point: Point, _side: Side) {} + fn simple_selection(&mut self, _point: Point, _side: Side) {} + fn copy_selection(&self, _buffer: ClipboardBuffer) {} + fn clear_selection(&mut self) {} + fn change_font_size(&mut self, _delta: f32) {} + fn reset_font_size(&mut self) {} + fn clear_history(&mut self) {} + fn clear_log(&mut self) {} + fn hide_window(&mut self) {} + fn spawn_new_instance(&mut self) {} fn terminal_mode(&self) -> TermMode { *self.terminal.mode() @@ -805,14 +820,6 @@ mod tests { *self.size_info } - fn copy_selection(&self, _buffer: ClipboardBuffer) { - // STUBBED - } - - fn clear_selection(&mut self) {} - fn update_selection(&mut self, _point: Point, _side: Side) {} - fn simple_selection(&mut self, _point: Point, _side: Side) {} - fn semantic_selection(&mut self, _point: Point) { // set something that we can check for here self.last_action = MultiClick::DoubleClick; @@ -851,21 +858,14 @@ mod tests { fn received_count(&mut self) -> &mut usize { &mut self.received_count } + fn suppress_chars(&mut self) -> &mut bool { &mut self.suppress_chars } + fn last_modifiers(&mut self) -> &mut ModifiersState { &mut self.last_modifiers } - fn change_font_size(&mut self, _delta: f32) { - } - fn reset_font_size(&mut self) { - } - fn clear_history(&mut self) { - } - fn hide_window(&mut self) { - } - fn clear_log(&mut self) {} } macro_rules! test_clickstate { diff --git a/src/tty/unix.rs b/src/tty/unix.rs index b341638f..e8a28c91 100644 --- a/src/tty/unix.rs +++ b/src/tty/unix.rs @@ -38,7 +38,7 @@ use std::os::unix::io::AsRawFd; /// Process ID of child process /// /// Necessary to put this in static storage for `sigchld` to have access -static mut PID: pid_t = 0; +pub static mut PID: pid_t = 0; /// Exit flag /// diff --git a/src/util.rs b/src/util.rs index 0b3b6644..2b30ce8d 100644 --- a/src/util.rs +++ b/src/util.rs @@ -14,6 +14,7 @@ #[cfg(not(windows))] use std::os::unix::process::CommandExt; use std::process::Command; +use std::ffi::OsStr; use std::{cmp, io}; /// Threading utilities @@ -77,7 +78,11 @@ pub mod fmt { } #[cfg(not(windows))] -pub fn start_daemon(program: &str, args: &[String]) -> io::Result<()> { +pub fn start_daemon(program: &str, args: I) -> io::Result<()> + where + I: IntoIterator, + S: AsRef, +{ Command::new(program) .args(args) .before_exec(|| unsafe { @@ -90,7 +95,11 @@ pub fn start_daemon(program: &str, args: &[String]) -> io::Result<()> { } #[cfg(windows)] -pub fn start_daemon(program: &str, args: &[String]) -> io::Result<()> { +pub fn start_daemon(program: &str, args: I) -> io::Result<()> + where + I: IntoIterator, + S: AsRef, +{ Command::new(program).args(args).spawn().map(|_| ()) }