How to use shift to select part of the commandline (like in many text editors) ?
问题:
回答1:
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
That assumes your terminal sends a different escape sequence upon Shift-Arrows from the one sent upon Arrow and that your terminfo database is properly populated with corresponding kLFT and kRIT capabilities, and that you're using emacs style key binding.
Or, to factorize the code a bit:
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
}
Above, hardcoded sequences for cases where the terminfo database doesn't have the information (using xterm sequences).
回答2:
Expanding on Stephane's excellent answer from almost 3 years ago, I added some more bindings to make the behaviour (almost) completely consistent with all of Windows' standard keyboard behaviour:
- Selection is cleared when using a navigation key (arrow, home, end) WITHOUT shift
Backspace
andDel
delete an active selection- Selection is extended to the next/previous word when using
Ctrl+Shift+Left
/Ctrl+Shift+Right
Shift+Home
andShift+End
extend the selection to the beginning and end of line respectively.Ctrl+Shift+Home
andCtrl+Shift+End
do the same.
Two things that are not exactly the same:
- Extending a selection to the next word includes trailing space, unlike windows. This could be fixed, but it doesn't bother me.
- Typing when there is an active selection will not delete it and replace it with the character you typed. This would seem to require a lot more work to remap the entire keyboard. Not worth the trouble to me.
Note that the default mintty behaviour is to bind Shift+End
and Shift+Home
to access the scroll back buffer. This supercedes the zsh configuration; the keys never get passed through. In order for these to work, you will need to configure a different key (or disable scroll back) in /etc/minttyrc
or ~/.minttyrc
. See "modifier for scrolling" here - the simplest solution is just set ScrollMod=2
to bind it to Alt
instead of Shift
.
So everything:
~/.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
}
This covers keycodes from several different keyboard configurations I have used.
Note: the values in the "key" column don't mean anything, they are just used to build a named reference for zle. They could be anything. What is important is the seq
, mode
and widget
columns.
Note 2: You can bind pretty much any keys you want, you just need the key codes used in your console emulator. Open a regular console (without running zsh) and type Ctrl+V and then the key you want. It should emit the code. ^[
means \E
.