Особенности синтаксиса Vim script относительно обычных скриптовых языков вроде Perl, Python или Bash.
Запуск команд и вывод результатов
В следующих трёх примерах команды начинаются на «:» и
заканчиваются «<Enter>» чтобы показать, что нужно нажимать.
Следующие примеры будут записаны так, как пишется код в ~/.vimrc
и *.vim файлах, без «:» и «<Enter>». |
echo выводит свои параметры через пробел:
:let i = 5<Enter>
:echo 'a b' i &textwidth getcwd()<Enter>
Группу команд можно записать в одну строку через "|" (но это работает не для всех команд, и для части тех где работает нельзя перед "|" ставить лишние пробелы, как сделано для наглядности в этом примере):
:let i=10 | echo 'i='.i<Enter>
Выполнить многострочный vim script скопированный в буфер (строчки не должны начинаться на ":", и иногда глючит если строки начинаются с пробелов - можно обойти если выделять/копировать вертикальный блок без начальных пробелов):
:@"<Enter>
Каждая строчка vim script должна начинаться на команду vim. Имена переменных и функций командами не являются!
" НЕ ПРАВИЛЬНО
i++
func(i)
" ПРАВИЛЬНО
let i += 1
call func(i)
Переменные
let выводит текущие определённые переменные.
let переменная = значение создаёт переменные и изменяет их значения.
unlet переменная удаляет переменные (unlet! переменная не ругается на несуществующие), можно указывать несколько переменных сразу.
var глобальная, внутри функции локальная
g:var глобальная (идентично var вне функций)
l:var локально для текущей функции (идентично var внутри функции)
a:var аргумент текущей функции
s:var локально для текущего скрипта
b:var локально для текущего буфера
w:var локально для текущего окна
t:var локально для текущего таба
v:var переменные самого Vim
$VAR переменная окружения
&opt опция vim
@r регистр vim
Number 10, 0.1
String 'str', "str"
List [], [1,'str']
Dictionary {}, {'key1': 1, "key2": 'str'}
Funcref function('FuncName')
if exists('s:var')
echo s:var
endif
Истина/ложь
Истина - всё кроме 0.
При логической проверке строки конвертируются в числа, так что строка 'true' вычисляется как 0, т.е. ложь.
Строки
В одинарных кавычках все символы означают сами себя, кроме '' - это одинарная кавычка. Это особенно удобно для записи регулярных выражений.
В двойных кавычках экранирование слешем, работают стандартные \", \\, \n, \x20, etc. плюс кнопки вроде \<Esc> или \<C-W>.
Строки конкатенируются оператором . (точка).
Строки со строками сравниваются по байтам.
При сравнении строки с числом она конвертируется в число.
if 0 == 'one'
echo 'Сюрприз!'
endif
При сравнении строк и применении регулярного выражения будет ли учтён регистр определяется опцией &ignorecase. Для форсирования регистра можно к операции сравнения добавить # для проверки регистра или ? для игнорирования регистра.
echo str =~# 'regex'
echo str ==? 'string'
Списки, хеши и объекты
Списки объявляются как ["val1","val2"].
Работа с элементом: list[0].
Списки конкатенируются оператором + (плюс) или функцией extend().
let alist = ["one","two",3]
for i in alist
echo i
endfor
Хеши объявляются как {"key1": "value1", "key2": "value2"}.
Работа с элементом: hash["key1"] или hash.key1.
let ahash = {"john":10,"alex":20}
for k in sort(keys(ahash))
echo k
endfor
Значениями ключей хеша могут быть функции, внутри функции доступна переменная self:
function ahash.showalex() dict
echo self.alex
endfunction
ООП - хеш "объект" это просто копия хеша "класса":
let class = {"property": default_value}
function class.method() dict
echo self.property
endfunction
let obj = copy(class)
call obj.method()
let subclass = copy(class)
function! subclass.method() dict
echo self.property + 1
endfunction
Операторы
if COND
elseif COND
else
endif
while COND
continue
break
endwhile
for VAR in LIST
endfor
try
catch
finally
endtry
try
catch /REGEX/
catch /REGEX/
finally
endtry
eval
execute 'echo ' . varname
echo {varname}
normal 1Gjj
execute 'normal ' . cmd_keys
execute 'normal i' . insert_keys . "\<Esc>"
let optval = eval('&' . optname)
execute 'let optval = &' . optname
Функции
function без параметров выводит все определённые функции.
function ИмяФункции выводит код этой функции.
function ИмяФункции(параметры) создаёт функцию (для переопределения функции её нужно объявлять через function!).
delfunction ИмяФункции удаляет функцию.
Имена должны начинаться с большой буквы (чтобы не путаться с встроенными функциями).
По умолчанию (без return) функция возвращают 0.
function Func(param1, param2)
return a:param1 + a:param2
endfunction
function HandleRange(param1) range
" при вызове а-ля: 10,20call HandleRange("some")
" так же получит a:firstline и a:lastfile
" (обычная функция будет вызвана по разу на каждую строку)
endfunction
function VariableParams(param1, ...)
" кол-во аргументов в a:0, сами аргументы начиная с a:1,...
endfunction
В выражениях вызываются обычно, а вне выражений - через call.
if func1()
let var = func2()
call func3()
endif
function("ИмяФункции") возвращает ссылку на функцию (которую нужно сохранять в переменную с именем начинающимся на большую букву).
let MyFunc = function("MyRealFunc")
echo MyFunc(param)
call MyFunc(param)
echo call(MyFunc, [param]);
call call(MyFunc, [param]);
echo call("MyRealFunc", [param]);
call call("MyRealFunc", [param]);
Скрипты/плагины
Func глобальная
s:Func локально для текущего скрипта
Локальные функции нужно map-ить внутри скрипта для вызова снаружи используя <SID> (который фактически добавит к имени уникальный префикс):
" НЕ ПРАВИЛЬНО (при вызове снаружи скрипта s:Func() не известен)
nmap <unique> <Leader>a :call s:Func()<CR>
" ПРАВИЛЬНО
nmap <unique> <Leader>a :call <SID>Func()<CR>
Недостаток этого подхода в том, что снаружи скрипта <SID> не работает, так что пользователь не сможет переназначить map. Это обходится либо объявлением вызываемых снаружи функций как глобальных (но тогда желательно включать в имя функции префиксом имя плагина, для избежания конфликтов), либо созданием глобальной "виртуальной кнопки" с именем <Plug>ПлагинФункция - на эту кнопку юзер сможет назначать свои map снаружи скрипта:
""" у пользователя в ~/.vimrc:
nmap <Leader>z <Plug>MypluginFunc
""" внутри плагина:
if !hasmapto('<Plug>MypluginFunc')
nmap <unique> <Leader>a <Plug>MypluginFunc
endif
noremap <unique> <Plug>MypluginFunc :call <SID>Func()<CR>
" либо, если точек входа несколько, то удобнее ввести промежуточный map
noremap <unique> <script> <Plug>MypluginFunc <SID>Func
noremenu <script> Myplugin.Func <SID>Func
noremap <SID>Func :call <SID>Func()<CR>
В ftplugin/
(FileType-плагинах) нужно не забывать использовать локальные
версии команд:
let s:var = 'значение общее для всех буферов этого типа'
let b:var = 'значение локальное для этого буфера'
setlocal ...
map <buffer> ... <LocalLeader>...
command -buffer ...
Автозагрузка: если имя функции содержит #, например Myplugin#Func, то
не найдя эту функцию Vim попытается подгрузить файл autoload/Myplugin.vim
.