Apply terminal protocol workarounds also in fish_key_reader

We don't care to check the latest value of these variables;
these should only be read on startup and are not meant to
be overridden by the user ever. Hence we don't need a parser.
This commit is contained in:
Johannes Altmanninger 2024-10-12 10:49:03 +02:00
parent fe3e3b3b50
commit 0d9dfb307b
3 changed files with 55 additions and 60 deletions

View file

@ -19,7 +19,10 @@ use fish::{
env::env_init,
eprintf, fprintf,
input::input_terminfo_get_name,
input_common::{terminal_protocols_enable_ifn, CharEvent, InputEventQueue, InputEventQueuer},
input_common::{
terminal_protocol_hacks, terminal_protocols_enable_ifn, CharEvent, InputEventQueue,
InputEventQueuer,
},
key::{self, char_to_symbol, Key},
panic::panic_handler,
print_help::print_help,
@ -136,6 +139,8 @@ fn setup_and_process_keys(continuous_mode: bool, verbose: bool) -> i32 {
// in fish-proper this is done once a command is run.
unsafe { libc::tcsetattr(STDIN_FILENO, TCSANOW, &*shell_modes()) };
terminal_protocol_hacks();
if continuous_mode {
eprintf!("\n");
eprintf!("To terminate this program type \"exit\" or \"quit\" in this window,\n");

View file

@ -1,7 +1,8 @@
use libc::STDOUT_FILENO;
use crate::common::{
fish_reserved_codepoint, is_windows_subsystem_for_linux, read_blocked, shell_modes, WSL,
fish_reserved_codepoint, is_windows_subsystem_for_linux, read_blocked, shell_modes,
str2wcstring, WSL,
};
use crate::env::{EnvStack, Environment};
use crate::fd_readable_set::FdReadableSet;
@ -20,6 +21,7 @@ use crate::wutil::{fish_wcstol, write_to_fd};
use std::collections::VecDeque;
use std::ops::ControlFlow;
use std::os::fd::RawFd;
use std::os::unix::ffi::OsStrExt;
use std::ptr;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
@ -427,10 +429,49 @@ pub fn update_wait_on_sequence_key_ms(vars: &EnvStack) {
static TERMINAL_PROTOCOLS: AtomicBool = AtomicBool::new(false);
pub(crate) static IS_TMUX: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
pub(crate) static IN_MIDNIGHT_COMMANDER: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
pub(crate) static IN_ITERM_PRE_CSI_U: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
pub(crate) static IN_WEZTERM: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
static IS_TMUX: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
static IN_MIDNIGHT_COMMANDER: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
static IN_ITERM_PRE_CSI_U: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
static IN_WEZTERM: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
pub fn terminal_protocol_hacks() {
use std::env::var_os;
IS_TMUX.store(var_os("TMUX").is_some());
IN_MIDNIGHT_COMMANDER.store(var_os("MC_TMPDIR").is_some());
IN_WEZTERM.store(
var_os("TERM_PROGRAM")
.is_some_and(|term_program| term_program.as_os_str().as_bytes() == b"WezTerm"),
);
IN_ITERM_PRE_CSI_U.store(
var_os("LC_TERMINAL").is_some_and(|term| term.as_os_str().as_bytes() == b"iTerm2")
&& var_os("LC_TERMINAL_VERSION").is_some_and(|version| {
let Some(version) = parse_version(&str2wcstring(version.as_os_str().as_bytes()))
else {
return false;
};
version < (3, 5, 6)
}),
);
}
fn parse_version(version: &wstr) -> Option<(i64, i64, i64)> {
let mut numbers = version.split('.');
let major = fish_wcstol(numbers.next()?).ok()?;
let minor = fish_wcstol(numbers.next()?).ok()?;
let patch = numbers.next()?;
let patch = &patch[..patch
.chars()
.position(|c| !c.is_ascii_digit())
.unwrap_or(patch.len())];
let patch = fish_wcstol(patch).ok()?;
Some((major, minor, patch))
}
#[test]
fn test_parse_version() {
assert_eq!(parse_version(L!("3.5.2")), Some((3, 5, 2)));
assert_eq!(parse_version(L!("3.5.3beta")), Some((3, 5, 3)));
}
pub fn terminal_protocols_enable_ifn() {
if IN_MIDNIGHT_COMMANDER.load() {

View file

@ -74,11 +74,9 @@ use crate::history::{
SearchType,
};
use crate::input::init_input;
use crate::input_common::IN_ITERM_PRE_CSI_U;
use crate::input_common::IN_MIDNIGHT_COMMANDER;
use crate::input_common::IN_WEZTERM;
use crate::input_common::{
terminal_protocols_enable_ifn, CharEvent, CharInputStyle, InputData, ReadlineCmd, IS_TMUX,
terminal_protocol_hacks, terminal_protocols_enable_ifn, CharEvent, CharInputStyle, InputData,
ReadlineCmd,
};
use crate::io::IoChain;
use crate::kill::{kill_add, kill_replace, kill_yank, kill_yank_rotate};
@ -126,7 +124,6 @@ use crate::wcstringutil::{
string_prefixes_string_case_insensitive, StringFuzzyMatch,
};
use crate::wildcard::wildcard_has;
use crate::wutil::fish_wcstol;
use crate::wutil::{fstat, perror, write_to_fd};
use crate::{abbrs, event, function, history};
@ -3958,55 +3955,7 @@ fn reader_interactive_init(parser: &Parser) {
.vars()
.set_one(L!("_"), EnvMode::GLOBAL, L!("fish").to_owned());
interactive_hacks(parser);
}
fn interactive_hacks(parser: &Parser) {
IS_TMUX.store(parser.vars().get_unless_empty(L!("TMUX")).is_some());
IN_MIDNIGHT_COMMANDER.store(parser.vars().get_unless_empty(L!("MC_TMPDIR")).is_some());
IN_WEZTERM.store(
parser
.vars()
.get_unless_empty(L!("TERM_PROGRAM"))
.is_some_and(|term_program| term_program.as_list() == [L!("WezTerm")]),
);
IN_ITERM_PRE_CSI_U.store(
parser
.vars()
.get(L!("LC_TERMINAL"))
.is_some_and(|term| term.as_list() == [L!("iTerm2")])
&& parser
.vars()
.get(L!("LC_TERMINAL_VERSION"))
.is_some_and(|version| {
if version.as_list().is_empty() {
return false;
}
let Some(version) = parse_version(&version.as_list()[0]) else {
return false;
};
version < (3, 5, 6)
}),
);
}
fn parse_version(version: &wstr) -> Option<(i64, i64, i64)> {
let mut numbers = version.split('.');
let major = fish_wcstol(numbers.next()?).ok()?;
let minor = fish_wcstol(numbers.next()?).ok()?;
let patch = numbers.next()?;
let patch = &patch[..patch
.chars()
.position(|c| !c.is_ascii_digit())
.unwrap_or(patch.len())];
let patch = fish_wcstol(patch).ok()?;
Some((major, minor, patch))
}
#[test]
fn test_parse_version() {
assert_eq!(parse_version(L!("3.5.2")), Some((3, 5, 2)));
assert_eq!(parse_version(L!("3.5.3beta")), Some((3, 5, 3)));
terminal_protocol_hacks();
}
/// Destroy data for interactive use.