В последнее время я упоролся по тюнингу своего zsh. Потратил на это кучу времени, но есть и плюсы: поучаствовав в правке пары плагинов, я начал понимать, как работает вся эта магия, которой я давно пользуюсь.
Так вот, у меня в терминале бывает частая задача: скопировать файл и положить рядом с немного другим именем. Раньше я пользовался такой схемой:
ls filename.ext
cp <Alt+.> <Alt+.>
То есть, я сначала вводил команду-пустышку, такую, чтобы в историю попала команда, где последним аргументом будет путь к файлу.
Потом через Alt+.
вставлял 2 раза последний аргумент предыдущей команды.
Другие примеры использования:
mv path/file1 path/file2
cp config.example config
mc /home/user /home/user
Теперь я могу делать так:
cp filename.ext <Alt+,>
В действии:
Когда я правил чужие виджеты (виджетом в zsh называется функция, повешенная на хоткей), я понял, что у zsh большие возможности по редактированию текущей строки комманд. Оставалось узнать, как это нагуглить.
Ключевик я нашел в тех же скриптах: ZLE
или Zsh Line Editor. ОК, гуглим zsh zle
,
попадаем на доку. Через 10 минут чтения и правок родилась эта функция.
После того, как я написал свой виджет, оказалось, что такая команда уже встроена в zsh, и даже лучше. Оставлю свой скрипт в конце статьи для того, чтобы было понятно, как можно писать свои виджеты, но пользоваться лучше этим:
# Example <Ctrl+.><Ctrl+,> inserts 2nd argument from end of prev. cmd
# http://chneukirchen.org/blog/archive/2013/03/10-fresh-zsh-tricks-you-may-not-know.html
autoload -Uz copy-earlier-word
zle -N copy-earlier-word
bindkey "^[," copy-earlier-word
Код надо вставить в .zshrc
или .zshrc.local
если вы пользуетесь
ansible-role-zsh
Виджет вставляет последний аргумент текущей команды, но если нажать еще дважды - вставит предпоследний.
Например, вы ввели команду some-command arg1 arg2
, чтобы вставить предпоследний аргумент, нажмите <Alt+.><Alt+,><Alt+,>
.
Как работают виджеты zsh:
Функция, вызванная через механизм виджетов, имеет доступ к куче внутренних переменных zsh, некоторые можно только читать, другие можно изменять на лету.
Я воспользовался двумя переменными:
BUFFER
- содержит текущую введенную команду. Переменную можно менять, но курсор при этом остается на месте.CURSOR
- позиция курсора
Оставалось сделать команде rtrim, отрезать последнее слово, добавить к буферу и передвинуть курсор на новое место.
Сам скрипт:
# Ctrl+, - duplicate last word in current command
zsh-duplicate-last-arg() {
BUFFER=$(echo "$BUFFER" | sed -e 's/[[:space:]]*$//')
BUFFER="$BUFFER ${BUFFER##* }"
CURSOR=$#BUFFER
}
zle -N zsh-duplicate-last-arg
bindkey '^[,' zsh-duplicate-last-arg