NeovimのためのLua入門 init.lua編
2022-07-12 追記
かなり情報が古くなっていたので更新しました。
lua-intro
にもあるnanotee/nvim-lua-guideも参照してください。
日本語訳もあります。
はじめに
今回はlua.txt
からLuaで設定を書くために必要なものを紹介します。
NVIM v0.8.0-dev+604-gd8360e903を使用しています。
どうやって読み込むのか
.config/nvim/init.vim
の代わりに.config/nvim/init.lua
を置くと、設定ファイルとして読み込まれます。
init.vim
とinit.lua
が同時に存在するとエラーになります。
プラグインとして使用したい場合もruntimepath
内でplugin/hoge.lua
のように配置し、今までの.vim
ファイルを置き換えれば自動で読み込んでくれます。
(Vim scriptを置き換える目的ならもうsetup()
は必須ではありません。)
モジュールを配置したい場合は、runtimepath
内のlua
ディレクトリ内にファイルを置くと、Luaのrequire
から読み込めるようになります。
-- lua/hi.lua
return 'hi'
--
:lua print(require('hi"))
"hi
lua/hello/init.lua
のようにディレクトリを作るとディレクトリ名でrequire
できます。
-- lua/hello/init.lua
return 'hello'
--
:lua print(require('hello'))
"hello
LuaからVim script
昔からあるNvim API(:h api.txt
)を使用する方法と、前回でてきたlua-stdlib
を使用する方法があります。
どちらもvimモジュールからアクセスできますが、ヘルプを探す時はapi.txt
とlua.txt
で別れているので注意が必要です。
また、api.txt
のサンプルコードはVim scriptなので読み変える必要があります。
lua-stdlib
の方は当然Lua用なのでAPIよりは使いやすくなっています。
関数
vim.fn
でvim側の関数を使用できます。
-- vim組込み
vim.fn.abs(-10)
-- autoload関数の場合
vim.fn['dein#update']()
-- API
print( tostring( vim.api.nvim_get_current_line() ) )
vim.api
はテーブルなので少しタイプ数を減らせます。
local api = vim.api
api.nvim_buf_line_count(0)
EXコマンド
文字列がEXコマンドとして実行されます。
何でもできる最終手段です。
vim.cmd('echo 1234')
変数
vim.g.loaded_netrw = 1
の用に変数に直接アクセスできます。
スコープはg,b,w,t,vと、Vim scriptと同様です。
環境変数はenv
を使います。
print( vim.env.TERM )
オプション
通常は:set
相当のことができるvim.opt
を使用します。
:setlocal
と:setglobal
に対応するvim.opt_local
とvim.opt_global
もあります。
詳細は:h lua-vim-opt
を参照してください。
vim.opt.number = true
vim.opt.background = 'light'
vim.opt.wildignore = { '*.o', '*.a', '__pycache__' }
:set +=
などの操作はテーブルをいじる方法と関数を使う方法があります。
vim.opt.wildignore = vim.opt.wildignore + { "*.pyc", "node_modules" }
vim.opt.wildignore:append { "*.pyc", "node_modules" }
ショートハンドとしてvim.o
、vim.bo
、vim.wo
、vim.go
といった変数もあります。
lua command global_value local_value
vim.o :set set set
vim.bo/vim.wo :setlocal - set
vim.go :setglobal set -
マッピング
nvim_set_keymap()
かvim.keymap.set()
を使います。
詳細は:h lua-keymap
を参照してください。
vim.keymap.set()
はおもしろい関数で通常の:map
とは動作が異なります。
デフォルトでremapが無効(noremap)になっていて、<Plug>
が含まれていると自動で有効(map)になります。
Luaの関数をそのままマッピングすることもできるので基本的にこちらを使うことになると思います。
-- 等価
vim.api.nvim_set_keymap( 'n', 'j', 'gj', {noremap = true} )
vim.keymap.set( 'n', 'j', 'gj' )
-- 関数
vim.keymap.set('n', 'lhs', function() print("real lua function") end)
vim.keymap.set('n', 'asdf', require('jkl').my_fun)
-- 複数のモード
vim.keymap.set({'n', 'v'}, '<leader>lr', vim.lsp.buf.references, { buffer=true })
-- <Plug>
vim.keymap.set('n', '[%', '<Plug>(MatchitNormalMultiBackward)')
autocmd
nvim_create_augroup()
とnvim_create_autocmd()
を使います。
nvim_create_augroup()
のオプションのclear
がデフォルトでオンになっていて、よくある:autocmd!
で多重登録を防ぐというのが不要になっています。
詳細は:h api-autocmd
を参照してください。
-- 従来
vim.cmd('augroup lua')
vim.cmd('autocmd!')
vim.cmd('autocmd InsertEnter * echo "insert enter"')
vim.cmd('augroup END')
-- 上と同じ
vim.api.nvim_create_augroup( 'lua', {} )
vim.api.nvim_create_autocmd( 'insertenter', {
group = 'lua',
callback = function() print( 'insert enter') end
})
-- Vim scriptも渡せます
vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
pattern = {"*.c", "*.h"},
command = "echo 'Entering a C or C++ file'",
})
ユーザー定義コマンド
nvim_create_user_command()
を使います。バッファを指定できるnvim_buf_create_user_command()
というのもあります。
詳細は:h api-command
を参照してください。
-- 等価
vim.cmd('command Hi echo "Hi!"')
vim.api.nvim_create_user_command( 'Hi', function() print( 'Hi!' ) end, {} )
発火するにはvim.api.nvim_exec_autocmds()
を使います。
vim.api.nvim_exec_autocmds( 'InsertEnter', {} )
Vim scriptからLua
:lua-heredoc
ヒアドキュメント Vim script内にLuaをそのまま埋め込むことができます。
ヒアドキュメント内のローカル変数はその中でしか使えません。
function! CurrentLineInfo()
lua << EOF
local linenr = vim.api.nvim_win_get_cursor(0)[1]
local curline = vim.api.nvim_buf_get_lines(0, linenr, linenr + 1, false)[1]
print(string.format("Current line [%d] has %d bytes",linenr, #curline))
EOF
endfunction
v:lua
Luaのグローバルな関数を呼ぶことができます。
lua << EOF
function Hello()
print("Hello")
end
EOF
call v:lua.Hello()
"Hello
Vim scriptの関数を設定するところにも使えるようです。
vim.api.nvim_buf_set_option(0, 'omnifunc', 'v:lua.mymod.omnifunc')
v:luaは関数を呼ぶことしかできず、式では使用できません。
let g:Myvar = v:lua.myfunc " Error
call SomeFunc(v:lua.mycallback) " Error
let g:foo = v:lua " Error
let g:foo = v:['lua'] " Error
おわりに
よく使いそうな物の紹介は以上です。
各機能の細かいところまでは書いていませんが、Luaから設定できるものが揃ってきた印象があります。
Discussion