СПРАВОЧНИК ПО VIM - Брам Мооленаар


Множество полезных советов содержится также в "Руководстве пользователя".

Редактирование программ на C
Поиск мест, где используется имя
Переключение экранов в xterm
Прокрутка в режиме Вставки
Мягкая прокрутка
Исправление типичных опечаток
Подсчёт слов, строк и т.д.
Восстановление позиции курсора
Переименование файлов
Ускорение работы внешних программ
Полезные привязки
Сжатие файлов справки
Выполнение команд оболочки в окне
Редактирование шестнадцатеричных файлов
Использование соглашения <> в автокомандах

Редактирование программ на С

В Vim имеется ряд функций для облегчения редактирования программ на С. Вот список меток по теме:

Перемещение в программном коде, глава в руководстве
Редактирование программ, глава в руководстве
Автоматическое форматирование отступов при наборе текста программы на C
Применение форматирования отступов для ряда строк
Форматирование комментариев

|:checkpath|        Показать все рекурсивно включённые файлы
|[i|            Поиск имени, расположенного под курсором в текущем и включённых файлах.
|[_CTRL-I|        Прыжок к соответствию для "[i"
|[I|            Показать все строки в текущем и включённых файлах, где есть соответствие имени под курсором.
|[d|            Поиск определения #define в текущем и включённых файлах.

|CTRL-]|        Прыжок к метке под курсором (например, к определению функции).
|CTRL-T|        Прыжок к позиции до команды CTRL-].
|:tselect|        Выбрать метку из списка соответствующих меток.

|gd|            Переход к декларации локальной переменой под курсором.
|gD|            Переход к декларации глобальной переменной под курсором.

|gf|            Переход к имени файла под курсором.

|%|            Переход к парному соответствию (), {}, [], /* */, #if, #else, #endif.
|[/|            Переход к предыдущему началу комментария.
|]/|            Переход к следующему концу комментария.
|[#|            Переход назад к незакрытому #if, #ifdef или #else.
|]#|            Переход вперёд к незакрытому #else или #endif.
|[(|            Переход назад к незакрытой '('
|])|            Переход вперёд к незакрытой ')'
|[{|            Переход назад к незакрытой '{'
|]}|            Переход вперёд к незакрытой '}'

|v_ab|            Выбор "блока" от "[(" до "])", включая скобки
|v_ib|            Выбор "внутреннего блока" от "[(" до "])"
|v_aB|            Выбор "блока" от "[{" до "]}", включая скобки
|v_iB|            Выбор "внутреннего блока" от "[{" до "]}"

Поиск мест, где используется имя

Вы, возможно, уже знаете, что |метки| позволяют прыгать в точку, где определена функция или переменная. Но иногда возникает необходимость перемещения по всем местам, где используется та или иная функция или переменная. Этого можно добиться двумя способами:

  1. Использовать команду |:grep|. Этот способ должен работать на большинстве Unix-систем, но он может оказаться слишком медленным (grep читает каждый файл) и поиск происходит только в одном каталоге.
  2. Можно пользоваться программами из пакета ID utils. Этот способ сочетает скорость и возможность работы с некоторыми каталогами. Для хранения позиций в файлах используется база данных. Для работы вам потребуются дополнительные программы, и нужно поддерживать базу данных в актуальном состоянии.

Использование GNU id-tools:

Что вам потребуется:

  • Установленный в системе пакет GNU id-tools (потребуются программы mkid для создания базы данных ID и lid для использования макросов).
  • База данных имён "ID" в текущем каталоге. Её можно создать с помощью команды оболочки "mkid file1 file2 ...".

Поместите в вашем файле .vimrc:

map _u :call ID_search()<Bar>execute "/\\<" . g:word . "\\>"<CR>
map _n :n<Bar>execute "/\\<" . g:word . "\\>"<CR>

function! ID_search()
  let g:word = expand("<cword>")
  let x = system("lid --key=none ". g:word)
  let x = substitute(x, "\n", " ", "g")
  execute "next " . x
endfun

Теперь можно подвести курсор к имени, нажать "_u" и Vim загрузит файл, в котором содержится указанное имя. Поиск следующего появления этого имени в том же файле производится по команде "n", переход к следующему файлу - по команде "_n"/

Этот метод проверялся на id-utils-3.2 (имя архива с пакетом id-tools на ftp-зеркалах GNU).

Идея принадлежит Андреасу Кучере.

Переключение экранов в xterm

(Из comp.editors, Юрген Вигерт в ответ на вопрос)

:> Ещё один вопрос. после выхода из Vim экран остаётся как есть, т.е. на
:> экране остаётся содержание файла, который я редактировал. Вывод предыдущих
:> команд, например "ls", теряется, т.е. его больше нельзя просмотреть даже с
:> прокруткой. Я слышал, что существует способ восстанавливать содержимое
:> экрана после выхода из Vim или других редакторов типа Vi. Я просто не знаю,
:> как это сделать. Помощь приветствуется. Спасибо заранее.
:
:Думаю, на этот вопрос кто-то может ответить. Хотя я только предполагаю, что
:Vim и Vi делают одно и то же в данной ситуации для xterm.

Совсем необязательно, что они делают одно и то же, поскольку это может быть проблема termcap vs. terminfo. Вы должны знать, что существует две базы данных для описания особенностей того или иного терминала: termcap и terminfo. Это может приводить к различиям, в тех случаях, когда описания различаются И одна из программ использует terminfo, а другая termcap (см. также |+terminfo|).

В вашем конкретном случае речь идёт об управляющих последовательностях ^[[?47h и ^[[?47l. Они позволяют переключаться между основным экранным буфером и другим xterm. В качестве быстрого решения могу предложить последовательность команд вроде:

echo -n "^[[?47h"; vim ... ; echo -n "^[[?47l"

возможно, это сработает. (Здесь ^[ означает символ ESC, дальше вы увидите, что в базе данных вместо этого используется \E).

При запуске, Vim выводит на терминал значение переменной termcap ti (в terminfo: smcup). При выходе, Vim выводит te (terminfo: rmcup). Указанные управляющие последовательности работают с этими переменными.

Сравните вашу запись для xterm (в /etc/termcap) с записью xterm в terminfo (например, /usr/5bin/infocmp -C xterm). Обе записи должны содержать элементы вроде:

:te=\E[2J\E[?47l\E8:ti=\E7\E[?47h:

PS: Если вы найдёте отличия, то кому-то (сисадмину?) следует проверить базы termcap и terminfo на предмет расхождений.

ЗАМЕЧАНИЕ 1: Если вы скомпилируете Vim с особенностью FEAT_XTERM_SAVE (включается в файле feature.h, то во встроенном xterm будут записи "te" и "ti".

ЗАМЕЧАНИЕ 2: Если вы хотите отключить переключение экранов и не хотите изменять termcap, то можете добавить в файл .vimrc строку:

:set t_ti= t_te=

Прокрутка в режиме Вставки

Если вы находитесь в режиме вставки и хотите немного прокрутить экран, то можно использовать команды CTRL-X CTRL-E и CTRL-X CTRL-Y. |i_CTRL-X_CTRL-E|

Чтобы сделать прокрутку более простой, можно настроить такие привязки:

:inoremap <C-E> <C-X><C-E>
:inoremap <C-Y> <C-X><C-Y>

Это нужно набирать буквально как есть, убедитесь, что флаг '<' не присутствует в значении опции 'cpoptions').
При этом вы потеряете возможность копировать текст из предыдущей/последующей строки |i_CTRL-E|.

Также подумайте о настройке опции 'scrolloff': её установка в большее значение позволит видеть больше контекстных строк возле курсора. Если значение опции 'scrolloff' больше половины экрана, то курсор всегда будет находиться в середине экрана, а текст будет прокручиваться при перемещении вверх или вниз.

Мягкая прокрутка

Если вы хотите добиться более мягкой прокрутки, то можете использовать такие привязки:

:map <C-U> <C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y>
:map <C-D> <C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E>

(Это нужно набирать буквально, убедитесь в отсутствии флага '<' среди значений опции 'cpoptions').

Исправление типичных опечаток

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

Например:

:ab teh the
:ab fro for

Подсчёт слов, строк и т.д.

Чтобы подсчитать как часто встречается в буфере соответствие тому или иному шаблону, установите значение опции 'report' равным 0 и используйте команду подстановки для замены шаблона на сам шаблон. Количество замен, указанное в отчете будет равно количеству указанных в шаблоне элементов. Примеры:

:set report=0
:%s/./&/g         символы
:%s/\i\+/&/g      слова
:%s/^             строки
:%s/the/&/g       "the" в любом месте текста
:%s/\<the\>/&/g   "the" как отдельное слово

Вы можете отключить опцию 'hlsearch' или выполнить команду ":nohlsearch".

Это не будет работать, если отключена опция 'modifiable'. В этом случае можно пользоваться в Визуальном режиме командой |v_g_CTRL-G|.

Чтобы посчитать байты, можно использовать следующий метод:

  • Визуально выделите необходимые символы (в том числе возможно использование блокового выделения)
  • Скопируйте символы по команде "y"
  • Используйте функцию strlen():
    :echo strlen(@")

Обратите внимание, что перенос строки считается за один байт.

Восстановление позиции курсора

Иногда требуется задать привязку, по которой производится какое-либо изменение где-то в тексте и затем курсор возвращается в исходную позицию, без прокрутки текста. Например, для изменения отметки даты в файле:

:map <F2> msHmtgg/Последнее [иИ]зменение:\s*/e+1<CR>"_D"=strftime("%Y %b %d")<CR>p'tzt`s

Разбор сохранения позиции:

ms сохранить позицию курсора в отметке 's'
H перейти к первой строке окна
mt сохранить позицию в отметке 't'

Разбор восстановления позиции:

't перейти к строке, находившейся в верхней части экрана
zt переместить эту строку в верх
`s переместиться к исходному положению курсора

Переименование файлов

Допустим, у нас есть каталог, в котором содержатся следующие файлы:

buffer.c
charset.c
digraph.c
...

и нам надо переименовать *.c в *.bla. Я делаю это так:

$ vim
:r! ls *.c
:%s/\(.*\).c/mv & \1.bla
:w !sh
:q!

Ускорение работы внешних программ

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

Если ваш файл .cshrc (или его аналог, в зависимости от используемой оболочки) слишком длинный, то имеет смысл разделить его на две части: одну для интерактивного использования, и другую для неинтерактивного использования, т.е. для вторичных оболочек. Когда вы выполняете команду оболочки из Vim, то интерактивные особенности (например, настройка приглашения оболочки) вам не нужны. Такие интерактивные особенности лучше всего поместить в файле .cshrc после строк:

if ($?prompt == 0) then
    exit 0
endif

Другой способ заключается в установке аргумента "-f" в опции 'shell', т.е.:

:set shell=csh\ -f

(обратная косая черта требуется для использования пробела в значении опции). Это позволит csh вообще не пользоваться файлом .cshrc. Этот метод, однако, не во всех случаях будет работать.

Полезные привязки

Вот несколько привязок, которые нравятся многим людям.

:map ' `

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

Для редактирования командной строки в стиле Emacs:

" начало строки
:cnoremap <C-A>        <Home>
" назад на один символ
:cnoremap <C-B>        <Left>
" удаление символа под курсором
:cnoremap <C-D>        <Del>
" конец строки
:cnoremap <C-E>        <End>
" вперёд на один символ
:cnoremap <C-F>        <Right>
" перейти к следующей команде в истории
:cnoremap <C-N>        <Down>
" перейти к предыдущей команде в истории
:cnoremap <C-P>        <Up>
" назад на одно слово
:cnoremap <Esc><C-B>    <S-Left>
" вперёд на одно слово
:cnoremap <Esc><C-F>    <S-Right>

ЗАМЕЧАНИЕ: Это требует, чтобы флаг '<' не присутствовал среди значений опцииv'cpoptions'. |<>|

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

:let m =     ":map _f  :set ai<CR>"   " включаем опцию 'autoindent'
:let m = m . "{O<Esc>"              " добавляем пустую строку над элементом
:let m = m . "}{)^W"              " перемещаем курсор к тексту указателя нового пункта в списке
:let m = m . "i     <CR>     <Esc>"   " добавляем пробел для отступа
:let m = m . "gq}"              " форматируем текст после указателя нового пункта в списке
:let m = m . "{dd"              " удаляем пустую строку
:let m = m . "5lDJ"              " вклеиваем текст после указателя нового пункта в списке
:execute m                  | " определяем привязку

(Используется соглашение о <> |<>|. Обратите внимание, что все команды набираются буквально. ^W это "^" "W", а не CTRL-W. Если флаг '<' отсутствует в значении опции 'cpoptions', то можете спокойно копировать этот текст и вклеивать его в командную строку.

Обратите внимание, что последний комментарий начинается с |", потому что команда ":execute" не допускает явных комментариев.

Вам также потребуется установить значение опции 'textwidth' в ненулевую величину, например:

:set tw=70

Привязка, которая выполняет то же самое, но берёт отступ для списка из первой строки:

:map _f :set ai<CR>}{a                                                          <Esc>WWmmkD`mi<CR><Esc>kkddpJgq}'mJO<Esc>j

(Замечание: Это одна длинная команда с большим количеством пробелов в середине).

Эти две привязки позволяют уменьшить количество пробельных (;b) или пустых (;n) строк до одной строки

:map ;b   GoZ<Esc>:g/^$/.,/./-j<CR>Gdd
:map ;n   GoZ<Esc>:g/^[ <Tab>]*$/.,/[^ <Tab>]/-j<CR>Gdd

Сжатие файлов справки

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

  1. Запакуйте все файлы справочника: "gzip doc/*.txt".
  2. Отредактируйте файл "doc/tags" и замените ".txt" на ".txt.gz":

    :%s=\(\t.*\.txt\)\t=\1.gz\t=
  3. Добавьте в ваш vimrc такую строку:

        set helpfile={каталог}/help.txt.gz

Где {каталог} это имя каталога, где находятся файлы справки. Модуль |gzip| сам позаботится о распаковке необходимых файлов. Вы должны убедиться, что $VIMRUNTIME установлена правильно, т.е. указывает на местоположение файлов, требуемых при работе Vim, если они находятся в другом, отличном от каталога с запакованными файлами справки месте. См. |$VIMRUNTIME|.

Выполнение команд оболочки в окне

Было несколько вопросов о возможности выполнения команд оболочки в окне Vim. Ответ: это невозможно! Включение такой возможности добавило бы слишком много кода в Vim, что является серьёзным аргументом против такой возможности. Vim это редактор, не стоит требовать от него выполнения иных задач. В то же время, вы можете попробовать разделить экран терминала на две части с помощью программы "splitvt", которую можно найти на ftp-серверах. Об этой программе больше знает Сэм Лантинга (Sam Lantinga, <Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.;). Другой подобной программой является "window", которая включена во многих BSD Unix системах. Эта программа поддерживает также множество перекрывающихся окон. Или посмотрите программу "screen", которая также поддерживает несколько окон (www.uni-erlangen.de).

Редактирование шестнадцатеричных файлов

См. раздел 23.4 руководства.

Если вы используете для двоичных файлов какое-либо особое расширение (например, exe, bin и т.д.), то процесс можно автоматизировать при помощи следующей последовательности автокоманд для файла <.vimrc>. Измените "*.bin" на список расширений, указанных через запятую, и вы сможете автоматически переходить в режим редактирования шестнадцатеричного кода:

" vim -b : редактирование бинарного файла с xxd!
augroup Binary
au!
  au BufReadPre  *.bin let &bin=1
  au BufReadPost *.bin if &bin | %!xxd
  au BufReadPost *.bin set ft=xxd | endif
  au BufWritePre *.bin if &bin | %!xxd -r
  au BufWritePre *.bin endif
  au BufWritePost *.bin if &bin | %!xxd
  au BufWritePost *.bin set nomod | endif
augroup END

Использование соглашения <> в автокомандах

Соглашение <> не работает в аргументах команды :autocmd. Чтобы избежать необходимости использования спецсимволов, можно воспользоваться самоликвидирующейся привязкой для передачи символов в формате соглашения <> и затем вызывать эту привязку из автокоманды. Пример:

" Автоматически добавляет имя файла в меню. Здесь применяется
" самоликвидирующаяся привязка!
" 1. используем строку в буфере для замены 'точек' в имени файла на \.
" 2. Сохраняем в регистре '"'
" 3. Добавляем имя в список в меню Буферы
" ВНИМАНИЕ! Побочные эффекты: переписывается содержимое текущего регистра,
" удаляется привязка для команды "i"
"
autocmd BufNewFile,BufReadPre * nmap i :nunmap i<CR>O<C-R>%<Esc>:.g/\./s/\./\\./g<CR>0"9y$u:menu Buffers.<C-R>9 :buffer <C-R>%<C-V><CR><CR>
autocmd BufNewFile,BufReadPre * normal i

Другой метод, возможно более лучший -- использование команды ":execute". В строке аргумента можно использовать соглашение <>, с предшествующим символом обратной косой черты. Не забудьте удваивать каждую обратную косую и экранировать с помощью обратной косой черты символ '"'.

autocmd BufNewFile,BufReadPre * exe "normal O\<C-R>%\<Esc>:.g/\\./s/\\./\\\\./g\<CR>0\"9y$u:menu Buffers.\<C-R>9 :buffer \<C-R>%\<C-V>\<CR>\<CR>"

Для настоящего меню Буферов следует применять функции пользователя (см. |:function|), но в этом случае соглашение <> не задействуется. Мы использовали эту задачу только в качестве примера использование <> в автокомандах.