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 | |
parent | b78f3d133960dad38ad21e808723e51661b59881 (diff) | |
download | alacritty-8bd2c13490f8cb6ad6b0c1104f9586b3554efea2.tar.gz alacritty-8bd2c13490f8cb6ad6b0c1104f9586b3554efea2.zip |
Add option to run command on bell
Fixes #1528.
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | alacritty.yml | 67 | ||||
-rw-r--r-- | alacritty/Cargo.toml | 1 | ||||
-rw-r--r-- | alacritty/src/config/mod.rs | 7 | ||||
-rw-r--r-- | alacritty/src/config/monitor.rs | 4 | ||||
-rw-r--r-- | alacritty/src/daemon.rs (renamed from alacritty_terminal/src/util.rs) | 77 | ||||
-rw-r--r-- | alacritty/src/display.rs | 2 | ||||
-rw-r--r-- | alacritty/src/event.rs | 21 | ||||
-rw-r--r-- | alacritty/src/input.rs | 9 | ||||
-rw-r--r-- | alacritty/src/main.rs | 1 | ||||
-rw-r--r-- | alacritty/src/renderer/mod.rs | 4 | ||||
-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 |
21 files changed, 292 insertions, 202 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index c19894cb..ed7783ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Expanding existing selections using the right mouse button - Support for `gopher` and `gemini` URLs - Unicode 13 support +- Option to run command on bell which can be set in `bell.command` ### Changed @@ -48,6 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - To use the cell's text color for selection with a modified background, the `color.selection.text` variable must now be set to `CellForeground` instead of omitting it - URLs are no longer highlighted without a clearly delimited scheme +- Renamed `visual_bell` to `bell` ### Fixed @@ -32,6 +32,7 @@ dependencies = [ "gl_generator 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "glutin 0.24.1 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.72 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "notify 4.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/alacritty.yml b/alacritty.yml index ed6feafc..5a14a417 100644 --- a/alacritty.yml +++ b/alacritty.yml @@ -265,31 +265,46 @@ # #indexed_colors: [] -# Visual Bell -# -# Any time the BEL code is received, Alacritty "rings" the visual bell. Once -# rung, the terminal background will be set to white and transition back to the -# default background color. You can control the rate of this transition by -# setting the `duration` property (represented in milliseconds). You can also -# configure the transition function by setting the `animation` property. -# -# Values for `animation`: -# - Ease -# - EaseOut -# - EaseOutSine -# - EaseOutQuad -# - EaseOutCubic -# - EaseOutQuart -# - EaseOutQuint -# - EaseOutExpo -# - EaseOutCirc -# - Linear -# -# Specifying a `duration` of `0` will disable the visual bell. -#visual_bell: -# animation: EaseOutExpo -# duration: 0 -# color: '#ffffff' +# Bell +# +# The bell is rung every time the BEL control character is received. +#bell: + # Visual Bell Animation + # + # Animation effect for flashing the screen when the visual bell is rung. + # + # Values for `animation`: + # - Ease + # - EaseOut + # - EaseOutSine + # - EaseOutQuad + # - EaseOutCubic + # - EaseOutQuart + # - EaseOutQuint + # - EaseOutExpo + # - EaseOutCirc + # - Linear + #animation: EaseOutExpo + + # Duration of the visual bell flash. A `duration` of `0` will disable the + # visual bell animation. + #duration: 0 + + # Visual bell animation color. + #color: '#ffffff' + + # Bell Command + # + # This program is executed whenever the bell is rung. + # + # When set to `command: None`, no command will be executed. + # + # Example: + # command: + # program: notify-send + # args: ["Hello, World!"] + # + #command: None # Background opacity # @@ -358,7 +373,7 @@ # # Alacritty defaults to using the newer ConPTY backend if it is available, # since it resolves a lot of bugs and is quite a bit faster. If it is not -# available, the the WinPTY backend will be used instead. +# available, the WinPTY backend will be used instead. # # Setting this option to `true` makes Alacritty use the legacy WinPTY backend, # even if the ConPTY backend is available. diff --git a/alacritty/Cargo.toml b/alacritty/Cargo.toml index 6cd63867..9ed2d9ce 100644 --- a/alacritty/Cargo.toml +++ b/alacritty/Cargo.toml @@ -23,6 +23,7 @@ parking_lot = "0.10.2" font = { path = "../font", features = ["force_system_fontconfig"] } urlocator = "0.1.3" copypasta = { version = "0.7.0", default-features = false } +libc = "0.2" unicode-width = "0.1" [build-dependencies] diff --git a/alacritty/src/config/mod.rs b/alacritty/src/config/mod.rs index f416039c..ffa7cbd3 100644 --- a/alacritty/src/config/mod.rs +++ b/alacritty/src/config/mod.rs @@ -217,6 +217,13 @@ fn print_deprecation_warnings(config: &Config) { the config" ); } + + if config.visual_bell.is_some() { + warn!( + target: LOG_TARGET_CONFIG, + "Config visual_bell has been deprecated; please use bell instead" + ) + } } #[cfg(test)] diff --git a/alacritty/src/config/monitor.rs b/alacritty/src/config/monitor.rs index 42603c7e..2ed0c426 100644 --- a/alacritty/src/config/monitor.rs +++ b/alacritty/src/config/monitor.rs @@ -4,7 +4,7 @@ use std::time::Duration; use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher}; -use alacritty_terminal::util; +use alacritty_terminal::thread; use crate::event::{Event, EventProxy}; @@ -20,7 +20,7 @@ impl Monitor { let path = path.into(); Monitor { - _thread: util::thread::spawn_named("config watcher", move || { + _thread: thread::spawn_named("config watcher", move || { let (tx, rx) = mpsc::channel(); // The Duration argument is a debouncing period. let mut watcher = diff --git a/alacritty_terminal/src/util.rs b/alacritty/src/daemon.rs index f996359a..4a6b6f83 100644 --- a/alacritty_terminal/src/util.rs +++ b/alacritty/src/daemon.rs @@ -1,34 +1,53 @@ use std::ffi::OsStr; +use std::fmt::Debug; 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; +use std::process::{Command, Stdio}; + +use log::{debug, warn}; + #[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") +/// Start the daemon and log error on failure. +pub fn start_daemon<I, S>(program: &str, args: I) +where + I: IntoIterator<Item = S> + Debug + Copy, + S: AsRef<OsStr>, +{ + match spawn_daemon(program, args) { + Ok(_) => debug!("Launched {} with args {:?}", program, args), + Err(_) => warn!("Unable to launch {} with args {:?}", program, args), } +} - pub use std::thread::*; +#[cfg(windows)] +fn spawn_daemon<I, S>(program: &str, args: I) -> io::Result<()> +where + I: IntoIterator<Item = S> + Copy, + 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(|_| ()) } #[cfg(not(windows))] -pub fn start_daemon<I, S>(program: &str, args: I) -> io::Result<()> +fn spawn_daemon<I, S>(program: &str, args: I) -> io::Result<()> where - I: IntoIterator<Item = S>, + I: IntoIterator<Item = S> + Copy, S: AsRef<OsStr>, { unsafe { @@ -38,13 +57,13 @@ where .stdout(Stdio::null()) .stderr(Stdio::null()) .pre_exec(|| { - match ::libc::fork() { + match libc::fork() { -1 => return Err(io::Error::last_os_error()), 0 => (), - _ => ::libc::_exit(0), + _ => libc::_exit(0), } - if ::libc::setsid() == -1 { + if libc::setsid() == -1 { return Err(io::Error::last_os_error()); } @@ -55,23 +74,3 @@ where .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(|_| ()) -} diff --git a/alacritty/src/display.rs b/alacritty/src/display.rs index 53e6fc58..0a3bea34 100644 --- a/alacritty/src/display.rs +++ b/alacritty/src/display.rs @@ -540,7 +540,7 @@ impl Display { 0., size_info.width, size_info.height, - config.visual_bell.color, + config.bell().color, visual_bell_intensity as f32, ); rects.push(visual_bell_rect); diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs index edbc4086..f264aab5 100644 --- a/alacritty/src/event.rs +++ b/alacritty/src/event.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use std::cmp::{max, min}; use std::env; +use std::fmt::Debug; #[cfg(unix)] use std::fs; use std::fs::File; @@ -20,7 +21,7 @@ use glutin::event_loop::{ControlFlow, EventLoop, EventLoopProxy, EventLoopWindow use glutin::platform::desktop::EventLoopExtDesktop; #[cfg(not(any(target_os = "macos", windows)))] use glutin::platform::unix::EventLoopWindowTargetExtUnix; -use log::{debug, info, warn}; +use log::info; use serde_json as json; #[cfg(target_os = "macos")] @@ -38,12 +39,12 @@ use alacritty_terminal::term::cell::Cell; use alacritty_terminal::term::{ClipboardType, SizeInfo, Term, TermMode}; #[cfg(not(windows))] use alacritty_terminal::tty; -use alacritty_terminal::util::start_daemon; use crate::cli::Options; use crate::clipboard::Clipboard; use crate::config; use crate::config::Config; +use crate::daemon::start_daemon; use crate::display::{Display, DisplayUpdate}; use crate::input::{self, ActionContext as _, FONT_SIZE_STEP}; use crate::scheduler::{Scheduler, TimerId}; @@ -290,10 +291,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon #[cfg(not(unix))] let args: Vec<String> = Vec::new(); - match start_daemon(&alacritty, &args) { - Ok(_) => debug!("Started new Alacritty process: {} {:?}", alacritty, args), - Err(_) => warn!("Unable to start new Alacritty process: {} {:?}", alacritty, args), - } + start_daemon(&alacritty, &args); } /// Spawn URL launcher when clicking on URLs. @@ -308,10 +306,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon let end = self.terminal.visible_to_buffer(url.end()); args.push(self.terminal.bounds_to_string(start, end)); - match start_daemon(launcher.program(), &args) { - Ok(_) => debug!("Launched {} with args {:?}", launcher.program(), args), - Err(_) => warn!("Unable to launch {} with args {:?}", launcher.program(), args), - } + start_daemon(launcher.program(), &args); } } @@ -839,8 +834,10 @@ impl<N: Notify + OnResize> Processor<N> { Event::TerminalEvent(event) => match event { TerminalEvent::Title(title) => processor.ctx.window.set_title(&title), TerminalEvent::Wakeup => processor.ctx.terminal.dirty = true, - TerminalEvent::Urgent => { - processor.ctx.window.set_urgent(!processor.ctx.terminal.is_focused) + TerminalEvent::Bell => { + let bell_command = processor.ctx.config.bell().command.as_ref(); + let _ = bell_command.map(|cmd| start_daemon(cmd.program(), cmd.args())); + processor.ctx.window.set_urgent(!processor.ctx.terminal.is_focused); }, TerminalEvent::ClipboardStore(clipboard_type, content) => { processor.ctx.clipboard.store(clipboard_type, content); diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs index 48450b12..cab0f0e2 100644 --- a/alacritty/src/input.rs +++ b/alacritty/src/input.rs @@ -10,7 +10,7 @@ use std::cmp::{max, min, Ordering}; use std::marker::PhantomData; use std::time::{Duration, Instant}; -use log::{debug, trace, warn}; +use log::trace; use glutin::dpi::PhysicalPosition; use glutin::event::{ @@ -30,11 +30,11 @@ use alacritty_terminal::message_bar::{self, Message}; use alacritty_terminal::selection::SelectionType; use alacritty_terminal::term::mode::TermMode; use alacritty_terminal::term::{ClipboardType, SizeInfo, Term}; -use alacritty_terminal::util::start_daemon; use alacritty_terminal::vi_mode::ViMotion; use crate::clipboard::Clipboard; use crate::config::{Action, Binding, Config, Key, ViAction}; +use crate::daemon::start_daemon; use crate::event::{ClickState, Event, Mouse, TYPING_SEARCH_DELAY}; use crate::scheduler::{Scheduler, TimerId}; use crate::url::{Url, Urls}; @@ -160,10 +160,7 @@ impl<T: EventListener> Execute<T> for Action { let program = program.program(); trace!("Running command {} with args {:?}", program, args); - match start_daemon(program, args) { - Ok(_) => debug!("Spawned new proc"), - Err(err) => warn!("Couldn't run command {}", err), - } + start_daemon(program, args); }, Action::ClearSelection => ctx.clear_selection(), Action::ToggleViMode => ctx.terminal_mut().toggle_vi_mode(), diff --git a/alacritty/src/main.rs b/alacritty/src/main.rs index ab4acaa7..9fbcab55 100644 --- a/alacritty/src/main.rs +++ b/alacritty/src/main.rs @@ -36,6 +36,7 @@ mod cli; mod clipboard; mod config; mod cursor; +mod daemon; mod display; mod event; mod input; diff --git a/alacritty/src/renderer/mod.rs b/alacritty/src/renderer/mod.rs index 7dc037a1..bd9f4ae7 100644 --- a/alacritty/src/renderer/mod.rs +++ b/alacritty/src/renderer/mod.rs @@ -24,7 +24,7 @@ use alacritty_terminal::index::{Column, Line}; use alacritty_terminal::term::cell::{self, Flags}; use alacritty_terminal::term::color::Rgb; use alacritty_terminal::term::{self, CursorKey, RenderableCell, RenderableCellContent, SizeInfo}; -use alacritty_terminal::util; +use alacritty_terminal::thread; use std::fmt::{self, Display, Formatter}; pub mod rects; @@ -660,7 +660,7 @@ impl QuadRenderer { let (msg_tx, msg_rx) = mpsc::channel(); if cfg!(feature = "live-shader-reload") { - util::thread::spawn_named("live shader reload", move || { + thread::spawn_named("live shader reload", move || { let (tx, rx) = std::sync::mpsc::channel(); // The Duration argument is a debouncing period. let mut watcher = 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") +} |