
我在 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 條目描述了發送的序列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