diff options
author | Kirill Chibisov <contact@kchibisov.com> | 2020-07-10 22:32:44 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-10 22:32:44 +0300 |
commit | 8bd2c13490f8cb6ad6b0c1104f9586b3554efea2 (patch) | |
tree | 6909d3be00c72c3c5acdd173aa7f411a1bc6b445 /alacritty_terminal | |
parent | b78f3d133960dad38ad21e808723e51661b59881 (diff) | |
download | alacritty-8bd2c13490f8cb6ad6b0c1104f9586b3554efea2.tar.gz alacritty-8bd2c13490f8cb6ad6b0c1104f9586b3554efea2.zip |
Add option to run command on bell
Fixes #1528.
Diffstat (limited to 'alacritty_terminal')
-rw-r--r-- | alacritty_terminal/src/config/bell.rs | 120 | ||||
-rw-r--r-- | alacritty_terminal/src/config/mod.rs | 17 | ||||
-rw-r--r-- | alacritty_terminal/src/config/visual_bell.rs | 76 | ||||
-rw-r--r-- | alacritty_terminal/src/event.rs | 4 | ||||
-rw-r--r-- | alacritty_terminal/src/event_loop.rs | 5 | ||||
-rw-r--r-- | alacritty_terminal/src/lib.rs | 2 | ||||
-rw-r--r-- | alacritty_terminal/src/term/color.rs | 10 | ||||
-rw-r--r-- | alacritty_terminal/src/term/mod.rs | 53 | ||||
-rw-r--r-- | alacritty_terminal/src/thread.rs | 11 | ||||
-rw-r--r-- | alacritty_terminal/src/util.rs | 77 |
10 files changed, 184 insertions, 191 deletions
diff --git a/alacritty_terminal/src/config/bell.rs b/alacritty_terminal/src/config/bell.rs new file mode 100644 index 00000000..97010f31 --- /dev/null +++ b/alacritty_terminal/src/config/bell.rs @@ -0,0 +1,120 @@ +use std::time::Duration; + +use log::error; +use serde::{Deserialize, Deserializer}; +use serde_yaml::Value; + +use crate::config::{failure_default, Program, LOG_TARGET_CONFIG}; +use crate::term::color::Rgb; + +const DEFAULT_BELL_COLOR: Rgb = Rgb { r: 255, g: 255, b: 255 }; + +#[serde(default)] +#[derive(Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct BellConfig { + /// Visual bell animation function. + #[serde(deserialize_with = "failure_default")] + pub animation: BellAnimation, + + /// Visual bell duration in milliseconds. + #[serde(deserialize_with = "failure_default")] + duration: u16, + + /// Visual bell flash color. + #[serde(deserialize_with = "deserialize_bell_color")] + pub color: Rgb, + + /// Command to run on bell. + #[serde(deserialize_with = "deserialize_bell_command")] + pub command: Option<Program>, +} + +impl Default for BellConfig { + fn default() -> Self { + Self { + animation: Default::default(), + duration: Default::default(), + command: Default::default(), + color: DEFAULT_BELL_COLOR, + } + } +} + +impl BellConfig { + /// Visual bell duration in milliseconds. + #[inline] + pub fn duration(&self) -> Duration { + Duration::from_millis(u64::from(self.duration)) + } +} + +fn deserialize_bell_color<'a, D>(deserializer: D) -> Result<Rgb, D::Error> +where + D: Deserializer<'a>, +{ + let value = Value::deserialize(deserializer)?; + match Rgb::deserialize(value) { + Ok(value) => Ok(value), + Err(err) => { + error!( + target: LOG_TARGET_CONFIG, + "Problem with config: {}, using default color value {}", err, DEFAULT_BELL_COLOR + ); + + Ok(DEFAULT_BELL_COLOR) + }, + } +} + +fn deserialize_bell_command<'a, D>(deserializer: D) -> Result<Option<Program>, D::Error> +where + D: Deserializer<'a>, +{ + // Deserialize to generic value. + let val = Value::deserialize(deserializer)?; + + // Accept `None` to disable the bell command. + if val.as_str().filter(|v| v.to_lowercase() == "none").is_some() { + return Ok(None); + } + + match Program::deserialize(val) { + Ok(command) => Ok(Some(command)), + Err(err) => { + error!(target: LOG_TARGET_CONFIG, "Problem with config: {}; ignoring field", err); + Ok(None) + }, + } +} + +/// `VisualBellAnimations` are modeled after a subset of CSS transitions and Robert +/// Penner's Easing Functions. +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq)] +pub enum BellAnimation { + // CSS animation. + Ease, + // CSS animation. + EaseOut, + // Penner animation. + EaseOutSine, + // Penner animation. + EaseOutQuad, + // Penner animation. + EaseOutCubic, + // Penner animation. + EaseOutQuart, + // Penner animation. + EaseOutQuint, + // Penner animation. + EaseOutExpo, + // Penner animation. + EaseOutCirc, + // Penner animation. + Linear, +} + +impl Default for BellAnimation { + fn default() -> Self { + BellAnimation::EaseOutExpo + } +} diff --git a/alacritty_terminal/src/config/mod.rs b/alacritty_terminal/src/config/mod.rs index e3d72fda..83dcd7b8 100644 --- a/alacritty_terminal/src/config/mod.rs +++ b/alacritty_terminal/src/config/mod.rs @@ -6,20 +6,20 @@ use log::error; use serde::{Deserialize, Deserializer}; use serde_yaml::Value; +mod bell; mod colors; mod debug; mod font; mod scrolling; -mod visual_bell; mod window; use crate::ansi::CursorStyle; +pub use crate::config::bell::{BellAnimation, BellConfig}; pub use crate::config::colors::Colors; pub use crate::config::debug::Debug; pub use crate::config::font::{Font, FontDescription}; pub use crate::config::scrolling::Scrolling; -pub use crate::config::visual_bell::{VisualBellAnimation, VisualBellConfig}; pub use crate::config::window::{Decorations, Dimensions, StartupMode, WindowConfig, DEFAULT_NAME}; pub const LOG_TARGET_CONFIG: &str = "alacritty_config"; @@ -69,9 +69,9 @@ pub struct Config<T> { #[serde(default, deserialize_with = "failure_default")] pub config_path: Option<PathBuf>, - /// Visual bell configuration. + /// Bell configuration. #[serde(default, deserialize_with = "failure_default")] - pub visual_bell: VisualBellConfig, + bell: BellConfig, /// Use dynamic title. #[serde(default, deserialize_with = "failure_default")] @@ -114,6 +114,10 @@ pub struct Config<T> { #[serde(skip)] pub hold: bool, + // TODO: DEPRECATED + #[serde(default, deserialize_with = "failure_default")] + pub visual_bell: Option<BellConfig>, + // TODO: REMOVED #[serde(default, deserialize_with = "failure_default")] pub tabspaces: Option<usize>, @@ -176,6 +180,11 @@ impl<T> Config<T> { pub fn background_opacity(&self) -> f32 { self.background_opacity.0 as f32 } + + #[inline] + pub fn bell(&self) -> &BellConfig { + self.visual_bell.as_ref().unwrap_or(&self.bell) + } } #[serde(default)] diff --git a/alacritty_terminal/src/config/visual_bell.rs b/alacritty_terminal/src/config/visual_bell.rs deleted file mode 100644 index 1a0a327b..00000000 --- a/alacritty_terminal/src/config/visual_bell.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::time::Duration; - -use serde::Deserialize; - -use crate::config::failure_default; -use crate::term::color::Rgb; - -#[serde(default)] -#[derive(Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct VisualBellConfig { - /// Visual bell animation function. - #[serde(deserialize_with = "failure_default")] - pub animation: VisualBellAnimation, - - /// Visual bell duration in milliseconds. - #[serde(deserialize_with = "failure_default")] - pub duration: u16, - - /// Visual bell flash color. - #[serde(deserialize_with = "failure_default")] - pub color: Rgb, -} - -impl Default for VisualBellConfig { - fn default() -> VisualBellConfig { - VisualBellConfig { - animation: Default::default(), - duration: Default::default(), - color: default_visual_bell_color(), - } - } -} - -impl VisualBellConfig { - /// Visual bell duration in milliseconds. - #[inline] - pub fn duration(&self) -> Duration { - Duration::from_millis(u64::from(self.duration)) - } -} - -/// `VisualBellAnimations` are modeled after a subset of CSS transitions and Robert -/// Penner's Easing Functions. -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq)] -pub enum VisualBellAnimation { - // CSS animation. - Ease, - // CSS animation. - EaseOut, - // Penner animation. - EaseOutSine, - // Penner animation. - EaseOutQuad, - // Penner animation. - EaseOutCubic, - // Penner animation. - EaseOutQuart, - // Penner animation. - EaseOutQuint, - // Penner animation. - EaseOutExpo, - // Penner animation. - EaseOutCirc, - // Penner animation. - Linear, -} - -impl Default for VisualBellAnimation { - fn default() -> Self { - VisualBellAnimation::EaseOutExpo - } -} - -fn default_visual_bell_color() -> Rgb { - Rgb { r: 255, g: 255, b: 255 } -} diff --git a/alacritty_terminal/src/event.rs b/alacritty_terminal/src/event.rs index 296e3bb0..863a2fbf 100644 --- a/alacritty_terminal/src/event.rs +++ b/alacritty_terminal/src/event.rs @@ -11,7 +11,7 @@ pub enum Event { ClipboardStore(ClipboardType, String), ClipboardLoad(ClipboardType, Arc<dyn Fn(&str) -> String + Sync + Send + 'static>), Wakeup, - Urgent, + Bell, Exit, } @@ -23,7 +23,7 @@ impl Debug for Event { Event::ClipboardStore(ty, text) => write!(f, "ClipboardStore({:?}, {})", ty, text), Event::ClipboardLoad(ty, _) => write!(f, "ClipboardLoad({:?})", ty), Event::Wakeup => write!(f, "Wakeup"), - Event::Urgent => write!(f, "Urgent"), + Event::Bell => write!(f, "Bell"), Event::Exit => write!(f, "Exit"), } } diff --git a/alacritty_terminal/src/event_loop.rs b/alacritty_terminal/src/event_loop.rs index 46216605..156510b0 100644 --- a/alacritty_terminal/src/event_loop.rs +++ b/alacritty_terminal/src/event_loop.rs @@ -6,6 +6,7 @@ use std::fs::File; use std::io::{self, ErrorKind, Read, Write}; use std::marker::Send; use std::sync::Arc; +use std::thread::JoinHandle; use log::error; #[cfg(not(windows))] @@ -18,8 +19,8 @@ use crate::config::Config; use crate::event::{self, Event, EventListener}; use crate::sync::FairMutex; use crate::term::{SizeInfo, Term}; +use crate::thread; use crate::tty; -use crate::util::thread; /// Max bytes to read from the PTY. const MAX_READ: usize = 0x10_000; @@ -300,7 +301,7 @@ where Ok(()) } - pub fn spawn(mut self) -> thread::JoinHandle<(Self, State)> { + pub fn spawn(mut self) -> JoinHandle<(Self, State)> { thread::spawn_named("PTY reader", move || { let mut state = State::default(); let mut buf = [0u8; MAX_READ]; diff --git a/alacritty_terminal/src/lib.rs b/alacritty_terminal/src/lib.rs index 1d2fe551..7130218b 100644 --- a/alacritty_terminal/src/lib.rs +++ b/alacritty_terminal/src/lib.rs @@ -22,8 +22,8 @@ pub mod panic; pub mod selection; pub mod sync; pub mod term; +pub mod thread; pub mod tty; -pub mod util; pub mod vi_mode; pub use crate::grid::Grid; diff --git a/alacritty_terminal/src/term/color.rs b/alacritty_terminal/src/term/color.rs index f20601d6..9aeb7061 100644 --- a/alacritty_terminal/src/term/color.rs +++ b/alacritty_terminal/src/term/color.rs @@ -1,4 +1,4 @@ -use std::fmt; +use std::fmt::{self, Display, Formatter}; use std::ops::{Index, IndexMut, Mul}; use std::str::FromStr; @@ -64,7 +64,7 @@ impl<'de> Deserialize<'de> for Rgb { impl<'a> Visitor<'a> for RgbVisitor { type Value = Rgb; - fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("hex color like #ff00ff") } @@ -94,6 +94,12 @@ impl<'de> Deserialize<'de> for Rgb { } } +impl Display for Rgb { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b) + } +} + impl FromStr for Rgb { type Err = (); diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs index d59838d4..f3f22d47 100644 --- a/alacritty_terminal/src/term/mod.rs +++ b/alacritty_terminal/src/term/mod.rs @@ -14,7 +14,7 @@ use unicode_width::UnicodeWidthChar; use crate::ansi::{ self, Attr, CharsetIndex, Color, CursorStyle, Handler, NamedColor, StandardCharset, }; -use crate::config::{Config, VisualBellAnimation}; +use crate::config::{BellAnimation, BellConfig, Config}; use crate::event::{Event, EventListener}; use crate::grid::{Dimensions, DisplayIter, Grid, IndexRegion, Indexed, Scroll}; use crate::index::{self, Boundary, Column, Direction, IndexRange, Line, Point, Side}; @@ -467,7 +467,7 @@ pub use crate::term::mode::TermMode; pub struct VisualBell { /// Visual bell animation. - animation: VisualBellAnimation, + animation: BellAnimation, /// Visual bell duration. duration: Duration, @@ -484,15 +484,6 @@ fn cubic_bezier(p0: f64, p1: f64, p2: f64, p3: f64, x: f64) -> f64 { } impl VisualBell { - pub fn new<C>(config: &Config<C>) -> VisualBell { - let visual_bell_config = &config.visual_bell; - VisualBell { - animation: visual_bell_config.animation, - duration: visual_bell_config.duration(), - start_time: None, - } - } - /// Ring the visual bell, and return its intensity. pub fn ring(&mut self) -> f64 { let now = Instant::now(); @@ -557,19 +548,17 @@ impl VisualBell { // VisualBell. When `time` is 0.0, `inverse_intensity` is 0.0, // and when `time` is 1.0, `inverse_intensity` is 1.0. let inverse_intensity = match self.animation { - VisualBellAnimation::Ease | VisualBellAnimation::EaseOut => { + BellAnimation::Ease | BellAnimation::EaseOut => { cubic_bezier(0.25, 0.1, 0.25, 1.0, time) }, - VisualBellAnimation::EaseOutSine => cubic_bezier(0.39, 0.575, 0.565, 1.0, time), - VisualBellAnimation::EaseOutQuad => cubic_bezier(0.25, 0.46, 0.45, 0.94, time), - VisualBellAnimation::EaseOutCubic => { - cubic_bezier(0.215, 0.61, 0.355, 1.0, time) - }, - VisualBellAnimation::EaseOutQuart => cubic_bezier(0.165, 0.84, 0.44, 1.0, time), - VisualBellAnimation::EaseOutQuint => cubic_bezier(0.23, 1.0, 0.32, 1.0, time), - VisualBellAnimation::EaseOutExpo => cubic_bezier(0.19, 1.0, 0.22, 1.0, time), - VisualBellAnimation::EaseOutCirc => cubic_bezier(0.075, 0.82, 0.165, 1.0, time), - VisualBellAnimation::Linear => time, + BellAnimation::EaseOutSine => cubic_bezier(0.39, 0.575, 0.565, 1.0, time), + BellAnimation::EaseOutQuad => cubic_bezier(0.25, 0.46, 0.45, 0.94, time), + BellAnimation::EaseOutCubic => cubic_bezier(0.215, 0.61, 0.355, 1.0, time), + BellAnimation::EaseOutQuart => cubic_bezier(0.165, 0.84, 0.44, 1.0, time), + BellAnimation::EaseOutQuint => cubic_bezier(0.23, 1.0, 0.32, 1.0, time), + BellAnimation::EaseOutExpo => cubic_bezier(0.19, 1.0, 0.22, 1.0, time), + BellAnimation::EaseOutCirc => cubic_bezier(0.075, 0.82, 0.165, 1.0, time), + BellAnimation::Linear => time, }; // Since we want the `intensity` of the VisualBell to decay over @@ -580,9 +569,19 @@ impl VisualBell { } pub fn update_config<C>(&mut self, config: &Config<C>) { - let visual_bell_config = &config.visual_bell; - self.animation = visual_bell_config.animation; - self.duration = visual_bell_config.duration(); + let bell_config = config.bell(); + self.animation = bell_config.animation; + self.duration = bell_config.duration(); + } +} + +impl From<&BellConfig> for VisualBell { + fn from(bell_config: &BellConfig) -> VisualBell { + VisualBell { + animation: bell_config.animation, + duration: bell_config.duration(), + start_time: None, + } } } @@ -763,7 +762,7 @@ impl<T> Term<T> { Term { dirty: false, - visual_bell: VisualBell::new(config), + visual_bell: config.bell().into(), grid, inactive_grid: alt, active_charset: Default::default(), @@ -1617,7 +1616,7 @@ impl<T: EventListener> Handler for Term<T> { fn bell(&mut self) { trace!("Bell"); self.visual_bell.ring(); - self.event_proxy.send_event(Event::Urgent); + self.event_proxy.send_event(Event::Bell); } #[inline] diff --git a/alacritty_terminal/src/thread.rs b/alacritty_terminal/src/thread.rs new file mode 100644 index 00000000..6a93b78d --- /dev/null +++ b/alacritty_terminal/src/thread.rs @@ -0,0 +1,11 @@ +use std::thread::{Builder, JoinHandle}; + +/// Like `thread::spawn`, but with a `name` argument. +pub fn spawn_named<F, T, S>(name: S, f: F) -> JoinHandle<T> +where + F: FnOnce() -> T + Send + 'static, + T: Send + 'static, + S: Into<String>, +{ + Builder::new().name(name.into()).spawn(f).expect("thread spawn works") +} diff --git a/alacritty_terminal/src/util.rs b/alacritty_terminal/src/util.rs deleted file mode 100644 index f996359a..00000000 --- a/alacritty_terminal/src/util.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::ffi::OsStr; -use std::io; -use std::process::{Command, Stdio}; - -#[cfg(not(windows))] -use std::os::unix::process::CommandExt; - -#[cfg(windows)] -use std::os::windows::process::CommandExt; -#[cfg(windows)] -use winapi::um::winbase::{CREATE_NEW_PROCESS_GROUP, CREATE_NO_WINDOW}; - -/// Threading utilities. -pub mod thread { - /// Like `thread::spawn`, but with a `name` argument. - pub fn spawn_named<F, T, S>(name: S, f: F) -> std::thread::JoinHandle<T> - where - F: FnOnce() -> T + Send + 'static, - T: Send + 'static, - S: Into<String>, - { - std::thread::Builder::new().name(name.into()).spawn(f).expect("thread spawn works") - } - - pub use std::thread::*; -} - -#[cfg(not(windows))] -pub fn start_daemon<I, S>(program: &str, args: I) -> io::Result<()> -where - I: IntoIterator<Item = S>, - S: AsRef<OsStr>, -{ - unsafe { - Command::new(program) - .args(args) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .pre_exec(|| { - match ::libc::fork() { - -1 => return Err(io::Error::last_os_error()), - 0 => (), - _ => ::libc::_exit(0), - } - - if ::libc::setsid() == -1 { - return Err(io::Error::last_os_error()); - } - - Ok(()) - }) - .spawn()? - .wait() - .map(|_| ()) - } -} - -#[cfg(windows)] -pub fn start_daemon<I, S>(program: &str, args: I) -> io::Result<()> -where - I: IntoIterator<Item = S>, - S: AsRef<OsStr>, -{ - // Setting all the I/O handles to null and setting the - // CREATE_NEW_PROCESS_GROUP and CREATE_NO_WINDOW has the effect - // that console applications will run without opening a new - // console window. - Command::new(program) - .args(args) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .creation_flags(CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW) - .spawn() - .map(|_| ()) -} |