Записки Вредного программиста

enjoy, motherfuckers ;)

Написание первого плагина для Vim

Я использую Vim уже больше года и только сейчас возникла необходимость написать свое первое для него расширение. Расширение будет преобразовывать старые хеши из версии 1.8 языка Ruby в новые, появившиеся в версии 1.9, т.е. нечто вида :a => ‘b’ превратится в нечто более читаемое и компактное a: ‘b’.

Для начала необходимо создать папку, где будем хранить наше расширение, я использую ~/Projects/viml/ruby-hashes, для того, чтобы проекты на одном языке не лежали в одной папке с проектами на другом. (Когда проектов очень много можно легко запутаться).

1
2
3
4
5
6
7
8
tree .
├── LICENSE-MIT.txt
├── README.md
├── autoload
│   └── rubyhashes.vim
└── doc

2 directories, 3 files

Вот что будет представлять из себя весь плагин. LICENSE-MIT.txt, думаю не вызывает вопросов, впрочем, как и README.md, остается только один файл с раширением .vim, в папке autoload, почему именно в эту папку, в не в папку plugin, наверное, спросите вы. Отвечу, что в папке autoload хранятся вещи, которые загружаются только по требованию, т.е., если нам не нужно будет это расширение, Vim загружать его не будет. (Надеюсь, ничего не перепутал).

Задача

Реализовать плагин, который сможет заменять старые хеши на новые во всем файле.

Реализация

Теперь приступим непосредственно к программирование на VimScript‘e. VimScript – достаточно богатый скриптовый язык ко всему прочему позволяющий также и объявлять функции, а куда же без них. Функции будем называть следующим образом #{названиеФайлаБезРасширения}#НазваниеФункции(), т.е. функцию в файле autoload/rubyhashes.vim, производящую замену по всему файлу, мы назовем rubyhashes#ReplaceAll(). И соответственно ее объявление будет выглядеть, как

1
2
3
func! rubyhashes#ReplaceAll()
  echo 'hello, world!'
endfunc

Для того, чтобы увидеть выполнение нашей функции, файл необходимо сохранить. Чтобы Vim интерпретировал нашу функцию, как часть своей экосистемы, необходимо написать :source %. (Примерно тоже самое есть и в bash).

Теперь давайте запустим нашу функцию, чтобы увидеть заветные хеллоу ворлд.

Если все было набрано верно, то вы увидите заветную фразу.

Следующим шагом будет составление регулярного выражения, по которому будут находиться старые хеши и заменяться на новые. Если бы мы его писали на Ruby, как и на многих других языках программирования, использующих PCRE – Perl-совместимые регулярные выражения, к коим относятся javascript, php и др., то оно бы выглядело следующим образом.

/:(\w+)\s*=>\s*/, если кто не очень хорошо с ними знаком, скажу что мы сначала ищем :, затем любой символ слова (\w+), дальше долго следовать любое количество пробелов \s* (ноль в том числе), дальше – символы => и любое количество пробелов.

Осталось только трансформировать данное регулярное выражение в vim-совместимое, для этого необходимо будет экранировать скобки и знак “плюс”, что в результате превращается в :\(\w\+\)\s*=>\s.

Вы можете написать старый рубишный хеш вида :a => ‘b’, нажать / (запускает поиск) и ввести там :\(\w\+\)\s*=>\s и увидите, что найденный текст подсветился.

Искать по регулярному выражения мы уже научились, теперь необходимо заменять текст по регулярному выражению. В Vim’е для того, чтобы менять текст существует команда substitute или сокращенно s. Чтобы заменить все вхождения символа “а”, на “б”, необходимо выполнить команду :%s/a/b/g, где % – это диапазон поиска и замены, в данном случае это шорткат для всего файла, “a” – что заменяем, “b” – чем заменяем, “g” – это флаг, указывающий, что необходимо не останавливаться на первой замене, а продолжить до конца.

Результирующее команда замены примет вид

%s/:\(\w\+\)\s*=>\s*/\1: /ge

где \1: – это на что меняем (наша (\w+) часть) /ge – g – глобальный поиск и замена, e – это не показывать ошибку, если искомое выражение не найдено.

Дело за малым, сейчас нужно сделать так, чтобы при вызове нашей функции запускалась команда из предыдущего пункта. И тут в Vim есть команда, которая так и называется execute или сокращенно exe. Удалим echo ‘hello, world!’ и допишем

1
2
3
func! rubyhashes#ReplaceAll()
  exe '%s/:\(\w\+\)\s*=>\s*/\1: /ge'
endfunc

Сохраним и запустим :source %, чтобы данные нашей функции обновились. Теперь пробуем. Пишем в командной строке call rubyhashes#ReplaceAll() после того, как нажмем :. Если вы запустили нашу функцию в окне, где находились старые хеши, то они должны были поменяться на новые.

Вот и все для небольшого туториала по Vim плагинам, надеюсь, вам понравилось. Ссылка на репозиторий на гитхабе, где имеется, помимо функции, заменяющей хеши во всем файле, функция, которая производит замену в выделенном.

Комментарии