aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAyose <ayosec@gmail.com>2025-02-24 00:00:00 +0000
committerAyose <ayosec@gmail.com>2025-02-24 00:00:00 +0000
commit814e8fefc60b4457ea155d11df9f27795de830ec (patch)
treeecc31d4e95680fd7f2a4dfb61cf30cefae387d3b
parentff44690b072de6cccffbc8e56b869b8842797692 (diff)
parent03c2907b44b4189aac5fdeaea331f5aab5c7072e (diff)
downloadr-alacritty-814e8fefc60b4457ea155d11df9f27795de830ec.tar.gz
r-alacritty-814e8fefc60b4457ea155d11df9f27795de830ec.tar.bz2
r-alacritty-814e8fefc60b4457ea155d11df9f27795de830ec.zip
Merge remote-tracking branch 'vendor/master' into graphics
-rw-r--r--CHANGELOG.md31
-rw-r--r--Cargo.lock42
-rw-r--r--alacritty/Cargo.toml8
-rw-r--r--alacritty/build.rs1
-rw-r--r--alacritty/src/cli.rs9
-rw-r--r--alacritty/src/config/ui_config.rs4
-rw-r--r--alacritty/src/daemon.rs13
-rw-r--r--alacritty/src/display/mod.rs133
-rw-r--r--alacritty/src/display/window.rs20
-rw-r--r--alacritty/src/event.rs25
-rw-r--r--alacritty/src/input/keyboard.rs21
-rw-r--r--alacritty/src/input/mod.rs5
-rw-r--r--alacritty/src/ipc.rs15
-rw-r--r--alacritty/src/main.rs19
-rw-r--r--alacritty/src/renderer/mod.rs69
-rw-r--r--alacritty/src/renderer/platform.rs22
-rw-r--r--alacritty/src/window_context.rs14
-rw-r--r--alacritty/windows/wix/alacritty.wxs2
-rw-r--r--alacritty_terminal/CHANGELOG.md14
-rw-r--r--alacritty_terminal/Cargo.toml4
-rw-r--r--alacritty_terminal/src/event_loop.rs19
-rw-r--r--alacritty_terminal/src/tty/mod.rs4
-rw-r--r--alacritty_terminal/src/tty/unix.rs29
-rw-r--r--alacritty_terminal/tests/ref.rs4
-rw-r--r--extra/man/alacritty.5.scd3
-rw-r--r--extra/osx/Alacritty.app/Contents/Info.plist2
26 files changed, 333 insertions, 199 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f23f442f..cf13eb7a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,17 +8,42 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
Notable changes to the `alacritty_terminal` crate are documented in its
[CHANGELOG](./alacritty_terminal/CHANGELOG.md).
-## 0.15.0-dev
+## 0.16.0-dev
+
+### Changed
+
+- Hide login message if `~/.hushlogin` is present
+
+### Fixed
+
+- Crash when OpenGL context resets
+
+## 0.15.1
+
+### Changed
+
+- Error out when socket fails to create with `--daemon`
+- Default URL hints now stop before backslashes
+
+### Fixed
+
+- Modifiers being out of sync for fast/synthetic input on X11
+- Child process creation failing while inside a deleted directory
+- Shifted key reported without a shift when using kitty keyboard protocol
+
+## 0.15.0
### Added
- Config option `window.level = "AlwaysOnTop"` to force Alacritty to always be the toplevel window
- Escape sequence to move cursor forward tabs ( CSI Ps I )
+- Pass activation token in `alacritty msg create-window` on Wayland/X11
### Changed
- Always focus new windows on macOS
- Don't switch to semantic/line selection when control is pressed
+- Always emit `1` for the first parameter when having modifiers in kitty keyboard protocol
### Fixed
@@ -29,6 +54,8 @@ Notable changes to the `alacritty_terminal` crate are documented in its
- Migrating nonexistent toml import breaking the entire migration
- First daemon mode window ignoring window options passed through CLI
- Report of Enter/Tab/Backspace in kitty keyboard's report event types mode
+- Crash when pressing certain modifier keys on macOS 15+
+- Cut off wide characters in preedit string
## 0.14.0
@@ -52,7 +79,6 @@ Notable changes to the `alacritty_terminal` crate are documented in its
- Moved config option `shell` to `terminal.shell`
- `ctrl+shift+u` binding to open links to `ctrl+shift+o` to avoid collisions with IMEs
- Use `Beam` cursor for single char cursor inside the IME preview
-- Always emit `1` for the first parameter when having modifiers in kitty keyboard protocol
### Fixed
@@ -74,7 +100,6 @@ Notable changes to the `alacritty_terminal` crate are documented in its
- Invalid URL highlights after terminal scrolling
- Hollow block cursor not spanning multiple chars being edited inside the IME preview
- Vi inline search only working for direct key input without modifiers
-- Crash when pressing certain modifier keys on macOS 15+
## 0.13.2
diff --git a/Cargo.lock b/Cargo.lock
index 60f10cfa..987a1715 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -32,7 +32,7 @@ dependencies = [
[[package]]
name = "alacritty"
-version = "0.15.0-dev"
+version = "0.16.0-dev"
dependencies = [
"ahash",
"alacritty_config",
@@ -95,7 +95,7 @@ dependencies = [
[[package]]
name = "alacritty_terminal"
-version = "0.24.2-dev"
+version = "0.25.1-dev"
dependencies = [
"base64",
"bitflags 2.6.0",
@@ -817,9 +817,9 @@ dependencies = [
[[package]]
name = "glutin"
-version = "0.32.1"
+version = "0.32.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec69412a0bf07ea7607e638b415447857a808846c2b685a43c8aa18bc6d5e499"
+checksum = "03642b8b0cce622392deb0ee3e88511f75df2daac806102597905c3ea1974848"
dependencies = [
"bitflags 2.6.0",
"cfg_aliases",
@@ -842,9 +842,9 @@ dependencies = [
[[package]]
name = "glutin_egl_sys"
-version = "0.7.0"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cae99fff4d2850dbe6fb8c1fa8e4fead5525bab715beaacfccf3fb994e01c827"
+checksum = "4c4680ba6195f424febdc3ba46e7a42a0e58743f2edb115297b86d7f8ecc02d2"
dependencies = [
"gl_generator",
"windows-sys 0.52.0",
@@ -852,9 +852,9 @@ dependencies = [
[[package]]
name = "glutin_glx_sys"
-version = "0.6.0"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c2b2d3918e76e18e08796b55eb64e8fe6ec67d5a6b2e2a7e2edce224ad24c63"
+checksum = "8a7bb2938045a88b612499fbcba375a77198e01306f52272e692f8c1f3751185"
dependencies = [
"gl_generator",
"x11-dl",
@@ -862,9 +862,9 @@ dependencies = [
[[package]]
name = "glutin_wgl_sys"
-version = "0.6.0"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a4e1951bbd9434a81aa496fe59ccc2235af3820d27b85f9314e279609211e2c"
+checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e"
dependencies = [
"gl_generator",
]
@@ -2060,26 +2060,16 @@ dependencies = [
[[package]]
name = "vte-graphics"
-version = "0.13.1"
+version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a567531be6ebf19138eed358a880b7959f206cb79dec94a83d145797aedc4bd"
+checksum = "6a7d926313d94a0ef0d992fe9ab507451cdb4a7977e653155c8e4fa9b69c178f"
dependencies = [
+ "arrayvec",
"bitflags 2.6.0",
"cursor-icon",
"log",
+ "memchr",
"serde",
- "utf8parse",
- "vte_generate_state_changes",
-]
-
-[[package]]
-name = "vte_generate_state_changes"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e"
-dependencies = [
- "proc-macro2",
- "quote",
]
[[package]]
@@ -2541,9 +2531,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winit"
-version = "0.30.8"
+version = "0.30.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5d74280aabb958072864bff6cfbcf9025cf8bfacdde5e32b5e12920ef703b0f"
+checksum = "a809eacf18c8eca8b6635091543f02a5a06ddf3dad846398795460e6e0ae3cc0"
dependencies = [
"ahash",
"android-activity",
diff --git a/alacritty/Cargo.toml b/alacritty/Cargo.toml
index 919394fb..19467e9d 100644
--- a/alacritty/Cargo.toml
+++ b/alacritty/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "alacritty"
-version = "0.15.0-dev"
+version = "0.16.0-dev"
authors = ["Christian Duerr <contact@christianduerr.com>", "Joe Wilm <joe@jwilm.com>"]
license = "Apache-2.0"
description = "A fast, cross-platform, OpenGL terminal emulator"
@@ -12,7 +12,7 @@ rust-version = "1.74.0"
[dependencies.alacritty_terminal]
path = "../alacritty_terminal"
-version = "0.24.2-dev"
+version = "0.25.1-dev"
[dependencies.alacritty_config_derive]
path = "../alacritty_config_derive"
@@ -28,7 +28,7 @@ bitflags = "2.2.1"
clap = { version = "4.2.7", features = ["derive", "env"] }
copypasta = { version = "0.10.1", default-features = false }
crossfont = "0.8.0"
-glutin = { version = "0.32.0", default-features = false, features = ["egl", "wgl"] }
+glutin = { version = "0.32.2", default-features = false, features = ["egl", "wgl"] }
home = "0.5.5"
libc = "0.2"
log = { version = "0.4", features = ["std", "serde"] }
@@ -43,7 +43,7 @@ tempfile = "3.12.0"
toml = "0.8.2"
toml_edit = "0.22.21"
unicode-width = "0.1"
-winit = { version = "0.30.8", default-features = false, features = ["rwh_06", "serde"] }
+winit = { version = "0.30.9", default-features = false, features = ["rwh_06", "serde"] }
[build-dependencies]
gl_generator = "0.14.0"
diff --git a/alacritty/build.rs b/alacritty/build.rs
index 2ecbdf8f..02f0fdaf 100644
--- a/alacritty/build.rs
+++ b/alacritty/build.rs
@@ -18,6 +18,7 @@ fn main() {
Registry::new(Api::Gl, (3, 3), Profile::Core, Fallbacks::All, [
"GL_ARB_blend_func_extended",
"GL_ARB_clear_texture",
+ "GL_KHR_robustness",
"GL_KHR_debug",
])
.write_bindings(GlobalGenerator, &mut file)
diff --git a/alacritty/src/cli.rs b/alacritty/src/cli.rs
index bb0a24f4..feac41bd 100644
--- a/alacritty/src/cli.rs
+++ b/alacritty/src/cli.rs
@@ -189,7 +189,7 @@ impl TerminalOptions {
pty_config.shell = Some(command.into());
}
- pty_config.hold |= self.hold;
+ pty_config.drain_on_exit |= self.hold;
}
}
@@ -198,7 +198,7 @@ impl From<TerminalOptions> for PtyOptions {
PtyOptions {
working_directory: options.working_directory.take(),
shell: options.command().map(Into::into),
- hold: options.hold,
+ drain_on_exit: options.hold,
env: HashMap::new(),
}
}
@@ -300,6 +300,11 @@ pub struct WindowOptions {
/// The window tabbing identifier to use when building a window.
pub window_tabbing_id: Option<String>,
+ #[clap(skip)]
+ #[cfg(not(any(target_os = "macos", windows)))]
+ /// `ActivationToken` that we pass to winit.
+ pub activation_token: Option<String>,
+
/// Override configuration file options [example: 'cursor.style="Beam"'].
#[clap(short = 'o', long, num_args = 1..)]
option: Vec<String>,
diff --git a/alacritty/src/config/ui_config.rs b/alacritty/src/config/ui_config.rs
index b44bda0d..960bdbbc 100644
--- a/alacritty/src/config/ui_config.rs
+++ b/alacritty/src/config/ui_config.rs
@@ -37,7 +37,7 @@ use crate::config::LOG_TARGET_CONFIG;
/// Regex used for the default URL hint.
#[rustfmt::skip]
const URL_REGEX: &str = "(ipfs:|ipns:|magnet:|mailto:|gemini://|gopher://|https://|http://|news:|file:|git://|ssh:|ftp://)\
- [^\u{0000}-\u{001F}\u{007F}-\u{009F}<>\"\\s{-}\\^⟨⟩`]+";
+ [^\u{0000}-\u{001F}\u{007F}-\u{009F}<>\"\\s{-}\\^⟨⟩`\\\\]+";
#[derive(ConfigDeserialize, Default, Clone, Debug, PartialEq)]
pub struct UiConfig {
@@ -130,7 +130,7 @@ impl UiConfig {
let shell = self.terminal.shell.clone().or_else(|| self.shell.clone()).map(Into::into);
let working_directory =
self.working_directory.clone().or_else(|| self.general.working_directory.clone());
- PtyOptions { working_directory, shell, hold: false, env: HashMap::new() }
+ PtyOptions { working_directory, shell, drain_on_exit: false, env: HashMap::new() }
}
/// Generate key bindings for all keyboard hints.
diff --git a/alacritty/src/daemon.rs b/alacritty/src/daemon.rs
index c8fb88d1..fa530fa0 100644
--- a/alacritty/src/daemon.rs
+++ b/alacritty/src/daemon.rs
@@ -9,6 +9,7 @@ use std::process::{Command, Stdio};
#[rustfmt::skip]
#[cfg(not(windows))]
use {
+ std::env,
std::error::Error,
std::os::unix::process::CommandExt,
std::os::unix::io::RawFd,
@@ -58,18 +59,22 @@ where
{
let mut command = Command::new(program);
command.args(args).stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
- if let Ok(cwd) = foreground_process_path(master_fd, shell_pid) {
- command.current_dir(cwd);
- }
+
+ let working_directory = foreground_process_path(master_fd, shell_pid).ok();
unsafe {
command
- .pre_exec(|| {
+ .pre_exec(move || {
match libc::fork() {
-1 => return Err(io::Error::last_os_error()),
0 => (),
_ => libc::_exit(0),
}
+ // Copy foreground process' working directory, ignoring invalid paths.
+ if let Some(working_directory) = working_directory.as_ref() {
+ let _ = env::set_current_dir(working_directory);
+ }
+
if libc::setsid() == -1 {
return Err(io::Error::last_os_error());
}
diff --git a/alacritty/src/display/mod.rs b/alacritty/src/display/mod.rs
index a679fe21..6ff8b1e3 100644
--- a/alacritty/src/display/mod.rs
+++ b/alacritty/src/display/mod.rs
@@ -5,10 +5,13 @@ use std::cmp;
use std::fmt::{self, Formatter};
use std::mem::{self, ManuallyDrop};
use std::num::NonZeroU32;
-use std::ops::{Deref, DerefMut};
+use std::ops::Deref;
use std::time::{Duration, Instant};
+use glutin::config::GetGlConfig;
use glutin::context::{NotCurrentContext, PossiblyCurrentContext};
+use glutin::display::GetGlDisplay;
+use glutin::error::ErrorKind;
use glutin::prelude::*;
use glutin::surface::{Surface, SwapInterval, WindowSurface};
@@ -33,6 +36,7 @@ use alacritty_terminal::term::{
};
use alacritty_terminal::vte::ansi::{CursorShape, NamedColor};
+use crate::config::debug::RendererPreference;
use crate::config::font::Font;
use crate::config::window::Dimensions;
#[cfg(not(windows))]
@@ -49,7 +53,7 @@ use crate::display::window::Window;
use crate::event::{Event, EventType, Mouse, SearchState};
use crate::message_bar::{MessageBuffer, MessageType};
use crate::renderer::rects::{RenderLine, RenderLines, RenderRect};
-use crate::renderer::{self, GlyphCache, Renderer};
+use crate::renderer::{self, platform, GlyphCache, Renderer};
use crate::scheduler::{Scheduler, TimerId, Topic};
use crate::string::{ShortenDirection, StrShortener};
@@ -395,10 +399,11 @@ pub struct Display {
hint_mouse_point: Option<Point>,
renderer: ManuallyDrop<Renderer>,
+ renderer_preference: Option<RendererPreference>,
surface: ManuallyDrop<Surface<WindowSurface>>,
- context: ManuallyDrop<Replaceable<PossiblyCurrentContext>>,
+ context: ManuallyDrop<PossiblyCurrentContext>,
glyph_cache: GlyphCache,
meter: Meter,
@@ -431,7 +436,7 @@ impl Display {
}
// Create the GL surface to draw into.
- let surface = renderer::platform::create_gl_surface(
+ let surface = platform::create_gl_surface(
&gl_context,
window.inner_size(),
window.raw_window_handle(),
@@ -520,9 +525,10 @@ impl Display {
}
Ok(Self {
- context: ManuallyDrop::new(Replaceable::new(context)),
+ context: ManuallyDrop::new(context),
visual_bell: VisualBell::from(&config.bell),
renderer: ManuallyDrop::new(renderer),
+ renderer_preference: config.debug.renderer,
surface: ManuallyDrop::new(surface),
colors: List::from(&config.colors),
frame_timer: FrameTimer::new(),
@@ -548,29 +554,69 @@ impl Display {
#[inline]
pub fn gl_context(&self) -> &PossiblyCurrentContext {
- self.context.get()
+ &self.context
}
pub fn make_not_current(&mut self) {
- if self.context.get().is_current() {
- self.context.replace_with(|context| {
- context
- .make_not_current()
- .expect("failed to disable context")
- .treat_as_possibly_current()
- });
+ if self.context.is_current() {
+ self.context.make_not_current_in_place().expect("failed to disable context");
}
}
- pub fn make_current(&self) {
- if !self.context.get().is_current() {
- self.context.make_current(&self.surface).expect("failed to make context current")
+ pub fn make_current(&mut self) {
+ let is_current = self.context.is_current();
+
+ // Attempt to make the context current if it's not.
+ let context_loss = if is_current {
+ self.renderer.was_context_reset()
+ } else {
+ match self.context.make_current(&self.surface) {
+ Err(err) if err.error_kind() == ErrorKind::ContextLost => {
+ info!("Context lost for window {:?}", self.window.id());
+ true
+ },
+ _ => false,
+ }
+ };
+
+ if !context_loss {
+ return;
+ }
+
+ let gl_display = self.context.display();
+ let gl_config = self.context.config();
+ let raw_window_handle = Some(self.window.raw_window_handle());
+ let context = platform::create_gl_context(&gl_display, &gl_config, raw_window_handle)
+ .expect("failed to recreate context.");
+
+ // Drop the old context and renderer.
+ unsafe {
+ ManuallyDrop::drop(&mut self.renderer);
+ ManuallyDrop::drop(&mut self.context);
}
+
+ // Activate new context.
+ let context = context.treat_as_possibly_current();
+ self.context = ManuallyDrop::new(context);
+ self.context.make_current(&self.surface).expect("failed to reativate context after reset.");
+
+ // Recreate renderer.
+ let renderer = Renderer::new(&self.context, self.renderer_preference)
+ .expect("failed to recreate renderer after reset");
+ self.renderer = ManuallyDrop::new(renderer);
+
+ // Resize the renderer.
+ self.renderer.resize(&self.size_info);
+
+ self.reset_glyph_cache();
+ self.damage_tracker.frame().mark_fully_damaged();
+
+ debug!("Recovered window {:?} from gpu reset", self.window.id());
}
fn swap_buffers(&self) {
#[allow(clippy::single_match)]
- let res = match (self.surface.deref(), &self.context.get()) {
+ let res = match (self.surface.deref(), &self.context.deref()) {
#[cfg(not(any(target_os = "macos", windows)))]
(Surface::Egl(surface), PossiblyCurrentContext::Egl(context))
if matches!(self.raw_window_handle, RawWindowHandle::Wayland(_))
@@ -1374,6 +1420,8 @@ impl Display {
(&mut self.highlighted_hint, &mut self.highlighted_hint_age, true),
(&mut self.vi_highlighted_hint, &mut self.vi_highlighted_hint_age, false),
];
+
+ let num_lines = self.size_info.screen_lines();
for (hint, hint_age, reset_mouse) in hints {
let (start, end) = match hint {
Some(hint) => (*hint.bounds().start(), *hint.bounds().end()),
@@ -1387,10 +1435,12 @@ impl Display {
}
// Convert hint bounds to viewport coordinates.
- let start = term::point_to_viewport(display_offset, start).unwrap_or_default();
- let end = term::point_to_viewport(display_offset, end).unwrap_or_else(|| {
- Point::new(self.size_info.screen_lines() - 1, self.size_info.last_column())
- });
+ let start = term::point_to_viewport(display_offset, start)
+ .filter(|point| point.line < num_lines)
+ .unwrap_or_default();
+ let end = term::point_to_viewport(display_offset, end)
+ .filter(|point| point.line < num_lines)
+ .unwrap_or_else(|| Point::new(num_lines - 1, self.size_info.last_column()));
// Clear invalidated hints.
if frame.intersects(start, end) {
@@ -1525,47 +1575,6 @@ pub struct RendererUpdate {
clear_font_cache: bool,
}
-/// Struct for safe in-place replacement.
-///
-/// This struct allows easily replacing struct fields that provide `self -> Self` methods in-place,
-/// without having to deal with constantly unwrapping the underlying [`Option`].
-struct Replaceable<T>(Option<T>);
-
-impl<T> Replaceable<T> {
- pub fn new(inner: T) -> Self {
- Self(Some(inner))
- }
-
- /// Replace the contents of the container.
- pub fn replace_with<F: FnMut(T) -> T>(&mut self, f: F) {
- self.0 = self.0.take().map(f);
- }
-
- /// Get immutable access to the wrapped value.
- pub fn get(&self) -> &T {
- self.0.as_ref().unwrap()
- }
-
- /// Get mutable access to the wrapped value.
- pub fn get_mut(&mut self) -> &mut T {
- self.0.as_mut().unwrap()
- }
-}
-
-impl<T> Deref for Replaceable<T> {
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- self.get()
- }
-}
-
-impl<T> DerefMut for Replaceable<T> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- self.get_mut()
- }
-}
-
/// The frame timer state.
pub struct FrameTimer {
/// Base timestamp used to compute sync points.
diff --git a/alacritty/src/display/window.rs b/alacritty/src/display/window.rs
index 1c8089bc..f9fb9272 100644
--- a/alacritty/src/display/window.rs
+++ b/alacritty/src/display/window.rs
@@ -2,6 +2,8 @@
use winit::platform::startup_notify::{
self, EventLoopExtStartupNotify, WindowAttributesExtStartupNotify,
};
+#[cfg(not(any(target_os = "macos", windows)))]
+use winit::window::ActivationToken;
#[cfg(all(not(feature = "x11"), not(any(target_os = "macos", windows))))]
use winit::platform::wayland::WindowAttributesExtWayland;
@@ -38,6 +40,7 @@ use winit::window::{
use alacritty_terminal::index::Point;
+use crate::cli::WindowOptions;
use crate::config::window::{Decorations, Identity, WindowConfig};
use crate::config::UiConfig;
use crate::display::SizeInfo;
@@ -106,6 +109,9 @@ pub struct Window {
/// Flag indicating whether redraw was requested.
pub requested_redraw: bool,
+ /// Hold the window when terminal exits.
+ pub hold: bool,
+
window: WinitWindow,
/// Current window title.
@@ -124,9 +130,7 @@ impl Window {
event_loop: &ActiveEventLoop,
config: &UiConfig,
identity: &Identity,
- #[rustfmt::skip]
- #[cfg(target_os = "macos")]
- tabbing_id: &Option<String>,
+ options: &mut WindowOptions,
#[rustfmt::skip]
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
x11_visual: Option<X11VisualInfo>,
@@ -138,7 +142,7 @@ impl Window {
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
x11_visual,
#[cfg(target_os = "macos")]
- tabbing_id,
+ &options.window_tabbing_id.take(),
);
if let Some(position) = config.window.position {
@@ -147,7 +151,12 @@ impl Window {
}
#[cfg(not(any(target_os = "macos", windows)))]
- if let Some(token) = event_loop.read_token_from_env() {
+ if let Some(token) = options
+ .activation_token
+ .take()
+ .map(ActivationToken::from_raw)
+ .or_else(|| event_loop.read_token_from_env())
+ {
log::debug!("Activating window with token: {token:?}");
window_attributes = window_attributes.with_activation_token(token);
@@ -193,6 +202,7 @@ impl Window {
let is_x11 = matches!(window.window_handle().unwrap().as_raw(), RawWindowHandle::Xlib(_));
Ok(Self {
+ hold: options.terminal_options.hold,
requested_redraw: false,
title: identity.title,
current_mouse_cursor,
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs
index 2ac6279d..c761f5ae 100644
--- a/alacritty/src/event.rs
+++ b/alacritty/src/event.rs
@@ -4,6 +4,7 @@ use crate::ConfigMonitor;
use glutin::config::GetGlConfig;
use std::borrow::Cow;
use std::cmp::min;
+use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet, VecDeque};
use std::error::Error;
use std::ffi::OsStr;
@@ -380,9 +381,14 @@ impl ApplicationHandler<Event> for Processor {
},
(EventType::Terminal(TerminalEvent::Exit), Some(window_id)) => {
// Remove the closed terminal.
- let window_context = match self.windows.remove(window_id) {
- Some(window_context) => window_context,
- None => return,
+ let window_context = match self.windows.entry(*window_id) {
+ // Don't exit when terminal exits if user asked to hold the window.
+ Entry::Occupied(window_context)
+ if !window_context.get().display.window.hold =>
+ {
+ window_context.remove()
+ },
+ _ => return,
};
// Unschedule pending events.
@@ -838,9 +844,8 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
#[cfg(not(windows))]
fn create_new_window(&mut self, #[cfg(target_os = "macos")] tabbing_id: Option<String>) {
let mut options = WindowOptions::default();
- if let Ok(working_directory) = foreground_process_path(self.master_fd, self.shell_pid) {
- options.terminal_options.working_directory = Some(working_directory);
- }
+ options.terminal_options.working_directory =
+ foreground_process_path(self.master_fd, self.shell_pid).ok();
#[cfg(target_os = "macos")]
{
@@ -869,7 +874,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
match result {
Ok(_) => debug!("Launched {} with args {:?}", program, args),
- Err(_) => warn!("Unable to launch {} with args {:?}", program, args),
+ Err(err) => warn!("Unable to launch {program} with args {args:?}: {err}"),
}
}
@@ -1793,7 +1798,11 @@ impl input::Processor<EventProxy, ActionContext<'_, Notifier, EventProxy>> {
},
WinitEvent::WindowEvent { event, .. } => {
match event {
- WindowEvent::CloseRequested => self.ctx.terminal.exit(),
+ WindowEvent::CloseRequested => {
+ // User asked to close the window, so no need to hold it.
+ self.ctx.window().hold = false;
+ self.ctx.terminal.exit();
+ },
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
let old_scale_factor =
mem::replace(&mut self.ctx.window().scale_factor, scale_factor);
diff --git a/alacritty/src/input/keyboard.rs b/alacritty/src/input/keyboard.rs
index af9bfbb2..417f599b 100644
--- a/alacritty/src/input/keyboard.rs
+++ b/alacritty/src/input/keyboard.rs
@@ -342,18 +342,21 @@ impl SequenceBuilder {
};
if character.chars().count() == 1 {
- let character = character.chars().next().unwrap();
- let base_character = character.to_lowercase().next().unwrap();
+ let shift = self.modifiers.contains(SequenceModifiers::SHIFT);
- let alternate_key_code = u32::from(character);
- let mut unicode_key_code = u32::from(base_character);
+ let ch = character.chars().next().unwrap();
+ let unshifted_ch = if shift { ch.to_lowercase().next().unwrap() } else { ch };
+
+ let alternate_key_code = u32::from(ch);
+ let mut unicode_key_code = u32::from(unshifted_ch);
// Try to get the base for keys which change based on modifier, like `1` for `!`.
- match key.key_without_modifiers().as_ref() {
- Key::Character(unmodded) if alternate_key_code == unicode_key_code => {
- unicode_key_code = u32::from(unmodded.chars().next().unwrap_or(base_character));
- },
- _ => (),
+ //
+ // However it should only be performed when `SHIFT` is pressed.
+ if shift && alternate_key_code == unicode_key_code {
+ if let Key::Character(unmodded) = key.key_without_modifiers().as_ref() {
+ unicode_key_code = u32::from(unmodded.chars().next().unwrap_or(unshifted_ch));
+ }
}
// NOTE: Base layouts are ignored, since winit doesn't expose this information
diff --git a/alacritty/src/input/mod.rs b/alacritty/src/input/mod.rs
index 60a50529..3f85512f 100644
--- a/alacritty/src/input/mod.rs
+++ b/alacritty/src/input/mod.rs
@@ -324,7 +324,10 @@ impl<T: EventListener> Execute<T> for Action {
#[cfg(not(target_os = "macos"))]
Action::Hide => ctx.window().set_visible(false),
Action::Minimize => ctx.window().set_minimized(true),
- Action::Quit => ctx.terminal_mut().exit(),
+ Action::Quit => {
+ ctx.window().hold = false;
+ ctx.terminal_mut().exit();
+ },
Action::IncreaseFontSize => ctx.change_font_size(FONT_SIZE_STEP),
Action::DecreaseFontSize => ctx.change_font_size(-FONT_SIZE_STEP),
Action::ResetFontSize => ctx.reset_font_size(),
diff --git a/alacritty/src/ipc.rs b/alacritty/src/ipc.rs
index 3d14c4ce..919035a6 100644
--- a/alacritty/src/ipc.rs
+++ b/alacritty/src/ipc.rs
@@ -19,7 +19,10 @@ use crate::event::{Event, EventType};
const ALACRITTY_SOCKET_ENV: &str = "ALACRITTY_SOCKET";
/// Create an IPC socket.
-pub fn spawn_ipc_socket(options: &Options, event_proxy: EventLoopProxy<Event>) -> Option<PathBuf> {
+pub fn spawn_ipc_socket(
+ options: &Options,
+ event_proxy: EventLoopProxy<Event>,
+) -> IoResult<PathBuf> {
// Create the IPC socket and export its path as env.
let socket_path = options.socket.clone().unwrap_or_else(|| {
@@ -28,13 +31,7 @@ pub fn spawn_ipc_socket(options: &Options, event_proxy: EventLoopProxy<Event>) -
path
});
- let listener = match UnixListener::bind(&socket_path) {
- Ok(listener) => listener,
- Err(err) => {
- warn!("Unable to create socket: {:?}", err);
- return None;
- },
- };
+ let listener = UnixListener::bind(&socket_path)?;
env::set_var(ALACRITTY_SOCKET_ENV, socket_path.as_os_str());
if options.daemon {
@@ -80,7 +77,7 @@ pub fn spawn_ipc_socket(options: &Options, event_proxy: EventLoopProxy<Event>) -
}
});
- Some(socket_path)
+ Ok(socket_path)
}
/// Send a message to the active Alacritty socket.
diff --git a/alacritty/src/main.rs b/alacritty/src/main.rs
index 6bbf8dfd..9260bfa4 100644
--- a/alacritty/src/main.rs
+++ b/alacritty/src/main.rs
@@ -55,6 +55,8 @@ mod gl {
#[cfg(unix)]
use crate::cli::MessageOptions;
+#[cfg(not(any(target_os = "macos", windows)))]
+use crate::cli::SocketMessage;
use crate::cli::{Options, Subcommands};
use crate::config::monitor::ConfigMonitor;
use crate::config::UiConfig;
@@ -89,7 +91,13 @@ fn main() -> Result<(), Box<dyn Error>> {
/// `msg` subcommand entrypoint.
#[cfg(unix)]
-fn msg(options: MessageOptions) -> Result<(), Box<dyn Error>> {
+#[allow(unused_mut)]
+fn msg(mut options: MessageOptions) -> Result<(), Box<dyn Error>> {
+ #[cfg(not(any(target_os = "macos", windows)))]
+ if let SocketMessage::CreateWindow(window_options) = &mut options.message {
+ window_options.activation_token =
+ env::var("XDG_ACTIVATION_TOKEN").or_else(|_| env::var("DESKTOP_STARTUP_ID")).ok();
+ }
ipc::send_message(options.socket, options.message).map_err(|err| err.into())
}
@@ -175,7 +183,14 @@ fn alacritty(mut options: Options) -> Result<(), Box<dyn Error>> {
// Create the IPC socket listener.
#[cfg(unix)]
let socket_path = if config.ipc_socket() {
- ipc::spawn_ipc_socket(&options, window_event_loop.create_proxy())
+ match ipc::spawn_ipc_socket(&options, window_event_loop.create_proxy()) {
+ Ok(path) => Some(path),
+ Err(err) if options.daemon => return Err(err.into()),
+ Err(err) => {
+ log::warn!("Unable to create socket: {:?}", err);
+ None
+ },
+ }
} else {
None
};
diff --git a/alacritty/src/renderer/mod.rs b/alacritty/src/renderer/mod.rs
index a1ffb311..ce6b0914 100644
--- a/alacritty/src/renderer/mod.rs
+++ b/alacritty/src/renderer/mod.rs
@@ -9,7 +9,7 @@ use ahash::RandomState;
use crossfont::Metrics;
use glutin::context::{ContextApi, GlContext, PossiblyCurrentContext};
use glutin::display::{GetGlDisplay, GlDisplay};
-use log::{debug, error, info, warn, LevelFilter};
+use log::{debug, info, LevelFilter};
use unicode_width::UnicodeWidthChar;
use alacritty_terminal::graphics::UpdateQueues;
@@ -101,6 +101,7 @@ pub struct Renderer {
text_renderer: TextRendererProvider,
rect_renderer: RectRenderer,
graphics_renderer: GraphicsRenderer,
+ robustness: bool,
}
/// Wrapper around gl::GetString with error checking and reporting.
@@ -148,6 +149,9 @@ impl Renderer {
info!("Running on {renderer}");
info!("OpenGL version {gl_version}, shader_version {shader_version}");
+ // Check if robustness is supported.
+ let robustness = Self::supports_robustness();
+
let is_gles_context = matches!(context.context_api(), ContextApi::Gles(_));
// Use the config option to enforce a particular renderer configuration.
@@ -181,7 +185,7 @@ impl Renderer {
}
}
- Ok(Self { text_renderer, rect_renderer, graphics_renderer })
+ Ok(Self { text_renderer, rect_renderer, graphics_renderer, robustness })
}
pub fn draw_cells<I: Iterator<Item = RenderableCell>>(
@@ -212,10 +216,10 @@ impl Renderer {
glyph_cache: &mut GlyphCache,
) {
let mut wide_char_spacer = false;
- let cells = string_chars.enumerate().map(|(i, character)| {
+ let cells = string_chars.enumerate().filter_map(|(i, character)| {
let flags = if wide_char_spacer {
wide_char_spacer = false;
- Flags::WIDE_CHAR_SPACER
+ return None;
} else if character.width() == Some(2) {
// The spacer is always following the wide char.
wide_char_spacer = true;
@@ -224,7 +228,7 @@ impl Renderer {
Flags::empty()
};
- RenderableCell {
+ Some(RenderableCell {
point: Point::new(point.line, point.column + i),
character,
extra: None,
@@ -233,7 +237,7 @@ impl Renderer {
fg,
bg,
underline: fg,
- }
+ })
});
self.draw_cells(size_info, glyph_cache, cells);
@@ -287,6 +291,49 @@ impl Renderer {
}
}
+ /// Get the context reset status.
+ pub fn was_context_reset(&self) -> bool {
+ // If robustness is not supported, don't use its functions.
+ if !self.robustness {
+ return false;
+ }
+
+ let status = unsafe { gl::GetGraphicsResetStatus() };
+ if status == gl::NO_ERROR {
+ false
+ } else {
+ let reason = match status {
+ gl::GUILTY_CONTEXT_RESET_KHR => "guilty",
+ gl::INNOCENT_CONTEXT_RESET_KHR => "innocent",
+ gl::UNKNOWN_CONTEXT_RESET_KHR => "unknown",
+ _ => "invalid",
+ };
+
+ info!("GPU reset ({})", reason);
+
+ true
+ }
+ }
+
+ fn supports_robustness() -> bool {
+ let mut notification_strategy = 0;
+ if GlExtensions::contains("GL_KHR_robustness") {
+ unsafe {
+ gl::GetIntegerv(gl::RESET_NOTIFICATION_STRATEGY_KHR, &mut notification_strategy);
+ }
+ } else {
+ notification_strategy = gl::NO_RESET_NOTIFICATION_KHR as gl::types::GLint;
+ }
+
+ if notification_strategy == gl::LOSE_CONTEXT_ON_RESET_KHR as gl::types::GLint {
+ info!("GPU reset notifications are enabled");
+ true
+ } else {
+ info!("GPU reset notifications are disabled");
+ false
+ }
+ }
+
pub fn finish(&self) {
unsafe {
gl::Finish();
@@ -387,7 +434,7 @@ impl GlExtensions {
extern "system" fn gl_debug_log(
_: gl::types::GLenum,
- kind: gl::types::GLenum,
+ _: gl::types::GLenum,
_: gl::types::GLuint,
_: gl::types::GLenum,
_: gl::types::GLsizei,
@@ -395,11 +442,5 @@ extern "system" fn gl_debug_log(
_: *mut std::os::raw::c_void,
) {
let msg = unsafe { CStr::from_ptr(msg).to_string_lossy() };
- match kind {
- gl::DEBUG_TYPE_ERROR | gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR => {
- error!("[gl_render] {}", msg)
- },
- gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR => warn!("[gl_render] {}", msg),
- _ => debug!("[gl_render] {}", msg),
- }
+ debug!("[gl_render] {}", msg);
}
diff --git a/alacritty/src/renderer/platform.rs b/alacritty/src/renderer/platform.rs
index 87ed29c2..3b2e2fce 100644
--- a/alacritty/src/renderer/platform.rs
+++ b/alacritty/src/renderer/platform.rs
@@ -4,9 +4,9 @@ use std::num::NonZeroU32;
use glutin::config::{ColorBufferType, Config, ConfigTemplateBuilder, GetGlConfig};
use glutin::context::{
- ContextApi, ContextAttributesBuilder, GlProfile, NotCurrentContext, Version,
+ ContextApi, ContextAttributesBuilder, GlProfile, NotCurrentContext, Robustness, Version,
};
-use glutin::display::{Display, DisplayApiPreference, GetGlDisplay};
+use glutin::display::{Display, DisplayApiPreference, DisplayFeatures, GetGlDisplay};
use glutin::error::Result as GlutinResult;
use glutin::prelude::*;
use glutin::surface::{Surface, SurfaceAttributesBuilder, WindowSurface};
@@ -110,18 +110,24 @@ pub fn create_gl_context(
raw_window_handle: Option<RawWindowHandle>,
) -> GlutinResult<NotCurrentContext> {
let debug = log::max_level() >= LevelFilter::Debug;
+ let mut builder = ContextAttributesBuilder::new().with_debug(debug);
+
+ // Try to enable robustness.
+ if gl_display.supported_features().contains(DisplayFeatures::CONTEXT_ROBUSTNESS) {
+ builder = builder.with_robustness(Robustness::RobustLoseContextOnReset);
+ }
+
let mut profiles = [
- ContextAttributesBuilder::new()
- .with_debug(debug)
+ builder
+ .clone()
.with_context_api(ContextApi::OpenGl(Some(Version::new(3, 3))))
.build(raw_window_handle),
// Try gles before OpenGL 2.1 as it tends to be more stable.
- ContextAttributesBuilder::new()
- .with_debug(debug)
+ builder
+ .clone()
.with_context_api(ContextApi::Gles(Some(Version::new(2, 0))))
.build(raw_window_handle),
- ContextAttributesBuilder::new()
- .with_debug(debug)
+ builder
.with_profile(GlProfile::Compatibility)
.with_context_api(ContextApi::OpenGl(Some(Version::new(2, 1))))
.build(raw_window_handle),
diff --git a/alacritty/src/window_context.rs b/alacritty/src/window_context.rs
index cfc3cd96..a0e66cc0 100644
--- a/alacritty/src/window_context.rs
+++ b/alacritty/src/window_context.rs
@@ -73,7 +73,7 @@ impl WindowContext {
event_loop: &ActiveEventLoop,
proxy: EventLoopProxy<Event>,
config: Rc<UiConfig>,
- options: WindowOptions,
+ mut options: WindowOptions,
) -> Result<Self, Box<dyn Error>> {
let raw_display_handle = event_loop.display_handle().unwrap().as_raw();
@@ -83,7 +83,7 @@ impl WindowContext {
// Windows has different order of GL platform initialization compared to any other platform;
// it requires the window first.
#[cfg(windows)]
- let window = Window::new(event_loop, &config, &identity)?;
+ let window = Window::new(event_loop, &config, &identity, &mut options)?;
#[cfg(windows)]
let raw_window_handle = Some(window.raw_window_handle());
@@ -102,10 +102,9 @@ impl WindowContext {
event_loop,
&config,
&identity,
+ &mut options,
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
gl_config.x11_visual(),
- #[cfg(target_os = "macos")]
- &options.window_tabbing_id,
)?;
// Create context.
@@ -123,7 +122,7 @@ impl WindowContext {
event_loop: &ActiveEventLoop,
proxy: EventLoopProxy<Event>,
config: Rc<UiConfig>,
- options: WindowOptions,
+ mut options: WindowOptions,
config_overrides: ParsedOptions,
) -> Result<Self, Box<dyn Error>> {
let gl_display = gl_config.display();
@@ -135,10 +134,9 @@ impl WindowContext {
event_loop,
&config,
&identity,
+ &mut options,
#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))]
gl_config.x11_visual(),
- #[cfg(target_os = "macos")]
- &options.window_tabbing_id,
)?;
// Create context.
@@ -214,7 +212,7 @@ impl WindowContext {
Arc::clone(&terminal),
event_proxy.clone(),
pty,
- pty_config.hold,
+ pty_config.drain_on_exit,
config.debug.ref_test,
)?;
diff --git a/alacritty/windows/wix/alacritty.wxs b/alacritty/windows/wix/alacritty.wxs
index 5c05d821..bcf59cf5 100644
--- a/alacritty/windows/wix/alacritty.wxs
+++ b/alacritty/windows/wix/alacritty.wxs
@@ -1,5 +1,5 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
- <Package Name="Alacritty" UpgradeCode="87c21c74-dbd5-4584-89d5-46d9cd0c40a7" Language="1033" Codepage="1252" Version="0.15.0-dev" Manufacturer="Alacritty" InstallerVersion="200">
+ <Package Name="Alacritty" UpgradeCode="87c21c74-dbd5-4584-89d5-46d9cd0c40a7" Language="1033" Codepage="1252" Version="0.16.0-dev" Manufacturer="Alacritty" InstallerVersion="200">
<MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<Icon Id="AlacrittyIco" SourceFile=".\alacritty\windows\alacritty.ico" />
<WixVariable Id="WixUILicenseRtf" Value=".\alacritty\windows\wix\license.rtf" />
diff --git a/alacritty_terminal/CHANGELOG.md b/alacritty_terminal/CHANGELOG.md
index a6ee32b2..9b2f9ebf 100644
--- a/alacritty_terminal/CHANGELOG.md
+++ b/alacritty_terminal/CHANGELOG.md
@@ -8,7 +8,19 @@ sections should follow the order `Added`, `Changed`, `Deprecated`, `Fixed` and
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
-## 0.24.2-dev
+## 0.25.1-dev
+
+### Changed
+
+- Pass `-q` to `login` on macOS if `~/.hushlogin` is present
+
+## 0.25.0
+
+### Changed
+
+- Replaced `Options::hold` with `Options::drain_on_exit`
+
+## 0.24.2
### Added
diff --git a/alacritty_terminal/Cargo.toml b/alacritty_terminal/Cargo.toml
index f8abf51d..04547103 100644
--- a/alacritty_terminal/Cargo.toml
+++ b/alacritty_terminal/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "alacritty_terminal"
-version = "0.24.2-dev"
+version = "0.25.1-dev"
authors = ["Christian Duerr <contact@christianduerr.com>", "Joe Wilm <joe@jwilm.com>"]
license = "Apache-2.0"
description = "Library for writing terminal emulators"
@@ -24,7 +24,7 @@ parking_lot = "0.12.0"
polling = "3.0.0"
regex-automata = "0.4.3"
unicode-width = "0.1"
-vte = { version = "0.13.0", package = "vte-graphics", default-features = false, features = ["ansi", "serde"] }
+vte = { version = "0.15.0", package = "vte-graphics", default-features = false, features = ["std", "ansi"] }
serde = { version = "1", features = ["derive", "rc"], optional = true }
smallvec = { version = "1.13.1", features = ["serde"] }
diff --git a/alacritty_terminal/src/event_loop.rs b/alacritty_terminal/src/event_loop.rs
index 62dd7440..1bef1d4f 100644
--- a/alacritty_terminal/src/event_loop.rs
+++ b/alacritty_terminal/src/event_loop.rs
@@ -17,8 +17,8 @@ use polling::{Event as PollingEvent, Events, PollMode};
use crate::event::{self, Event, EventListener, WindowSize};
use crate::sync::FairMutex;
use crate::term::Term;
-use crate::vte::ansi;
use crate::{thread, tty};
+use vte::ansi;
/// Max bytes to read from the PTY before forced terminal synchronization.
pub(crate) const READ_BUFFER_SIZE: usize = 0x10_0000;
@@ -50,7 +50,7 @@ pub struct EventLoop<T: tty::EventedPty, U: EventListener> {
tx: Sender<Msg>,
terminal: Arc<FairMutex<Term<U>>>,
event_proxy: U,
- hold: bool,
+ drain_on_exit: bool,
ref_test: bool,
}
@@ -64,7 +64,7 @@ where
terminal: Arc<FairMutex<Term<U>>>,
event_proxy: U,
pty: T,
- hold: bool,
+ drain_on_exit: bool,
ref_test: bool,
) -> io::Result<EventLoop<T, U>> {
let (tx, rx) = mpsc::channel();
@@ -76,7 +76,7 @@ where
rx: PeekableReceiver::new(rx),
terminal,
event_proxy,
- hold,
+ drain_on_exit,
ref_test,
})
}
@@ -151,9 +151,7 @@ where
}
// Parse the incoming bytes.
- for byte in &buf[..unprocessed] {
- state.parser.advance(&mut **terminal, *byte);
- }
+ state.parser.advance(&mut **terminal, &buf[..unprocessed]);
processed += unprocessed;
unprocessed = 0;
@@ -263,13 +261,10 @@ where
if let Some(code) = code {
self.event_proxy.send_event(Event::ChildExit(code));
}
- if self.hold {
- // With hold enabled, make sure the PTY is drained.
+ if self.drain_on_exit {
let _ = self.pty_read(&mut state, &mut buf, pipe.as_mut());
- } else {
- // Without hold, shutdown the terminal.
- self.terminal.lock().exit();
}
+ self.terminal.lock().exit();
self.event_proxy.send_event(Event::Wakeup);
break 'event_loop;
}
diff --git a/alacritty_terminal/src/tty/mod.rs b/alacritty_terminal/src/tty/mod.rs
index eed2a76d..208547ba 100644
--- a/alacritty_terminal/src/tty/mod.rs
+++ b/alacritty_terminal/src/tty/mod.rs
@@ -28,8 +28,8 @@ pub struct Options {
/// Shell startup directory.
pub working_directory: Option<PathBuf>,
- /// Remain open after child process exits.
- pub hold: bool,
+ /// Drain the child process output before exiting the terminal.
+ pub drain_on_exit: bool,
/// Extra environment variables.
pub env: HashMap<String, String>,
diff --git a/alacritty_terminal/src/tty/unix.rs b/alacritty_terminal/src/tty/unix.rs
index 6565f20b..884cb5c1 100644
--- a/alacritty_terminal/src/tty/unix.rs
+++ b/alacritty_terminal/src/tty/unix.rs
@@ -8,6 +8,8 @@ use std::os::fd::OwnedFd;
use std::os::unix::io::AsRawFd;
use std::os::unix::net::UnixStream;
use std::os::unix::process::CommandExt;
+#[cfg(target_os = "macos")]
+use std::path::Path;
use std::process::{Child, Command};
use std::sync::Arc;
use std::{env, ptr};
@@ -158,12 +160,12 @@ impl ShellUser {
}
#[cfg(not(target_os = "macos"))]
-fn default_shell_command(shell: &str, _user: &str) -> Command {
+fn default_shell_command(shell: &str, _user: &str, _home: &str) -> Command {
Command::new(shell)
}
#[cfg(target_os = "macos")]
-fn default_shell_command(shell: &str, user: &str) -> Command {
+fn default_shell_command(shell: &str, user: &str, home: &str) -> Command {
let shell_name = shell.rsplit('/').next().unwrap();
// On macOS, use the `login` command so the shell will appear as a tty session.
@@ -173,12 +175,20 @@ fn default_shell_command(shell: &str, user: &str) -> Command {
// `login` normally does this itself, but `-l` disables this.
let exec = format!("exec -a -{} {}", shell_name, shell);
+ // Since we use -l, `login` will not change directory to the user's home. However,
+ // `login` only checks the current working directory for a .hushlogin file, causing
+ // it to miss any in the user's home directory. We can fix this by doing the check
+ // ourselves and passing `-q`
+ let has_home_hushlogin = Path::new(home).join(".hushlogin").exists();
+
// -f: Bypasses authentication for the already-logged-in user.
// -l: Skips changing directory to $HOME and prepending '-' to argv[0].
// -p: Preserves the environment.
+ // -q: Act as if `.hushlogin` exists.
//
// XXX: we use zsh here over sh due to `exec -a`.
- login_command.args(["-flp", user, "/bin/zsh", "-fc", &exec]);
+ let flags = if has_home_hushlogin { "-qflp" } else { "-flp" };
+ login_command.args([flags, user, "/bin/zsh", "-fc", &exec]);
login_command
}
@@ -208,7 +218,7 @@ pub fn from_fd(config: &Options, window_id: u64, master: OwnedFd, slave: OwnedFd
cmd.args(shell.args.as_slice());
cmd
} else {
- default_shell_command(&user.shell, &user.user)
+ default_shell_command(&user.shell, &user.user, &user.home)
};
// Setup child stdin/stdout/stderr as slave fd of PTY.
@@ -231,6 +241,7 @@ pub fn from_fd(config: &Options, window_id: u64, master: OwnedFd, slave: OwnedFd
builder.env_remove("XDG_ACTIVATION_TOKEN");
builder.env_remove("DESKTOP_STARTUP_ID");
+ let working_directory = config.working_directory.clone();
unsafe {
builder.pre_exec(move || {
// Create a new process group.
@@ -239,6 +250,11 @@ pub fn from_fd(config: &Options, window_id: u64, master: OwnedFd, slave: OwnedFd
return Err(Error::new(ErrorKind::Other, "Failed to set session id"));
}
+ // Set working directory, ignoring invalid paths.
+ if let Some(working_directory) = working_directory.as_ref() {
+ let _ = env::set_current_dir(working_directory);
+ }
+
set_controlling_terminal(slave_fd);
// No longer need slave/master fds.
@@ -256,11 +272,6 @@ pub fn from_fd(config: &Options, window_id: u64, master: OwnedFd, slave: OwnedFd
});
}
- // Handle set working directory option.
- if let Some(dir) = &config.working_directory {
- builder.current_dir(dir);
- }
-
// Prepare signal handling before spawning child.
let (signals, sig_id) = {
let (sender, recv) = UnixStream::pair()?;
diff --git a/alacritty_terminal/tests/ref.rs b/alacritty_terminal/tests/ref.rs
index 1f992941..454f2e5d 100644
--- a/alacritty_terminal/tests/ref.rs
+++ b/alacritty_terminal/tests/ref.rs
@@ -112,9 +112,7 @@ fn ref_test(dir: &Path) {
let mut terminal = Term::new(options, &size, Mock);
let mut parser: ansi::Processor = ansi::Processor::new();
- for byte in recording {
- parser.advance(&mut terminal, byte);
- }
+ parser.advance(&mut terminal, &recording);
// Truncate invisible lines from the grid.
let mut term_grid = terminal.grid().clone();
diff --git a/extra/man/alacritty.5.scd b/extra/man/alacritty.5.scd
index 18172487..e2f5b252 100644
--- a/extra/man/alacritty.5.scd
+++ b/extra/man/alacritty.5.scd
@@ -740,7 +740,8 @@ post_processing = _true_++
persist = _false_++
mouse.enabled = _true_++
binding = { key = _"O"_, mods = _"Control|Shift"_ }++
-regex = _"(ipfs:|ipns:|magnet:|mailto:|gemini://|gopher://|https://|http://|news:|file:|git://|ssh:|ftp://)[^\\u0000-\\u001F\\u007F-\\u009F<>\\"\\\\s{-}\\\\^⟨⟩`]+"_
+regex =
+_"(ipfs:|ipns:|magnet:|mailto:|gemini://|gopher://|https://|http://|news:|file:|git://|ssh:|ftp://)[^\\u0000-\\u001F\\u007F-\\u009F<>\\"\\\\s{-}\\\\^⟨⟩`\\\\\\\\]+"_
# KEYBOARD
diff --git a/extra/osx/Alacritty.app/Contents/Info.plist b/extra/osx/Alacritty.app/Contents/Info.plist
index 59c70ff2..ca8d2d7b 100644
--- a/extra/osx/Alacritty.app/Contents/Info.plist
+++ b/extra/osx/Alacritty.app/Contents/Info.plist
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>0.15.0-dev</string>
+ <string>0.16.0-dev</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>