Продублировать последний аргумент текущей команды в zsh, zle widget

18.03.2017, 22:20 - 2 мин читать

В последнее время я упоролся по тюнингу своего 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 duplicate last argument

Когда я правил чужие виджеты (виджетом в 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

, теги: zsh zle fast