mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-14 07:42:45 +08:00
Swap alt-{left,right,backspace,delete} with ctrl-* on macOS
See https://github.com/fish-shell/fish-shell/issues/ 10926
This commit is contained in:
parent
e0c6384ed3
commit
ebdc3a0393
|
@ -29,6 +29,7 @@ Synopsis
|
||||||
status job-control CONTROL_TYPE
|
status job-control CONTROL_TYPE
|
||||||
status features
|
status features
|
||||||
status test-feature FEATURE
|
status test-feature FEATURE
|
||||||
|
status client-os
|
||||||
status buildinfo
|
status buildinfo
|
||||||
|
|
||||||
Description
|
Description
|
||||||
|
@ -98,6 +99,10 @@ The following operations (subcommands) are available:
|
||||||
**test-feature** *FEATURE*
|
**test-feature** *FEATURE*
|
||||||
Returns 0 when FEATURE is enabled, 1 if it is disabled, and 2 if it is not recognized.
|
Returns 0 when FEATURE is enabled, 1 if it is disabled, and 2 if it is not recognized.
|
||||||
|
|
||||||
|
**client-os**
|
||||||
|
Print the name of the OS (**bsd**, **macos**, **linux** or **unknown**) that the terminal emulator is running on.
|
||||||
|
When running inside SSH, this will be the client OS.
|
||||||
|
|
||||||
**buildinfo**
|
**buildinfo**
|
||||||
This prints information on how fish was build - which architecture, which build system or profile was used, etc.
|
This prints information on how fish was build - which architecture, which build system or profile was used, etc.
|
||||||
This is mainly useful for debugging.
|
This is mainly useful for debugging.
|
||||||
|
|
|
@ -16,6 +16,7 @@ complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_com
|
||||||
|
|
||||||
# The subcommands that are not "is-something" which don't change the fish state.
|
# The subcommands that are not "is-something" which don't change the fish state.
|
||||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a buildinfo -d "Print information on how this version fish was built"
|
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a buildinfo -d "Print information on how this version fish was built"
|
||||||
|
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a client-os -d "Print the name of the OS the terminal is running on"
|
||||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-command -d "Print the name of the currently running command or function"
|
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-command -d "Print the name of the currently running command or function"
|
||||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-commandline -d "Print the currently running command with its arguments"
|
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-commandline -d "Print the currently running command with its arguments"
|
||||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-filename -d "Print the filename of the currently running script"
|
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-filename -d "Print the filename of the currently running script"
|
||||||
|
|
|
@ -217,6 +217,13 @@ end" >$__fish_config_dir/config.fish
|
||||||
end
|
end
|
||||||
__fish_update_cwd_osc # Run once because we might have already inherited a PWD from an old tab
|
__fish_update_cwd_osc # Run once because we might have already inherited a PWD from an old tab
|
||||||
|
|
||||||
|
if set -q TMUX
|
||||||
|
# NOTE This will be stale when the next tmux client attaches to fish's window.
|
||||||
|
# This isn't oo bad since we only use this to detect the client OS.
|
||||||
|
# TODO we should have a client scope.
|
||||||
|
set -g __fish_tmux_client_tty (tmux display-message -p '#{client_tty}' 2>/dev/null)
|
||||||
|
end
|
||||||
|
|
||||||
# Bump this whenever some code below needs to run once when upgrading to a new version.
|
# Bump this whenever some code below needs to run once when upgrading to a new version.
|
||||||
# The universal variable __fish_initialized is initialized in share/config.fish.
|
# The universal variable __fish_initialized is initialized in share/config.fish.
|
||||||
set __fish_initialized 3800
|
set __fish_initialized 3800
|
||||||
|
|
|
@ -21,8 +21,20 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod
|
||||||
$legacy_bind --preset $argv -k left backward-char
|
$legacy_bind --preset $argv -k left backward-char
|
||||||
|
|
||||||
# Ctrl-left/right - these also work in vim.
|
# Ctrl-left/right - these also work in vim.
|
||||||
bind --preset $argv ctrl-right forward-word
|
bind --preset $argv ctrl-right '
|
||||||
bind --preset $argv ctrl-left backward-word
|
if test (status client-os) = macos
|
||||||
|
commandline -f forward-token
|
||||||
|
else
|
||||||
|
commandline -f forward-word
|
||||||
|
end
|
||||||
|
'
|
||||||
|
bind --preset $argv ctrl-left '
|
||||||
|
if test (status client-os) = macos
|
||||||
|
commandline -f backward-token
|
||||||
|
else
|
||||||
|
commandline -f backward-word
|
||||||
|
end
|
||||||
|
'
|
||||||
|
|
||||||
bind --preset $argv pageup beginning-of-history
|
bind --preset $argv pageup beginning-of-history
|
||||||
bind --preset $argv pagedown end-of-history
|
bind --preset $argv pagedown end-of-history
|
||||||
|
@ -49,13 +61,25 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod
|
||||||
bind --preset $argv up up-or-search
|
bind --preset $argv up up-or-search
|
||||||
$legacy_bind --preset $argv -k up up-or-search
|
$legacy_bind --preset $argv -k up up-or-search
|
||||||
|
|
||||||
bind --preset $argv shift-right forward-bigword
|
bind --preset $argv shift-right forward-token
|
||||||
bind --preset $argv shift-left backward-bigword
|
bind --preset $argv shift-left backward-token
|
||||||
$legacy_bind --preset $argv -k sright forward-bigword
|
$legacy_bind --preset $argv -k sright forward-token
|
||||||
$legacy_bind --preset $argv -k sleft backward-bigword
|
$legacy_bind --preset $argv -k sleft backward-token
|
||||||
|
|
||||||
bind --preset $argv alt-right nextd-or-forward-token
|
bind --preset $argv alt-right '
|
||||||
bind --preset $argv alt-left prevd-or-backward-token
|
if test (status client-os) = macos
|
||||||
|
commandline -f nextd-or-forward-word
|
||||||
|
else
|
||||||
|
nextd-or-forward-token
|
||||||
|
end
|
||||||
|
'
|
||||||
|
bind --preset $argv alt-left '
|
||||||
|
if test (status client-os) = macos
|
||||||
|
commandline -f prevd-or-backward-word
|
||||||
|
else
|
||||||
|
prevd-or-backward-token
|
||||||
|
end
|
||||||
|
'
|
||||||
|
|
||||||
bind --preset $argv alt-up history-token-search-backward
|
bind --preset $argv alt-up history-token-search-backward
|
||||||
bind --preset $argv alt-down history-token-search-forward
|
bind --preset $argv alt-down history-token-search-forward
|
||||||
|
|
|
@ -57,10 +57,34 @@ function fish_default_key_bindings -d "emacs-like key binds"
|
||||||
bind --preset $argv alt-u upcase-word
|
bind --preset $argv alt-u upcase-word
|
||||||
|
|
||||||
bind --preset $argv alt-c capitalize-word
|
bind --preset $argv alt-c capitalize-word
|
||||||
bind --preset $argv alt-backspace backward-kill-token
|
bind --preset $argv alt-backspace '
|
||||||
bind --preset $argv ctrl-backspace backward-kill-word
|
if test (status client-os) = macos
|
||||||
bind --preset $argv alt-delete kill-token
|
commandline -f backward-kill-word
|
||||||
bind --preset $argv ctrl-delete kill-word
|
else
|
||||||
|
commandline -f backward-kill-token
|
||||||
|
end
|
||||||
|
'
|
||||||
|
bind --preset $argv ctrl-backspace '
|
||||||
|
if test (status client-os) = macos
|
||||||
|
commandline -f backward-kill-token
|
||||||
|
else
|
||||||
|
commandline -f backward-kill-word
|
||||||
|
end
|
||||||
|
'
|
||||||
|
bind --preset $argv alt-delete '
|
||||||
|
if test (status client-os) = macos
|
||||||
|
commandline -f kill-word
|
||||||
|
else
|
||||||
|
commandline -f kill-token
|
||||||
|
end
|
||||||
|
'
|
||||||
|
bind --preset $argv ctrl-delete '
|
||||||
|
if test (status client-os) = macos
|
||||||
|
commandline -f kill-token
|
||||||
|
else
|
||||||
|
commandline -f kill-word
|
||||||
|
end
|
||||||
|
'
|
||||||
bind --preset $argv alt-b backward-word
|
bind --preset $argv alt-b backward-word
|
||||||
bind --preset $argv alt-f forward-word
|
bind --preset $argv alt-f forward-word
|
||||||
if test "$TERM_PROGRAM" = Apple_Terminal
|
if test "$TERM_PROGRAM" = Apple_Terminal
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use std::os::unix::prelude::*;
|
use std::os::unix::prelude::*;
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
use crate::common::{get_executable_path, str2wcstring, PROGRAM_NAME};
|
use crate::common::{get_executable_path, str2wcstring, PROGRAM_NAME};
|
||||||
use crate::future_feature_flags::{self as features, feature_test};
|
use crate::future_feature_flags::{self as features, feature_test};
|
||||||
|
use crate::input_common::{ClientOS, CLIENT_OS};
|
||||||
use crate::proc::{
|
use crate::proc::{
|
||||||
get_job_control_mode, get_login, is_interactive_session, set_job_control_mode, JobControl,
|
get_job_control_mode, get_login, is_interactive_session, set_job_control_mode, JobControl,
|
||||||
};
|
};
|
||||||
|
@ -58,6 +60,7 @@ enum StatusCmd {
|
||||||
STATUS_TEST_FEATURE,
|
STATUS_TEST_FEATURE,
|
||||||
STATUS_CURRENT_COMMANDLINE,
|
STATUS_CURRENT_COMMANDLINE,
|
||||||
STATUS_BUILDINFO,
|
STATUS_BUILDINFO,
|
||||||
|
STATUS_CLIENT_OS,
|
||||||
}
|
}
|
||||||
|
|
||||||
str_enum!(
|
str_enum!(
|
||||||
|
@ -65,6 +68,7 @@ str_enum!(
|
||||||
(STATUS_BASENAME, "basename"),
|
(STATUS_BASENAME, "basename"),
|
||||||
(STATUS_BASENAME, "current-basename"),
|
(STATUS_BASENAME, "current-basename"),
|
||||||
(STATUS_BUILDINFO, "buildinfo"),
|
(STATUS_BUILDINFO, "buildinfo"),
|
||||||
|
(STATUS_CLIENT_OS, "client-os"),
|
||||||
(STATUS_CURRENT_CMD, "current-command"),
|
(STATUS_CURRENT_CMD, "current-command"),
|
||||||
(STATUS_CURRENT_COMMANDLINE, "current-commandline"),
|
(STATUS_CURRENT_COMMANDLINE, "current-commandline"),
|
||||||
(STATUS_DIRNAME, "current-dirname"),
|
(STATUS_DIRNAME, "current-dirname"),
|
||||||
|
@ -599,6 +603,11 @@ pub fn status(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> O
|
||||||
streams.out.appendln(path);
|
streams.out.appendln(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
STATUS_CLIENT_OS => {
|
||||||
|
let os: ClientOS =
|
||||||
|
unsafe { std::mem::transmute(CLIENT_OS.load(Ordering::Relaxed)) };
|
||||||
|
streams.out.appendln(format!("{}", os));
|
||||||
|
}
|
||||||
STATUS_SET_JOB_CONTROL | STATUS_FEATURES | STATUS_TEST_FEATURE => {
|
STATUS_SET_JOB_CONTROL | STATUS_FEATURES | STATUS_TEST_FEATURE => {
|
||||||
unreachable!("")
|
unreachable!("")
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ use std::ops::ControlFlow;
|
||||||
use std::os::fd::RawFd;
|
use std::os::fd::RawFd;
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering};
|
||||||
|
|
||||||
// The range of key codes for inputrc-style keyboard functions.
|
// The range of key codes for inputrc-style keyboard functions.
|
||||||
pub const R_END_INPUT_FUNCTIONS: usize = (ReadlineCmd::ReverseRepeatJump as usize) + 1;
|
pub const R_END_INPUT_FUNCTIONS: usize = (ReadlineCmd::ReverseRepeatJump as usize) + 1;
|
||||||
|
@ -450,6 +450,31 @@ static TERMINAL_PROTOCOLS: AtomicBool = AtomicBool::new(false);
|
||||||
pub(crate) static SCROLL_FORWARD_SUPPORTED: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
pub(crate) static SCROLL_FORWARD_SUPPORTED: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
||||||
pub(crate) static CURSOR_UP_SUPPORTED: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
pub(crate) static CURSOR_UP_SUPPORTED: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub(crate) enum ClientOS {
|
||||||
|
Bsd,
|
||||||
|
Linux,
|
||||||
|
macOS,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ClientOS {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let name = match self {
|
||||||
|
ClientOS::Bsd => "bsd",
|
||||||
|
ClientOS::Linux => "linux",
|
||||||
|
ClientOS::macOS => "macos",
|
||||||
|
ClientOS::Unknown => "unknown",
|
||||||
|
};
|
||||||
|
f.write_str(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// As first approximation, use the target OS. This should be overwritten by the XTGETTCAP
|
||||||
|
// query later.
|
||||||
|
pub(crate) static CLIENT_OS: AtomicU8 = AtomicU8::new(ClientOS::Unknown as _);
|
||||||
|
|
||||||
static KITTY_KEYBOARD_SUPPORTED: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
static KITTY_KEYBOARD_SUPPORTED: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
||||||
|
|
||||||
macro_rules! kitty_progressive_enhancements {
|
macro_rules! kitty_progressive_enhancements {
|
||||||
|
@ -468,7 +493,7 @@ pub(crate) fn enable_kitty_progressive_enhancements() -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
static IS_TMUX: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
pub(crate) static IS_TMUX: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
||||||
pub static IN_MIDNIGHT_COMMANDER_PRE_CSI_U: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
pub static IN_MIDNIGHT_COMMANDER_PRE_CSI_U: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
||||||
static IN_ITERM_PRE_CSI_U: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
static IN_ITERM_PRE_CSI_U: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
||||||
|
|
||||||
|
@ -485,6 +510,20 @@ pub fn terminal_protocol_hacks() {
|
||||||
version < (99, 5, 6)
|
version < (99, 5, 6)
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
CLIENT_OS.store(
|
||||||
|
(if cfg!(target_os = "macos")
|
||||||
|
|| var_os("LC_TERMINAL").is_some_and(|term| term.as_os_str().as_bytes() == b"iTerm2")
|
||||||
|
{
|
||||||
|
ClientOS::macOS
|
||||||
|
} else if cfg!(bsd) {
|
||||||
|
ClientOS::Bsd
|
||||||
|
} else if cfg!(target_os = "linux") {
|
||||||
|
ClientOS::Linux
|
||||||
|
} else {
|
||||||
|
ClientOS::Unknown
|
||||||
|
}) as _,
|
||||||
|
Ordering::Relaxed,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_version(version: &wstr) -> Option<(i64, i64, i64)> {
|
fn parse_version(version: &wstr) -> Option<(i64, i64, i64)> {
|
||||||
|
@ -1320,6 +1359,16 @@ pub trait InputEventQueuer {
|
||||||
CURSOR_UP_SUPPORTED.store(true);
|
CURSOR_UP_SUPPORTED.store(true);
|
||||||
FLOG!(reader, "Cursor up is supported");
|
FLOG!(reader, "Cursor up is supported");
|
||||||
}
|
}
|
||||||
|
if key == b"kitty-query-os_name" {
|
||||||
|
let os = match &value[..] {
|
||||||
|
b"bsd" => ClientOS::Bsd,
|
||||||
|
b"macos" => ClientOS::macOS,
|
||||||
|
b"linux" => ClientOS::Linux,
|
||||||
|
_ => ClientOS::Unknown,
|
||||||
|
};
|
||||||
|
CLIENT_OS.store(os as _, Ordering::Relaxed);
|
||||||
|
FLOG!(reader, "Client OS: ", os);
|
||||||
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2479,7 +2479,7 @@ impl<'a> Reader<'a> {
|
||||||
self.stop_waiting_for_cursor_position();
|
self.stop_waiting_for_cursor_position();
|
||||||
}
|
}
|
||||||
ImplicitEvent::SynchronizedOutputSupported => {
|
ImplicitEvent::SynchronizedOutputSupported => {
|
||||||
if query_capabilities_via_dcs() {
|
if query_capabilities_via_dcs(self) {
|
||||||
self.save_screen_state();
|
self.save_screen_state();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2506,7 +2506,7 @@ fn xtgettcap(out: &mut impl Write, cap: &str) {
|
||||||
let _ = write!(out, "\x1bP+q{}\x1b\\", DisplayAsHex(cap));
|
let _ = write!(out, "\x1bP+q{}\x1b\\", DisplayAsHex(cap));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_capabilities_via_dcs() -> bool {
|
fn query_capabilities_via_dcs(reader: &Reader) -> bool {
|
||||||
static QUERIED: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
static QUERIED: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
||||||
if QUERIED.load() {
|
if QUERIED.load() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2518,6 +2518,17 @@ fn query_capabilities_via_dcs() -> bool {
|
||||||
let _ = out.write(b"\x1b[?1049h"); // enable alternative screen buffer
|
let _ = out.write(b"\x1b[?1049h"); // enable alternative screen buffer
|
||||||
xtgettcap(out.by_ref(), "indn");
|
xtgettcap(out.by_ref(), "indn");
|
||||||
xtgettcap(out.by_ref(), "cuu");
|
xtgettcap(out.by_ref(), "cuu");
|
||||||
|
// Query the name of the Client OS.
|
||||||
|
xtgettcap(out.by_ref(), "kitty-query-os_name");
|
||||||
|
if let Some(client_tty) = reader.vars().get_unless_empty(L!("__fish_tmux_client_tty")) {
|
||||||
|
if let Ok(mut client_tty) = wopen_cloexec(
|
||||||
|
&client_tty.as_list()[0],
|
||||||
|
OFlag::O_WRONLY,
|
||||||
|
Mode::from_bits_truncate(0o666),
|
||||||
|
) {
|
||||||
|
xtgettcap(&mut client_tty, "kitty-query-os_name");
|
||||||
|
}
|
||||||
|
}
|
||||||
let _ = out.write(b"\x1b[?1049l"); // disable alternative screen buffer
|
let _ = out.write(b"\x1b[?1049l"); // disable alternative screen buffer
|
||||||
let _ = out.write(b"\x1b[?2026l"); // end synchronized update
|
let _ = out.write(b"\x1b[?2026l"); // end synchronized update
|
||||||
out.end_buffering();
|
out.end_buffering();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user