mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-18 13:55:23 -05:00
parent
31a27e9f9f
commit
215a0becb6
5 changed files with 90 additions and 7 deletions
|
@ -1,4 +1,5 @@
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -195,6 +196,7 @@ impl From<TerminalOptions> for PtyOptions {
|
||||||
working_directory: options.working_directory.take(),
|
working_directory: options.working_directory.take(),
|
||||||
shell: options.command().map(Into::into),
|
shell: options.command().map(Into::into),
|
||||||
hold: options.hold,
|
hold: options.hold,
|
||||||
|
env: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,7 +167,12 @@ impl UiConfig {
|
||||||
/// Derive [`PtyOptions`] from the config.
|
/// Derive [`PtyOptions`] from the config.
|
||||||
pub fn pty_config(&self) -> PtyOptions {
|
pub fn pty_config(&self) -> PtyOptions {
|
||||||
let shell = self.shell.clone().map(Into::into);
|
let shell = self.shell.clone().map(Into::into);
|
||||||
PtyOptions { shell, working_directory: self.working_directory.clone(), hold: false }
|
PtyOptions {
|
||||||
|
shell,
|
||||||
|
working_directory: self.working_directory.clone(),
|
||||||
|
hold: false,
|
||||||
|
env: HashMap::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate key bindings for all keyboard hints.
|
/// Generate key bindings for all keyboard hints.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! TTY related functionality.
|
//! TTY related functionality.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{env, io};
|
use std::{env, io};
|
||||||
|
@ -29,6 +30,9 @@ pub struct Options {
|
||||||
|
|
||||||
/// Remain open after child process exits.
|
/// Remain open after child process exits.
|
||||||
pub hold: bool,
|
pub hold: bool,
|
||||||
|
|
||||||
|
/// Extra environment variables.
|
||||||
|
pub env: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shell options.
|
/// Shell options.
|
||||||
|
|
|
@ -217,9 +217,11 @@ pub fn new(config: &Options, window_size: WindowSize, window_id: u64) -> Result<
|
||||||
builder.env("ALACRITTY_WINDOW_ID", &window_id);
|
builder.env("ALACRITTY_WINDOW_ID", &window_id);
|
||||||
builder.env("USER", user.user);
|
builder.env("USER", user.user);
|
||||||
builder.env("HOME", user.home);
|
builder.env("HOME", user.home);
|
||||||
|
|
||||||
// Set Window ID for clients relying on X11 hacks.
|
// Set Window ID for clients relying on X11 hacks.
|
||||||
builder.env("WINDOWID", window_id);
|
builder.env("WINDOWID", window_id);
|
||||||
|
for (key, value) in &config.env {
|
||||||
|
builder.env(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
builder.pre_exec(move || {
|
builder.pre_exec(move || {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use log::info;
|
use log::{info, warn};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::ffi::OsStr;
|
||||||
use std::io::Error;
|
use std::io::Error;
|
||||||
|
use std::os::windows::ffi::OsStrExt;
|
||||||
use std::os::windows::io::IntoRawHandle;
|
use std::os::windows::io::IntoRawHandle;
|
||||||
use std::{mem, ptr};
|
use std::{mem, ptr};
|
||||||
|
|
||||||
|
@ -13,8 +16,8 @@ use windows_sys::{s, w};
|
||||||
|
|
||||||
use windows_sys::Win32::System::Threading::{
|
use windows_sys::Win32::System::Threading::{
|
||||||
CreateProcessW, InitializeProcThreadAttributeList, UpdateProcThreadAttribute,
|
CreateProcessW, InitializeProcThreadAttributeList, UpdateProcThreadAttribute,
|
||||||
EXTENDED_STARTUPINFO_PRESENT, PROCESS_INFORMATION, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
CREATE_UNICODE_ENVIRONMENT, EXTENDED_STARTUPINFO_PRESENT, PROCESS_INFORMATION,
|
||||||
STARTF_USESTDHANDLES, STARTUPINFOEXW, STARTUPINFOW,
|
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, STARTF_USESTDHANDLES, STARTUPINFOEXW, STARTUPINFOW,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::event::{OnResize, WindowSize};
|
use crate::event::{OnResize, WindowSize};
|
||||||
|
@ -198,8 +201,18 @@ pub fn new(config: &Options, window_size: WindowSize) -> Option<Pty> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare child process creation arguments.
|
||||||
let cmdline = win32_string(&cmdline(config));
|
let cmdline = win32_string(&cmdline(config));
|
||||||
let cwd = config.working_directory.as_ref().map(win32_string);
|
let cwd = config.working_directory.as_ref().map(win32_string);
|
||||||
|
let mut creation_flags = EXTENDED_STARTUPINFO_PRESENT;
|
||||||
|
let custom_env_block = convert_custom_env(&config.env);
|
||||||
|
let custom_env_block_pointer = match &custom_env_block {
|
||||||
|
Some(custom_env_block) => {
|
||||||
|
creation_flags |= CREATE_UNICODE_ENVIRONMENT;
|
||||||
|
custom_env_block.as_ptr() as *mut std::ffi::c_void
|
||||||
|
},
|
||||||
|
None => ptr::null_mut(),
|
||||||
|
};
|
||||||
|
|
||||||
let mut proc_info: PROCESS_INFORMATION = unsafe { mem::zeroed() };
|
let mut proc_info: PROCESS_INFORMATION = unsafe { mem::zeroed() };
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -209,8 +222,8 @@ pub fn new(config: &Options, window_size: WindowSize) -> Option<Pty> {
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
false as i32,
|
false as i32,
|
||||||
EXTENDED_STARTUPINFO_PRESENT,
|
creation_flags,
|
||||||
ptr::null_mut(),
|
custom_env_block_pointer,
|
||||||
cwd.as_ref().map_or_else(ptr::null, |s| s.as_ptr()),
|
cwd.as_ref().map_or_else(ptr::null, |s| s.as_ptr()),
|
||||||
&mut startup_info_ex.StartupInfo as *mut STARTUPINFOW,
|
&mut startup_info_ex.StartupInfo as *mut STARTUPINFOW,
|
||||||
&mut proc_info as *mut PROCESS_INFORMATION,
|
&mut proc_info as *mut PROCESS_INFORMATION,
|
||||||
|
@ -230,6 +243,63 @@ pub fn new(config: &Options, window_size: WindowSize) -> Option<Pty> {
|
||||||
Some(Pty::new(conpty, conout, conin, child_watcher))
|
Some(Pty::new(conpty, conout, conin, child_watcher))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Windows environment variables are case-insensitive, and the caller is responsible for
|
||||||
|
// deduplicating environment variables, so do that here while converting.
|
||||||
|
//
|
||||||
|
// https://learn.microsoft.com/en-us/previous-versions/troubleshoot/windows/win32/createprocess-cannot-eliminate-duplicate-variables#environment-variables
|
||||||
|
fn convert_custom_env(custom_env: &HashMap<String, String>) -> Option<Vec<u16>> {
|
||||||
|
// Windows inherits parent's env when no `lpEnvironment` parameter is specified.
|
||||||
|
if custom_env.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut converted_block = Vec::new();
|
||||||
|
let mut all_env_keys = HashSet::new();
|
||||||
|
for (custom_key, custom_value) in custom_env {
|
||||||
|
let custom_key_os = OsStr::new(custom_key);
|
||||||
|
if all_env_keys.insert(custom_key_os.to_ascii_uppercase()) {
|
||||||
|
add_windows_env_key_value_to_block(
|
||||||
|
&mut converted_block,
|
||||||
|
custom_key_os,
|
||||||
|
OsStr::new(&custom_value),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
"Omitting environment variable pair with duplicate key: \
|
||||||
|
'{custom_key}={custom_value}'"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull the current process environment after, to avoid overwriting the user provided one.
|
||||||
|
for (inherited_key, inherited_value) in std::env::vars_os() {
|
||||||
|
if all_env_keys.insert(inherited_key.to_ascii_uppercase()) {
|
||||||
|
add_windows_env_key_value_to_block(
|
||||||
|
&mut converted_block,
|
||||||
|
&inherited_key,
|
||||||
|
&inherited_value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
converted_block.push(0);
|
||||||
|
Some(converted_block)
|
||||||
|
}
|
||||||
|
|
||||||
|
// According to the `lpEnvironment` parameter description:
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa#parameters
|
||||||
|
//
|
||||||
|
// > An environment block consists of a null-terminated block of null-terminated strings. Each
|
||||||
|
// string is in the following form:
|
||||||
|
// >
|
||||||
|
// > name=value\0
|
||||||
|
fn add_windows_env_key_value_to_block(block: &mut Vec<u16>, key: &OsStr, value: &OsStr) {
|
||||||
|
block.extend(key.encode_wide());
|
||||||
|
block.push('=' as u16);
|
||||||
|
block.extend(value.encode_wide());
|
||||||
|
block.push(0);
|
||||||
|
}
|
||||||
|
|
||||||
// Panic with the last os error as message.
|
// Panic with the last os error as message.
|
||||||
fn panic_shell_spawn() {
|
fn panic_shell_spawn() {
|
||||||
panic!("Unable to spawn shell: {}", Error::last_os_error());
|
panic!("Unable to spawn shell: {}", Error::last_os_error());
|
||||||
|
|
Loading…
Reference in a new issue