- Введение
- Куда класть файлы Lua
- Использование Lua в Vimscript
- Пространство имён vim
- Использование Vimscript из Lua
- Управление опции vim
- Управление внутренними переменными vim
- Вызов функций Vimscript
- Определение сопоставлений клавиш
- Определение пользовательских команд
- Определение автокоманд
- Определение синтаксиса/подсветки
- Общие советы и рекомендации
- Разное
Created by gh-md-toc
Интеграция Lua в Neovim в качестве языка с первоклассной поддержкой превращает её в одну из важнейших особенностей редактора. Тем не менее, количество учебных материалов по написанию плагинов на Lua значительно меньше таковых на Vimscript. Это руководство является попыткой предоставления необходимой информации для написания плагинов на Lua.
Это руководство предполагает, что пользователь использует последнюю версию Neovim nightly build. Так как версия 0.5 Neovim находится на стадии разработки, имейте в виду, что API, которые находятся в активной разработке нестабильны и могут быть подвержены изменениям до релиза.
Если вы незнакомы с языком, имеется большое количество материалов для изучения:
- Ресурс Learn X in Y minutes page about Lua позволит вам пробежаться по основам языка
- Если вы предпочитаете видеоуроки, то у Дерека Банаса (Derek Banas) имеется часовой видеоурок 1-hour tutorial on the language
- Сайт lua-users wiki содержит большое количество полезной информации относительно Lua
- Сайт official reference manual for Lua должен дать исчерпывающую информацию о языке
Следует заметить, что Lua является очень чистым и простым языком. Язык легко изучить, особенно если имеется опыт использования аналогичного скриптового языка наподобие Javascript. Возможно, вы разбираетесь в Lua больше, чем вы представляете!
Заметка: версия Lua, встроенное в Neovim является LuaJIT 2.1.0, что поддерживает совместимость с Lua 5.1 (с некоторыми исключениями в виде расширений версии 5.2)
Было написано несколько туториалов, чтобы помочь людям написать плагины на Lua. Некоторые из них значительно помогли для написания этого руководства. Большое спасибо их авторам.
- teukka.tech - From init.vim to init.lua
- 2n.pl - How to write neovim plugins in Lua
- 2n.pl - How to make UI for neovim plugins in Lua
- ms-jpq - Neovim Async Tutorial
- Vimpeccable - Плагин, помогающий написать .vimrc на Lua
- plenary.nvim - Все функции Lua, которые я не хоче переписывать
- popup.nvim - Имплементация API Всплывающих окон vim(vim Popup API) для Neovim
- nvim_utils
- nvim-luadev - REPL/дебаг консоль для плагинов Neovim, написанных на lua
- nvim-luapad - Интерактивный Neovim скратчпад для встроенного движка Lua
- nlua.nvim - Lua Разработка для Neovim
- BetterLua.vim - Лучшая синтаксическая подсветка Lua в Vim/NeoVim
Neovim поддерживает загрузку файла init.lua
вместо init.vim
для конфигурации.
Для справок:
:help config
Файлы Lua обычно находятся внутри папки lua/
в вашей runtimepath
(для большинства пользователей это папка ~/.config/nvim/lua
на *nix-овых системах и ~/AppData/Local/nvim/lua
для Windows). Вы можете вызвать эти файлы с помощью require()
в качестве Lua модулей.
В качестве примера возьмем следующую структуру папок:
📂 ~/.config/nvim
├── 📁 after
├── 📁 ftplugin
├── 📂 lua
│ ├── 🌑 myluamodule.lua
│ └── 📂 other_modules
│ ├── 🌑 anothermodule.lua
│ └── 🌑 init.lua
├── 📁 pack
├── 📁 plugin
├── 📁 syntax
└── 🇻 init.vim
Lua код ниже загрузит модуль myluamodule.lua
:
require('myluamodule')
Заметьте отсутствие расширения файла .lua
.
Аналогично, загрузка other_modules/anothermodule.lua
выполняется следующим образом:
require('other_modules.anothermodule')
-- or
require('other_modules/anothermodule')
Разделители путей обозначены либо точкой .
либо слэшем /
.
Папка содержащая файл init.lua
может быть загружена напрямую без необходимости уточнять имя файла.
require('other_modules') -- загружает other_modules/init.lua
Для большей информации: :help lua-require
В отличие от файлов с расширением .vim, файлы с расширением .lua не загружаются автоматически, если они находятся в специальных папках runtimepath
. К примеру, Neovim загрузит plugin/foo.vim
, но не загрузит plugin/foo.lua
.
Также смотрите:
Некоторые Lua плагины могут имет идентичные имена файлов внутри папки lua/
. Это может привести к коллизии пространств имён.
Если два плагина имеют файл lua/main.lua
, То вызов require('main')
неопределён: какой файл необходимо загрузить?
Поэтому это хорошая идея создать пространство имен вашей конфигурации или плагина с помощью папки в самом верхнем уровне, наподобие: lua/plugin_name/main.lua
Обновление: если вы используете последнюю ночную сборку, это [больше не проблема] (neovim/neovim#13119), и вы можете спокойно пропустить этот раздел.
Если вы используете функцию packages
или основанного на ней менеджера подключаемых модулей (например, packer.nvim, minpac или vim-packager), при использовании плагинов Lua следует помнить о некоторых вещах.
Пакеты в папке start
загружаются только после считывания вашего init.vim
. Это означает, что пакет не добавляется в runtimepath
до тех пор, пока Neovim не закончит обработку файла. Это может вызвать проблемы, если плагин ожидает, что вы загрузите(require
) модуль Lua или вызовете автоматически загружаемую функцию.
Предполагая, что в пакете start/foo
есть файл lua/bar.lua
, выполнение кода ниже в init.vim
вызовет ошибку, потому что runtimepath
еще не обновлен:
lua require('bar')
Вы должны использовать команду packadd! foo
перед тем как вызвать модуль через require
.
packadd! foo
lua require('bar')
Добавление !
к packadd
означает, что Neovim поместит пакет в runtimepath
без загрузки каких-либо скриптов в его папках plugin
или ftdetect
.
Также смотрите:
:help :packadd
- Issue #11409
Эта команда выполняет фрагмент кода Lua.
:lua require('myluamodule')
Многострочные скрипты возможны с использованием синтаксиса heredoc:
echo "Here's a bigger chunk of Lua code"
lua << EOF
local mod = require('mymodule')
local tbl = {1, 2, 3}
for k, v in ipairs(tbl) do
mod.method(v)
end
print(tbl)
EOF
Примечание: каждая команда :lua
имеет свою собственную область видимости, и переменные, объявленные с ключевым словом local
, недоступны вне команды. Это не сработает:
:lua local foo = 1
:lua print(foo)
" выводит 'nil' вместо '1'
Примечание 2: функция print()
в Lua ведет себя аналогично команде :echomsg
. Его вывод сохраняется в истории сообщений и может быть подавлен командой :silent
.
Также смотрите:
:help :lua
:help :lua-heredoc
Эта команда выполняет фрагмент кода Lua, который воздействует на диапазон строк в текущем буфере. Если диапазон не указан, вместо него используется весь буфер. Строка возвращаемая из блока, используется для определения того, чем должна быть заменена каждая строка в диапазоне.
Следующая команда заменит каждую строку в текущем буфере текстом hello world
:
:luado return 'hello world'
Также предусмотрены две неявные переменные line
и linenr
. line
- это текст строки, по которой выполняется итерация, а linenr
- ее номер. Следующая команда сделает каждую строку, номер которой делится на 2, в верхний регистр:
:luado if linenr % 2 == 0 then return line:upper() end
Также смотрите:
:help :luado
Эта команда считывает файл Lua.
:luafile ~/foo/bar/baz/myluafile.lua
Эта команда аналогична команде :source
для файлов .vim или встроенной функции dofile()
в Lua.
Также смотрите:
:help :luafile
Вам может быть интересно, в чем разница между lua require()
и luafile
, и стоит ли вам использовать одно вместо другого. У них разные варианты использования:
require()
:- это встроенная функция Lua. Это позволяет вам использовать модульную систему Lua
- ищет модули в папках
lua
в вашемruntimepath
- отслеживает, какие модули были загружены, и предотвращает повторный парсинг и выполнение скрипта. Если вы измените файл, содержащий код для модуля, и попытаетесь
require()
второй раз во время работы Neovim, модуль на самом деле не будет обновляться
:luafile
:- является Ex командой. Не поддерживает модули
- принимает абсолютный или относительный путь к рабочей папке текущего окна
- выполняет содержимое скрипта независимо от того, выполнялся ли он раньше
:luafile
также может быть полезен, если вы хотите запустить файл Lua, над которым вы работаете:
:luafile %
Эта встроенная функция Vimscript оценивает выражение Lua в форме строки и возвращает ее значение. Типы данных Lua автоматически преобразуются в типы Vimscript (и наоборот).
" Вы можете сохранить результат в переменной
let variable = luaeval('1 + 1')
echo variable
" 2
let concat = luaeval('"Lua".." is ".."awesome"')
echo concat
" 'Lua is awesome'
" Таблицы в виде списков преобразуются в списки Vim.
let list = luaeval('{1, 2, 3, 4}')
echo list[0]
" 1
echo list[1]
" 2
" Обратите внимание, что в отличие от таблиц Lua, списки Vim индексируются с нуля
" Таблицы в виде словарей конвертируются в словари Vim.
let dict = luaeval('{foo = "bar", baz = "qux"}')
echo dict.foo
" 'bar'
" То же самое для логических значений и значений nil
echo luaeval('true')
" v:true
echo luaeval('nil')
" v:null
" Вы можете создавать алиас в Vimscript для функций Lua.
let LuaMathPow = luaeval('math.pow')
echo LuaMathPow(2, 2)
" 4
let LuaModuleFunction = luaeval('require("mymodule").myfunction')
call LuaModuleFunction()
" Также можно передавать функции Lua в качестве значений функциям Vim.
lua X = function(k, v) return string.format("%s:%s", k, v) end
echo map([1, 2, 3], luaeval("X"))
luaeval()
принимает необязательный второй аргумент, который позволяет передавать данные в выражение. Затем вы можете получить доступ к этим данным из Lua, используя волшебную глобальную переменную _A
:
echo luaeval('_A[1] + _A[2]', [1, 1])
" 2
echo luaeval('string.format("Lua is %s", _A)', 'awesome')
" 'Lua is awesome'
Также смотрите:
:help luaeval()
Эта глобальная переменная Vim позволяет вам вызывать глобальные функции Lua прямо из Vimscript. Опять же, типы данных Vim преобразуются в типы Lua и наоборот.
call v:lua.print('Hello from Lua!')
" 'Hello from Lua!'
let scream = v:lua.string.rep('A', 10)
echo scream
" 'AAAAAAAAAA'
" Загрузка модулей работает
call v:lua.require('mymodule').myfunction()
" Как насчет неплохой статусной строки?
lua << EOF
function _G.statusline()
local filepath = '%f'
local align_section = '%='
local percentage_through_file = '%p%%'
return string.format(
'%s%s%s',
filepath,
align_section,
percentage_through_file
)
end
EOF
set statusline=%!v:lua.statusline()
" Также работает в сопоставлениях выражений
lua << EOF
function _G.check_back_space()
local col = vim.fn.col('.') - 1
if col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') then
return true
else
return false
end
end
EOF
inoremap <silent> <expr> <Tab>
\ pumvisible() ? '\<C-n>' :
\ v:lua.check_back_space() ? '\<Tab>' :
\ completion#trigger_completion()
Также смотрите:
:help v:lua
:help v:lua-call
Эта переменная может использоваться только для вызова функций. Следующий код всегда будет вызывать ошибку:
" Создание алиасов не работает
let LuaPrint = v:lua.print
" Доступ к словарям не работает
echo v:lua.some_global_dict['key']
" Использование функции в качестве значения не работает
echo map([1, 2, 3], v:lua.global_callback)
Вы можете получить подсветку синтаксиса Lua внутри файлов .vim, поместив let g: vimsyn_embed = 'l'
в свой файл конфигурации. См. :help g:vimsyn_embed
для получения дополнительной информации об этой опции.
Neovim предоставляет глобальную переменную vim
, которая служит точкой входа для взаимодействия с её API из Lua. Она предоставляет пользователям расширенную "стандартную библиотеку" функций, а также различные подмодули.
Некоторые примечательные функции и модули включают:
vim.inspect
: вывод Lua объектов (полезно для проверки таблиц)vim.regex
: использование регулярных выражений Vim из Luavim.api
: модуль, который предоставляет функции API (тот же API, что используют удалённые(remote) плагины)vim.loop
: модуль, который предоставляет функционал цикла событий Neovim (с использованием LibUV)vim.lsp
: модуль, который управляет встроенным клиентом LSPvim.treesitter
: модуль, который предоставляет функционал библиотеки tree-sitter
Этот список ни в коем случае не является исчерпывающим. Если вы хотите узнать больше о том, что делает переменная vim
, :help lua-stdlib
и :help lua-vim
вам в помощь :). В качестве альтернативы вы можете выполнить :lua print (vim.inspect (vim))
, чтобы получить список всех модулей.
Писать print(vim.inspect(x))
каждый раз, когда вы хотите проверить содержимое объекта, может оказаться довольно утомительным. Возможно, стоит иметь где-нибудь в вашей конфигурации глобальную функцию-оболочку:
function _G.dump(...)
local objects = vim.tbl_map(vim.inspect, {...})
print(unpack(objects))
end
Затем вы можете очень быстро проверить содержимое объекта в своем коде или из командной строки:
dump({1, 2, 3})
:lua dump(vim.loop)
Кроме того, вы можете обнаружить, что встроенных функций Lua иногда не хватает по сравнению с тем, что вы найдете в других языках (например, os.clock()
возвращает значение только в секундах, а не в миллисекундах). Обязательно посмотрите Neovim stdlib (и vim.fn
, подробнее об этом позже), вероятно, в нем есть то, что вы ищете.
Эта функция оценивает строку выражения Vimscript и возвращает ее значение. Типы данных Vimscript автоматически преобразуются в типы Lua (и наоборот).
Это Lua-эквивалент функции luaeval()
в Vimscript.
-- Типы данных конвертируются правильно
print(vim.api.nvim_eval('1 + 1')) -- 2
print(vim.inspect(vim.api.nvim_eval('[1, 2, 3]'))) -- { 1, 2, 3 }
print(vim.inspect(vim.api.nvim_eval('{"foo": "bar", "baz": "qux"}'))) -- { baz = "qux", foo = "bar" }
print(vim.api.nvim_eval('v:true')) -- true
print(vim.api.nvim_eval('v:null')) -- nil
TODO: возможно ли, чтобы vim.api.nvim_eval()
возвращала funcref
?
В отличие от luaeval()
, vim.api.nvim_eval()
не предоставляет неявную переменную _A
для передачи данных в выражение.
Эта функция оценивает фрагмент кода Vimscript. Она принимает строку, содержащую исходный код для выполнения, и логическое значение, чтобы определить, должен ли вывод кода возвращаться функцией (вы можете сохранить вывод в переменной, для примера).
local result = vim.api.nvim_exec(
[[
let mytext = 'hello world'
function! MyFunction(text)
echo a:text
endfunction
call MyFunction(mytext)
]],
true)
print(result) -- 'hello world'
TODO: в документации указано, что скриптовая область действия(s:
) поддерживается, но запуск этого фрагмента с переменной скриптовой области действия вызывает ошибку. Почему?
Эта функция выполняет команду ex. Она принимает строку, содержащую команду для выполнения.
vim.api.nvim_command('new')
vim.api.nvim_command('wincmd H')
vim.api.nvim_command('set nonumber')
vim.api.nvim_command('%s/foo/bar/g')
Примечание: vim.cmd
- более короткий alias для этой функции.
vim.cmd('buffers')
Поскольку вам нужно передавать строки этим функциям, вам часто приходится экранировать обратный слэш:
vim.cmd('%s/\\Vfoo/bar/g')
Строковые литералы проще использовать, поскольку они не требуют экранирующих символов:
vim.cmd([[%s/\Vfoo/bar/g]])
Neovim предоставляет набор функций API для изменения опции или получения её текущего значения:
- Глобальные опции:
vim.api.nvim_set_option()
vim.api.nvim_get_option()
- Локальные опции буферов:
vim.api.nvim_buf_set_option()
vim.api.nvim_buf_get_option()
- Локальные опции окон:
vim.api.nvim_win_set_option()
vim.api.nvim_win_get_option()
Они принимают строку, содержащую имя опции, которую нужно установить / получить, а также значение, которое вы хотите установить.
Логические параметры (например, (no)number
) должны иметь значение true
или false
:
vim.api.nvim_set_option('smarttab', false)
print(vim.api.nvim_get_option('smarttab')) -- false
Неудивительно, что параметры строки должны быть строками:
vim.api.nvim_set_option('selection', 'exclusive')
print(vim.api.nvim_get_option('selection')) -- 'exclusive'
Числовые опции принимают число:
vim.api.nvim_set_option('updatetime', 3000)
print(vim.api.nvim_get_option('updatetime')) -- 3000
Локальные опции буффера и окна также нуждаются в номере буфера или номере окна (использование 0
установит/получит опцию для текущего буфера/окна)
vim.api.nvim_win_set_option(0, 'number', true)
vim.api.nvim_buf_set_option(10, 'shiftwidth', 4)
print(vim.api.nvim_win_get_option(0, 'number')) -- true
print(vim.api.nvim_buf_get_option(10, 'shiftwidth')) -- 4
Если вы хотите установить параметры более "идиоматическим" способом, доступны несколько мета-аксессуаров. По сути, они обертывают вышеуказанные функции API и позволяют управлять параметрами, как если бы они были переменными:
vim.o.{option}
: глобальные опцииvim.bo.{option}
: локальные опции буффераvim.wo.{option}
: локальные опции окна
vim.o.smarttab = false
print(vim.o.smarttab) -- false
vim.bo.shiftwidth = 4
print(vim.bo.shiftwidth) -- 4
Вы можете указать номер для опций, локальных для буфера и для локального окна. Если номер не указан, используется текущий буфер / окно:
vim.bo[4].expandtab = true -- тоже самое что и vim.api.nvim_buf_set_option(4, 'expandtab', true)
vim.wo.number = true -- тоже самое что и vim.api.nvim_win_set_option(0, 'number', true)
Также смотрите:
:help lua-vim-internal-options
В Lua нет эквивалента команде :set
, вы либо устанавливаете параметр глобально, либо локально.
Также смотрите:
:help :setglobal
:help global-local
Как и у параметров, внутренние переменные имеют собственный набор функций API:
- Глобальные переменные (
g:
):vim.api.nvim_set_var ()
vim.api.nvim_get_var ()
vim.api.nvim_del_var ()
- Переменные буфера (
b:
):vim.api.nvim_buf_set_var ()
vim.api.nvim_buf_get_var ()
vim.api.nvim_buf_del_var ()
- Оконные переменные (
w:
):vim.api.nvim_win_set_var ()
vim.api.nvim_win_get_var ()
vim.api.nvim_win_del_var ()
- Переменные вкладки (
t:
):vim.api.nvim_tabpage_set_var ()
vim.api.nvim_tabpage_get_var ()
vim.api.nvim_tabpage_del_var ()
- Предопределенные переменные Vim (
v:
):vim.api.nvim_set_vvar ()
vim.api.nvim_get_vvar ()
За исключением предопределенных переменных Vim, они также могут быть удалены (команда :unlet
является эквивалентом в Vimscript). Локальные переменные (l:
), скриптовые переменные (s:
) и аргументы функции (a:
) не могут быть изменены, поскольку они имеют смысл только в контексте Vimscript, Lua имеет свои собственные правила области видимости
Если вы не знакомы с тем, что делают эти переменные, :help internal-variables
описывает их подробно.
Эти функции принимают строку, содержащую имя переменной для изменения/получения/удаления, а также значение, которое вы хотите установить.
vim.api.nvim_set_var('some_global_variable', { key1 = 'value', key2 = 300 })
print(vim.inspect(vim.api.nvim_get_var('some_global_variable'))) -- { key1 = "value", key2 = 300 }
vim.api.nvim_del_var('some_global_variable')
Переменные, которые ограничены буфером, окном или вкладкой, также получают номер (использование 0
изменит/получит/удалит переменную для текущего буфера/окна/вкладки):
vim.api.nvim_win_set_var(0, 'some_window_variable', 2500)
vim.api.nvim_tab_set_var(3, 'some_tabpage_variable', 'hello world')
print(vim.api.nvim_win_get_var(0, 'some_window_variable')) -- 2500
print(vim.api.nvim_buf_get_var(3, 'some_tabpage_variable')) -- 'hello world'
vim.api.nvim_win_del_var(0, 'some_window_variable')
vim.api.nvim_buf_del_var(3, 'some_tabpage_variable')
Внутренними переменными можно управлять более интуитивно с помощью этих мета-аксессоров:
vim.g.{name}
: глобальные переменныеvim.b.{name}
: буферные переменныеvim.w.{name}
: переменные окнаvim.t.{name}
: переменные вкладкиvim.v.{name}
: предопределенные переменные Vim
vim.g.some_global_variable = {
key1 = 'value',
key2 = 300
}
print(vim.inspect(vim.g.some_global_variable)) -- { key1 = "value", key2 = 300 }
Чтобы удалить одну из этих переменных, просто присвойте ей nil
:
vim.g.some_global_variable = nil
В отличие от мета-аксессоров опций, вы не можете указать число для переменных с областью буфера/окна/вкладки.
Кроме того, вы не можете добавлять/обновлять/удалять ключи из словаря, хранящегося в одной из этих переменных. Например, этот фрагмент кода Vimscript не работает:
let g:variable = {}
lua vim.g.variable.key = 'a'
echo g:variable
" {}
Это известная проблема:
vim.call()
вызывает функцию Vimscript. Это может быть встроенная функция Vim или пользовательская функция. Опять же, типы данных конвертируются из Lua в Vimscript и обратно.
Она принимает имя функции, за которым следуют аргументы, которые вы хотите передать этой функции:
print(vim.call('printf', 'Hello from %s', 'Lua'))
local reversed_list = vim.call('reverse', { 'a', 'b', 'c' })
print(vim.inspect(reversed_list)) -- { "c", "b", "a" }
local function print_stdout(chan_id, data, name)
print(data[1])
end
vim.call('jobstart', 'ls', { on_stdout = print_stdout })
vim.call('my#autoload#function')
See also:
:help vim.call()
vim.fn
does the exact same thing as vim.call()
, but looks more like a native Lua function call:
print(vim.fn.printf('Hello from %s', 'Lua'))
local reversed_list = vim.fn.reverse({ 'a', 'b', 'c' })
print(vim.inspect(reversed_list)) -- { "c", "b", "a" }
local function print_stdout(chan_id, data, name)
print(data[1])
end
vim.fn.jobstart('ls', { on_stdout = print_stdout })
Хэши #
не являются допустимыми символами для идентификаторов в Lua, поэтому функции автозагрузки должны вызываться с таким синтаксисом:
vim.fn['my#autoload#function']()
Также смотрите:
:help vim.fn
Neovim имеет обширную библиотеку мощных встроенных функций, которые очень полезны для плагинов. Смотрите :help vim-function
для списка в алфавитном порядке и :help function-list
для списка функций, сгруппированных по темам.
Некоторые функции Vim, которые должны возвращать логическое значение 1
или 0
. В Vimscript это не проблема, поскольку 1
истинно, а 0
ложно, что позволяет использовать такие конструкции:
if has('nvim')
" do something...
endif
Однако в Lua ложными считаются только false
и nil
, числа всегда оцениваются как true
, независимо от их значения. Вы должны явно проверить 1
или 0
:
if vim.fn.has('nvim') == 1 then
-- do something...
end
Neovim предоставляет список функций API для установки, получения и удаления сопоставлений:
- Для глобальных сопоставлений:
vim.api.nvim_set_keymap()
vim.api.nvim_get_keymap()
vim.api.nvim_del_keymap()
- Для локальных сопоставлений:
vim.api.nvim_buf_set_keymap()
vim.api.nvim_buf_get_keymap()
vim.api.nvim_buf_del_keymap()
Начнем с vim.api.nvim_set_keymap()
и vim.api.nvim_buf_set_keymap()
Первым аргументом, переданным в функцию, является строка, содержащая имя режима, для которого сопоставление будет действовать:
Строчное значение | Страница помощи | Затронутые режимы | Эквивалент Vimscript |
---|---|---|---|
'' (пустая строка) |
mapmode-nvo |
Normal, Visual, Select, Operator-pending | :map |
'n' |
mapmode-n |
Normal | :nmap |
'v' |
mapmode-v |
Visual and Select | :vmap |
's' |
mapmode-s |
Select | :smap |
'x' |
mapmode-x |
Visual | :xmap |
'o' |
mapmode-o |
Operator-pending | :omap |
'!' |
mapmode-ic |
Insert and Command-line | :map! |
'i' |
mapmode-i |
Insert | :imap |
'l' |
mapmode-l |
Insert, Command-line, Lang-Arg | :lmap |
'c' |
mapmode-c |
Command-line | :cmap |
't' |
mapmode-t |
Terminal | :tmap |
Второй аргумент - это строка, содержащая левую часть отображения (ключ или набор ключей, запускающих команду, определенную в сопоставлении). Пустая строка эквивалентна <Nop>
, который отключает ключ.
Третий аргумент - это строка, содержащая правую часть сопоставления (команду для выполнения).
Последний аргумент - это таблица, содержащая логические параметры для сопоставления, как определено в :help :map-arguments
(включая noremap
и исключая buffer
).
Сопоставления локальных буферов также принимают номер буфера в качестве первого аргумента (0
устанавливает сопоставление для текущего буфера).
vim.api.nvim_set_keymap('n', '<leader><Space>', ':set hlsearch!<CR>', { noremap = true, silent = true })
-- :nnoremap <silent> <leader><Space> :set hlsearch<CR>
vim.api.nvim_buf_set_keymap(0, '', 'cc', 'line(".") == 1 ? "cc" : "ggcc"', { noremap = true, expr = true })
-- :noremap <buffer> <expr> cc line('.') == 1 ? 'cc' : 'ggcc'
vim.api.nvim_get_keymap()
принимает строку, содержащую краткое имя режима, для которого вы хотите получить список сопоставлений (см. таблицу выше). Возвращаемое значение - это таблица, содержащая все глобальные сопоставления для режима.
print(vim.inspect(vim.api.nvim_get_keymap('n')))
-- :verbose nmap
vim.api.nvim_buf_get_keymap ()
принимает дополнительный номер буфера в качестве своего первого аргумента (0
получит сопоставления для текущего буфера)
print(vim.inspect(vim.api.nvim_buf_get_keymap(0, 'i')))
-- :verbose imap <buffer>
vim.api.nvim_del_keymap()
принимает режим и левую часть сопоставления.
vim.api.nvim_del_keymap('n', '<leader><Space>')
-- :nunmap <leader><Space>
Опять же, vim.api.nvim_buf_del_keymap ()
принимает номер буфера в качестве своего первого аргумента, где 0
представляет текущий буфер.
vim.api.nvim_buf_del_keymap(0, 'i', '<Tab>')
-- :iunmap <buffer> <Tab>
В настоящее время в Lua нет интерфейса для создания пользовательских команд. Тем не менее, планы имеются:
В настоящее время вам, вероятно, лучше создавать команды в Vimscript.
Augroup-ы и autcommand-ы еще не имеют интерфейса, но над ним работают:
А пока вы можете создавать автокоманды в Vimscript или использовать эту оболочку из norcalli/nvim_utils
Синтаксический API все еще находится в стадии разработки. Вот пара указателей:
- Issue #9876
- tjdevries/colorbuddy.vim, библиотека для создания цветовых схем в Lua
:help lua-treesitter
Если вы используете линтеры и/или языковые серверы для диагностики и автозаполнения для проектов Lua, возможно, вам придется настроить для них параметры, специфичные для Neovim. Вот несколько рекомендуемых настроек для популярных инструментов:
Вы можете заставить luacheck распознать глобал vim
, поместив эту конфигурацию в ~/.luacheckrc
(или $XDG_CONFIG_HOME/luacheck/.luacheckrc
):
globals = {
"vim",
}
Языковой сервер Alloyed/lua-lsp использует luacheck для обеспечения линтинга и читает тот же файл.
Для получения дополнительной информации о том, как настроить luacheck
, обратитесь к его документации
Пример конфигурации для sumneko/lua-language-server (в примере используется встроенный клиент LSP, но конфигурация для другого клиента LSP должна быть идентична):
require'lspconfig'.sumneko_lua.setup {
settings = {
Lua = {
runtime = {
-- Заставьте языковой сервер распознавать глобальные переменные LuaJIT, такие как `jit` и` bit`
version = 'LuaJIT',
- Настройте путь к lua
path = vim.split(package.path, ';'),
},
diagnostics = {
- Заставьте языковой сервер распознавать глобальную переменную `vim`
globals = {'vim'},
},
workspace = {
-- Сделать так, чтобы сервер знал о рантайм файлах Neovim
library = {
[vim.fn.expand('$VIMRUNTIME/lua')] = true,
[vim.fn.expand('$VIMRUNTIME/lua/vim/lsp')] = true,
},
},
},
},
}
Для получения дополнительной информации о настройке sumneko/lua-language-server см. "Setting without VSCode"
Источник автодополнения rafcamlet/coc-nvim-lua для coc.nvim предоставляет элементы автодополнения для библиотеки Neovim stdlib.
TODO:
- Горячая перезагрузка модулей
vim.validate()
?- Добавить материал о модульных тестах? Я знаю, что Neovim использует фреймворк busted, но я не знаю, как использовать его для плагинов.
- Лучшие практики? Я не Lua мастер, поэтому не знаю
- Как использовать пакеты LuaRocks (wbthomason/packer.nvim?)
vim.loop
- это модуль, который предоставляет API LibUV . Некоторые ресурсы:
Также смотрите:
:help vim.loop
vim.lsp
- это модуль, который управляет встроенным клиентом LSP. Репозиторий neovim/nvim-lspconfig содержит конфигурации по умолчанию для популярных языковых серверов.
Поведение клиента можно настроить с помощью обработчиков "lsp-handlers". Для дополнительной информации:
:help lsp-handler
- neovim/neovim#12655
- How to migrate from diagnostic-nvim
Вы также можете взглянуть на плагины, построенные вокруг клиента LSP:
Также смотрите:
:help lsp
vim.treesitter
- это модуль, который управляет интеграцией библиотеки Tree-sitter в Neovim. Если вы хотите узнать больше о Tree-sitter, вам может быть интересна эта презентация (38:37).
Организация nvim-treeitter размещает различные плагины, использующие преимущества библиотеки.
See also:
:help lua-treesitter
Одним из преимуществ использования Lua является то, что вам фактически не нужно писать код Lua! Для этого языка доступно множество транспайлеров.
Вероятно, один из самых известных транспилеров для Lua. Добавляет множество удобных функций, таких как классы, списковое включение или функциональные литералы. Плагин svermeulen/nvim-moonmaker позволяет писать плагины и настройку Neovim непосредственно в Moonscript.
Lisp, который компилируется в Lua. Вы можете написать конфигурацию и плагины для Neovim в Fennel с помощью плагина Olical/aniseed. Кроме того, плагин Olical/conjure предоставляет интерактивную среду разработки, которая поддерживает Fennel (среди других языков).
Другие интересные проекты: