Skip to content

Commit

Permalink
Add option to run command on bell
Browse files Browse the repository at this point in the history
Fixes #1528.
  • Loading branch information
kchibisov committed Jul 10, 2020
1 parent b78f3d1 commit 8bd2c13
Show file tree
Hide file tree
Showing 21 changed files with 292 additions and 202 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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

Expand All @@ -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

Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

67 changes: 41 additions & 26 deletions alacritty.yml
Expand Up @@ -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
#
Expand Down Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions alacritty/Cargo.toml
Expand Up @@ -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]
Expand Down
7 changes: 7 additions & 0 deletions alacritty/src/config/mod.rs
Expand Up @@ -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)]
Expand Down
4 changes: 2 additions & 2 deletions alacritty/src/config/monitor.rs
Expand Up @@ -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};

Expand All @@ -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 =
Expand Down
77 changes: 38 additions & 39 deletions alacritty_terminal/src/util.rs → 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 {
Expand All @@ -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());
}

Expand All @@ -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(|_| ())
}
2 changes: 1 addition & 1 deletion alacritty/src/display.rs
Expand Up @@ -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);
Expand Down
21 changes: 9 additions & 12 deletions alacritty/src/event.rs
Expand Up @@ -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;
Expand All @@ -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")]
Expand All @@ -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};
Expand Down Expand Up @@ -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.
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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);
Expand Down
9 changes: 3 additions & 6 deletions alacritty/src/input.rs
Expand Up @@ -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::{
Expand All @@ -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};
Expand Down Expand Up @@ -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(),
Expand Down
1 change: 1 addition & 0 deletions alacritty/src/main.rs
Expand Up @@ -36,6 +36,7 @@ mod cli;
mod clipboard;
mod config;
mod cursor;
mod daemon;
mod display;
mod event;
mod input;
Expand Down
4 changes: 2 additions & 2 deletions alacritty/src/renderer/mod.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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 =
Expand Down

0 comments on commit 8bd2c13

Please sign in to comment.