How to use shift to select part of the commandline (like in many text editors) ?
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).
Expanding on Stéphane'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
}
# restore backward-delete-char for Backspace in the incremental
# search keymap so it keeps working there:
bindkey -M isearch '^?' backward-delete-char
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
.
shome
, csleft
, etc? Google is not friendly here. –
Uric bck-i-search
. –
Equal backward-delete-char
which is the default binding for BS doens't act the same when called from a function in the bck-i-search
context). You can still use CTRL+H as backspace; I guess one needs to decide whether BS key should work in this context or on the normal CLI. –
Symbiosis \E[1;6D
codes determines the modifier: base 1, +1 for Shift, +2 for Alt/Option/Meta, +4 for Ctrl. So 6 means Shift+Ctrl (1+1+4). Alt is 3, Shift+Alt is 4. –
Jeffjeffcoat 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).
Expanded on Jamie Treworgy's answer.
Includes the following functionality:
cmd+a
: select entire command-line prompt textcmd+x
: cut (copy & delete) current command-line selection to clipboardcmd+c
: copy current command-line selection to clipboardcmd+v
: pastes clipboard selectionctrl+u
: delete backwards till beginning of linecmd+z
: undocmd+shift+z
: redo- shift select:
shift-left
: select character to the leftshift-right
: select character to the rightshift-up
: select line upwardsshift-down
: select live downwardscmd-shift-left
: select till beginning of linecmd-shift-right
: select till end of linealt-shift-left
: select word to the leftalt-shift-right
: select word to the rightctrl-shift-left
: select till beginning of linectrl-shift-right
: select till end of linectrl-shift-a
: select till beginning of linectrl-shift-e
: select till end of line
- unselect: works as expected, on
left/right
,alt-left/right
,cmd/ctrl-left/right
,esc+esc
. - delete selection: works as expected on
Delete
,ctrl+d
,backspace
- delete selection & insert character: works as expected for all visible ASCII characters and whitespace
- delete selection & insert clipboard: works as expected
.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
)
Bonus
Some people might also find these useful, though I didn't include them above, just add them to the for-loop array:
Tab
tab x $'\x09' insertchar '\ '
- note that tab completion will fail
Other
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
OLD but maybe still useful for some
Note
Certain keyboard key sequences were first configured on the terminal application (in my case iTerm2) to send the shell program specific signals. The bindings used in the above code are:
➤ iTerm2
➤ Preferences
➤ Keys
➤ Key Bindings:
Key Sequence | Keybinding |
---|---|
cmd+shift+left |
Send Escape Sequence: a |
cmd+shift+right |
Send Escape Sequence: e |
ctrl+shift+a |
Send Escape Sequence: a |
ctrl+shift+e |
Send Escape Sequence: e |
cmd+left |
Send Hex Codes: \x01 |
cmd+right |
Send Hex Codes: \x05 |
cmd+a |
Send Escape Sequence: å |
cmd+c |
Send Escape Sequence: ç |
cmd+v |
Send Escape Sequence: √ |
cmd+x |
Send Escape Sequence: ≈ |
cmd+z |
Send Escape Sequence: Ω |
cmd+shift+z |
Send Escape Sequence: ¸ |
This step binds terminal keys to shell signals, i.e tells the terminal program/application (iTerm2) what signals to send the shell program (zsh
) upon pressing certain keyboard key sequences. Depending on your terminal program, and preference, you can bind your keys however you'd like, or use the default signals.
keyboard --> cmd+z --> iTerm2 --> ^[Ω --> zsh --> undo (widget)
Then the script above binds the received signals to shell functions, called widgets. I.e we tell the shell program, to run a specified widget upon receiving a specified signal (key sequence).
So on your command-line, upon pressing keyboard key sequences, the terminal sends the appropriate signal to the shell, and the shell calls the corresponding widget (function). The functions we tell the shell to bind to are in this case functions that edit the command-line itself, as though it was a file.
The widgets defined above use zsh
's builtin zle
(zsh line editor) module API. For more information you can see the official documentation: ZSH ➤ 18 Zsh Line Editor, and official guide: ZSH ➤ Chapter 4: The Z-Shell Line Editor.
A neat trick to see what signals are received by the shell is running
cat
and then pressing keys:❯ cat ^[[1;2D^[[1;2C^[Ω^[≈^[ç
That was the output for after having pressed:
shift-left
,shift-right
,cmd+z
,cmd+x
, andcmd+c
.Certain keys might not appear. In this case, check your terminal's configurations, the key might be binded to some terminal functionality (e.g.
cmd+n
might open up a new terminal pane,cmd+t
might open up a new terminal tab).Also see
terminfo(5)
, another way of finding certain keys.
Known Issues & Issue Fixes
if you're on iTerm2, changing what
cmd+v
is binded to might make pasting on anything other than the command-line act different, and requires remapping on that specific program (e.g. in the search prompts for programs likeless
). if you want to avoid this, then don't change the mapping of iTerm2'scmd+v
, and comment-out/remove thewidget::paste
.esc
might clash withoh-my-zsh
'ssudo
plugin and give weird behavior. You can comment-out/remove theesc
line in the array, or suggest a fix.right
clashes withzsh-autosuggestion
, i.e it won't accept the suggestion. You can comment-out/removeright
from the array, or suggest a fix. This is probably possible, I just currently don't know how, and spent enough time for now trying.I tried many things, I think the closest thing to working might of been something like:
function widget::key-right() { REGION_ACTIVE=0 zle autosuggest-accept zle forward-char } zle -N widget::key-right bindkey $'\eOC' widget::key-right
But to no avail. It doesn't complete the suggestion. You could however always create a new keybinding for it:
bindkey $'\e\'' autosuggest-accept
I got
autosuggestion-accept
from the Github repo: zsh-users/zsh-autosuggestions.To fix right-key clashing with
zsh-autosuggestion
, and/or other clashes you might have, add to one of your shell initialization files (e.g..zshrc
) the following:export ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(<shell-function> ...)
(suggested by @e.nikolov). see above for an example.
export ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=widget::key-right
–
Landgrabber export ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(widget::key-right widget::key-shift-right widget::key-shift-cmd-right widget::key-cmd-right)
. If it's not an array, there are some other compatibility issues. –
Landgrabber All solutions on this page are either incomplete or too invasive, so they negatively interfere with other plugins (e.g. zsh-autosuggestions or zsh-syntax-highlighting). I have therefore come up with a different approach that works significantly better.
https://github.com/jirutka/zsh-shift-select/
This plugin does not override any existing widgets and binds only shifted keys. It creates a new shift-select keymap that is automatically activated when the shift selection is invoked (using any of the defined shifted keys) and deactivated (the current keymap switches back to main) on any key that is not defined in the shift-select keymap. Thanks to this approach, it does not interfere with other plugins (for example, it works with zsh-autosuggestions without any change).
For Windows and WSL users.
This is combination of other authors answers with respect to them, modified to work in WSL with Window Terminal. Behaviour as in standard PowerShell: ctrl+shift+arrows select, ctrl+z,x,c,v,a etc.
# zsh-shift-select https://stackoverflow.com/a/30899296
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
}
# Fix zsh-autosuggestions https://stackoverflow.com/a/30899296
export ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(
key-right
)
# ctrl+x,c,v https://unix.stackexchange.com/a/634916/424080
function zle-clipboard-cut {
if ((REGION_ACTIVE)); then
zle copy-region-as-kill
print -rn -- $CUTBUFFER | clip.exe
zle kill-region
fi
}
zle -N zle-clipboard-cut
function zle-clipboard-copy {
if ((REGION_ACTIVE)); then
zle copy-region-as-kill
print -rn -- $CUTBUFFER | clip.exe
else
zle send-break
fi
}
zle -N zle-clipboard-copy
function zle-clipboard-paste {
if ((REGION_ACTIVE)); then
zle kill-region
fi
LBUFFER+="$(cat clip.exe)"
}
zle -N zle-clipboard-paste
function zle-pre-cmd {
stty intr "^@"
}
precmd_functions=("zle-pre-cmd" ${precmd_functions[@]})
function zle-pre-exec {
stty intr "^C"
}
preexec_functions=("zle-pre-exec" ${preexec_functions[@]})
for key kcap seq widget arg (
cx _ $'^X' zle-clipboard-cut _
cc _ $'^C' zle-clipboard-copy _
cv _ $'^V' zle-clipboard-paste _
) {
if [ "${arg}" = "_" ]; then
eval "key-$key() {
zle $widget
}"
else
eval "key-$key() {
zle-$widget $arg \$@
}"
fi
zle -N key-$key
bindkey ${terminfo[$kcap]-$seq} key-$key
}
# ctrl+a https://mcmap.net/q/513008/-zsh-zle-shift-selection
function widget::select-all() {
local buflen=$(echo -n "$BUFFER" | wc -m | bc)
CURSOR=$buflen
zle set-mark-command
while [[ $CURSOR > 0 ]]; do
zle beginning-of-line
done
}
zle -N widget::select-all
bindkey '^a' widget::select-all
# ctrl+z
bindkey "^Z" undo
Tested on WSL2 "Linux 5.15.79.1-microsoft-standard-WSL2" with Windows Terminal "1.15.3466.0".
Thanks for this answers, i take peace of all and do my script to select and copy just using keyboard.
if someone wanna filter to things be more clean i will appreciate.
its a part of ~/.zshrc file into home user folder.
alias pbcopy="xclip -selection clipboard"
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
super sup $'\ec' widget::copy-selection
) {
functions[shift-$key]="shift-arrow $widget"
zle -N shift-$key
bindkey ${terminfo[k$kcap]-$seq} shift-$key
}
zle -N widget::copy-selection
# copy selected terminal text to clipboard
function widget::copy-selection {
if ((REGION_ACTIVE)); then
zle copy-region-as-kill
printf "%s" $CUTBUFFER | pbcopy
fi
}
i used de windows+c button to copy selected characters. I'm using ubuntu 20.04 and configured keyboard option to using win button like meta! After this in preferences of terminator i change paste shortcut to windows+v, jts because a think its be more faster like control+x and COntrol+v
Here is my implementation of @8c6b5df0d16ade6c 's answer:
Code
###############
# Keybindings #
###############
# Bind Alt + Delete for forward deleting a word
bindkey -M emacs '^[[3;3~' kill-word
# Bind Delete to delete a letter to the right
bindkey "^[[3~" delete-char
# Ctrl binds
# Bind Ctrl + Delete to delete word to the right
bindkey '^[[3;5~' kill-word
# Bind Ctrl + Backspace to delete word to the left
bindkey '^H' backward-kill-word
# Bind Ctrl + Right Arrow to move to the next word
bindkey '^[[1;5C' forward-word
################
# Shift Select #
################
# 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_B='^[b'
export KEY_ALT_D='^[d'
export KEY_ALT_F='^[f'
export KEY_CTRL_A='^A'
export KEY_CTRL_E='^E'
export KEY_CTRL_L='^L'
export KEY_CTRL_R='^R'
export KEY_CTRL_U='^U'
export KEY_CTRL_Z='^Z'
export KEY_SHIFT_CTRL_A='^[[27;6;65~'
export KEY_SHIFT_CTRL_C='^[[27;6;67~'
export KEY_SHIFT_CTRL_E='^[[27;6;69~'
export KEY_SHIFT_CTRL_V='^[[27;6;86~'
export KEY_SHIFT_CTRL_X='^[[27;6;88~'
export KEY_SHIFT_CTRL_Z='^[[27;6;90~'
export KEY_LEFT='^[[D'
export KEY_RIGHT='^[[C'
export KEY_SHIFT_UP='^[[1;2A'
export KEY_SHIFT_DOWN='^[[1;2B'
export KEY_SHIFT_RIGHT='^[[1;2C'
export KEY_SHIFT_LEFT='^[[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;6C'
export KEY_CTRL_LEFT='^[[1;5D'
export KEY_CTRL_RIGHT='^[[1;5C'
export KEY_SHIFT_CTRL_LEFT='^[[1;6D'
export KEY_SHIFT_CTRL_RIGHT='^[[1;6C'
export KEY_END='^[[F;'
export KEY_HOME='^[[H'
export KEY_SHIFT_END='^[[1;2F'
export KEY_SHIFT_HOME='^[[1;2H'
export KEY_DELETE='^[[3~'
export KEY_BACKSPACE='^?'
export KEY_CTRL_BACKSPACE='^H'
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# copy selected terminal text to clipboard
zle -N widget::copy-selection
function widget::copy-selection {
if ((REGION_ACTIVE)); then
zle copy-region-as-kill
if test "$XDG_SESSION_TYPE" = "x11"; then
printf "%s" $CUTBUFFER | xclip
elif test "$XDG_SESSION_TYPE" = "wayland"; then
printf "%s" $CUTBUFFER | wl-copy
fi
fi
}
# cut selected terminal text to clipboard
zle -N widget::cut-selection
function widget::cut-selection() {
if ((REGION_ACTIVE)) then
zle kill-region
if test "$XDG_SESSION_TYPE" = "x11"; then
printf "%s" $CUTBUFFER | xclip
elif test "$XDG_SESSION_TYPE" = "wayland"; then
printf "%s" $CUTBUFFER | wl-copy
fi
fi
}
# paste clipboard contents
zle -N widget::paste
function widget::paste() {
((REGION_ACTIVE)) && zle kill-region
# change to use xclip/wl-copy
if test "$XDG_SESSION_TYPE" = "x11"; then
RBUFFER="$(xclip -o -selection clipboard)${RBUFFER}"
CURSOR=$(( CURSOR + $(echo -n "$(xclip -o -selection clipboard)" | wc -m | bc) ))
elif test "$XDG_SESSION_TYPE" = "wayland"; then
RBUFFER="$(wl-paste)${RBUFFER}"
CURSOR=$(( CURSOR + $(echo -n "$(wl-paste)" | wc -m | bc) ))
fi
}
# 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 -- $@
zle copy-region-as-kill
printf "%s" $CUTBUFFER | wl-copy --primary
if test "$XDG_SESSION_TYPE" = "x11"; then
printf "%s" $CUTBUFFER | xclip -selection --primary
elif test "$XDG_SESSION_TYPE" = "wayland"; then
printf "%s" $CUTBUFFER | wl-copy --primary
fi
}
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_CTRL_BACKSPACE backward-kill-word
bindkey $KEY_CTRL_Z undo
bindkey $KEY_SHIFT_CTRL_Z redo
bindkey $KEY_CTRL_R history-incremental-search-backward
bindkey $KEY_SHIFT_CTRL_C widget::copy-selection
bindkey $KEY_SHIFT_CTRL_X widget::cut-selection
bindkey $KEY_SHIFT_CTRL_V widget::paste
bindkey $KEY_SHIFT_CTRL_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
ctrl-right x $KEY_CTRL_RIGHT unselect forward-word
ctrl-left x $KEY_CTRL_LEFT unselect backward-word
shift-cmd-right x $KEY_SHIFT_CTRL_RIGHT select end-of-line
shift-cmd-left x $KEY_SHIFT_CTRL_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 forward-word
shift-ctrl-left x $KEY_SHIFT_CTRL_LEFT select backward-word
end kend $KEY_END unselect end-of-line
shift-end kEND $KEY_SHIFT_END select end-of-line
home khome $KEY_HOME unselect beginning-of-line
shift-home kHOM $KEY_SHIFT_HOME select beginning-of-line
del x $KEY_DELETE delselect delete-char
backspace x $KEY_BACKSPACE delselect backward-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
}
# 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
)
Use case
This is intended to be used with non-MacOS setups often using Ctrl + Shift instead of Cmd as the mod key(s) for the bind.
Custom escape sequences and example
You will also have to set custom escape sequences for Ctrl + Shift binds in your terminal emulator, because terminal emulators receive the same escape codes for Ctrl + <letter> and Ctrl + Shift + <letter>. Here is an example for the Foot terminal emulator:
[text-bindings]
\x1b[1;2F = Shift+KP_End
\x1b[1;2H = Shift+KP_Home
\x1b[27;6;65~ = Control+Shift+a
\x1b[27;6;66~ = Control+Shift+b
#\x1b[27;6;67~ = Control+Shift+c
\x1b[27;6;68~ = Control+Shift+d
\x1b[27;6;69~ = Control+Shift+e
\x1b[27;6;70~ = Control+Shift+f
\x1b[27;6;71~ = Control+Shift+g
\x1b[27;6;72~ = Control+Shift+h
\x1b[27;6;73~ = Control+Shift+i
\x1b[27;6;74~ = Control+Shift+j
\x1b[27;6;75~ = Control+Shift+k
\x1b[27;6;76~ = Control+Shift+l
\x1b[27;6;77~ = Control+Shift+m
#\x1b[27;6;78~ = Control+Shift+n
#\x1b[27;6;79~ = Control+Shift+o
\x1b[27;6;80~ = Control+Shift+p
\x1b[27;6;81~ = Control+Shift+q
#\x1b[27;6;82~ = Control+Shift+r
\x1b[27;6;83~ = Control+Shift+s
\x1b[27;6;84~ = Control+Shift+t
#\x1b[27;6;85~ = Control+Shift+u
#\x1b[27;6;86~ = Control+Shift+v
\x1b[27;6;87~ = Control+Shift+w
\x1b[27;6;88~ = Control+Shift+x
#\x1b[27;6;89~ = Control+Shift+y
\x1b[27;6;90~ = Control+Shift+z
This of course would go into your foot.ini
.
ZSH bindings conflicting with terminal bindings
I actually don't recommend using the foot terminal for this. Instead I recommend that you use the Kitty terminal because of an issue there is with conflicting keybinding.
The best meathod for shift selection in zsh would be to have it integrate with the terminal so that the terminal can preform actions on that selected text. Unfortunately, I do not know how to do this. So the work around is to have ZSH preform actions on the selected text instead. To copy selected text in a terminal emulator, the convention is to use Ctrl + Shift + c. So for consintency, I have that as the copy to clipboard bind in the shift selection implementation. The issue is that the keybinding conflicts with the terminal binding, so the escape code is not sent because the terminal binding supercedes the ZSH binding. Furthurmore, your terminal emulator will probably give you an error if you try to bind to text and another action. At least this is my experience in foot.
In other terminal emulators it is possible that you may be able to bind to text and another action such as copying selected text. If this was true, then it might be possible to set up Ctrl + Shift + c to copy selected text in both the terminal and in ZSH. I am not sure which one gets priority because ZSH selection is seperate from terminal selection, meaning that you can select text in both ZSH the terminal at the same time. Nevertheless that is a possible solution. I am not sure which terminals have or don't have the ability to bind to an escape code and another action with the same bind.
The solution that brings me to recommending Kitty as the terminal to use with this implementation is that Kitty has the ability to change a setting for an instance at runtime. That means that you could easily make it so that the keybinding for copying text in the terminal is turned off when text is selected in ZSH, and the escape code binding is enabled. Then make it so that when text is deselected, the terminal copy binding is turned back on, and the escape code binding is turned back off. This would make shift selection function almost as the selection was properly integrated with the terminal.
To run a command when text is selected, and run a command when text is deselected, you must edit the following chunks of code:
function widget::util-select() {
((REGION_ACTIVE)) || zle set-mark-command
local widget_name=$1
shift
zle $widget_name -- $@
zle copy-region-as-kill
printf "%s" $CUTBUFFER | wl-copy --primary
}
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
}
Ctrl + Shift + c is not the only binding that is effected by this. Any binding set by your terminal can conflict.
Copying selected text
Another thing that my setup does differently is use wl-copy
(often provided by the package wl-clipboard
) or xclip
instead of pbcopy
. pbcopy
is the MacOS command for copying text. wl-copy
is the Linux Wayland equivilent. xclip
is the Linux Xorg equivilant. If you are using Xorg replace I have implemented something that will use wl-copy
with xclip
. I might later implement something that does this replacement automatically based on the running display server protocol.xclip
or wl-copy
based on the running display server protocol.
This implementation also copies selected text to the primary clipboard as all selection should. This is done with wl-copy
but can also be done and with xclip
.
Conclusion
Issues
There are three main issues that I have yet to solve in this implementation of ZSH shift selection:
- Keybindings conflicting with terminal keybindings. I plan on setting this up with Kitty, and editing this answer.
wl-copy
being Wayland-specific and not portable to Xorg. I plan on implementingxclip
commands and having the used copy command be based on the running display server protocol.- I haven't mentiond this yet, but this implementation breaks Ctrl + r history search even with a plugin like H-S-MW. I honestly don't know how to fix this, but I suspect that it would be similar to fixing autosuggestions.
What this implementation does differently
Some things that this implementation does differently:
- Different keybindings
- The keybindings in this implementation are optimized to be used with Linux systems rather than a MacOS system that uses the Cmd key.
- Different escape codes
- Once again, the implementation by @8c6b5df0d16ade6c is optimized for MacOS, and the escape codes are optimized for iTerm.
- Some other quality of life keybindings
- The top part of the code block is from my config. This includes most of the keybindings that I use outside of the ones that I use for shift selection. And those are the bindings for moving one word at a time and deleting one word at a time.
- Diffirent clipboard commands (Support for Xorg and Wayland
- Copying selected text to primary clipboard
Dependencies
Currently, Wayland because I have not yet added support for and Xorg. I just added support for xclip
, though it should be very easy to doxclip
.
xclip
or wl-copy
.
Also, you need to set custom escape sequences in your terminal just like I did in my Foot example.
Resolving keybinding conflictions by changing settings at runtime or possibly setting a keybind to an action and an escape code both at the same time.
Anyways
If you want to make this better, please comment on how you might go about fixing the Ctrl + r issue. You could also comment and tell me how shift selection might be properly integrated into the terminal, where basically the ZSH bindings would control the actual terminal selection instead of zle
.
© 2022 - 2024 — McMap. All rights reserved.
set-mark-command
, so the data I can provide won't be much helpful. By usingshift
you meant<S-Right>
and<S-Left>
combos? You can use<C-v>
to get what terminal actually emit when you press<S-{Arrow}>
and bind this to something, but it will be terminal-specific. If you want highligted selection and it is absent (I do not actually know), you should look at$zle_highlighting
andxclip
. It is not impossible to emulate selection in zsh, but I never bothered to do it and know nobody who did bother. – Begley