From f1802c1cda7b9922f23d872705653beb6b053f2e Mon Sep 17 00:00:00 2001 From: Jorge Carrasco Date: Sat, 18 Dec 2021 18:27:10 +0100 Subject: [PATCH] Spawn children from foreground working directory To allow applications spawned by Alacritty to make use of the shell/foreground process' working directory, it is now set for all new processes spawned by Alacritty on Unix platforms. Fixes #5616. Co-authored-by: Christian Duerr --- CHANGELOG.md | 1 + alacritty/src/daemon.rs | 45 ++++++++++++++++++++++++++++++++++----- alacritty/src/event.rs | 47 +++++++---------------------------------- 3 files changed, 49 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64cd7c5e..69623b97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Reload configuration files when their symbolic link is replaced - Strip trailing whitespaces when yanking from a block selection - Display area keeps history position when viewport is cleared +- Commands spawn from the current directory of the foreground shell in Unix-like systems ### Fixed diff --git a/alacritty/src/daemon.rs b/alacritty/src/daemon.rs index b199c353..4b95cb6b 100644 --- a/alacritty/src/daemon.rs +++ b/alacritty/src/daemon.rs @@ -1,16 +1,28 @@ +#[cfg(not(windows))] +use std::error::Error; use std::ffi::OsStr; use std::fmt::Debug; +#[cfg(not(any(target_os = "macos", windows)))] +use std::fs; use std::io; #[cfg(not(windows))] use std::os::unix::process::CommandExt; #[cfg(windows)] use std::os::windows::process::CommandExt; +#[cfg(not(windows))] +use std::path::PathBuf; use std::process::{Command, Stdio}; use log::{debug, warn}; #[cfg(windows)] use winapi::um::winbase::{CREATE_NEW_PROCESS_GROUP, CREATE_NO_WINDOW}; +#[cfg(not(windows))] +use alacritty_terminal::tty; + +#[cfg(target_os = "macos")] +use crate::macos; + /// Start the daemon and log error on failure. pub fn start_daemon(program: &str, args: I) where @@ -43,18 +55,41 @@ where .map(|_| ()) } +/// Get working directory of controlling process. +#[cfg(not(windows))] +pub fn foreground_process_path() -> Result> { + let mut pid = unsafe { libc::tcgetpgrp(tty::master_fd()) }; + if pid < 0 { + pid = tty::child_pid(); + } + + #[cfg(not(any(target_os = "macos", target_os = "freebsd")))] + let link_path = format!("/proc/{}/cwd", pid); + #[cfg(target_os = "freebsd")] + let link_path = format!("/compat/linux/proc/{}/cwd", pid); + + #[cfg(not(target_os = "macos"))] + let cwd = fs::read_link(link_path)?; + + #[cfg(target_os = "macos")] + let cwd = macos::proc::cwd(pid)?; + + Ok(cwd) +} + #[cfg(not(windows))] fn spawn_daemon(program: &str, args: I) -> io::Result<()> where I: IntoIterator + Copy, S: AsRef, { + 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() { + command.current_dir(cwd); + } unsafe { - Command::new(program) - .args(args) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) + command .pre_exec(|| { match libc::fork() { -1 => return Err(io::Error::last_os_error()), diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs index 4af372c9..7fb54b39 100644 --- a/alacritty/src/event.rs +++ b/alacritty/src/event.rs @@ -30,20 +30,18 @@ use alacritty_terminal::index::{Boundary, Column, Direction, Line, Point, Side}; use alacritty_terminal::selection::{Selection, SelectionType}; use alacritty_terminal::term::search::{Match, RegexSearch}; use alacritty_terminal::term::{ClipboardType, SizeInfo, Term, TermMode}; -#[cfg(not(windows))] -use alacritty_terminal::tty; use crate::cli::{Options as CliOptions, TerminalOptions as TerminalCliOptions}; use crate::clipboard::Clipboard; use crate::config::ui_config::{HintAction, HintInternalAction}; use crate::config::{self, UiConfig}; +#[cfg(not(windows))] +use crate::daemon::foreground_process_path; use crate::daemon::start_daemon; use crate::display::hint::HintMatch; use crate::display::window::Window; use crate::display::{self, Display}; use crate::input::{self, ActionContext as _, FONT_SIZE_STEP}; -#[cfg(target_os = "macos")] -use crate::macos; use crate::message_bar::{Message, MessageBuffer}; use crate::scheduler::{Scheduler, TimerId, Topic}; use crate::window_context::WindowContext; @@ -354,27 +352,19 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext for ActionCon let mut env_args = env::args(); let alacritty = env_args.next().unwrap(); - // Use working directory of controlling process, or fallback to initial shell, then add it - // as working-directory parameter. - #[cfg(unix)] - let mut args = foreground_process_path() - .map(|path| vec!["--working-directory".into(), path]) - .unwrap_or_default(); - - #[cfg(not(unix))] - let mut args: Vec = Vec::new(); - - let working_directory_set = !args.is_empty(); + let mut args: Vec = Vec::new(); // Reuse the arguments passed to Alacritty for the new instance. + #[allow(clippy::while_let_on_iterator)] while let Some(arg) = env_args.next() { - // Drop working directory from existing parameters. - if working_directory_set && arg == "--working-directory" { + // On unix, the working directory of the foreground shell is used by `start_daemon`. + #[cfg(not(windows))] + if arg == "--working-directory" { let _ = env_args.next(); continue; } - args.push(arg.into()); + args.push(arg); } start_daemon(&alacritty, &args); @@ -1389,24 +1379,3 @@ impl EventListener for EventProxy { let _ = self.proxy.send_event(Event::new(event.into(), self.window_id)); } } - -#[cfg(not(windows))] -pub fn foreground_process_path() -> Result> { - let mut pid = unsafe { libc::tcgetpgrp(tty::master_fd()) }; - if pid < 0 { - pid = tty::child_pid(); - } - - #[cfg(not(any(target_os = "macos", target_os = "freebsd")))] - let link_path = format!("/proc/{}/cwd", pid); - #[cfg(target_os = "freebsd")] - let link_path = format!("/compat/linux/proc/{}/cwd", pid); - - #[cfg(not(target_os = "macos"))] - let cwd = std::fs::read_link(link_path)?; - - #[cfg(target_os = "macos")] - let cwd = macos::proc::cwd(pid)?; - - Ok(cwd) -}