我在 Ubuntu 和 Arch 上使用 zsh shell 作为默认 shell。
我配置了一个快捷方式(向上箭头)以在 zsh shell 中自动完成历史记录,在我的 中使用以下行.zshrc
:
bindkey "^[[A" history-beginning-search-backward
然而,当我在 Ubuntu 中启动.zshrc
和/或重新启动时,快捷方式不起作用(无论我开始输入什么,我只得到上一个命令),而在 Arch 上它工作得很好(我只得到最后一个以什么开头的命令)我打字)。
有谁知道如何解决这个问题?
答案1
在大多数类似 xterm 的终端上,Up(与大多数导航键类似)发送␛[A
或 ,␛OA
具体取决于终端是否已放入键盘传输模式与否。和terminfosmkx
条目rmkx
可用于将终端置于或退出该模式。
kcuu1
(按键光标向上 1) terminfo 条目描述了当 in 时发送的Up序列键盘传输模式,即␛OA
.
Debian 及其衍生版本有一个/etc/zsh/zshrc
文件可以执行以下操作:
function zle-line-init () {
emulate -L zsh
printf > /dev/tty '%s' ${terminfo[smkx]}
}
当 zle 处于活动状态时,这会将终端置于该模式,这意味着您现在可以依靠 terminfo 数据库来了解按键传输的字符序列。
该文件还定义$key
关联数组基于 terminfo 条目来帮助您将它们映射到小部件。因此,在这些系统上,您可以执行以下操作:
(($+key[Up])) && bindkey $key[Up] history-beginning-search-backward
对于在终端所在的系统上运行的东西键盘传输模式和那些没有或没有哈希的模式$key
,你可以这样做:
bindkey $terminfo[kcuu1] history-beginning-search-backward
bindkey ${terminfo[kcuu1]/O/[} history-beginning-search-backward
也可以看看:
- 我的光标键不起作用(ncurses 常见问题解答)
- 为什么我不能使用(任何)shell 中的光标键?(xterm 常见问题解答)
答案2
光标键很有趣。
尽管它们不如编辑键那么有趣,编辑键是真的乐趣。
你有两套键盘上的光标键、光标键盘以及那些关于计算器键盘。
大多数终端仿真器尝试(有时非常糟糕)采用 DEC VT 模型,其中每组按键都可以单独在应用方式和正常模式分别使用私人模式设置 DECCKM
(光标键盘模式)和DECNKM
(数字键盘模式)。应用模式的思想本质上是相关键盘上的按键变成额外的应用功能键。
- ⇐ 这是光标键盘。
-
- 在正常模式下,箭头键发送 ECMA-48
CUB
、CUF
、CUU
和CUD
控制序列,除非⎇ Alt修改器有效,在这种情况下它们发送DECFNK
控制序列。 - 在应用模式下,箭头键发送
SS3
单移 3 序列。
- 在正常模式下,箭头键发送 ECMA-48
- ⇐ 这是计算器键盘。
-
- 在正常模式下,箭头键发送 ECMA-48
CUB
、CUF
、CUU
和CUD
控制序列,除非⎇ Alt修改器有效(在这种情况下它们发送DECFNK
控制序列),或者除非数字锁定和移位的组合导致它们发送数字。 - 在应用程序模式下,方向键发送一组不同的
SS3
single-shift 3 序列(除非数字锁定和移位的组合导致它们发送数字)。
- 在正常模式下,箭头键发送 ECMA-48
␛
[
A
您告诉 ZLE 绑定到小部件的序列是控制序列的 ECMA-48 7 位别名,CSI
A
即CUP
(“光标向上”)控制序列。当键盘处于正常模式且修改⎇ Alt器无效时,该控制序列仅由 DEC VT 及其模拟器终端仿真器生成。当相关键盘处于应用程序模式时,它不会匹配发送的换档序列。
terminfo 数据库使情况变得更加混乱,并且在这里带来了额外的乐趣,因为它没有将这种模型用于终端 I/O。相反,它使用自己的不同的体现“本地”和“远程”键概念的模型,这根本不是 DEC VT 应用程序/正常模式切换实际涉及的内容;它有一个本地/远程切换机制,最终切换两个都应用程序/正常模式之间的键盘不可分割。
terminfo 是一种不硬连线到您配置 ZLE 的特定终端类型的方法,以防万一您发现自己使用的终端或终端仿真器不模仿 DEC VT。 Z shell 为您提供了从数据库记录访问必要功能条目的方法。因此,您可以从 terminfo 读取 terminfo 期望上/下/左/右光标键产生什么控制序列,并发出将bindkey
这些控制序列映射到小部件的适当命令。
问题是 terminfo 不足以完成这项工作。它只有一种记录方式一每个键的控制序列,而正如您所看到的,键可以发送至少三种不同的序列,取决于按下的模式和修饰符。 (在 DEC VT 模型中,修饰符可以显着影响发送的控制序列。)因此,您需要将终端切换到生成 terminfo 告诉您期望的内容的模式。
但情况变得更糟:terminfo 不一致。单个控制序列有时是 DEC VT 应用模式序列,如 terminfo 记录终端putty
类型,有时是 DEC VT 正常模式序列,如 terminfo 记录终端rxvt
类型,但从来没有DECFNK
顺序。因此,您无法知道是否应该使用任何给定的终端或终端模拟器切换到应用程序或正常模式。对一个人来说正确的事情,对另一个人来说却是错误的。
因此,另一种方法是忽略 terminfo 并意识到您是已经并且很高兴地假设您的终端总是像带有您原始bindkey
命令的 DEC VT 一样。您只需要其中两个,即可确保您的终端无论是处于应用程序模式还是正常模式,它发送的控制序列都会匹配:
绑定键“^[OA”历史开始向后搜索
然而,这无法应对按下的修改键,这会向CUP
控制序列添加额外的参数,导致 ZLE 使用的简单字符串匹配在它查找的只是普通的旧的无参数时失败CUP
。您必须为每个可能的修饰符组合产生的每个bindkey
可能的控制序列手动发出附加命令。CUP
序列 1 8 | 读-ri时 做 绑定键“^[[1;${i}A”历史开始向后搜索 完毕
ZLE 并不孤单。其他基于 terminfo 的程序(例如fish
shell)也会遇到同样的问题。 (fish
shell 人员也发现,对于一个终端仿真器来说正确的应用程序/正常模式选择对于另一个终端仿真器来说可能会出错。)重新构建这个(比较libtermkey
这些程序中早就应该有一个实际的 ECMA-48 控制序列解析器用于输入)。但目前还没有人解决这个问题。
进一步阅读
- https://unix.stackexchange.com/a/444270/5132
- “键盘功能”。 VT510视频终端编程器信息。 EK-VT510-RM。 1993 年 11 月。数字。
- https://unix.stackexchange.com/a/289871/5132
- 乔纳森·德·博因·波拉德 (2018-05-14)。某些终端需要键盘模式(smkx)。鱼壳错误#2139。
- https://unix.stackexchange.com/a/419092/5132