Примечание от переводчика: это первая часть монументальной (на самом деле монументальной) статьи о Vim и его возможностях от разработчика из Миннеаполиса и автора проекта PostgREST Джо begriffs Нельсона.
Первая часть статьи отводится на знакомство с историей Vim как редактора и автор рассказывает ряд интересных фактов и о возможностях Vim. Во второй части перевода будут сконцентрированы все фишки и лайфхаки, которыми Джо решил поделиться с аудиторией, там повествование, как таковое, затухает и остается лишь набор руководств к действию. Так как оригинал текста обладает совершенно неприемлемыми габаритами, мы разделили эту историю на две примерно равные по размерам статьи. Сегодня — первая из двух публикаций. Приятного чтения.
Эта статья основана на исследовании истории Vim и прочтении его руководства пользователя от корки до корки. Надеюсь, эти заметки помогут вам открыть (или переоткрыть?) для себя основные функциональные возможности этого редактора, а также позволят отказаться от использования предупакованных файлов vimrc и более вдумчиво использовать плагины.
Список литературы
Чтобы выйти за границы привычных тем, я бы порекомендовал обзавестись бумажной копией этого руководства и емким карманным справочником. Я не смог найти печатную копию руководства пользователя для Vim, так что в итоге просто распечатал идущий вместе с редактором PDF-файл с помощью printme1.com. Он идет вместе с софтом в $VIMRUNTIME/doc/usr_??
. В качестве удобного списка команд могу посоветовать справочник «Vi and Vim Editors Pocket».
Содержание
- История
- Иерархия конфигурации
- Сторонние плагины
- Бекапы и откаты
- Include и path
- Редактирование и компиляция цикла
- Диффы и патчи
- Буфер ввода / вывода
- Типы файлов
- Не забывайте про мышь
- Разное
История
Рождение vi
Команды и функции Vi существуют уже более пятидесяти лет, начиная с редактора QED. Вот его таймлайн:
- 1966: QED («Быстрый редактор») в Berkeley Timesharing System
- 1969 июл: с его помощью проводили посадку на Луну (ну так, для справки)
- 1969 Авг: QED → ed в AT&T
- 1976 Фев: ed → em («Editor for Mortals») в колледже королевы Марии
- 1976: em → ex («EXtended») в Калифорнийском университете в Беркли
- 1977 окт: ex получает визуальный режим, vi — текстовый терминал
Если вы почитаете руководство по QED и ex, то сможете обнаружить между ними некоторое сходство. Оба редактора используют схожу грамматику для указания и работы с диапазонами строк.
Такие редакторы как QED ed и em разрабатывались для печатных терминалов, которые в основной своей массе были обычными электрическими пишущими машинками с подключенным к ним модемом. Такие «полнокопирные» терминалы выводили команды на бумагу и очевидно, после ввода внести какие-либо исправления было невозможно. Поэтому процесс редактирования заключался в ручных правках пользовательских команд на бумаге, а после — повторного ввода.
К 1976 году появились видеотерминалы, например, ADM-3A. В Ex-редактор добавили «открытый режим», который позволял редактирование через видеотерминал в рамках одной страницы. Был добавлен и визуальный режим для ориентирования на строках терминала с помощью курсора. Визуальный режим активировался командой «vi» и постоянно обновлял отображаемый на экране файла, сохраняя при этом позиционирование командной строки в нижней части экрана. Интересный факт: на клавишах h, j, k, l на ADM-3A были нанесены стрелки, которые позволяли перемещать курсор в vi.
Узнать больше об этом периоде перехода от ed к ex/vi можно в интервью Билла Джоя. В нем он рассказывает о том, как создал ex/vi и о некоторых вещах, которые в итоге его разочаровали.
Классический vi — это просто альтер-это ex. Оба представлены одним и тем же двоичным файлом, который может запускаться как в ex-режиме, так и vi-режиме в зависимости от имени исполняемого файла. Наследие всей этой истории в том, что ex / vi «раскрывается» при использовании, почти не требует системных ресурсов и может работать в условиях ограниченной полосы пропускания. Он также доступен в большинстве существующих систем и полностью описан в POSIX.
От vi к Vim
Будучи производным от ed, редактор ex / vi являлся интеллектуальной собственностью AT&T. Чтобы использовать vi на платформах, отличных от Unix, люди должны были писать клоны, которые имели другую кодовую базу исходника.
Вот некоторые из них:
- nvi — 1980 для 4BSD
- calvin — 1987 для DOS
- vile — 1990 для DOS
- stevie — 1987 для Atari ST
- elvis — 1990 для Minix и 386BSD
- vim — 1991 для Amiga
- viper — 1995 для Emacs
- elwin — 1995 для Windows
- lemmy — 2002 для Windows
Мы сосредоточимся на клоне из центра списка — Vim. Брэм Муленаар хотел использовать vi на Amiga и начал переносить с Atari и развивать клона vi «stevie». А назвал он свою версию порта «Vi Imitation». Если хотите узнать об этом процессе из первых рук, то посмотрите его интервью для Free Software Magazine.
В версии 1.22 Vim был переименован в «Vi IMproved», что указывает на превосходство копии над оригиналом. Вот график следующих основных версий с описанием некоторых функций:
Для получения дополнительной информации о каждой версии стоит курить help, например, для vim8. Чтобы увидеть планируемые обновления, а так же список известных ошибок, стоит обратиться к todo.txt.
Например, восьмая версия включала некоторую поддержку асинхронных заданий по причине давления на проект со стороны NeoVim. Разработчики последнего хотели запускать отладку и REPL для веб-сценариев прямо внутри редактора.
Вообще Vim суперпортативный. Приспосабливаясь всю историю своего существования к работе на абсолютно разных платформах, этот редактор был вынужден держаться в рамках «легкой» культуры кодинга. Vim работает на OS / 390, Amiga, BeOS и BeBox, Macintosh Classic, Atari MiNT, MS-DOS, OS / 2, QNX, RISC-OS, BSD, Linux, OS X, VMS и MS-Windows. Вы можете положиться на Vim где угодно, и плевать, какое оборудование вы используете.
В конце пути оригинального vi, в 2002 году, исходный код ex / vi все же был опубликован под лицензией свободного программного обеспечения BSD. Сорцы доступны по адресу ex-vi.sourceforge.net.
Но давайте перейдем к делу. Прежде чем начать анализ Vim, полезно знать, как он организует и читает свои файлы конфигурации.
Иерархия конфига
Раньше я ошибочно считал, что Vim достает все свои настройки и сценарии только из файла .vimrc. Просмотр репозиториев случайных «дотфайлов» может только укрепить в этом мнении. Довольно часто люди выкладывают чудовищные по своей сути одиночные файлы .vimrc, задача которых — контроль каждого аспекта редактора. Эти громадные конфиги еще иногда называют «vim distros».
На самом деле Vim имеет аккуратную структуру, в которой .vimrc — это только одна из множества «точек входа». Фактически, вы можете сами спросить у Vim, какие именно скрипты он загружает. Для этого отредактируйте какой-нибудь исходник случайного проекта на вашей машине, загрузите его а после запустите команду
:scriptnames
Этот список стоит почитать. Попробуйте угадать, что делают эти скрипты и запишите каталоги, в которых они размещены.
Список оказался длиннее, чем вы ожидали? Если вы установили множество плагинов, то редактору предстоит и многое сделать. Проверьте, что замедляет его работу при запуске, выполнив следующую команду создания start.log:
vim --startuptime start.log name-of-your-file
Просто сравните, как быстро Vim запускается с из коробки:
vim --clean --startuptime clean.log name-of-your-file
Чтобы определить, какие именно сценарии следует подгружать при запуске или во время загрузки буфера, нужно проверить «runtime path» Vim. Этот путь представлен разделенным через запятую списком каталогов, каждый из которых содержит в себе общую структуру. Vim проверяет эти структуры в каждом каталоге в поиске своих скриптов запуска. Обрабатываются каталоги строго по порядку, в котором они расположены в списке.
Проверьте путь выполнения в своей системе через эту команду:
:set runtimepath
Моя система содержит следующие каталоги, указанные по умолчанию для runtimepath-проверки. Не все из них даже существуют, но Vim все равно будет пытаться обратиться к ним и станет проверять содержимое, если они все же на месте:
~/.vim
Домашний каталог, предназначен для созданных профилей.
/usr/local/share/vim/vimfiles
Общесистемный каталог Vim, для профилей с правами системного администратора.
/usr/local/share/vim/vim81
Aka $ VIMRUNTIME, для файлов, распространяемых вместе с Vim.
/usr/local/share/vim/vimfiles/after
В общесистемном каталоге Vim есть еще каталог «after». Он предназначен для добавления персональных настроек системного администратора «по умолчанию».
~/.vim/after
Каталог «after» в домашнем каталоге. Нужен для того, чтобы личные конфиги не отменяли или не пересекались с общесистемным или настройками «по умолчанию».
Вообще каталоги обрабатываются в том же порядке, в котором они записаны в start.log, исключение сделано только для «after». Этот всегда стоит в конце списка и обрабатывается последним.
При обработке каждого каталога, Vim ищет в них подпапки с конкретными именами. Чтобы больше узнать об этом, посмотрите help runtimepath. Вот краткое описание тех, которые мы будем рассматривать далее по тексту:
plugin /
Тут лежат файлы сценариев Vim, которые автоматически загружаются при редактировании любого типа файла. Еще их называют «глобальными».
autoload /
(Не путать с «plugin»). Эти скрипты автозагрузки содержат функции, которые подтягиваются только по запросу других скриптов.
ftdetect /
Скрипты для определения типов файлов. В своей работе они опираются на расширение, расположение или внутреннее содержимое файла.
ftplugin /
Скрипты, которые выполняются при редактировании файлов известного типа.
compiler /
Определяет, как запускать различные компиляторы или lint-проверку, и как анализировать их вывод. Может быть разделен сразу между несколькими ftplugins. Compiler не выполняется автоматически и должен вызываться командой.
pack /
Контейнер для собственных пакетов Vim 8, преемник управления пакетами в стиле Pathogen. Имеет собственную систему упаковки, не требует для работы стороннего кода.
И, наконец, ~ / .vimrc
— ловушка для общих настроек редактора. Используется для конфигурации настроек «по умолчанию», которые можно привязать к определенному типу файлов. Для ознакомления со всем списком можете выбрать .vimrc и запустить команду options.
Сторонние плагины
Плагины — это просто скрипты Vim, для выполнения которых их достаточно разместить в правильные места в runtimepath. В целом, процесс установки крайне прост: просто загрузите файл(ы). Проблема заключается в том, что некоторые плагины достаточно трудно обновить или удалить, поскольку их разбрасывает по разным подкаталогам и они засоряют пути выполнения своими сценариями. То есть, в итоге сложно определить, какой файл к какому плагину относится.
Именно для решения этого вопроса и стали развиваться «менеджеры плагинов». На vim.org был реестр плагинов как минимум до 2003 года включительно (если архив не врет). Однако в моду «менеджеры плагинов» как сущность вошли только к 2008 году.
Эти инструмент добавляют специальные каталоги для плагинов, чтобы отслеживать пути выполнения и расставлять теги, по которым можно отслеживать плагины. Большинство менеджеров также подтягивают обновления плагинов из сети.
Ниже я выстроил менеджеры плагинов по хронологии их возникновения. За основу были взяты диапазоны дат выхода первой и последней версии. Если официальных релизов не было, то я брал за основу самые ранние даты выхода и последнего обновления.
- Mar 2006 — Jul 2014: Vimball
- Oct 2008 — Dec 2015: Pathogen
- Aug 2009 — Dec 2009: Vimana
- Dec 2009 — Dec 2014: VAM
- Aug 2010 — Nov 2010: Jolt
- Oct 2010 — Nov 2012: tplugin
- Oct 2010 — Feb 2014: Vundle
- Mar 2012 — Mar 2018: vim-flavor
- Apr 2012 — Mar 2016: NeoBundle
- Jan 2013 — Aug 2017: infect
- Feb 2013 — Aug 2016: vimogen
- Oct 2013 — Jan 2015: vim-unbundle
- Dec 2013 — Jul 2015: Vizardry
- Feb 2014 — Oct 2018: vim-plug
- Jan 2015 — Oct 2015: enabler
- Aug 2015 — Apr 2016: Vizardry 2
- Jan 2016 — Jun 2018: dein.vim
- Sep 2016 — Present: native in Vim 8
- Feb 2017 — Sep 2018: minpac
- Mar 2018 — Mar 2018: autopac
- Feb 2017 — Jun 2018: pack
- Mar 2017 — Sep 2017: vim-pck
- Sep 2017 — Sep 2017: vim8-pack
- Sep 2017 — May 2019: volt
- Sep 2018 — Feb 2019: vim-packager
- Feb 2019 — Feb 2019: plugpac.vim
Первое, на что нужно обратить внимание в списке выше — это огромное разнообразие. Второе — каждый из представленных инструментов «живет» примерно четыре года, а потом, по всей видимости, выходит из моды.
Путь наименьшего сопротивления в управлении плагинами — это просто использовать встроенную функциональность Vim 8, которая не требует подтягивания какого-то стороннего кода. Давайте рассмотрим, как это делать.
Для начала создайте две директории внутри вашего runtimepath: opt и start.
mkdir -p ~/.vim/pack/foobar/{opt,start}
Обратите внимание на плейсхолдер «foobar» (имя можно изменить). Он полностью классифицирует все пакеты, которые попадут внутрь. Большинство пользователей просто сбрасывают все свои плагины в какую-нибудь одну категорию и, в общем-то, это нормально. Выберите любое имя, которое вам нравится; Я продолжу использовать foobar. В теории, вы также можете создать несколько категорий, например ~/.vim/pack/navigation
и ~/.vim/pack/linting
. Обратите внимание, что Vim не распознает дублирование между категориями и дважды загружает дубликаты, если они существуют.
Пакеты в «start» загружаются автоматически, тогда как пакеты в «opt» не загружаются до тех пор, пока они не будут из в Vim с помощью команды :packadd
. Эта опция хороша для редко используемых пакетов и поддерживается Vim «из коробки», без необходимости запуска скриптов. Обратите внимание, что у :packadd
нет аналога для выгрузки пакетов.
Для рассмотрения этого примера мы добавим плагин нечеткого поиска ctrlp в opt. Загрузите и распакуйте его последнюю версию по адресу:
curl -L https://github.com/kien/ctrlp.vim/archive/1.79.tar.gz \
| tar zx -C ~/.vim/pack/foobar/opt
Эта команда создаст папку ~ / .vim / pack / foobar / opt / ctrlp.vim-1.79
и выгрузит готовый к использованию пакет. Вернитесь в vim и создайте указатели справочных тегов (helptags index) для нового пакета:
:helptags ~/.vim/pack/foobar/opt/ctrlp.vim-1.79/doc
Эта команда создаст файл с именем «tags» в папке с сорцами пакета, которые делают темы доступными для просмотра во внутренней системе Vim. Альтернативный путь: запустить helptags ALL после загрузки пакета, и команда позаботится обо всех файлах и их путях выполнения.
Когда вы захотите использовать пакет, просто загрузите его и помните, что в этом случае работает завершение с помощью табуляции, так что полное имя вводить не потребуется:
:packadd ctrlp.vim-1.79
Базовый каталог Packadd лежит в runtimepath, что позволяет ему использовать сценарии его плагина и ftdetect. После загрузки ctrlp вы сможете использовать команду CTRL-P, чтобы открыть поиск файлов по частичному совпадению.
Некоторые люди следят за своим каталогом ~ / .vim и для контроля версий каждого пакета используют git. Я же, со своей стороны, просто распаковываю пакеты из tar-архивов и отслеживают их по репозиторию вручную. Если вы используете достаточно зрелые пакеты, которые не требуют частых обновлений, а также скрипты, то они достаточно маленькие и не загромождают историю git.
Бэкапы и откаты версий
В зависимости от пользовательских настроек, Vim может защитить вас от четырех возможных причин потери данных:
- Сбой во время редактирования (между сохранениями). Vim может защитить от этого, периодически сохраняя вносимые изменения в файле подкачки.
- Защита от редактирования одного и того же файла двумя экземплярами Vim, защита от перезаписи изменений, внесенных через один или несколько экземпляров. Это тоже делается через файл подкачки.
- Сбой во время самого процесса сохранения после изменения конечного файла, но до полной записи нового содержимого. Vim может защитить вас от этого с помощью функции «writebackup». Для этого он создает в процессе сохранения новый файл, которым впоследствии заменяет оригинал, если все прошло гладко. Способ замены определяется настройкой «backupcopy».
- Сохранение нового содержимого файла при условии восстановления оригинала. Vim позволяет сохранить резервную копию файла после внесения изменений.
Но прежде чем заняться изучением этих умных настроек, как насчет пары шуток? Вот несколько примеров комментариев из файлов vimrc на GitHub:
«Не создавайте файл подкачки. Управляйте всем через контроль версий».
«Резервные копии для ссыкунов. Используйте контроль версий».
«Только контроль версий! Только хардкор!»
«Мы живем в мире контроля версий, поэтому свопам и резервным копиям место на помойке».
«Зачем вам файлы резервных копий, если достаточно контроля версий».
«Я никогда не пользовался файлами резервных копий Vim… Пользуйтесь контролем версий».
«Большинство вещей можно найти с помощью контроля версий».
«Отключите резервное копирование файлов, ведь вы все равно пользуетесь системой контроля версий ;)».
«И пришел контроль версий, и Git спас нас».
«Отключите файлы подкачки и систему резервного копирования. Всегда используйте контроль версий! ВСЕГДА!»
«Мне не нужно резервное копирование, ведь я работаю с контролем версий».
Ирония в том, что комменты выше отражают лишь понимание четвертого и, частично, третьего типа сбоя. Если вы откажетесь от файла подкачки и резервного копирования, вы лишитесь защиты в случая, описанных в пунктах №1 и №2.
Вот пример конфигурации, которую я рекомендую для обеспечения безопасной работы:
" Protect changes between writes. Default values of
" updatecount (200 keystrokes) and updatetime
" (4 seconds) are fine
set swapfile
set directory^=~/.vim/swap//
" protect against crash-during-write
set writebackup
" but do not persist backup after successful write
set nobackup
" use rename-and-write-new method whenever safe
set backupcopy=auto
" patch required to honor double slash at end
if has("patch-8.1.0251")
" consolidate the writebackups -- not a big
" deal either way, since they usually get deleted
set backupdir^=~/.vim/backup//
end
" persist the undo tree for each file
set undofile
set undodir^=~/.vim/undo//
Эти настройки включают резервное копирование для незавершенной записи, но не сохраняют файлы после успешного окончания операции, потому что у нас же есть контроль версий, самый лучший контроль версий, бла-бла-бла и т.д. и т.п. Обратите внимание на то, что вам может понадобиться mkdir ~ / .vim / {swap, undodir, backup}, иначе Vim будет обращаться к следующей доступной для чтения папке. Также, вероятно, нужно будет выполнить команду chmod для целевых папок, чтобы их содержимое было приватным, поскольку файлы подкачки и история бэкапов могут содержать конфиденциальную информацию.
Стоит отметить, что особенность путей нашего конфига заключаются в том, что закрываются они всегда слэшем. Такое написание позволяет функции устранять возможную неоднозначность в путях файлов подкачки и резервных копий для файлов с одинаковыми именами, которые при этом находятся в разных каталогах. Например, файл подкачки для / foo / bar будет сохранен в ~ / .vim / swap /% foo% bar.swp (слэши я экранировал знаками процента). В недавнем патче Vim была ошибка, из-за которой слэш не учитывался для backupdir, так что защита от нее показана выше.
Также наш Vim сохраняет историю откатов для каждого файла, так что вы можете восстановить нужную версию даже после выхода из режима редактирования. Хотя подобная функция может и показаться избыточной на фоне уже имеющегося у нас файла подкачки, история откатов является дополнительным рубежом защиты во время записи файла.
Когда мы говорим об откатах, то стоит помнить о том, что Vim поддерживает полное древо истории редактирования файлов. Это означает, что вы можете внести изменение, откатить его, а потом повторить те же изменения вновь, и все это будет тремя разными точками восстановления. Время и объем внесенных изменений можно проверить с помощью команды undolist, но именно древо вытащить из нее проблематично. С помощью этой команды вы можете перемещаться между конкретными изменениями или разными версиями в зависимости от времени: прыгать с шагом в 5 минут, или опираться на количество сохраненных файлов. При этом на мой взгляд, навигация по каталогу откатов с помощью плагина — хороший вариант, но undotree — вариант железобетонный.
Включение перечисленных настроек резервного копирования и восстановления файлов может принести вам некоторое душевное спокойствие. Раньше я методично сохранял все файлы вручную после внесения блока изменений или если отходил от компьютера. Потом я переучился: старался оставлять документы несохраненными по несколько часов кряду. В итоге это заставило меня досконально изучить, как работает файл подкачки.
Ну и несколько финальных оговорок: следите за всеми файлами резервного восстановления, они могут накапливаться в папке ,vim и со временем начнут отжирать солидный объем дискового пространства. Также вам может потребоваться использование установки nowritebackup, если вы работаете с огромным по объему файлом, а дисковое пространство у вас ограничено. Об этом моменте стоит помнить, потому что Vim попытается сделать полную копию вашего файла, что приведет к очевидным последствиям. По умолчанию параметр backupskip отключает резервное копирование файла во временном системном каталоге.
Еще «patchmode» Vim напрямую связан с механизмом резервного копирования. Вы можете использовать его в каталогах, в которых нет контроля версий. Например, когда вы хотите загрузить tar-архив, внесите изменения и отправьте патч по списку рассылки, не добавляя его в git. Запустите set patchmod = .orig и любой foo-файл будет скопирован и перезаписан в foo.orig.
Include и path
Большинство языков программирования позволяют включать (include) один модуль или файл в другой. Vim умеет отслеживать идентификаторы через path, include, suffixesadd, и includeexpr. Поиск по индентификатору (см. help include-search) — это альтернатива мониторингу файлов по тегам ctags для системных заголовков.
Из коробки все это работает для программ на Си. Другие языки тоже поддерживаются, но в этом случае требуется ручная настройка. Так как эта тема выходит за пределы обозначенной для этой статьи, то могу порекомендовать курить help include
.
Если все работает правильно, вы можете нажать [i
на идентификаторе, чтобы получить его описание, либо же нажать [d
для получения макропостоянной переменной. Также при использовании gf
на имени файла Vim ищет путь перехода к нему. Поскольку путь влияет и на команду :find, некоторые пользователи имеют привычку добавлять **/*
или другие общедоступные каталоги к имени пути для того, чтобы использовать нечеткий поиск. Последнее замедляет поиск по идентификатору и каталогам, т.к. просматривается и то, что не имеет отношения к нашей задаче.
Есть способ получить тот же эффект нечеткого поиска, не загрязняя при этом сам путь. Суть заключается в нажатии (обычно это пробел с обратным косым слэшем) и вводе имени файла с использованием табуляции или CTRL-D. Это поможет найти файл.
" fuzzy-find lite
nmap <Leader><space> :e ./**/
И опять повторюсь: параметр path был разработан для верхних (headers) файлов. Если вам нужны еще пруфы, есть целая команда: checkpath, которая показывает, работает ли путь. Загрузите любой файл из C и запустите checkpath. Он вернет вам дамп файлов, которые он не смог найти, но которые были включены в текущий файл. Также стоит помнить, что checkpath принудительно сбрасывает всю иерархическую цепочку файлов, зацепленных за текущий.
По умолчанию путь имеет вид «., / Usr / include ,,»
. Он означает, что наша рабочая директория — это /usr/include, а все файлы являются родственными для активного буфера. Спецификации директорий и глобов достаточно мощная штука, посмотрите подробнее в мануале :help file-searching
.
В моем ftplugin для Си (подробнее расскажу позже) также есть поиск пути для файлов, включенных в текущий проект. Пример: ./src/include или ./include.
setlocal path=.,,*/include/**3,./*/include/**3
setlocal path+=/usr/include
Конструкция вида «**3»
— это ограничитель глубины поиска по каталогам. В этом конкретном случае, глубина ограничена тремя подкаталогами. Нужно это, что избежать блокировки поиска по идентификатору.
Ниже вы увидите другие шаблоны, в которые можете добавить свой путь в случае, если :checkpath говорит, что файлы не могут быть найдены. Но, конечно, все зависит от ваших настроек и системы.
Также посмотрите команды: :he [, :he gf, :he :find
.
Конец первой части.