Fix CreateNewWindow CLI fallback

The existing behavior for the new CreateNewWindow actions was to always
pass in their own options, which would discard the existing options
configured on the terminal's PTY config.

To fix this the behavior for CreateNewWindow is now the same as for the
initial window creation, the config values are overwritten conditionally
based on their individual presence in the CLI options.

However all temporary CLI options set on the "master" Alacritty
instance are discarded by all future windows.

Fixes #5659.
This commit is contained in:
Christian Duerr 2021-12-23 10:23:06 +00:00 committed by GitHub
parent 6d1a63ef28
commit 3af1940192
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 55 additions and 60 deletions

View File

@ -100,21 +100,6 @@ impl Options {
/// Override configuration file with options from the CLI.
pub fn override_config(&self, config: &mut UiConfig) {
if let Some(working_directory) = &self.terminal_options.working_directory {
if working_directory.is_dir() {
config.terminal_config.pty_config.working_directory =
Some(working_directory.to_owned());
} else {
error!("Invalid working directory: {:?}", working_directory);
}
}
if let Some(command) = self.terminal_options.command() {
config.terminal_config.pty_config.shell = Some(command);
}
config.terminal_config.pty_config.hold = self.terminal_options.hold;
if let Some(title) = self.title.clone() {
config.window.title = title
}
@ -218,27 +203,37 @@ pub struct TerminalOptions {
}
impl TerminalOptions {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.working_directory.is_none() && !self.hold && self.command.is_empty()
}
/// Shell override passed through the CLI.
pub fn command(&self) -> Option<Program> {
let (program, args) = self.command.split_first()?;
Some(Program::WithArgs { program: program.clone(), args: args.to_vec() })
}
/// Override the [`PtyConfig`]'s fields with the [`TerminalOptions`].
pub fn override_pty_config(&self, pty_config: &mut PtyConfig) {
if let Some(working_directory) = &self.working_directory {
if working_directory.is_dir() {
pty_config.working_directory = Some(working_directory.to_owned());
} else {
error!("Invalid working directory: {:?}", working_directory);
}
}
if let Some(command) = self.command() {
pty_config.shell = Some(command);
}
pty_config.hold |= self.hold;
}
}
impl From<TerminalOptions> for PtyConfig {
fn from(mut options: TerminalOptions) -> Self {
let working_directory = options.working_directory.take();
let shell = options.command();
let hold = options.hold;
PtyConfig { shell, working_directory, hold }
PtyConfig {
working_directory: options.working_directory.take(),
shell: options.command(),
hold: options.hold,
}
}
}

View File

@ -78,8 +78,7 @@ impl HintState {
if hint.post_processing {
matches
.drain(..)
.map(|rm| HintPostProcessor::new(term, regex, rm).collect::<Vec<_>>())
.flatten()
.flat_map(|rm| HintPostProcessor::new(term, regex, rm).collect::<Vec<_>>())
.collect()
} else {
matches.0

View File

@ -34,7 +34,7 @@ use alacritty_terminal::selection::{Selection, SelectionType};
use alacritty_terminal::term::search::{Match, RegexSearch};
use alacritty_terminal::term::{ClipboardType, SizeInfo, Term, TermMode};
use crate::cli::{Options as CliOptions, TerminalOptions as TerminalCliOptions};
use crate::cli::{Options as CliOptions, TerminalOptions};
use crate::clipboard::Clipboard;
use crate::config::ui_config::{HintAction, HintInternalAction};
use crate::config::{self, UiConfig};
@ -88,7 +88,7 @@ pub enum EventType {
ConfigReload(PathBuf),
Message(Message),
Scroll(Scroll),
CreateWindow(Option<TerminalCliOptions>),
CreateWindow(TerminalOptions),
BlinkCursor,
SearchNext,
}
@ -379,21 +379,19 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
#[cfg(not(windows))]
fn create_new_window(&mut self) {
let cwd = foreground_process_path(self.master_fd, self.shell_pid);
let options = if let Ok(working_directory) = cwd {
let mut options = TerminalCliOptions::new();
let mut options = TerminalOptions::default();
if let Ok(working_directory) = foreground_process_path(self.master_fd, self.shell_pid) {
options.working_directory = Some(working_directory);
Some(options)
} else {
None
};
}
let _ = self.event_proxy.send_event(Event::new(EventType::CreateWindow(options), None));
}
#[cfg(windows)]
fn create_new_window(&mut self) {
let _ = self.event_proxy.send_event(Event::new(EventType::CreateWindow(None), None));
let _ = self
.event_proxy
.send_event(Event::new(EventType::CreateWindow(TerminalOptions::default()), None));
}
fn spawn_daemon<I, S>(&self, program: &str, args: I)
@ -753,7 +751,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
}
} else if self.terminal().mode().contains(TermMode::BRACKETED_PASTE) {
self.write_to_pty(&b"\x1b[200~"[..]);
self.write_to_pty(text.replace("\x1b", "").into_bytes());
self.write_to_pty(text.replace('\x1b', "").into_bytes());
self.write_to_pty(&b"\x1b[201~"[..]);
} else {
// In non-bracketed (ie: normal) mode, terminal applications cannot distinguish
@ -762,7 +760,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
// pasting... since that's neither practical nor sensible (and probably an impossible
// task to solve in a general way), we'll just replace line breaks (windows and unix
// style) with a single carriage return (\r, which is what the Enter key produces).
self.write_to_pty(text.replace("\r\n", "\r").replace("\n", "\r").into_bytes());
self.write_to_pty(text.replace("\r\n", "\r").replace('\n', "\r").into_bytes());
}
}
@ -1207,12 +1205,15 @@ impl Processor {
pub fn create_window(
&mut self,
event_loop: &EventLoopWindowTarget<Event>,
options: Option<TerminalCliOptions>,
proxy: EventLoopProxy<Event>,
options: TerminalOptions,
) -> Result<(), Box<dyn Error>> {
let mut pty_config = self.config.terminal_config.pty_config.clone();
options.override_pty_config(&mut pty_config);
let window_context = WindowContext::new(
&self.config,
options,
&pty_config,
event_loop,
proxy,
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
@ -1320,7 +1321,7 @@ impl Processor {
GlutinEvent::UserEvent(Event {
payload: EventType::CreateWindow(options), ..
}) => {
if let Err(err) = self.create_window(event_loop, options, proxy.clone()) {
if let Err(err) = self.create_window(event_loop, proxy.clone(), options) {
error!("Could not open window: {:?}", err);
}
},

View File

@ -802,11 +802,8 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
self.ctx.clear_selection();
let utf8_len = c.len_utf8();
let mut bytes = Vec::with_capacity(utf8_len);
unsafe {
bytes.set_len(utf8_len);
c.encode_utf8(&mut bytes[..]);
}
let mut bytes = vec![0; utf8_len];
c.encode_utf8(&mut bytes[..]);
if self.ctx.config().alt_send_esc
&& *self.ctx.received_count() == 0
@ -1007,7 +1004,7 @@ mod tests {
}
fn terminal_mut(&mut self) -> &mut Term<T> {
&mut self.terminal
self.terminal
}
fn size_info(&self) -> SizeInfo {

View File

@ -58,8 +58,8 @@ pub fn spawn_ipc_socket(options: &Options, event_proxy: EventLoopProxy<Event>) -
// Handle IPC events.
match message {
SocketMessage::CreateWindow(terminal_options) => {
let event = Event::new(EventType::CreateWindow(Some(terminal_options)), None);
SocketMessage::CreateWindow(options) => {
let event = Event::new(EventType::CreateWindow(options), None);
let _ = event_proxy.send_event(event);
},
}

View File

@ -178,11 +178,14 @@ fn alacritty(options: Options) -> Result<(), String> {
};
// Event processor.
let cli_options = options.terminal_options.clone();
let mut processor = Processor::new(config, options, &window_event_loop);
// Create the first Alacritty window.
let proxy = window_event_loop.create_proxy();
processor.create_window(&window_event_loop, None, proxy).map_err(|err| err.to_string())?;
processor
.create_window(&window_event_loop, proxy, cli_options)
.map_err(|err| err.to_string())?;
info!("Initialisation complete");

View File

@ -1,6 +1,5 @@
//! Terminal window context.
use std::borrow::Cow;
use std::error::Error;
use std::fs::File;
use std::io::Write;
@ -20,6 +19,7 @@ use serde_json as json;
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
use wayland_client::EventQueue;
use alacritty_terminal::config::PtyConfig;
use alacritty_terminal::event::Event as TerminalEvent;
use alacritty_terminal::event_loop::{EventLoop as PtyEventLoop, Msg, Notifier};
use alacritty_terminal::grid::{Dimensions, Scroll};
@ -28,7 +28,6 @@ use alacritty_terminal::sync::FairMutex;
use alacritty_terminal::term::{Term, TermMode};
use alacritty_terminal::tty;
use crate::cli::TerminalOptions as TerminalCliOptions;
use crate::clipboard::Clipboard;
use crate::config::UiConfig;
use crate::display::Display;
@ -61,7 +60,7 @@ impl WindowContext {
/// Create a new terminal window context.
pub fn new(
config: &UiConfig,
options: Option<TerminalCliOptions>,
pty_config: &PtyConfig,
window_event_loop: &EventLoopWindowTarget<Event>,
proxy: EventLoopProxy<Event>,
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
@ -98,10 +97,7 @@ impl WindowContext {
// The PTY forks a process to run the shell on the slave side of the
// pseudoterminal. A file descriptor for the master side is retained for
// reading/writing to the shell.
let pty_config = options
.map(|o| Cow::Owned(o.into()))
.unwrap_or(Cow::Borrowed(&config.terminal_config.pty_config));
let pty = tty::new(&pty_config, &display.size_info, display.window.x11_window_id())?;
let pty = tty::new(pty_config, &display.size_info, display.window.x11_window_id())?;
#[cfg(not(windows))]
let master_fd = pty.file().as_raw_fd();

View File

@ -697,6 +697,7 @@ pub enum NamedColor {
}
impl NamedColor {
#[must_use]
pub fn to_bright(self) -> Self {
match self {
NamedColor::Foreground => NamedColor::BrightForeground,
@ -721,6 +722,7 @@ impl NamedColor {
}
}
#[must_use]
pub fn to_dim(self) -> Self {
match self {
NamedColor::Black => NamedColor::DimBlack,

View File

@ -20,6 +20,7 @@ pub enum Direction {
}
impl Direction {
#[must_use]
pub fn opposite(self) -> Self {
match self {
Side::Right => Side::Left,
@ -133,6 +134,7 @@ pub struct Line(pub i32);
impl Line {
/// Clamp a line to a grid boundary.
#[must_use]
pub fn grid_clamp<D: Dimensions>(self, dimensions: &D, boundary: Boundary) -> Self {
match boundary {
Boundary::Cursor => max(Line(0), min(dimensions.bottommost_line(), self)),