Shift を使用してコマンドラインの一部を選択する方法 (多くのテキスト エディターのように) ?
4 に答える
ほぼ 3 年前の Stephane の優れた回答を拡張して、Windows の標準的なキーボードの動作のすべてと (ほぼ) 完全に一致するように、いくつかのバインディングを追加しました。
- シフトなしでナビゲーション キー (矢印、ホーム、終了) を使用すると、選択がクリアされます。
Backspace
Del
アクティブな選択を削除しますCtrl+Shift+Left
/を使用すると、選択範囲が次/前の単語に拡張されますCtrl+Shift+Right
Shift+Home
選択範囲をそれぞれ行頭とShift+End
行末まで拡張します。Ctrl+Shift+Home
そしてCtrl+Shift+End
同じことをします。
まったく同じではない 2 つの点:
- 選択範囲を次の単語に拡張すると、ウィンドウとは異なり、末尾のスペースが含まれます。これは修正される可能性がありますが、私は気にしません。
- アクティブな選択があるときに入力しても、それは削除されず、入力した文字に置き換えられます。キーボード全体を再マッピングするには、さらに多くの作業が必要になるようです。私に面倒をかける価値はありません。
mintty のデフォルトの動作は、バインドShift+End
しShift+Home
てスクロール バック バッファにアクセスすることであることに注意してください。これは zsh 構成に取って代わります。キーが通過することはありません。これらを機能させるには、 または で別のキーを構成する (またはスクロール バックを無効にする) 必要があり/etc/minttyrc
ます~/.minttyrc
。ここで「スクロールの修飾子」を参照してください。ScrollMod=2
最も簡単な解決策はAlt
、Shift
.
だからすべて:
~/.minttyrc
ScrollMod=2
~/.zshrc
r-delregion() {
if ((REGION_ACTIVE)) then
zle kill-region
else
local widget_name=$1
shift
zle $widget_name -- $@
fi
}
r-deselect() {
((REGION_ACTIVE = 0))
local widget_name=$1
shift
zle $widget_name -- $@
}
r-select() {
((REGION_ACTIVE)) || zle set-mark-command
local widget_name=$1
shift
zle $widget_name -- $@
}
for key kcap seq mode widget (
sleft kLFT $'\e[1;2D' select backward-char
sright kRIT $'\e[1;2C' select forward-char
sup kri $'\e[1;2A' select up-line-or-history
sdown kind $'\e[1;2B' select down-line-or-history
send kEND $'\E[1;2F' select end-of-line
send2 x $'\E[4;2~' select end-of-line
shome kHOM $'\E[1;2H' select beginning-of-line
shome2 x $'\E[1;2~' select beginning-of-line
left kcub1 $'\EOD' deselect backward-char
right kcuf1 $'\EOC' deselect forward-char
end kend $'\EOF' deselect end-of-line
end2 x $'\E4~' deselect end-of-line
home khome $'\EOH' deselect beginning-of-line
home2 x $'\E1~' deselect beginning-of-line
csleft x $'\E[1;6D' select backward-word
csright x $'\E[1;6C' select forward-word
csend x $'\E[1;6F' select end-of-line
cshome x $'\E[1;6H' select beginning-of-line
cleft x $'\E[1;5D' deselect backward-word
cright x $'\E[1;5C' deselect forward-word
del kdch1 $'\E[3~' delregion delete-char
bs x $'^?' delregion backward-delete-char
) {
eval "key-$key() {
r-$mode $widget \$@
}"
zle -N key-$key
bindkey ${terminfo[$kcap]-$seq} key-$key
}
これは、私が使用したいくつかの異なるキーボード構成のキーコードをカバーしています。
注:「キー」列の値は何の意味もありません。zle の名前付き参照を作成するために使用されるだけです。それらは何でもかまいません。重要なのはseq
、、mode
およびwidget
列です。
注 2:必要なほとんどすべてのキーをバインドできます。必要なのは、コンソール エミュレーターで使用されるキー コードだけです。通常のコンソールを (zsh を実行せずに) 開き、Ctrl+Vを入力してから必要なキーを入力します。コードを発行する必要があります。^[
を意味し\E
ます。
shift-arrow() {
((REGION_ACTIVE)) || zle set-mark-command
zle $1
}
shift-left() shift-arrow backward-char
shift-right() shift-arrow forward-char
shift-up() shift-arrow up-line-or-history
shift-down() shift-arrow down-line-or-history
zle -N shift-left
zle -N shift-right
zle -N shift-up
zle -N shift-down
bindkey $terminfo[kLFT] shift-left
bindkey $terminfo[kRIT] shift-right
bindkey $terminfo[kri] shift-up
bindkey $terminfo[kind] shift-down
Shift-Arrowsこれは、端末が送信されたものとは異なるエスケープ シーケンスを送信Arrowし、terminfo データベースに対応する kLFT および kRIT 機能が適切に入力され、emacs スタイルのキー バインディングを使用していることを前提としています。
または、コードを少し因数分解するには:
shift-arrow() {
((REGION_ACTIVE)) || zle set-mark-command
zle $1
}
for key kcap seq widget (
left LFT $'\e[1;2D' backward-char
right RIT $'\e[1;2C' forward-char
up ri $'\e[1;2A' up-line-or-history
down ind $'\e[1;2B' down-line-or-history
) {
functions[shift-$key]="shift-arrow $widget"
zle -N shift-$key
bindkey ${terminfo[k$kcap]-$seq} shift-$key
}
上記の、terminfo データベースに情報がない場合のハードコーディングされたシーケンス (xterm
シーケンスを使用)。
Jamie Treworgy の回答を拡張しました。
次の機能が含まれます。
cmd+a
: コマンド ライン プロンプト テキスト全体を選択します。cmd+x
: 現在のコマンドライン選択をクリップボードに切り取り (コピー & 削除)cmd+c
: 現在のコマンドライン選択をクリップボードにコピーcmd+v
: クリップボードの選択を貼り付けますctrl+u
: 行頭までさかのぼって削除cmd+z
: 元に戻すcmd+shift+z
: やり直し- シフト選択:
shift-left
: 左の文字を選択shift-right
: 右側の文字を選択shift-up
: 行を上に選択shift-down
: ライブ下向きを選択cmd-shift-left
: 行頭まで選択cmd-shift-right
: 行末まで選択alt-shift-left
: 左の単語を選択alt-shift-right
: 右の単語を選択ctrl-shift-left
: 行頭まで選択ctrl-shift-right
: 行末まで選択ctrl-shift-a
: 行頭まで選択ctrl-shift-e
: 行末まで選択
- unselect : 、 、 、 で期待どおりに
left/right
動作alt-left/right
しcmd/ctrl-left/right
ますesc+esc
。 - 選択範囲の削除:
Delete
、ctrl+d
、 で期待どおりに動作しますbackspace
- 選択範囲を削除して文字を挿入: 表示されているすべての ASCII 文字と空白に対して期待どおりに機能します
- 選択範囲の削除とクリップボードの挿入: 期待どおりに動作します
.zshrc
# for my own convenience I explicitly set the signals
# that my terminal sends to the shell as variables.
# you might have different signals. you can see what
# signal each of your keys sends by running `$> cat`
# and pressing keys (you'll be able to see most keys)
# also some of the signals sent might be set in your
# terminal emulator application/program
# configurations/preferences. finally some terminals
# have a feature that shows you what signals are sent
# per key press.
#
# for context, at the time of writing these variables are
# set for the kitty terminal program, i.e these signals
# are mostly ones sent by default by this terminal.
export KEY_ALT_F='ƒ'
export KEY_ALT_B='∫'
export KEY_ALT_D='∂'
export KEY_CTRL_U=$'\x15' # ^U
export KEY_CMD_BACKSPACE=$'^[b' # arbitrary; added via kitty config (send_text)
export KEY_CMD_Z=^[[122;9u
export KEY_SHIFT_CMD_Z=^[[122;10u
export KEY_CTRL_R=$'\x12' # ^R
export KEY_CMD_C=^[[99;9u
export KEY_CMD_X=^[[120;9u
export KEY_CMD_V=^[[118;9u
export KEY_CMD_A=^[[97;9u
export KEY_CTRL_L=$'\x0c' # ^L
export KEY_LEFT=${terminfo[kcub1]:-$'^[[D'}
export KEY_RIGHT=${terminfo[kcuf1]:-$'^[[C'}
export KEY_SHIFT_UP=${terminfo[kri]:-$'^[[1;2A'}
export KEY_SHIFT_DOWN=${terminfo[kind]:-$'^[[1;2B'}
export KEY_SHIFT_RIGHT=${terminfo[kRIT]:-$'^[[1;2C'}
export KEY_SHIFT_LEFT=${terminfo[kLFT]:-$'^[[1;2D'}
export KEY_ALT_LEFT=$'^[[1;3D'
export KEY_ALT_RIGHT=$'^[[1;3C'
export KEY_SHIFT_ALT_LEFT=$'^[[1;4D'
export KEY_SHIFT_ALT_RIGHT=$'^[[1;4C'
export KEY_CMD_LEFT=$'^[[1;9D'
export KEY_CMD_RIGHT=$'^[[1;9C'
export KEY_SHIFT_CMD_LEFT=$'^[[1;10D'
export KEY_SHIFT_CMD_RIGHT=$'^[[1;10C'
export KEY_CTRL_A=$'\x01' # ^A
export KEY_CTRL_E=$'\x05' # ^E
export KEY_SHIFT_CTRL_A=$'^[[97;6u'
export KEY_SHIFT_CTRL_E=$'^[[101;6u'
export KEY_SHIFT_CTRL_LEFT=$'^[[1;6D'
export KEY_SHIFT_CTRL_RIGHT=$'^[[1;6C'
export KEY_CTRL_D=$'\x04' # ^D
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# copy selected terminal text to clipboard
zle -N widget::copy-selection
function widget::copy-selection {
if ((REGION_ACTIVE)); then
zle copy-region-as-kill
printf "%s" $CUTBUFFER | pbcopy
fi
}
# cut selected terminal text to clipboard
zle -N widget::cut-selection
function widget::cut-selection() {
if ((REGION_ACTIVE)) then
zle kill-region
printf "%s" $CUTBUFFER | pbcopy
fi
}
# paste clipboard contents
zle -N widget::paste
function widget::paste() {
((REGION_ACTIVE)) && zle kill-region
RBUFFER="$(pbpaste)${RBUFFER}"
CURSOR=$(( CURSOR + $(echo -n "$(pbpaste)" | wc -m | bc) ))
}
# select entire prompt
zle -N widget::select-all
function widget::select-all() {
local buflen=$(echo -n "$BUFFER" | wc -m | bc)
CURSOR=$buflen # if this is messing up try: CURSOR=9999999
zle set-mark-command
while [[ $CURSOR > 0 ]]; do
zle beginning-of-line
done
}
# scrolls the screen up, in effect clearing it
zle -N widget::scroll-and-clear-screen
function widget::scroll-and-clear-screen() {
printf "\n%.0s" {1..$LINES}
zle clear-screen
}
function widget::util-select() {
((REGION_ACTIVE)) || zle set-mark-command
local widget_name=$1
shift
zle $widget_name -- $@
}
function widget::util-unselect() {
REGION_ACTIVE=0
local widget_name=$1
shift
zle $widget_name -- $@
}
function widget::util-delselect() {
if ((REGION_ACTIVE)) then
zle kill-region
else
local widget_name=$1
shift
zle $widget_name -- $@
fi
}
function widget::util-insertchar() {
((REGION_ACTIVE)) && zle kill-region
RBUFFER="${1}${RBUFFER}"
zle forward-char
}
# | key sequence | command
# --------------------- | ------------------------------- | -------------
bindkey $KEY_ALT_F forward-word
bindkey $KEY_ALT_B backward-word
bindkey $KEY_ALT_D kill-word
bindkey $KEY_CTRL_U backward-kill-line
bindkey $KEY_CMD_BACKSPACE backward-kill-line
bindkey $KEY_CMD_Z undo
bindkey $KEY_SHIFT_CMD_Z redo
bindkey $KEY_CTRL_R history-incremental-search-backward
bindkey $KEY_CMD_C widget::copy-selection
bindkey $KEY_CMD_X widget::cut-selection
bindkey $KEY_CMD_V widget::paste
bindkey $KEY_CMD_A widget::select-all
bindkey $KEY_CTRL_L widget::scroll-and-clear-screen
for keyname kcap seq mode widget (
left kcub1 $KEY_LEFT unselect backward-char
right kcuf1 $KEY_RIGHT unselect forward-char
shift-up kri $KEY_SHIFT_UP select up-line-or-history
shift-down kind $KEY_SHIFT_DOWN select down-line-or-history
shift-right kRIT $KEY_SHIFT_RIGHT select forward-char
shift-left kLFT $KEY_SHIFT_LEFT select backward-char
alt-right x $KEY_ALT_RIGHT unselect forward-word
alt-left x $KEY_ALT_LEFT unselect backward-word
shift-alt-right x $KEY_SHIFT_ALT_RIGHT select forward-word
shift-alt-left x $KEY_SHIFT_ALT_LEFT select backward-word
cmd-right x $KEY_CMD_RIGHT unselect end-of-line
cmd-left x $KEY_CMD_LEFT unselect beginning-of-line
shift-cmd-right x $KEY_SHIFT_CMD_RIGHT select end-of-line
shift-cmd-left x $KEY_SHIFT_CMD_LEFT select beginning-of-line
ctrl-e x $KEY_CTRL_E unselect end-of-line
ctrl-a x $KEY_CTRL_A unselect beginning-of-line
shift-ctrl-e x $KEY_SHIFT_CTRL_E select end-of-line
shift-ctrl-a x $KEY_SHIFT_CTRL_A select beginning-of-line
shift-ctrl-right x $KEY_SHIFT_CTRL_RIGHT select end-of-line
shift-ctrl-left x $KEY_SHIFT_CTRL_LEFT select beginning-of-line
del x $KEY_CTRL_D delselect delete-char
a x 'a' insertchar 'a'
b x 'b' insertchar 'b'
c x 'c' insertchar 'c'
d x 'd' insertchar 'd'
e x 'e' insertchar 'e'
f x 'f' insertchar 'f'
g x 'g' insertchar 'g'
h x 'h' insertchar 'h'
i x 'i' insertchar 'i'
j x 'j' insertchar 'j'
k x 'k' insertchar 'k'
l x 'l' insertchar 'l'
m x 'm' insertchar 'm'
n x 'n' insertchar 'n'
o x 'o' insertchar 'o'
p x 'p' insertchar 'p'
q x 'q' insertchar 'q'
r x 'r' insertchar 'r'
s x 's' insertchar 's'
t x 't' insertchar 't'
u x 'u' insertchar 'u'
v x 'v' insertchar 'v'
w x 'w' insertchar 'w'
x x 'x' insertchar 'x'
y x 'y' insertchar 'y'
z x 'z' insertchar 'z'
A x 'A' insertchar 'A'
B x 'B' insertchar 'B'
C x 'C' insertchar 'C'
D x 'D' insertchar 'D'
E x 'E' insertchar 'E'
F x 'F' insertchar 'F'
G x 'G' insertchar 'G'
H x 'H' insertchar 'H'
I x 'I' insertchar 'I'
J x 'J' insertchar 'J'
K x 'K' insertchar 'K'
L x 'L' insertchar 'L'
M x 'M' insertchar 'M'
N x 'N' insertchar 'N'
O x 'O' insertchar 'O'
P x 'P' insertchar 'P'
Q x 'Q' insertchar 'Q'
R x 'R' insertchar 'R'
S x 'S' insertchar 'S'
T x 'T' insertchar 'T'
U x 'U' insertchar 'U'
V x 'V' insertchar 'V'
W x 'W' insertchar 'W'
X x 'X' insertchar 'X'
Y x 'Y' insertchar 'Y'
Z x 'Z' insertchar 'Z'
0 x '0' insertchar '0'
1 x '1' insertchar '1'
2 x '2' insertchar '2'
3 x '3' insertchar '3'
4 x '4' insertchar '4'
5 x '5' insertchar '5'
6 x '6' insertchar '6'
7 x '7' insertchar '7'
8 x '8' insertchar '8'
9 x '9' insertchar '9'
exclamation-mark x '!' insertchar '!'
hash-sign x '\#' insertchar '\#'
dollar-sign x '$' insertchar '$'
percent-sign x '%' insertchar '%'
ampersand-sign x '\&' insertchar '\&'
star x '\*' insertchar '\*'
plus x '+' insertchar '+'
comma x ',' insertchar ','
dot x '.' insertchar '.'
forwardslash x '\\' insertchar '\\'
backslash x '/' insertchar '/'
colon x ':' insertchar ':'
semi-colon x '\;' insertchar '\;'
left-angle-bracket x '\<' insertchar '\<'
right-angle-bracket x '\>' insertchar '\>'
equal-sign x '=' insertchar '='
question-mark x '\?' insertchar '\?'
left-square-bracket x '[' insertchar '['
right-square-bracket x ']' insertchar ']'
hat-sign x '^' insertchar '^'
underscore x '_' insertchar '_'
left-brace x '{' insertchar '{'
right-brace x '\}' insertchar '\}'
left-parenthesis x '\(' insertchar '\('
right-parenthesis x '\)' insertchar '\)'
pipe x '\|' insertchar '\|'
tilde x '\~' insertchar '\~'
at-sign x '@' insertchar '@'
dash x '\-' insertchar '\-'
double-quote x '\"' insertchar '\"'
single-quote x "\'" insertchar "\'"
backtick x '\`' insertchar '\`'
whitespace x '\ ' insertchar '\ '
) {
eval "function widget::key-$keyname() {
widget::util-$mode $widget \$@
}"
zle -N widget::key-$keyname
bindkey $seq widget::key-$keyname
}
# suggested by "e.nikolov", fixes autosuggest completion being
# overriden by keybindings: to have [zsh] autosuggest [plugin
# feature] complete visible suggestions, you can assign an array
# of shell functions to the `ZSH_AUTOSUGGEST_ACCEPT_WIDGETS`
# variable. when these functions are triggered, they will also
# complete any visible suggestion. Example:
export ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(
widget::key-right
widget::key-shift-right
widget::key-cmd-right
widget::key-shift-cmd-right
)
ボーナス
上記には含めていませんが、これらを for-loop 配列に追加するだけで便利だと思う人もいるでしょう。
タブ
tab x $'\x09' insertchar '\ '
- タブ補完は失敗することに注意してください
他の
send kEND $'\E[1;2F' select end-of-line send2 x $'\E[4;2~' select end-of-line shome kHOM $'\E[1;2H' select beginning-of-line shome2 x $'\E[1;2~' select beginning-of-line end kend $'\EOF' deselect end-of-line end2 x $'\E4~' deselect end-of-line home khome $'\EOH' deselect beginning-of-line home2 x $'\E1~' deselect beginning-of-line csend x $'\E[1;6F' select end-of-line cshome x $'\E[1;6H' select beginning-of-line cleft x $'\E[1;5D' deselect backward-word cright x $'\E[1;5C' deselect forward-word del kdch1 $'\E[3~' delregion delete-char
古いですが、一部の人にとってはまだ役立つかもしれません
ノート
特定のキーボード キー シーケンスは、シェル プログラム固有の信号を送信するために、端末アプリケーション (私の場合は iTerm2) で最初に構成されました。上記のコードで使用されているバインディングは次のとおりです。
➤ iTerm2
➤ Preferences
➤ Keys
➤ Key Bindings:
キー シーケンス | キーバインディング |
---|---|
cmd+shift+left |
エスケープ シーケンスの送信:a |
cmd+shift+right |
エスケープ シーケンスの送信:e |
ctrl+shift+a |
エスケープ シーケンスの送信:a |
ctrl+shift+e |
エスケープ シーケンスの送信:e |
cmd+left |
16 進コードを送信:\x01 |
cmd+right |
16 進コードを送信:\x05 |
cmd+a |
エスケープ シーケンスの送信:å |
cmd+c |
エスケープ シーケンスの送信:ç |
cmd+v |
エスケープ シーケンスの送信:√</code> |
cmd+x |
エスケープ シーケンスの送信:≈</code> |
cmd+z |
エスケープ シーケンスの送信:Ω |
cmd+shift+z |
エスケープ シーケンスの送信:¸ |
このステップは、ターミナル キーをシェル シグナルにバインドします。つまり、ターミナル プログラム/アプリケーション (iTerm2) に、zsh
特定のキーボード キー シーケンスを押したときにシェル プログラム ( ) に送信するシグナルを伝えます。端末プログラムと好みに応じて、好きなようにキーをバインドしたり、デフォルトのシグナルを使用したりできます。
keyboard --> cmd+z --> iTerm2 --> ^[Ω --> zsh --> undo (widget)
次に、上記のスクリプトは、受信したシグナルをウィジェットと呼ばれるシェル関数にバインドします。つまり、シェル プログラムに、指定されたシグナル (キー シーケンス) を受信したときに指定されたウィジェットを実行するように指示します。
したがって、コマンドラインでキーボードのキー シーケンスを押すと、ターミナルは適切なシグナルをシェルに送信し、シェルは対応するウィジェット (関数) を呼び出します。この場合、シェルにバインドするように指示する関数は、コマンドライン自体をファイルであるかのように編集する関数です。
上記で定義されたウィジェットは、zsh
の組み込みzle
(zsh ライン エディター) モジュール API を使用します。詳細については、公式ドキュメント: ZSH ➤ 18 Zsh Line Editorおよび公式ガイド: ZSH ➤ Chapter 4: The Z-Shell Line Editorを参照してください。
シェルが受信したシグナルを確認するための巧妙なトリックは、実行
cat
してからキーを押すことです。❯ cat ^[[1;2D^[[1;2C^[Ω^[≈^[ç
shift-left
これは、 、shift-right
、cmd+z
、cmd+x
、およびを押した後の出力ですcmd+c
。特定のキーが表示されない場合があります。この場合、ターミナルの設定を確認してください。キーが何らかのターミナル機能にバインドされている可能性があります (たとえば
cmd+n
、新しいターミナル ペインをcmd+t
開く、新しいターミナル タブを開くなど)。また
terminfo(5)
、特定のキーを見つける別の方法も参照してください。
既知の問題と問題の修正
iTerm2 を使用している場合、バインド先を変更する
cmd+v
と、コマンド ライン以外での貼り付けが異なる動作をする可能性があり、その特定のプログラムでの再マッピングが必要になります (たとえば、 のようなプログラムの検索プロンプトでless
)。これを回避したい場合は、iTerm2 の のマッピングを変更せず、.cmd+v
をコメントアウト/削除してwidget::paste
ください。esc
oh-my-zsh
のプラグインと衝突しsudo
、奇妙な動作をする可能性があります。配列内の行をコメントアウト/削除するesc
か、修正を提案できます。right
と衝突しzsh-autosuggestion
ます。つまり、提案を受け入れません。配列からコメントアウト/削除するright
か、修正を提案できます。これはおそらく可能です。私は現在、その方法がわからず、今試しているのに十分な時間を費やしました。私は多くのことを試しましたが、作業に最も近いのは次のようなものだったと思います:
function widget::key-right() { REGION_ACTIVE=0 zle autosuggest-accept zle forward-char } zle -N widget::key-right bindkey $'\eOC' widget::key-right
しかし、役に立たない。提案は完了しません。ただし、いつでも新しいキーバインドを作成できます。
bindkey $'\e\'' autosuggest-accept
autosuggestion-accept
Github リポジトリから取得しました: zsh-users/zsh-autosuggestions。との右キー衝突
zsh-autosuggestion
、および/またはその他の衝突を修正するには、シェル初期化ファイル (例:.zshrc
) の 1 つに次を追加します:export ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(<shell-function> ...)
( @e.nikolovによる提案)。例については上記を参照してください。