Zsh zle shift выбор
Как использовать shift для выбора части командной строки (как во многих текстовых редакторах)?
6 ответов
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
Это предполагает, что ваш терминал отправляет другую escape-последовательность по 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).
Развивая превосходный ответ Стефана почти 3 года назад, я добавил еще несколько привязок, чтобы поведение (почти) полностью соответствовало стандартному поведению клавиатуры Windows:
- Выбор очищается при использовании навигационной клавиши (стрелка, дом, конец) БЕЗ сдвига
Backspace
а такжеDel
удалить активный выбор- Выбор расширяется до следующего / предыдущего слова при использовании
Ctrl+Shift+Left
/Ctrl+Shift+Right
Shift+Home
а такжеShift+End
расширить выбор до начала и конца строки соответственно.Ctrl+Shift+Home
а такжеCtrl+Shift+End
делать то же самое.
Две вещи, которые не совсем одинаковы:
- Расширение выделения до следующего слова включает конечный пробел, в отличие от окон. Это можно исправить, но меня это не беспокоит.
- Ввод текста при активном выделении не удалит его и заменит введенный вами символ. Казалось бы, для переназначения всей клавиатуры потребуется намного больше работы. Не стоит хлопот со мной.
Обратите внимание, что стандартное поведение 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
,
Расширен ответ Джейми Трюорги.
Включает следующие функции:
-
cmd+a
: скопировать всю командную строку в буфер обмена - : скопировать текущий выбор командной строки в буфер обмена
- : вырезать (скопировать и удалить) текущий выделенный фрагмент командной строки в буфер обмена
-
ctrl+u
: удалить назад до начала строки - : отменить
-
cmd+shift+z
: redo - выбор смены:
- : выберите символ слева
- : выберите символ справа
-
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
CTRL_U='^U'
CMD_A=$'\eå'
CMD_C=$'\eç'
CMD_X=$'\e≈'
CMD_Z=$'\eΩ'
CMD_SHIFT_Z=$'\e¸'
CMD_SHIFT_LEFT=$'\ea'
CMD_SHIFT_RIGHT=$'\ee'
CTRL_SHIFT_A=$'\ea'
CTRL_SHIFT_E=$'\ee'
# shell-key widget
bindkey $CTRL_U backward-kill-line
bindkey $CMD_Z undo
bindkey $CMD_SHIFT_Z redo
# `pbpaste` and `pbcopy` are MacOS specific
# clipboard handler commands, for Linux I think
# it's `xclip`
if [[ `uname -s` = Darwin ]];
then
# copy entire terminal line to clipboard
function widget::copy-line() {
printf "%s" "$BUFFER" | pbcopy
}
zle -N widget::copy-line
bindkey $CMD_A widget::copy-line # cmd+a
# copy selected terminal text to clipboard
function widget::copy-selection {
if ((REGION_ACTIVE)); then
zle copy-region-as-kill
printf "%s" $CUTBUFFER | pbcopy
fi
}
zle -N widget::copy-selection
bindkey $CMD_C widget::copy-selection # cmd+c
# cut selected terminal text to clipboard
function widget::cut-selection() {
if ((REGION_ACTIVE)) then
zle kill-region
printf "%s" $CUTBUFFER | pbcopy
fi
}
zle -N widget::cut-selection
bindkey $CMD_X widget::cut-selection # cmd+x
fi
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
}
for keyname kcap seq mode widget (
left kcub1 $'\eOD' unselect backward-char
right kcuf1 $'\eOC' unselect forward-char
shift-left kLFT $'\e[1;2D' select backward-char
shift-right kRIT $'\e[1;2C' select forward-char
shift-up kri $'\e[1;2A' select up-line-or-history
shift-down kind $'\e[1;2B' select down-line-or-history
alt-left x $'\eb' unselect backward-word
alt-right x $'\ef' unselect forward-word
alt-shift-left x $'\e[1;10D' select backward-word
alt-shift-right x $'\e[1;10C' select forward-word
cmd-left x $'^a' unselect backward-word
cmd-right x $'^b' unselect forward-word
cmd-shift-left x $CMD_SHIFT_LEFT select backward-word
cmd-shift-right x $CMD_SHIFT_RIGHT select forward-word
ctrl-a x $'^a' unselect beginning-of-line
ctrl-e x $'^e' unselect end-of-line
ctrl-shift-a x $CTRL_SHIFT_A select beginning-of-line
ctrl-shift-e x $CTRL_SHIFT_E select end-of-line
ctrl-shift-left x $'\e[1;6D' select beginning-of-line
ctrl-shift-right x $'\e[1;6C' select end-of-line
esc x $'\e' unselect reset-prompt
del x $'^D' delselect delete-char
backspace x $'^?' 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 ${terminfo[$kcap]:-$seq} widget::key-$keyname
}
Бонус
Некоторые люди также могут найти их полезными, хотя я не включил их выше, просто добавьте их в массив for-loop:
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:
Этот шаг связывает клавиши терминала с сигналами оболочки, т.е. сообщает программе / приложению терминала (iTerm2), какие сигналы отправлять программе оболочки () при нажатии определенных последовательностей клавиш клавиатуры. В зависимости от вашей программы терминала и предпочтений вы можете привязать свои ключи, как хотите, или использовать сигналы по умолчанию.
keyboard --> cmd+z --> iTerm2 --> ^[Ω --> zsh --> undo (widget)
Затем приведенный ниже сценарий связывает полученные сигналы с функциями оболочки, называемыми виджетами. Т.е. мы говорим программе оболочки запускать указанный виджет при получении указанного сигнала (последовательности клавиш).
Таким образом, в командной строке при нажатии последовательностей клавиш клавиатуры терминал отправляет соответствующий сигнал в оболочку, а оболочка вызывает соответствующий виджет (функцию). Функции, которые мы указываем оболочке для привязки, в данном случае являются функциями, которые редактируют саму командную строку, как если бы это был файл.
Определенные ниже виджеты используют
zsh
встроенный
zle
(редактор строк zsh) API модуля. Дополнительную информацию можно найти в официальной документации: ZSH ➤ 18 Zsh Line Editor.
Изящный трюк, чтобы увидеть, какие сигналы принимает оболочка.
cat
а затем нажав клавиши:❯ cat ^[[1;2D^[[1;2C^[Ω^[≈^[ç
Это был результат после нажатия:
shift-left
,shift-right
,cmd+z
,cmd+x
, а такжеcmd+c
.Некоторые ключи могут не отображаться. В этом случае проверьте настройки вашего терминала, ключ может быть привязан к некоторым функциям терминала (например,
cmd+n
может открыть новую панель терминала,cmd+t
может открыть новую вкладку терминала).Также см
terminfo(5)
, еще один способ найти определенные ключи.
Известные вопросы
может столкнуться с
oh-my-zsh
сsudo
плагин и дают странное поведение. Вы можете закомментировать / удалитьesc
строку в массиве или предложите исправление.столкновения с
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-autosuggestions или zsh-syntax-highlighting). Поэтому я придумал другой подход, который работает значительно лучше.
https://github.com/jirutka/zsh-shift-select/
Этот плагин не переопределяет существующие виджеты и привязывает только смещенные клавиши. Он создает новую раскладку клавиш выбора сдвига, которая автоматически активируется при вызове выбора сдвига (с использованием любой из определенных сдвинутых клавиш) и деактивируется (текущая раскладка переключается обратно на основную) для любой клавиши, которая не определена в выборе сдвига. раскладка. Благодаря такому подходу он не мешает другим плагинам (например, работает с zsh-autosuggestions без каких-либо изменений).
Для пользователей Windows и WSL .
Это комбинация ответов других авторов по отношению к ним, модифицированная для работы в WSL с Window Terminal . Поведение как в стандартной PowerShell: ctrl+shift+стрелки select, ctrl+z,x,c,v,a и т.д.
# 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://stackoverflow.com/a/68987551/13658418
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
Протестировано на WSL2 «Linux 5.15.79.1-microsoft-standard-WSL2» с терминалом Windows «1.15.3466.0».
Спасибо за эти ответы, я мирюсь со всеми и делаю свой сценарий для выбора и копирования, просто используя клавиатуру.
Если кто-то хочет отфильтровать вещи, которые будут более чистыми, я буду признателен.
это часть файла ~/.zshrc в домашнюю папку пользователя.
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
}
Я использовал кнопку de windows+c, чтобы скопировать выбранные символы. Я использую ubuntu 20.04 и настроил клавиатуру для использования кнопки выигрыша, такой как мета! После этого в настройках терминатора я меняю ярлык вставки на windows+v, jts, потому что думаю, что он будет быстрее, как control + x и COntrol + v