
多くの欲求不満の終わりに、最初はメインシェルではなくスクリプトに影響を与えるように$EDITOR
設定されており、この初期状態を元に戻すことができるものは何もないように見えました。vim
環境変数をオフにして空の文字列に設定すると、使用法はbindkey -e
スクリプトに伝播されません。bindkey -v
デフォルトのシェルを使用してモードを切り替えて再切り替えすると、すべてのキーが両方のモードで期待どおりに機能します。
スクリプト内では、viの編集はデフォルトのシェルと同じようにうまく機能しますが、実行後のbindkey -e
入力は奇妙に機能します。後続のキー入力と印刷のみが妨げHomeられます。EndDel~
キーを押して送信する内容をテストし、各キーを押す前にCtrl+を追加すると、デフォルトのシェルに入りますが、Vスクリプトに入ります。だから、2つは異なって行動し、1つは同じですが、振る舞います。[OH^[OF^[[3~
[[H^[[F^[[3~
もちろん、スクリプトの移植性のためにのみキーバインディングを定義する必要はありません。なぜ壊れるの?
Zshはv5.9で、スクリプトは次のようになります。
#!/usr/bin/zsh
bindkey -e
vared -p 'x: ' -c x
私はあらかじめ入力された提案で文字列を編集するためのヒントを提供したいと思います。他のEmacsシーケンスも機能しますが、技術的な知識がないユーザーには教えない方が最善です。
答え1
Home、、、、、、、はデフォルトでzshキーマップ(emacs、vi-insert、vi-command)を持つキーボードとBindingを押したときに一意の文字または文字シーケンスを送信する端末のキーマップではありEndませInsertん。..、完全なリストは参照または配列)。DeletePageUpPageDownbindkey -l
$keymaps
または、上記のファンクションキーまたはファンクションキーまたは矢印キー、またはと組み合わせるとバインディングはTabまったくありません(対応するキーの固有シーケンスを送信する端末の場合も同様)。BackspaceEscapeShiftControlAlt
UpDownLeftRight矢印キー()は、ほとんどの端末がこれらのキーに同じエスケープシーケンスを送信するため、デフォルトでバインドされています。これは、ターミナルと/またはターミナルにあるかどうかに応じて、ほぼ常に^[[A
...^[[D
または^[OA
...です。^[OD
キーボード転送モード(参照smkx
)terminfo(5)
そうではありません。
オプション(システムまたはユーザー初期化ファイルをスキップ(zshenvを除く))を使用して実行し、次を実行してさまざまなキーマップzsh
の主キーバインディングを表示できます。zsh
-f
for m ($keymaps) bindkey -M $m | grep -H --label=$m .
手動また、キーマップのどのキーに対してどのemacs
ウィジェットが見つかったかが表示されます。vicmd
viins
上記のループを上にパイプすると、次のgrep '\^\[[[O][A-D]'
値に関係なくその内容が表示されます$TERM
。
% (for m ($keymaps) bindkey -M $m | grep -H --label=$m .) | grep '\^\[[[O][A-D]'
visual:"^[OA" up-line
visual:"^[OB" down-line
visual:"^[[A" up-line
visual:"^[[B" down-line
viopp:"^[OA" up-line
viopp:"^[OB" down-line
viopp:"^[[A" up-line
viopp:"^[[B" down-line
vicmd:"^[OA" up-line-or-history
vicmd:"^[OB" down-line-or-history
vicmd:"^[OC" vi-forward-char
vicmd:"^[OD" vi-backward-char
vicmd:"^[[A" up-line-or-history
vicmd:"^[[B" down-line-or-history
vicmd:"^[[C" vi-forward-char
vicmd:"^[[D" vi-backward-char
main:"^[OA" up-line-or-history
main:"^[OB" down-line-or-history
main:"^[OC" forward-char
main:"^[OD" backward-char
main:"^[[A" up-line-or-history
main:"^[[B" down-line-or-history
main:"^[[C" forward-char
main:"^[[D" backward-char
viins:"^[OA" up-line-or-history
viins:"^[OB" down-line-or-history
viins:"^[OC" vi-forward-char
viins:"^[OD" vi-backward-char
viins:"^[[A" up-line-or-history
viins:"^[[B" down-line-or-history
viins:"^[[C" vi-forward-char
viins:"^[[D" vi-backward-char
emacs:"^[OA" up-line-or-history
emacs:"^[OB" down-line-or-history
emacs:"^[OC" forward-char
emacs:"^[OD" backward-char
emacs:"^[[A" up-line-or-history
emacs:"^[[B" down-line-or-history
emacs:"^[[C" forward-char
emacs:"^[[D" backward-char
ほとんどのキーマップでは、この4つの矢印キーの2つのエスケープシーケンスは、特定の状況で通常実行されると予想される操作に関連付けられています。
これらのウィジェットはまた、一般的に使用されるemacs / viキー(たとえば、^B
emacsモードの^F
、、、、^P
またはvi-cmdモードの、、、、など)にバインドされます。^N
h
j
k
l
もちろん、すべての端末が送信するよく知られている単一の制御文字である、およびへのバインディングもありますEsc(TabBSを送信する端末があり、DELを送信する端末がありますが)。BackspaceEnterBackspace
ただし、他のファンクションキーに関する情報は見つかりません。
たとえば、端末が押されたときに端末が送信する内容の概要を取得する方法があります。これはterminfoデータベースに知られていますEnd。
$ (typeset -A count; for TERM (/usr/share/terminfo/*/*(.:t)) (( count[\$terminfo[kend]]++ )); typeset -p1 count)
typeset -A count=(
[$'\M-\C-@O']=8
['']=1341
[$'\M-\C-?\M-(']=6
[$'\C-Ak\C-M']=1
[$'\C-SI']=3
[$'\C-[)4\C-M']=4
[$'\C-[0']=8
[$'\C-[F']=1
[$'\C-[K']=4
[$'\C-[OF']=99
[$'\C-[T']=13
[$'\C-[Y']=1
[$'\C-[[146q']=23
[$'\C-[[1~']=11
[$'\C-[[220z']=21
[$'\C-[[24;1H']=3
[$'\C-[[4~']=139
[$'\C-[[5~']=9
[$'\C-[[8~']=28
[$'\C-[[F']=49
[$'\C-[[K']=1
[$'\C-[[OF']=1
[$'\C-[[U']=15
[$'\C-[[Y']=16
[$'\C-[[d']=1
[$'\C-[_1\C-[\\']=1
[$'\C-[k']=3
[$'\C-[z']=13
['- @']=1
['-45~']=1
['-4~']=5
[1!]=1
)
ほとんどの端末では、彼らが何をしているのかわかりません。$'\C-[[4~'
最も一般的です。
Delete現在は通常送信されますが、\e[3~
時にはDEL(^?
)(最も一般的にはバックスペースキーで送信されます)が送信され、多くの人がそれをターミナルエミュレータ設定で設定できます。一部の端末エミュレータは、エミュレートするキーボードの種類を知らせ、そのファンクションキーに対して異なるシーケンスを送信します。たとえば、ドキュメントを引用したxtermを参照してください。
-kt
キーボードタイプ
このオプションはkeyboardType
リソースを設定します。可能な値は、「unknown」、「default」、「legacy」、「hp」、「sco」、「sun」、「tcap」、および「vt220」です。
これで、ユーザーはどのタイプのキーボードを使用するのか、どの端末エミュレータとどのシステムで使用するのかを知ることができます。オペレーティングシステムのベンダーはzshよりも正確な推測をすることができます(zshは30年以上にわたって数千のさまざまなシステムで使用されています)。
たとえば、x86 PC用のDebian GNU / Linuxディストリビューションは、パッケージに含まれている何十もの端末エミュレータ(ほとんど同様xterm
)に合理的に忠実なterminfoデータベースを維持しようとします。通常、送信される複数のファンクションキーを知っています。 PCキーボードのキーボードは、ユーザーがターミナルエミュレータのデフォルト設定を変更せずに外部オペレーティングシステムからリモートでログインしない限り、使用できます。
/etc/zsh/zshrc
したがって、Debianはこれを(対話的に呼び出されるシステムカスタムファイル)に追加することに気付くでしょうzsh
。
# /etc/zsh/zshrc: system-wide .zshrc file for zsh(1).
#
# This file is sourced only for interactive shells. It
# should contain commands to set up aliases, functions,
# options, key bindings, etc.
#
# Global Order: zshenv, zprofile, zshrc, zlogin
READNULLCMD=${PAGER:-/usr/bin/pager}
# An array to note missing features to ease diagnosis in case of problems.
typeset -ga debian_missing_features
if [[ -z "${DEBIAN_PREVENT_KEYBOARD_CHANGES-}" ]] &&
[[ "$TERM" != 'emacs' ]]
then
typeset -A key
key=(
BackSpace "${terminfo[kbs]}"
Home "${terminfo[khome]}"
End "${terminfo[kend]}"
Insert "${terminfo[kich1]}"
Delete "${terminfo[kdch1]}"
Up "${terminfo[kcuu1]}"
Down "${terminfo[kcud1]}"
Left "${terminfo[kcub1]}"
Right "${terminfo[kcuf1]}"
PageUp "${terminfo[kpp]}"
PageDown "${terminfo[knp]}"
)
function bind2maps () {
local i sequence widget
local -a maps
while [[ "$1" != "--" ]]; do
maps+=( "$1" )
shift
done
shift
sequence="${key[$1]}"
widget="$2"
[[ -z "$sequence" ]] && return 1
for i in "${maps[@]}"; do
bindkey -M "$i" "$sequence" "$widget"
done
}
bind2maps emacs -- BackSpace backward-delete-char
bind2maps viins -- BackSpace vi-backward-delete-char
bind2maps vicmd -- BackSpace vi-backward-char
bind2maps emacs -- Home beginning-of-line
bind2maps viins vicmd -- Home vi-beginning-of-line
bind2maps emacs -- End end-of-line
bind2maps viins vicmd -- End vi-end-of-line
bind2maps emacs viins -- Insert overwrite-mode
bind2maps vicmd -- Insert vi-insert
bind2maps emacs -- Delete delete-char
bind2maps viins vicmd -- Delete vi-delete-char
bind2maps emacs viins vicmd -- Up up-line-or-history
bind2maps emacs viins vicmd -- Down down-line-or-history
bind2maps emacs -- Left backward-char
bind2maps viins vicmd -- Left vi-backward-char
bind2maps emacs -- Right forward-char
bind2maps viins vicmd -- Right vi-forward-char
# Make sure the terminal is in application mode, when zle is
# active. Only then are the values from $terminfo valid.
if (( ${+terminfo[smkx]} )) && (( ${+terminfo[rmkx]} )); then
function zle-line-init () {
emulate -L zsh
printf '%s' ${terminfo[smkx]}
}
function zle-line-finish () {
emulate -L zsh
printf '%s' ${terminfo[rmkx]}
}
zle -N zle-line-init
zle -N zle-line-finish
else
for i in {s,r}mkx; do
(( ${+terminfo[$i]} )) || debian_missing_features+=($i)
done
unset i
fi
unfunction bind2maps
fi # [[ -z "$DEBIAN_PREVENT_KEYBOARD_CHANGES" ]] && [[ "$TERM" != 'emacs' ]]
[...]
上記のように、キー名を対応するエスケープシーケンスにマップする連想配列を定義します。これらのエスケープシーケンスは、デフォルトでDebianに付属のterminfoデータベースから取得されます(アイテムリストはデフォルトでは制限されていますが)。
ただし、terminfoデータベースは端末から送信されたエスケープシーケンスのみを提供するためキーボード転送モード、zshrcがZLEに起動時にこのモードに入り、終了時にそのままにするように指示することがわかります。
zshrc
これは、インタラクティブzshシェル(シェルが実行される場所)のプロンプト(ZLE内)とプロンプトなしで異なるシーケンスが表示される理由を説明します。
zshのスクリプトとより一般的な非対話型呼び出しはzshrcを読みません。 zshrcはすべてのカスタム、エイリアス、関数を保存する場所なので、スクリプトがそれを読むと確実に壊れます。
ZLEvared
も使用され、zshrcを読み取らないスクリプトから呼び出されると、これは/ etc / zsh / zshrcからオペレーティングシステムが提供するバインディングを取得しないことを意味します。
したがって、これらのバインディングが好きで、スクリプトユーザーが同じオペレーティングシステムを使用しているかどうかに関係なく、ユーザーが使用できるようにするには、スクリプトに直接含める必要があります。
また、ZLEのデフォルト値は、emacs
orで始まるかどうかに応じてorモードに設定されます。スクリプトユーザーが一貫したキーバインディングを使用できるようにするには、パターンを強制的に適用する必要があります。デフォルトでは、emacsモードまたはviモードが選択されているか(または使用されている)かに応じて、またはのエイリアスであるキーマップバインディングが設定されます。vi
$EDITOR
$VISUAL
vi
/vi
bindkey
main
emacs
viins
bindkey -e
bindkey -v
Debianに加えて、他のエディタの動作を模倣するShiftためAltに//と組み合わせることを含む、ファンクションキーバインディングに関する他の多くのカスタム提案を見つけることができます(そのエディタに一意のシーケンスを送信する端末から)。Ctrl
たとえば、参照してください。zsh zle シフト選択スタックオーバーフロー情報oh-my-zsh
キーバインディング彼らからインスピレーションを得ることができます。
1このような問題が発生しないように、cshスクリプトに通常読み込みをスキップする#! /bin/csh -f
shebangがある方法を確認してください。-f
~/.cshrc