Советы пользователям

Documentation
Login

Title: Vim editor

Author:: Vitus Wagner

Введение

Когда-то давно меня спросили, чем мне не нравится текстовый редактор notepad. На что я ответил, что в нём нужно каждую буковку руками набирать.

Дело в том, что я к тому моменту уже много лет пользовался редактором vim. Поэтому идея, что программа большую часть буковок в редактируемом текстовом файле способна сделать за тебя, была для меня вполне естественной.

vim это редактор для программистов. То есть для людей, которые любую более-менее повторяющуюся работу с компьютером норовят на тот самый компьютер и переложить.

Ещё одним крайне ценным для меня свойством vim является то, что он не забыл своего происхождения из тех времён, когда компьютеры были большими, а каналы связи медленными.

Swap-файл

Vim это единственный редактор из доживших до наших дней, который рассчитан на то, что питание компьютера может пропасть или процесс редактора в может быть убит сигналом то ли от OOMKiller-а то ли при разрыве соединения с удалённым компьютером. Поэтому при работе vim постоянно записывает действия пользователя в так называемый swap-файл (обычно имя своп-файла создаётся из имени редактируемого файла путём добавления расширения .swp и точки в начале).

Если вдруг процесс редактирования был насильственно прерван, то своп-файл остаётся в файловой системе и при последующей попытке редактирования того же файла (равно как и при попытке запуска редактирования того же файла из другого сеанса) будет выдано предупреждающее сообщение, предлагающее либо открыть файл только для чтения, либо восстановить.

Если вы уверены, что это не запущенный в другом окне процесс редактирования, а последствия падения, то надо запустить процесс восстановления. И скорее всего все изменения сделанные перед падением будут на месте.

Три режима или семь?

Как правило, все начинающие пользователи vim быстро усваивают, что в нём есть три режима: нормальный, вставки и командной строки.

В режиме вставки набираемые на клавиатуре символы вставляются в текст. В нормальном - они являются командами редактирования. В режиме командной строки мы набираем команды, которые производят действие с большими кусками текста в целом.

Для перехода из нормального режима в командную строку надо нажать двоеточие. Тогда в нижней строке экрана образуется командная строка, где можно набрать какую-нибудь команду, например сделать глобальную замену по всему файлу или запустить внешнюю команду, передав ей в качестве параметра слово под курсором. Запись файла или выход из редактора — тоже операции режима командной строки. После нажатия Enter и выполнения команды vim автоматически возвращается в нормальный режим.

Попасть из нормального режима в режим вставки можно разными способами:

  1. клавиша i (insert) — символы нчинают вставляться перед текущим положением курсора.
  2. Клавиша a (append) — символы начинают вставляться после того места, где перед нажатием этой клавиши был курсор
  3. A — символы добавляются в конец текущей строки.
  4. I — символы добавляются в начале (перед первым не пробелом) текущей строки.
  5. o (open new line) — после текущей строки добавляется пустая строка и символы вводятся туда
  6. O - то же, но перед текущей строкой.
  7. c<команда перемещения> (сhange <region>) удаляет кусок текст, заданный командой перемещения и позволяет ввести вместо него что-то другое. Например cl - заменить символ на вводимый текст, cw — слово, ct" — заменить все до ближайшей кавычки.
  8. s (subsitute) — то же, что cl.:

Для выхода из режима вставки используется клавиша Esc, независимо от того, как мы туда вошли.

Но если внимательно присмотреться, этими режимами набор не исчерпывается.

Во-первых, есть режим замены. Который похож на режим вставки, но вводимые символы в нём не раздвигают уже существующие, а заменяют их.

Во-вторых, есть режим визуального выделения блока. У которого есть три варианта:

  1. Потоковый (v) когда блок начинается в произвольном месте строки и кончается в произвольном месте одной из следующих строк.
  2. Построчны (V) когда блок состоит из целых строк
  3. Прямоугольный (Ctrl-V), по нынешним временам редкость. Все привыкли рассматривать текст как линейную последовательность символов, некоторые из которых являются символами перевода строки. А vim умеет ещё и рассматривать текст как двумерную матрицу символов. В таком режиме удобно редактировать, например, таблицы.

В-третьих, нажав в нормальном режиме '/' или '?' мы попадём в режим редактирования поисковой строки. Который похож на режим командной строки, но всё же от него несколько отличается.

И, наконец, есть терминальные буфера, то есть буфера в которых выполняется какая-то внешняя программа. В этих буферах большая часть набираемых символов переправляется этой программе.

Нормальный режим - это нормально

Если вы хотите научиться пользоваться vim-ом эффективно, не поддавайтесь искушению запускать его в режиме вставки по умолчанию. Существует уйма способов это сделать:

Но вы так не делайте. Большую часть времени при работе над текстом все равно занимает не набор его, а редактирование. А перемещение по тексту, удаление, поиск и форматирование удобнее делать из нормального режима.

Нормальный режим vim отличается тем что все буквенные клавиши (кроме тех кто переключает в другие режимы) выполняют какие-нибудь команды, а не попадают в текст в виде букв. То есть если более других редакторов для перемещения вам доступны только клавиши цифровой клавиатуры (или дублирующие их клавиши, остающиеся клавишами перемещения даже при включённом NumLock) либо комбинации с клавишами-модификаторами Control и Command, то в vim-е к вашим услугам вся клавиатура.

Более того заметная часть операций изменения текста может сопровождаться операцией перемещения. Если вам надо удалить фрагмент, вы нажимаете d и команду перемещения — на один символ, на слово, в конец абзаца, да хоть до конца текста, и удалится именно этот фрагмент. Аналогично дело обстоит с копированием текста в регистр.

Хочу обратить ваше внимание на команды перемещения с поиском. В vim-е есть две команды перемещения с поиском одного символа - f и t (А если надо назад по тексту — соответствующие большие буквы). Отличаются они тем что f<символ> помещает курсор на указанный символ, а t<символ> - перед ним. Соответственно, если у вас в тексте есть строка в кавычках, и вы хотите её заменить то последовательность действий такая: f" (нашли открывающую кавычку) l (сместились на следующий символ) ct" изменить (удалить и перейти в режим вставки) все до следующей кавычки, но не включая её.

Кроме команд перемещения дяя указания блока текста, который нужно изменить, можно использовать команды «a» (мнемоника неопределённый артикль) daw - «delete a word», удалить текущее слово, das - «delete a sentence». Будучи употреблёнными нормальном режиме вне контекста оператора изменения текста команды a и i переключают в режим вставки, а в режиме выделения или после оператора указывают объект. Обратите внимание, что сокращения для указания в качестве объекта предложения или параграфа не соответствуют сокращениям для указания этих объектов в командах перемещения.

Впрочем разница между «удалить это предложение (на котором стоит курсор)» и «удалить от курсора до конца предложения» (что получится при указании перемещения в конец предложения) это очень разные действия.

Почти все команды нормального режима могут сопровождаться числовым модификатором. Например h перемещает на один символ вправо, а 10h — на 10 символов.

langmap

Большим неудобством при работе в нормальном режиме является то, что у русскоязычных пользователей есть две переключаемых раскладки клавиатуры. И если мы вышли из режима вставки, не переключившись обратно на латинскую раскладку, то внезапно обнаружим, что vim нас понимать перестал.

Чтобы такого не случилось, надо задать в своём .vimrc переменную langmap. Значение которой представляет собой последовательность пар символов, расположенных на одной клавише. Тогда по крайней мере те, команды, которые соответствуют латинским буквам, будут работать независимо от раскладки. Хуже с теми символами (знаками препинания, например), которые есть и в русской и латинской раскладке, но на разных клавишах. Тут langmap не спасёт. Он работает по принципу «если пользователь прислал неизвестную букву, посмотрим нет ли ей соответствия». А если вместо вопросительного знака прилетела запятая, то тут уж он ничего сделать не может.

Кто такой

Читая хелп по разнообразным плагинам vim вы достаточно часто будете встречать обозначения клавиш в виде строки в угловых скобках. Как правило, слова в угловых скобках говорят сами за себя. Если написано что данная команда повешена на или на , вы знаете что надо нажимать на клавиатуре, чтобы её выполнить. А вот что такое или ? Оказывается в vim есть парочка внутренних переменных, куда можно записать код клавиши, которая будет использоваться в этом качестве. Если вы туда ничего не написали, то vim в качестве будет воспринимать обратный слэш.

Пойди туда, знаю куда

То, что в нормальном режиме у нас вводимые буквы не попадают в текст, а используются как команды, открывает очень большие возможности для создания легкозапоминаемых команд. Почти все команды нормального режима vim мнемоничны. То есть представляют собой сочетания первых букв английской фразы, описывающей требуемое действие. Например разобранные в предыдущей главе команды f и t запоминаются как find и till, а команда ct" как change till quote.

Исключение представляют собой команды перемещения на один символ. У них другая мнемоника. Клавиши h j k l расположены под пальцами правой руки при слепом методе печати. И они запоминаются по относительному расположению - крайние h и l это влево и вправо соответственно. Средние j и k - это вниз и вверх. Можно использовать для облегчения запоминания правило, что текст мы обычно читаем справа налево и сверху вниз, поэтому первой (левой) из клавиш вертикального перемещения идёт клавиша «вниз», вперёд по тексту.

Иногда можно столкнуться с такой ситуацией, что вдруг при нажатии стрелки вниз или буквы j курсор вдруг проскакивает полэкрана вместо одной строки. Что это значит? Это значит что эти полэкрана занимает одна строка. Просто она очень длинная, а vim по умолчанию работает в режиме wrap и если строка не умещается в ширину экрана, переносит её остаток на следующую экранную строку, потом на следующую и так далее. Можно, конечно это выключить, сказав в командной строке set nowrap, но это обычно неудобно.

Для перемещения по экранным строкам вместо содержащихся в файле, нужно перед клавишей j или k нажать g. То есть последовательности gj и gk позволят двигаться по строкам как мы их видим, а не как они лежат в файле.

Как правило, такое бывает если мы начинаем редактировать в vim текст, созданный в какой-то другой программе, особенно если это текст, предназначенный для чтения машиной, а не человеком, например xml или json.

Потому что в vim есть опция textwidth (tw) и обычно она установлена во что-то меньше ширины экрана. И если мы в режиме вставки печатаем не оглядываясь на ширину набранного текста, vim автоматически вставит перевод строки.

Перемещения по структурным элементам текста

Текст с точки зрения vim состоит из слов, строк, предложений, абзацев и секций. Это, конечно касается в первую очередь текстов на естественном языке.

Впрочем перемещение по секциям вряд ли удастся использовать — ни TeX-овские, ни маркдауновские заголовки в качестве разделителей секций vim по умолчанию не воспринимает. Этот режим ориентирован на старинный язык форматирования nroff, который до сих пор используется для хранения man-страниц (но обычно в XXI веке не пишется руками, а генерируется из того же markdown).

А перемещения по словам и предложениям — вещь полезная. Полезно и перемщение по абзацам (параграфам), поскольку здесь как раз и vim и TeX и стандарт markdown соглашаются в том, что разделитель абзацев это пустая строка.

Соответственно w это у нас перемещение вперёд на слово (на начало следующего слова) e на конец слова (end of word) b — на слово назад (на начало текущего слова если без указания количества повторений).

В vim бывают слова и СЛОВА. Перемещение по первым осуществляется с помощью маленьких букв, по вторым — большими.

Разница в том, что запятая (или любой другой знак препинания кроме подчёркивания, которое всегда считается буквой) написанный слитно с последовательностью букв, не считается частью слова (а скорее всего будет воспринят как отдельное слово), но считается частью СЛОВА.

По предложениям мы перемещается с помощью круглых скобок. Открывающая — в начало предложения, закрывающая — в конец.

Перемещению по абзацам отведены фигурные скобки.

А секциям — квадратные. Надо отметить что они употребляются парами, и [[ имеет несколько другой смысл чем [].

Перемещения по блокам языков программирования

Тэги и навигация по вызовам функций

Marks, jumplist и changelist

Что можно делать в режиме вставки

Вставка странных символов

Иногда возникает необходимость вставить в текст символ, которого нет в вашей клавиатурной раскладке.

Для этого в vim есть два механизма

  1. Вставка символа по коду (ascii или unicode)

  2. Использование диграфов (digraphs)

Для вставки символа по коду нужно нажать т.е клавишу control одновремено с v. После этого либо набрать от одной до трёх десятичных цифр (код ascii), либо u и четыре шестнадцатиричных (код юникода).

Понятно что регулярно пользоваться этим способом не будешь. Никто не держит в памяти всю таблицу юникода даже для одного алфавита. Но для незнакомого алфавита это может быть спасением (хотя я обычно в таких случаях просто копирую из википедии).

Если буквами не своего алфавита приходится пользоваться чаще, но не настолько часто чтобы прописать их в системный механизм compose, а тем более добавить ещё одну раскладку клавиатуры, то есть механизм digraphs.

Здесь мы вводим два символа. Какие именно символы, можно посмотреть в :help digraphs-default, там их на все случаи жизни. Я, например таким способом ввожу греческие буквы, когда они попадаются в названиях звёзд, например, α Центавра.

Но если вдруг там нужного символа не нашлось, можно определить его в своём .vimrc (или (.lvimrc проекта) с помощю команды :digraph.

Автодополнение

Ну вот мы и добрались до того, с чего я начал введение в данный текст. Как сделать так, чтобы редактор сам писал за вас слова.

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

Самый простой способ это /. Если в режиме вставки набрать несколько букв слова, а потом нажать одну из этих комбинаций клавиш, то vim предложит меню из слов, начинающихся с этого префикса, встретившихся в редактируемом файле либо до, либо после текущей позиции.

Более продвинутое автодополнение включается с помощью Ctrl-X. Например Ctrl-X s предложит вам замену текущего слова из словаря спеллчекера, а Ctrl-X Ctrl-F - имена файлов, имеющихся на диске.

Перечислять все прочие возможности не буду, стоит почитать help.

Регистры

Большая часть программ в современных графических средах умеет пользоваться системным буфером обмена, куда можно вырезать кусок текста, а потом вставить его в другое место (или даже совсем другой файл). Vim, собранный с графическим интерфейсом тоже так умеет. Но кроме системного буфера у него есть ещё четыре десятка своих, называемых регистрами.

Любая операция удаления в нормальном режиме помещает удалённый текст в один из регистров. При этом, если регистр не был указан, то
операция yank помещает текст в регистр 0, а операция delete - в регистр 1. При вставке автоматически используется тот из этих регистров, который менялся последним. Так что если вы забрали в буфер ценный текст, а потом что-то удалили, чтобы освободить место для вставки этого, то текст в буфере не пропал. Вам всего лишь надо перед командой p указать из какого именно регистра вы хотите вставить. "0p. Остальные цифровые регистры от 2 до 9 представляют собой стэк куда выталкиваются данные из регистра 1 при последующих удалениях.

Так что вам обычно доступны для вставки обратно результаты девяти предыдущих удалений.

В 26 регистров, обозначаемых латинскими буквами, текст попадает только если вы это явно попросите. При этом unnamed register начинает указывать на этот буквенный регистр.

Регистр . содержит текст, введенный в ходе последней сессии режима вставки. См команду . в следующей главе. Регистр : - последняя выполненная командная строка.

Регистры % и # содержат имена текущего и альтернативного редактируемого файла.

Регистр * соответствует буферу обмена GUI-системы, а + - primary selection в X window.

Ещё у vim есть возможность включить запись все выполняемых действий (нажимаемых клавиш) в регистр с помощью команды q<имя-регистра>. Остановить запись можно просто q. И, соответственно выполнить регистр с помощью @<имя регистра>.

Вставить содержимое регистра в командную строку можно посредством Ctrl-R<имя регистра>

Когда программа пишет текст за вас

Autoindent

Completion

Аббревиатуры

Команда .

Поиск с заменой

Вставка в текст вывода внешней команды

Подстановки в командную строку

filename-modifiers

help filename-modifiers

Пишем грамотно

Встроенный spellcheck

LanguageTool

Асинхронный linting кода

Как не видеть лишнего

Режим quickfix

Фолдинг

vimdiff

Vim и управление версиями

fugitive

Шифрование

Редактор как оконная среда

Окна, вкладки и буфера

Терминальные буфера

Отладка в vim

С появлением в vim терминальных буферов появилась возможность использовать vim как интегрированную среду для отладки. В одном окне открываем исходный текст, в другом — командную строку отладчика, в третьем — отлаживаемую программу (если она имеет консольный интерфейс).

Эта функциональность входит в состав vim, но не включена по умолчанию. Чтобы она появилась, нужно сказать в командной строке vim

:packadd termdebug

Пожалуй, включать эту команду в .vimrc не стоит. Разве что в .lvimrc в директории проекта над которым вы работаете.

После загрузки пакета появляются команды Termdebug и TermdebugCommand. В качестве аргументов первой передаются имя отлаживаемого исполняемого файла и, если требуется, имя файла core или pid процесса, который надо отлаживать, если мы не запускаем программу из отладчика, а цепляемся отладчиком к уже запущеному процессу.

Вторая команда позволяет указать командную строку отлаживаемой программы (очевидно что это имеет смысл только если мы программу из отладчика запускаем, а не анализируем core dump или отлаживаем существующий процесс).

Когда фокус находится в окне gdb или отлаживаемой программы, то эти окна ведут себя как обычные терминальные буфера. Только по мере выполнения команд отладчика меняется текущая строка в соседнем окне с исходным текстом.

Если же текущим окном является окно исходного текста то появляется несколько команд командной строки vim, с помощью которых можно управлять процессом отладки.

Например команда :Break устанавливает точку останова в текущей строке кода. Или :Evaluate вычисляет выражение в текущей позиции курсора.

Удобно ли пользоваться командами :Step, :Over, :Finish, :Continue вместо того, чтобы переключаться в окно gdb и там использвать их однобуквенные эквиваленты — дело вкуса. Но можно их развесить по клавишам с помощью map, и тогда кнопок нажимать надо будет явно меньше. Можно повесить на клавиши и команды gdb, для которых нет предопределённых команд в пакете termdebug, используя функцию TermDebugSendCommand. (cм :help termdebug_shortcuts)

А команды :Up и :Down позволяющие перемещаться по стеку вызовов, уже по умолчанию замэплены на клавиши плюс и минус соответственно.

Ещё можно открыть окно дизассемблированного текста командой :Asm или окно с содержимым текущих переменных командой :Var.

Полезные плагины

matchit

localvimrc

voom

xmledit

dbext

tabular

calendar