NeovimとLua
luaでのoption設定が2021年7月時点の情報です。それ以外は、2021年2月上旬時点から更新していません。そのため、Neovim v0.5.1以上に対応していません。
HEADのBreaking Changesはこのissueにまとまっています。
NeovimのLuaプラグインを作成する場合、次のtemplateが役に立つはずです。lintとtestの設定をしているtemplate達です。
- luacheck(linter)なし
-
Neovim plugin boilerplate
他とは違いドキュメント生成、自動リリースがある - ellisonleao/nvim-plugin-template
-
Neovim plugin boilerplate
- luacheck(linter)あり
Newslettersもあります。
設定フレームワーク
Luaで書かれているNeovimプラグインを沢山発見し、理由が気になり調べた結果をまとめたものです。次の3つを記載しています。
- NeovimとLuaの相性がいい理由
- Luaを利用したNeovimの設定
- Lua製のプラグインの紹介
プラグインマネージャーやLSP,fuzzy finderなどがあります。
NeovimとLuaの関係
NeovimはLua 5.1を組み込んでおり、Luaを実行できます。そのため、Neovimのコマンドモードで lua print('Hello World')
を実行すれば、 Hello world
とメッセージを表示します。
NeovimとLuaが相性が良い理由
Neovimの有名なコントリビューターのTJさんはVimconfのプレゼンで次の5つといっています。
- 簡単
Luaの学習コストは低く、誰でもすぐ書けます。 - Luaのサイズが小さい
バイナリサイズ(linux用)は200KB以下です。 - 移植性
ISO Cで実装されているため、OS Kernel内でもLuaは実行できます。 - 埋め込みに適している。
Vim scriptからLuaの関数を呼び出すことができます。その逆もできます。 - Vim scriptよりスピードが早い
Vim scriptなら約5.5秒かかる処理をLua(LuaJIT)は約0.003秒で処理します。
Lua単体の感想
- 配列とdict両方になるtableは慣れれば見やすい
{1, 2, 3} -- 配列
{a = 1, b = 2, c = 3} -- dict
{1, b = 2, 3} -- 配列とdict
- エスケープシーケンスがいらない
[[]]
が便利
'a\\a' -- a\a
[[a\\a]] -- a\\a
- 配列のindexが1開始は慣れれば気にならない
JavaScriptのTypeScriptのように、Luaのコードに変換するtranspilersがあり、次のようなものがあります。
- TypescriptをLuaに変換するTypeScriptToLua
- coffeescriptと構文が似ているmoonscript
nvim-moonmakerがあれば、moonscriptでNeovimのプラグイン開発ができます。 - lispと構文が似ているFennel
- Luaに型を付けたtl
- 静的型付けのHaxe
Vim scriptとLuaの比較
Luaの良い点
- 改行時の
\
がいらない
Vim script
echo({ 'a': 1,
\ 'b': 2 }) " `\` を削除するとエラー
Lua
print({ a = 1,
b = 2 })
- 変数や関数のスコープ周りが楽
Vim script
function s:hoo(num)
let num = 1
" 引数の `num` ではなく、関数内で宣言した `num` の値(1)が表示されます。
" 引数の `num` を表示させたい場合は `echo a:num` と書きます。
echo num
endfunction
Lua
function hoo(num)
print(num) -- 引数の `num` が表示されます。
end
- dict時のkeyが文字列の場合、
''
で囲む必要がない
Vim script
{ 'a' : 1, 2 : 2 }
" `#{}` を使えばいりません。
" ネストする場合は、そのdictも `#{}` にする必要があります。
#{a: 1, 2: 2, d: {'a': 1}}
Lua
-- 数値の場合は `[]` で囲む必要があります。
-- 数値より文字列のkeyを使う場面が多いので、こちらのほうが楽です。
{ a = 1, [2] = 2 }
- 関数を呼ぶときに
call
がいらない
Vim script
" `echo` は関数ではなくコマンドなので `call` はいりません。
call foo()
Lua
foo()
- 関数やif文などの終わりが
end
に統一されている
Vim script
function foo()
...
endfunction
if i == 0
...
endif
for i in [1,2,3]
...
endfor
Lua
function foo()
...
end
if i == 0 then
...
end
for i, val in pairs({'a','b','c'}) do
...
end
Luaの気になる点
- ifの
then
やforのdone
snippetを使えば自動で挿入されるので悪い点とまでは感じません。
Lua
if i == 0 then
...
end
for i, val in pairs({'a','b','c'}) do
...
end
LuaでのNeovim設定
Vim scriptよりLuaのほうが設定は楽に感じています。大きいのが次の2点です。
- オプション(e.g.
set number
)やキーマップ(e.g.nnoremap <silent> <C-w>d :delete<CR>
)などのコマンドを関数で実行できる
キーマップなどで変数の値を利用するときにexecute
コマンドを使う必要がありません。
Lua
-- execute('nnoremap <silent> <leader>' .. l:key .. ' :' .. l:cmd .. '<CR>')
vim.api.nvim_set_keymap('n', '<leader>' .. key, ':' .. cmd .. '<CR>',
{ noremap = true, silent = true })
- 変数のスコープが楽
Vim scriptのように引数を参照するためa:
をつける必要はありません。l
やs
,g
などを気にするのはVim scriptの変数を利用するときのみです。
学習コスト
Vim scriptを知っている人の場合、slinさんが書いている記事も含む、次の参考資料を読めば30分もあれば理解できる印象です。Luaを知らない場合でも、Luaの文法は簡単なので合わせて1時間もあれば大丈夫な感じです。
- nanotee/nvim-lua-guide: A guide to using Lua in Neovim
- NeovimのためのLua入門 Lua基礎編
- NeovimのためのLua入門 init.lua編
変数やオプションなどの操作
LuaでNeovimの次の要素の管理や操作ができます。
Vim script変数
vim.{g|b|w|t|v|env}.<variable_name>でVim script変数を管理できます。
-- let g:hoo = 1
vim.g.hoo = 1
-- unlet g:hoo
vim.g.hoo = nil
-- let b:hoo = 1
vim.b.hoo = 1
-- let g:filename#variablename = 0
-- `''` で囲まないとエラーになります。
vim.g['filename#variablename'] = 0
vim.api.nvim_***_{set|get|del}_varでも、Vim script変数を管理できます。
vim.{b|w|t}
と違い、バッファ/ウィンドウ/タブを指定できます。
- グローバル(
g:
): nvim_set_var - バッファ(
b:
): nvim_buf_set_var - ウィンドウ(
w:
): nvim_win_set_var - タブ(
t:
): nvim_tabpage_set_var - Vimの定義済(
v:
): nvim_set_vvar
option
vim.{o|go|bo|wo}.<option_name>でoptionの値を変更・取得できます。
-- set cmdheight=2
vim.o.cmdheight = 2
-- set cmdheight?
print(vim.o.cmdheight)
-- 切り替えオプションはbooleanを利用します。
-- set noruler
vim.o.ruler = false
-- 略名も使えます。
-- set slm=""
vim.o.slm = ""
-- optsには {cmdheight = 2, ...} のようなオプションと値のobjectが格納されています。
for opt, val in pairs(opts) do vim.o.[opt] = val end
set
のようにグローバルとローカル両方変変更したい場合は o
を使います。
-- set cmdheight=1
vim.o.winminheight = 1
setglobal
のようにグローバルの値だけを変更する場合は go
setlocal
のようにローカルの値だけを変更する場合は bo
or wo
を使います。
:help '<option-name>'
で表示されるhelpに
global
ならグローバル、local to {window|buffer}
ならローカルオプションです。
-- setglobal laststatus=0
vim.go.laststatus = 0
-- setlocal nonumber
vim.wo.number = false
ローカル(bo
or wo
)の場合は、バッファとウィンドウの番号を指定できます。
0の場合は、カレントバッファ/ウィンドウを指定します。
vim.bo[0].tabstop = 2
opt
も o
と同じように set
のように動作します。
オプションの値を返すとき、o
と opt
で値が違います。
o
の場合は文字列、数値、真偽値を返します。
opt
の場合はoption objectを返します。
-- set showtabline=0
vim.opt.showtabline = 0
print(vim.o.colorcolumn) -- 80
print(vim.inspect(vim.opt.colorcolumn)) -- { _info = { ... }, _name = "colorcolumn", _value = "80", <metatable> = <1>{ ... } }
print(vim.inspect(vim.opt.colorcolumn:get())) -- { "80" }
set+=
set-=
set^=
と同じ動作をするメソッドが opt
にはあります。
-- set tabstop+=10
vim.opt.tabstop:append(10)
vim.o.tabstop = vim.opt.tabstop + 10
-- set tabstop-=10
vim.opt.tabstop:remove(10)
vim.o.tabstop = vim.opt.tabstop - 10
-- set backupdir^='~/.config/nvim'
vim.opt.backupdir:prepend('~/.config/nvim')
opt
は set
に対応しており、
opt_global
は setglobal
、opt_local
は setlocal
に対応しています。
-- setlocal foldlevel+=2
vim.opt_local.foldlevel:append(2)
lua vim.wo.foldlevel = vim.wo.foldlevel + 2
vim.api.nvim_***_{set|get}_optionでも、optionの値を変更・取得できます。
ただ、set
や vim.o
のようにグローバル・ローカル両方の値を変更できません。
-
go
: nvim_set_option -
bo
: nvim_buf_set_option -
wo
: nvim_win_set_option
Keymap
vim.api.nvim_set_keymapとvim.api.nvim_buf_set_keymapを使います。
-- nnoremap <silent> <C-w>d :bdelete<CR>
vim.api.nvim_set_keymap('n', '<C-w>d', ':bdelete<CR>',
{ noremap = true, silent = true })
-- mapsには {l = 'Lint', ...} のようなkeyとコマンドのdictが格納されています。
for key, cmd in pairs(maps) do
vim.api.nvim_set_keymap(
'n',
'<leader>' .. key
':ALE' .. cmd .. '<CR>',
{ noremap = true, silent = true }
)
end
vim.keymap.nnoremap { '<leader>h', function() print("Hello world") end }
のような書き方ができるAPIを開発中です。astronauta.nvimをインストールすると、開発中のAPIを使用できます。
関数
vim.fn.<func_name>を使います。
-- call abs(1)
vim.fn.abs(1)
-- call filename#funcname(1)
vim.fn['filename#funcname'](1)
Vim script実行
vim.cmdを使います。
-- echo 123
vim.cmd('echo 123')
次の設定のinterfaceは現在実装されていませんが、実装される予定はあります。
vim.cmd
でVim scriptを書いても設定できます。
- User commandの作成
- autocmdの定義
-
Syntax/Highlightの定義
colorbuddy.nvim: Your color buddy for making cool neovim color schemes
Luaファイルの読み込み
Vim scriptで書かれた設定 init.vim
の代わりに、luaで書かれた設定 init.lua
を読ませることができます。 init.lua
を置く場所は init.vim
と同じです。両方は読み込めず、両方ある場合は Conflicting configs: ...
のメッセージが表示されます。
require
require('file_path')
でluaファイルをモジュールとして読み込みます。Neovimの runtimepath
ディレクトリ内の lua
ディレクトリに格納されているLuaファイルを require
で読み込めます。
例
init.vim
-
lua require('plugins')
~/.config/nvim/lua/plugins/init.lua
を読み込みます。 -
lua require('plugins.completion')
~/.config/nvim/lua/plugins/completion.lua
を読み込みます。 -
lua require('plugins/completion')
.
or/
どっちでもOKです。.
のほうがよく見ます。
ディレクトリ構成
# `~/.config/nvim` は `runtimepath` に含まれるディレクトリです。
~/.config/nvim
> ls init.vim lua/plugins/
init.vim
lua/plugins/:
completion.lua finder.lua linter.lua parser.lua
download_plugin_manager.lua git.lua lsp.lua status_and_tab_line.lua
filer.lua init.lua markdown.lua template.lua
require
はモジュールをキャッシュします
require
でロードしたモジュールを変更した後、変更したモジュールをもう1度 require
しても、モジュールは更新されません。どのモジュールをロードしたか require
が記憶しているからです。
packer.loaded
グローバルテーブルを変更すれば、モジュールを更新できます。
package.loaded['module_name'] = nil
require('module_name')
モジュールを更新するプラグイン
-
lreload.nvim
Luaモジュールのhot-reloadingができます。 -
nvim-lua/plenary.nvim
Luaライブラリで、モジュール更新をする関数があります。
自動で読みこまれるLuaファイル
runtimepath
内の特定のフォルダ内にあるluaファイルを自動的に読みこみます。
現在、次のフォルダ内のluaファイルを読みこみます。
- colors
- compiler
- ftplugin
- ftdetect
- indent
- plugin
- syntax
Luaと他言語のプラグインの違い
他言語よりLuaで実装したプラグインのほうが処理速度は速いです。LuaはNeovim内部で動くため、プラグインとNeovim間のRTT(Round-Trip Time)が他の言語より短いです。
Vim scriptやLua以外の言語はRPC(MessagePack-RPC)を使用して、Neovimを動かせます。Luaと違いNeovim内部で完結しているわけではないため、LuaよりRTTが長くなります。
Vim9 script
VimでもVim scriptを改良したVim9 Scriptを開発中です。今までのVim scriptより書きやすく、速度も改善されています。LuaJITが有効ではないLuaより処理速度が速いです。開発中なので処理速度は今より速くなる可能性があります。Vim8.2のhelp fileに記載されている通り、開発中のVim9 scriptはVim8.2で試せます。
NeovimがVim9 Scriptに対応するかどうかは調べておらず、対応するという情報は見つけていません。ただ、NeovimのコントリビューターのTJさんがLuaJITとLPEGを利用してVim9 scriptのparserを開発しているようです。
Lua製のプラグイン
紹介するプラグインの大半は、開発中のv0.5のNeovimであることが必須条件です。
Packer.nvim
emacsのuse-packageに触発されたplugin/package managerです。
Packer.nvimの作者によるdein.vimとの比較
特徴
-
Native Packagesを使ってプラグインを読み込む
プラグインの読み込みはpackadd
を利用するpackages
なため、Packer.nvim
を利用しないor削除してもプラグインは読み込まれます。 - Luaで設定を書ける
- プラグインの遅延読み込みができる
- プラグインの依存関係を設定できる
- Post-install/update hook対応
- Luarocks対応
詳細
Native Packagesを使ってプラグインを読み込む
Packagesはプラグインを含むディレクトリで、プラグインの数は1つor複数どちらでも大丈夫です。Pacakgesになるディレクトリは packpath
(set packpath?
で表示)にある pack
という名前のディレクトリです。
PacakgeはNeovim起動時にプラグインを runtimepath
へ追加して、scriptを読み込むか選択できます。これはプラグインを置いたディレクトリで決まります。
ディレクトリ | 起動時にプラグインを読み込むか |
---|---|
start |
O |
opt |
X |
起動時に読み込まない opt
ディレクトリ内のプラグインは packadd <direcotry_name>
で読み込みます。次のls結果の opt/
内にある packer.nvim
を読み込む場合 packadd packer.nvim
を実行します。packadd! <direcotry_name>
のように !
をつけた場合は runtimepath
へ追加されますが、プラグインのファイルやftdetect scriptsは読み込まれません。runtimepath
に追加されるため、プラグインのautoload関数は使えます。この packadd!
は init.vim
や .vimrc
に書くときに便利です。
# `~/.local/share/nvim/site` はpackpathに含まれます。
# packpathの `~/.local/share/nvim/site` にある `pack` ディレクトリ内の
# `packer` がpacakgesになります。
~/.local/share/nvim/site/pack/packer
> ls opt/ start/
# 起動時に読み込まないプラグイン
opt/:
ale neosnippet.vim popup.nvim vim-fugitive
auto-pairs nnn.vim preview-markdown.vim vim-quickrun
completion-buffers nvim-treesitter sonictemplate-vim vim-surround
completion-nvim nvim-treesitter-context tcomment_vim
completion-treesitter packer.nvim telescope.nvim
neosnippet-snippets plenary.nvim undotree
# 起動時に読み込むプラグイン
start/:
indentLine nvim-lsp tokyonight-vim vim-gitgutter vimdoc-ja
start
のプラグインを読み込む手順は次のとおりです。
-
init.vim
を読み込む -
start
ディレクトリ内のプラグインを読み込む -
plugins
ディレクトリ内のファイルを読み込む
このため pluigns
ディレクトリに start
のプラグインに依存しているVim scriptを書いてもエラーは発生しません。
Packer.nvim
の大きな役割は次の2つです。
- プラグイン管理
- Install(
PackerInstall
) - Update(
PackerUpdate
) - 使用しないプラグインの削除(
PackerClean
)
- Install(
- プラグインの設定をするVim scriptファイルの生成(
PackerCompile
)
デフォルトで~/.config/nvim/plugin/packer_compiled.vim
として出力します。~/.config/nvim/plugin
内のVim scriptは起動時に読み込まれるので、起動時に生成した設定ファイルは読み込まれす。 起動時に読み込むプラグインはplugin
ディレクトリ内のscirptを読み込む前に利用できますのでエラーは発生しません。
設定ファイルに書き込まれる内容は次のようなものがあります。- Neovim起動時に読み込む設定 (e.g. 変数やキーマップ)
起動時に読み込むプラグインの場合Neovim起動時 = プラグイン読み込み時になりますが、遅延読み込みするプラグインの場合は違います。 - プラグイン読み込み時の設定 (e.g. 変数やキーマップ)
- 遅延読み込みするプラグインの読み込むトリガー
- 特定keyを押す
- 特定のfiletypeのバッファを開く
- 特定のcommand or eventを実行
- Neovim起動時に読み込む設定 (e.g. 変数やキーマップ)
この2つの動作をするときに packer.nvim
を読み込むよう作成者のWil Thomasonさんは設定しており、Neovim起動時に packer.nvim
を読み込んでいません。
Luaで設定を書ける
次のように利用するプラグインを設定していきます。
return require('packer').startup(function()
-- `packer.nvim` を管理するプラグインに追加します。
-- `opt` はプラグインの設定の1つです。値の意味は後述します。
use { 'wbthomason/packer.nvim', opt = true }
-- 1つの `use` で複数のプラグインを追加できます。
use { 'tpope/vim-fugitive', 'airblade/vim-gitgutter' }
use {
{
'nvim-lua/completion-nvim',
event = 'InsertEnter *',
config = function() vim.cmd('packadd completion-buffers') end
},
{ 'steelsojka/completion-buffers', opt = true },
}
end)
プラグインの設定の1つの config
はプラグイン読み込み時に実行するコードを記載します。プラグイン読み込み時なので、起動時に読み込まない遅延読み込みのプラグインの場合はNeovim起動時に実行されません。遅延読み込みするプラグインでNeovim起動時に実行したいコードがある場合は setup
を使います。
use {
'tpope/vim-fugitive',
config = function()
local maps = {s = 'status', ... }
for key, cmd in pairs(maps) do
vim.api.nvim_set_keymap('n', '[git]' .. key, ':G' .. cmd .. '<CR>',
{ noremap = true, silent = false })
end
end
}
Luaの require
を使い、プラグインを複数のファイルに分けることができます。
return require('packer').startup(function()
-- for _, path in pairs{ 'git', ... } do use(require('plugins.' .. path)) end
-- でもOKです。
vim.tbl_map(
function(path) use(require('plugins.' .. path)) end,
{
'git', 'template', 'linter', 'status_and_tab_line', 'parser', 'finder',
'lsp', 'filer', 'completion', 'markdown'
}
)
end)
return {
{
'tpope/vim-fugitive',
-- 長いコード
},
{
'airblade/vim-gitgutter'
}
}
# `~/.config/nvim` はruntimepahtに含まれるディレクトリです
~/.config/nvim
> ls init.vim lua/plugins/
init.vim
lua/plugins/:
completion.lua finder.lua linter.lua parser.lua
download_plugin_manager.lua git.lua lsp.lua status_and_tab_line.lua
filer.lua init.lua markdown.lua template.lua
プラグインの遅延読み込みができる
use { 'wbthomason/packer.nvim', opt = true }
の opt
はプラグインの設定の1つです。opt
が true
ならプラグインを opt
ディレクトリに配置して、起動時読み込まないようにします。読み込む場合は packadd <plugin_name>
を使います。opt
を記載しない場合の値は設定で変更でき、デフォルトでは false
です。
opt
以外にも遅延読み込みプラグインに設定するオプションは次があります。設定するとプラグインは opt
ディレクトリに配置され、起動時に読み込まれません。起動時に読み込むプラグインを遅延読み込みに変更する場合は PackerUpdate
が必要です。
key | プラグインを読み込む瞬間 |
---|---|
cmd | 値のcommandを実行 |
ft | 値のfiletypeのバッファを開く |
keys | 値のkeyを押す |
event | 値のeventを実行 |
cond | 値のtestが通ったとき |
setup | なし |
use {
'skanehira/preview-markdown.vim',
-- プラグインを読み込むトリガーが2つある場合、
-- 1つでも条件が成立したときに
-- プラグインは読み込まれます。
ft = 'markdown',
cmd = 'PreviewMarkdown',
setup = function()
-- `<M-r>m` で `cmd` のコマンドを実行するので、
-- `<M-r>m` を押せば、プラグインは読み込まれます。
-- `setup` ではなく `config` にキーマップのコードを書いた場合、
-- プラグイン読み込み時にキーマップが登録されるので、
-- `<M-r>m` を押しても何も反応せず、プラグインも読み込まれません。
vim.api.nvim_set_keymap('n', '<M-r>m', ':PreviewMarkdown<CR>',
{ noremap = true, silent = true })
end,
config = function()
vim.g.preview_markdown_parser = "mdcat"
vim.g.preview_markdown_vertical = 1
vim.g.preview_markdown_auto_update = 1
end
}
プラグインの依存関係を設定できる
requires
keyを使い依存するプラグインを設定できます。
use {
...
requires = { 'depend/plugin' },
},
依存されている(i.e. depend/plugin
)のプラグインがない場合、デフォルトではインストールします。インストールしないようにすることもできます。
依存しているプラグインが利用されていない場合、 requires
内のプラグインは必要ないプラグインとなり PackerClear
で削除されます。
-- PackerCleanすると両方のプラグインは削除されます。
use {
'plugin/a',
opt = true,
-- プラグインを無効にして利用しないようにします。
disable = true,
requires = { 'plugin/a', opt = true },
}
-- 1つの `use` で複数のプラグインを設定している場合
-- `plugin/a` のみ削除されます。
use {
{ 'plugin/a', opt = true, disable = true },
{ 'plugin/b', opt = true },
},
Post-install/update hook対応
installer
や updater
, run
を使えばプラグインをinstall,update時に指定の処理を実行できます。
use {
'iamcco/markdown-preview.nvim',
-- Install,Update時に実行する処理
run = 'cd app && yarn install'
}
run
が文字列の場合、先頭の文字が :
ならneovimのコマンドが実行され、:
ではない場合shellコマンドとして実行されます。Shellの場合 $SHELL -c 'cd <plugin dir> && <run>'
で実行します。
Luarocks対応
-
rocks
: プラグインに依存しているrocksを設定します -
use_rocks
: インストールするrocksを設定します
注意事項
PackerCompile
を実行しないと設定は反映されません
config
や event
などの設定を変更しても PackerCompile
を実行して packer_compiled.vim
を更新しないと設定は反映されません。use { ... }
を記載している設定ファイルではなく、 PackerCompile
で出力している packer_compiled.vim
を、Neovimが起動時に読み込んでいるからです。
PackerCompile
を変更するたびに実行するのがめんどくさい場合は autocmd BufWritePost plugins.lua PackerCompile
のような設定をしてください。
config
や setup
の値の関数にエラーがあっても PackerCompile
実行時に発生しません
設定内のLuaにエラーがある場合、 PackerCompile
実行時にエラーは発生します。 config
に文字列を設定した場合もそうです。しかし config
に関数を設定し、その関数内にエラーがある場合 PackerCompile
実行時ではなく、プラグインが読み込まれ関数を実行するときにエラーは発生します。setup
や cond
も同じです。
関数の場合なので config = require('<存在しないプラグイン名>')
の場合は PackerCompile
実行時にエラーが発生します。config = function() require('<存在しないプラグイン名>') end
の場合は発生せず、関数実行時に発生します。
vim:config = function() require('<存在しないプラグイン名>') end
のときのエラー内容
" `packer_compiled.vim` は `PackerCompile` で生成するファイル
Error detected while processing ... /plugin/packer_compiled.vim:
line 297:
E5108: Error executing lua [string "..."]:0: module 'aaa' not found:
no field package.preload['aaa']
no file './aaa.lua'
...
PackerUpdate
する必要があります
遅延読み込みのON・OFFの変更は use { ..., opt = false }
の opt
を true
に変更して、起動時に読み込むのではなく遅延読み込みに変更する場合 PackerCompile
を実行して packer_compiled.vim
を更新し設定を変更するだけでは駄目です。PackerUpdate
を実行する必要があります。
実行しないとプラグインが start
ディレクトリに存在するため、Neovimが起動時に読み込んでしまい、遅延読み込みになりません。PackerUpdate
を実行してプラグインのディレクトリを start
から opt
に移動すれば、起動時に読み込まれません。
遅延読み込みから起動時読み込むに変更するときも同じです。
この PackerUpdate
忘れによる start
と opt
ディレクトリの移動し忘れは config
や setup
などでエラーが発生する原因になります。
PackerClean
をする必要があります
起動時に読み込むプラグインの削除する場合は 起動時に読み込むプラグインを削除したい場合、そのプラグインの use
のコードを削除して PackerCompile
して設定を変更するだけでは駄目です。 start
ディレクトリにプラグインが残っているので起動時にNeovimはそのプラグインを読み込みます。 PackerClean
を実行して start
ディレクトリから削除する必要があります。disable = true
も同じです。
PackerUpdate
を実行しても削除はしません。PackerSync
を実行すれば PackerClean
をやったあとに PackerUpdate
を実行してくれます。
use
や requires
のプラグインが複数の場合、tableで書かないとオプションは適用されません
次の設定で completion-nvim
はインストールされますが {}
で囲まれていないので event
や config
の設定は PackerCompile
しても packer_compiled.vim
に反映されません。そのため completion-nvim
は遅延読み込みではなく、起動時に読み込まれます。
{}
で囲まれてないから PackerCompile
時にエラーが発生することはありません。
use {
-- `{}` に囲まれていないため
-- `{ 'nvim-lua/completion-nvim', { ... }` と
-- 同じ設定になります。
'nvim-lua/completion-nvim',
event = 'InsertEnter *',
config = vim.cmd('packadd completion-buffers')
{ 'steelsojka/completion-buffers', opt = true },
}
-- `requires` の場合も同じなのでtableにする必要があります。
use {
...,
requires = {{ 'plugin/a', opt = true }, { 'plugin/b', opt = true }}`
}
nvim-lspconfig
v0.5で実装される組込みのLSP(Language Server Protocol)クライアント用の共通設定集です。
組み込みのLSPクライアントの設定が簡単になるだけで、これがないと組み込みのLSPクライアントが使えず、LSPの機能が使えないというわけではありません。クライアントはneovim本体に組み込まれており、Luaで書かれています。なぜNeovimにLSPクライアントが組み込まれたかはtjさんの動画が参考になります。
vim-lspやcoc.nvim,LanguageClient-neovimなどの有名なLSPクライアントとNeovimの組み込みのLSPクライアントとの違いなどは次の記事を参考にしてみてください。
- Vim で使える LSP クライアント各種を使った感想
- Why I still prefer LSC to Neovim LSP + completion.nvim, even as Neovim user : neovim
利用方法
Luaのlanguage serverを利用するには次の手順でやります。
- nvim-lspconfigをインストール
- LuaのLSP serverのsumneko_luaをインストール
両方ともbuild systemのninjaが必要です。- 手動
sumneko_luaのwikiの手順でインストールします。
CONFIG.mdの設定をそのまま使用したいのでgit clone https://github.com/sumneko/lua-language-server
はgit clone https://github.com/sumneko/lua-language-server ~/.cache/nvim/lspconfig/sumneko_lua/lua-language-server
に変更します。 -
nvim-lspinstallを利用
nvim-lspinstallをインストールし、LspInstall sumneko_lua
コマンドを実行します。
~/.local/share/nvim/lspinstall/lua-langauge-server
に配置されます。
- 手動
-
init.vim
orinit.lua
にCONFIG.mdの設定を追加
nvim-lspinstallの場合はsumneko_root_path
をvim.fn.stdpath('data') .. '/lspinstall/lua-langauge-server'
に変更してください。 - Neovimを再起動
-
set ft=lua
で編集中のバッファをluaに変更する -
sumneko_lua
が起動して、編集中のバッファに接続する
診断機能が有効になっているのでsyntax errorがあると、syntax errorの診断メッセージがvirtual textで表示されます。
LspInfo
で起動しているLSPクライアントや編集中のバッファと接続しているLSPクライアントの情報がわかります。動かない場合はcheckhealth
を実行してみましょう。
定義ジャンプやsymbol参照などの方法は help lsp-config
やslinさんのNeovimのBuiltin LSPを使ってみるを参照してください。LSPで何ができるかは北川亮さんのvim-lspでできることも参考になります。vim-lspについて書いてますが、大体はNeovimの組み込みのLSPでもできるはずです。
注意事項
LspIntall
と LspInstallInfo
の廃止
Remove all installers and install logic #498により廃止されました。Pull requestの作成者のmjlbachさんのコメントを読むと次の2点があるようです。
- LSP serverが古いせいで発生するbugを修正する仕組みがない
- LSP serverをインストールできるソース(npm, linux package manager, brew)が多種多様で、全てをサポートするのが大変
今後LSP serverをインストールする際は次の手段があります。
- CONFIG.mdを読みながら手動でする
- vim-lsp-settingsを使う
-
nvim-lspinstallを使う
CONFIG.mdの全てをまだインストールできません。将来的には全てできる予定です。 -
nvim-lspupdateを使う
インストールとアップデート、両方できます。
LSP関連の他のプラグイン
-
lspsaga.nvim
定義や参照一覧、定義やdocument情報をfloating windowで表示できます。 -
nvim-lsputils
使用できるcode actionsをfloating windowで表示したり、定義ジャンプやsymbol参照の一覧とそのpreviewをquickfixを使って表示できます。 -
nvim-lspfuzzy
FZFを利用して、定義ジャンプなどのLSP操作を行います。 -
nvim-lightbulb
現在の行でtextDocument/codeAction
ができるか表示します。 -
aerial.nvim
Symbolsを目次形式で表示し、選択したsymbolに移動します。 -
folding-nvim
折りたたみにLSPを使います。 -
nvim-lsp-smag
NeovimにLSPをシームレスに統合できるようにして、タグファイルまたはvim.lsp.client
を利用する処理全体を単純化します。tagfunc
オプションを利用して、tagの検索方法をカスタマイズできます。 -
lsp-status.nvim
組み込みのLSPクライアントからstatuslineのcomponentを生成します。 -
onsails/lspkind-nvim
VSCode-like iconsを追加します。 - lsp_extensions.nvim
diagnostics
-
nvim-ale-diagnostic
Neovim LSPのdiagnostics結果をaleで表示します。
言語特有のプラグイン
-
nvim-lsp-ts-utils
TypeScriptの開発を支援します。-
importの整理(
LspOrganize
)
未使用importの削除&並べ替えを行ないます。 - 現在行に利用可能なコードアクション(
vim.lsp.buf.code_action()
)を利用(LspFixCurrent
)
複数ある場合は1番最初のコードアクションを実行します。 - ファイル名変更とimportの更新(
LspRenameFile
) - 足りないimportを追加(
LspImportAll
)
-
importの整理(
coc.nvimの違い
組み込みのLSPクライアントとnvim-lspconfigのコントリビューターのmjlbachさんのコメントを自分なりに解釈して、それをまとめた文です。
- 組み込みのLSPクライアントは拡張性が高く、neovimの設定を変更すれば多くの点を変更できる
全てluaで書かれているため、簡単にカスタマイズできます。ハンドラベースで、動作を上書きするのも非常に簡単です。 - nvim-lspconfigはCocプラグインと同等の機能を提供しない
エコシステムではなく、最低限のdefault機能を提供するのをnvim-lspconfigは目的としているからです。nvim-jdtlsのようなCocプラグインと同等の機能を持ったプラグインは今後増えていく可能性があります。
参考にしたコメント
- Why should I use the in built LSP over coc.vim? : neovim
- How to use (and contribute) to neovim's built-in language server client and nvim-lspconfig : neovim
nvim-treesitter.nvim
Tree-sitterの設定をするプラグインです。Neovimに存在するtree-sitterのlibraryを利用しています。
Tree-sitterとは
詳細
役割
- Parserの作成
- 漸進的分析(Incremental Parsing) library
特徴
- Concrete Syntax Treeを構築します
()
などの言語の意味を理解するのに必要ないものを省略して、意味のある部分だけを抽出したAbstract Syntax Treeと違い、省略せず全てのコードの情報を持っています。全ての情報を持っているためsyntaxに一致するコードの開始と終了位置がわかります。それによりsyntaxが別のsyntax内に含まれているのがわかり、プログラミング言語の文法としてそのsyntaxがどのような意味を持つか正確に把握できます。(この理解であっている自信がありません。間違っていたら教えていただくとありがたいです) - 変更部分のみを分析してsyntax treeを更新します
大きなsyntax tree(e.g. 長いコードや複雑なコード)であっても、変更部分のみを分析更新するため、処理速度が速いです。
Tree-sitterの公式サイトでtree-sitterを試せて、syntax treeの動きを確認できます。
目標
- どんなプログラミング言語でもparsesする
- Key操作全てを解析できる速さ
- Syntax errorがあっても有効な情報を提供する
- 任意のアプリケーションへ組み込めるようにする
tree-sitterは純粋なC言語で書かれているため依存しているものはありません。
エディタのどの機能に役立つか
実際に動かしている動画がリンク先にあります。
-
Syntax Highlighting
今まで色がついてなかった文字に色がつきます。 -
Code Folding(折りたたみ表示)
Indentとsyntaxが一致しない場合でも関数などが折りたたみ表示されます。 -
Extend Selection(範囲選択拡大)
1つ上のスコープなどに選択範囲を拡大などができます。 -
Refactoring with Extend Selection
選択範囲のコードを変更できます。選択範囲は複数かつ、離れ離れでもOKです。
Language serversとの比較
- ParseがLanguage serverより速い
- 依存関係がない
Language serverはそれぞれに依存関係がある
機能
-
highlight
今まで色がついてない部分に色がつきます。 - Incemental selection
textobject単位の選択の拡大ができます。 - Indent
Indentを整える(={motion}
)処理をTreesitterのparseをもとにおこないます。
追加モジュールとプラグイン
モジュール
-
-
ip
やap
のようにtextobjectを選択します。 - 前後のtextobjectに移動します。
- 関数の引数などの順番の前後を交換します。
- textobject全体をfloating windowを使って表示します。
Neovimの組み込みのLSPが必要です。 - textobjectは設定で変えられます。
言語によって利用できるtextobjectは違います。今後追加される可能性があります。
-
-
- カーソルの下にあるsymbolの定義位置に移動したり、定義されているsymbol一覧を表示します。
- カーソルの下にあるsymbolをrenameします。
同じスコープ内のsymbolが対象のため、違うスコープ内のsymbolはrenameされません。 - カーソルの下にあるsymbolをhighlightします。
同じスコープ内のsymbolが対象のため、違うスコープ内のsymbolはhighlightされません。
Colorschemeの設定でhighlightされているか分かりづらいことがあります。 - カーソルが存在するスコープ全体をhighlightします。
Colorschemeの設定でhighlightされているか分かりづらいことがあります。
-
rainbow
vim-rainbowのように括弧(e.g.{([])}
)の色をネストごとに変更します。 -
nvim-ts-autotag
HTMLタグの終了タグを自動的に挿入します。rename機能もあります。HTML専用のようです。
プラグイン
-
context
関数の引数部分や直近のif文の条件を常に表示させるようにします。リンク先のgifを見ればどんな機能かわかります。
tree-sitterなしで同じ機能をcontext.vimでもできますが、信頼性が低く、正しく表示できないことがあるみたいです。context.vim
がnvim-treesitter-context
の機能を統合する予定はあるようです。 -
sidekick.nvim
関数や変数一覧を表示し、選択した定義に移動します。
Command
-
TSInstall {language}
language
のparserをインストールします。TSInstall
のときにtabを押せば対応している言語一覧が表示されます。all
の場合全てインストールします。
checkhealth
でインストールしたparserの状態を確認できます。 -
TSUninstall {language}
language
のparserをuninstallします。 -
TSInstallInfo
対応している言語のparserをインストールしているか確認できます。 -
TSUpdate
インストールしているparser全てをupdateします。 -
TSConfigInfo
tree-sitterの設定情報を表示します。
設定方法
context以外の機能はモジュールにあたり、デフォルトで無効になっているため動きません。動かすには TSEnableAll <機能名>
を使うか設定を変えます。contextはデフォルトで有効になっているため動きます。
設定例
require'nvim-treesitter.configs'.setup { -- 設定された言語のparserがインストールされていない場合、
-- インストールします。
ensure_installed = {'ruby', 'lua'},
highlight = {
-- `false` の場合、highlight機能を動かしません。
enable = true,
-- highlightの機能を無効にする、filetypeを指定します。
disable = { "bash", "c" },
},
incremental_selection = {
enable = true,
keymaps = {
-- 範囲選択を開始します。
init_selection = "gnn",
-- 1つ上のnodeに選択範囲を拡大します。
node_incremental = "grn",
-- 1つ上のスコープに選択範囲を拡大します。
scope_incremental = "grc",
-- 1つ下のnodeに選択範囲を縮小します。
node_decremental = "grm",
},
},
indent = {
enable = true
},
textobjects = {
-- `ip` や `ap` のようにtextobjectを選択します。
select = {
enable = true,
keymaps = {
["af"] = "@function.outer",
["if"] = "@function.inner",
["ac"] = "@class.outer",
["ic"] = "@class.inner",
},
},
-- 前後のtextobjectに移動します。
move = {
enable = true,
goto_next_start = {
["]m"] = "@function.outer",
["]]"] = "@class.outer",
},
goto_next_end = {
["]M"] = "@function.outer",
["]["] = "@class.outer",
},
goto_previous_start = {
["[m"] = "@function.outer",
["[["] = "@class.outer",
},
goto_previous_end = {
["[M"] = "@function.outer",
["[]"] = "@class.outer",
},
},
-- 関数の引数の位置を交換します。
swap = {
enable = true,
swap_next = {
["<leader>a"] = "@parameter.inner",
},
swap_previous = {
["<leader>A"] = "@parameter.inner",
},
},
-- textobject全体をfloating windowを使って表示します。
lsp_interop = {
enable = true,
peek_definition_code = {
["df"] = "@function.outer",
["dF"] = "@class.outer",
},
},
},
refactor = {
-- カーソルの下にあるsymbolの定義位置に移動したり、
-- 定義されているsymbol一覧を表示します。
navigation = {
enable = true,
keymaps = {
-- 定義に移動します。
goto_definition = "gnd",
-- 定義一覧を表示します。
list_definitions = "gnD",
-- 定義一覧を本の目次のようにネストがわかるように表示します。
list_definitions_toc = "gO",
-- カーソル下のsymbolの前後の利用位置に移動します。
goto_next_usage = "<a-*>",
goto_previous_usage = "<a-#>",
},
},
-- カーソルの下にあるsymbolをrenameします。
smart_rename = {
enable = true,
keymaps = {
-- `grr` でrename処理が開始できます。
smart_rename = "grr",
},
},
-- カーソルの下にあるsymbolをhighlightします。
highlight_definitions = { enable = true },
-- カーソルが存在するスコープ全体をhighlightします。
highlight_current_scope = { enable = true },
},
-- 括弧の色をネストごとに変更します。
rainbow = {
enable = true
},
}
Colorschemes
nvim-treesitterから定義されたhighlight groupを利用しているcolorschemesがあります。
-
nvim-treesitterのWiki
colorschemeのpreviewがあります。 - awesome-neovim
-
nvcode-color-schemes.vim
開発している生放送のアーカイブ
completion-nvim
非同期の補完フレームワークです。組み込みのLSPに補完を提供するのが目的です。
機能
-
選択した補完のドキュメント情報を表示
-
Snippet pluginとの連携
g:completion_enable_snippet
で設定できます。デフォルトの値はv:null
です。
新しいsnippet pluginのdeoppet.nvimを開発しているShougoさんのスニペットプラグインについて 2020 年版を読めば利用できるSnippetの特徴がわかります。- snippets.nvim
- Neosnippet
- UltiSnips
-
vim-vsnip
vim-vsnip-integがあればLSPを利用したsnippetも利用できます。ただ、neovimのbuilt-inのLSPのsnippetのデフォルト設定が無効に変更されたため、LSPの設定を変更する必要があるようです。また、vim-vsnip作成者のhrsh7thさんも自動補完プラグインのnvim-compeを開発しています。
-
補完のsourceを追加
設定方法
- 全てのバッファで機能を有効する場合
autocmd BufEnter * lua require'completion'.on_attach()
- LSPが有効なバッファ場合のみ機能を有効する場合
" `vimls` の部分は使用するlnaguage serverに変更してください。
lua require'lspconfig'.vimls.setup{on_attach=require'completion'.on_attach}`
telescope.nvim
NeovimのコントリビューターのTJさんが作成している組み込みのLSPやtree-sitterとの連携ができるfuzzy finderです。
fzfやfzy,skとの依存性はありません。fzfやfzyと連携したい場合は拡張機能を利用してください。
プレビュー表示もあり、batがあれば色付きで表示されます。
今回紹介する残りのfuzzy finderと違いtree-sitterと連携できます。
TJさんはこのtelescopeも含むプラグインやneovimの新機能の開発をtwitchで配信しています。redditのneovimのコミュニティでスレッドをたてたりコメントもしています。telescopeの作成理由もyoutubueに投稿しています。
fzfやfzf-preview,denite,ctrlpなどとの違いは、Tips集のKatapediaとプラグインの選択・管理のポイントを記載しているVimプラグイン"の"カテゴリまとめの作者のyutakatayさんのVimにたくさんあるファジーファインダー系プラグインを比較してみるを参考にしてみてください。
Picker
コマンドラインでの使い方
Telescope <piker_name>
で実行できます。
-
Telescope builtin
オプションなし -
Telescope git_files cwd=~/dotfiles
オプションを設定 -
Telescope find_files find_command=rg,--ignore,--hidden,--files
table型のオブションの場合は,
で区切る
次のpicker達は全てtelescopeに組み込まれています。独自のpickerを追加したい場合はREADMEのCustomizationやWikiのConfiguration Recipesが参考になります。
組み込まれているpicker一覧
ファイル名
-
find_files
(aliasfd
)
検索に利用するコマンドの優先順位はfd
=>fdfind
=>rg
=>find
です。 oldfiles
file_browser
Git
git_files
git_status
git_commits
git_bcommits
git_branches
Grep
grep_string
live_grep
tags
tags
current_buffer_tags
バッファ
buffers
marks
-
current_buffer_fuzzy_find
現在のバッファの行がリストされ、選択した行に移動します。
quickfix & location
quickfix
loclist
コマンド
commands
command_history
autocommand
autocommands
registers
registers
ヘルプ
help_tags
man_pages
キーマップ
keymaps
ファイルタイプ
filetypes
オプション
vim_options
colorscheme
colorscheme
highlight
highlights
spell
-
spell_suggest
オプションspell
が有効である必要があります。
パッケージ
-
reloader
選択したパッケージモジュールを再読込します。
LSP
lsp_references
lsp_definitions
lsp_workspace_symbols
lsp_document_symbols
lsp_code_actions
lsp_range_code_actions
lsp_document_diagnostics
lsp_workspace_diagnostics
treesitter
-
treesitter
編集しているバッファ内の関数や変数一覧から選択したものに移動します。
Telescope
-
builtin
実行できるpickerをリストし、選択したものを実行します。 -
planets
惑星のドット絵が見れます。
Layout
リストやプレビューなどのレイアウトは設定できます。デフォルトのレイアウトだと、ディスプレイが縦だとプレビューが表示されません。Dropdownを使えば縦画面でもプレビューは表示されます。
デフォルトのレイアウトを変更するには次のようにします。値はsupported layoutsが利用できます。
require'telescope'.setup{
-- 画面幅に応じたレイアウトになるため、
-- ディスプレイの向き関係なく、
-- プレビューが表示されます。
defaults = {layout_strategy = 'flex'}
}
拡張機能
-
DAP(Debug Adapter Protocol)
-
vimspector
PythonとVim scriptで書かれているvimspectorを利用します。 -
dap
Luaで書かれているnvim-dapを利用します。
-
vimspector
- fuzzy finder
-
frecency
MozillaのFrecencyアルゴリズムを利用して、最近使ったファイルの優先順位を高くします。 -
github
IssueやPull Request,gistを表示します。 -
ghq
ghq list
の結果を表示します。
もっと
-
z
z -l
を表示して、そのディレクトリに対してファイル検索(Telescope fd
),cd
やlch
を行います。 -
Packer
プラグイン管理のpackerで管理しているプラグイン一覧を表示します。 -
node-modules
node_modules
directory内のpackagesを検索して、そのpackageのdirectoryにcd
やlcd
を行ないます。 -
media-files
画像や動画、pdfなどのpreviewを見ます。 -
sonic-template
sonictemplateにあるtemplateを展開します。 -
memo
mattn/memoに対して、listやgrepを行ないます。 -
cheat
cheat.shの結果をします。cheat.shのデータはSQLiteに保存するのでsql.nvimが必要です。 -
snippets
snippets.nvimとの統合です。 -
symbols
絵文字や顔文字一覧を表示します。 -
openbrowser
設定したbookmark listから選択したURIをブラウザで開きます。
Package Manager
-
paq-nvim
シンプルなwrapperを目指している、小さい(約175行)なpackage managerです。Packerとは目指しているものが違うため、依存関係の設定や遅延読み込みはできません。
Fuzzy Finder
-
nvim-fzf
fzfを利用します。fzf.vimより使いやすく、カスタマイズ性が高いと主張しています。ただ、Files
やHistory
などのpickerは標準で実装されていません。Action APIでneovimの関数を利用して、preview windowに表示する情報を変更できます。これを利用するためにfzf.vimを削除する必要はありません。 -
fuzzy.nvim
telescopeから多くのアイデアを取り入れて作成されました。シンプルなAPIなので他のfuzzy finderのバックエンド追加は簡単です。組み込みのLSPを利用するコマンドも実装しています。 -
FZTerm
fzfを利用しています。こちらも組み込みのLSPにも対応しており、git blameのコマンドを実装しています。全てをカスタマイズできることを重視しているため、telescopeより拡張するのは簡単みたいです。 -
nvim-fzy
fzyに依存しています。
Statusline
-
express_line.nvim
Gitの情報を取得する関数が実装されています。組み込みのLSPの情報を取得する場合はlsp-status.nvimを使えばいいようです。 -
galaxyline.nvim
組み込みのLSPやcoc.nvimの診断結果を表示する関数があります。
Gitの情報を取得する関数がありますが、ブランチ名取得以外は次のgit signを表示するプラグインが必要です。 -
lualine.nvim
速さと簡単な設定を売りにしています。lightlineやairlineより速く、0.1秒でプラグインを読み込みます。テーマはいくつか内蔵されており、lualine.theme = 'onedark'
のように設定します。
galaxylineと比較した際、使いやすさはlualine、カスタマイズ性の高さはgalaxylineが良いと作者がredditでコメントしています。 -
neoline.vim
lightline.vimにインスパイされて作られており、statusとtab両方とも変更できます。 -
nvim-hardline
vim-airlineにインスパイアしており、簡単で軽いのを目標として作られています。statusとtab両方とも変更できます。 -
statusline.lua
設定は必要せず、他のプラグインと連携してgitの情報などを表示します。Tablineも変更できます。
表示する情報と連携できるプラグイン- Git diff: vim-signify
- Git branch: vim-fugitive
- Lint status: ale
-
bubbly.nvim
モードやファイル名をbubbleのような丸で表示します。
Tabline
-
barbar.nvim
- 全てのバッファをtablineに表示
- tabの並び替え
- ファイル名が同じバッファを開いた場合ディレクトリ名を追加して重複表示を防ぐ
-
nvim-bufferline.lua
バッファ選択や並び替えもできます。barbar.nvimと違う点は、1つのウィンドウで複数のバッファを開いているときにそのバッファだけをタブラインに表示するMulti-window modeがあることです。
補完
-
nvim-compe
vim-vsnip作成者のhrsh7thさんが開発している補完プラグインです。組み込みのLSPやvim-vsnip、hrsh7thさんが開発しているLSPクライアントのvim-lampと連携できます。
括弧・テキストオブジェクト
-
nvim-autopairs
lexima.vimのように閉じ括弧などを自動入力します。 -
nvim-ts-autotag
HTMLタグの終了タグを自動的に挿入します。rename機能もあります。HTML専用のようです。nvim-treesitterに依存しています。 -
surround.nvim
vim-surroundのように括弧や引用符などで囲まれているテキストを編集できます。
インクリメント・デグリメント
-
dial.nvim
日付(日本語も含む)やアルファベット、Markdownのヘッダー(#
)をインクリメント・デクリメントできます。独自のインクリメント・デクメントも定義できます。 -
nrpattern.nvim
標準のインクリメント・デクリメントを拡張します。dial.nvimとは違い、日付やアルファベットは自分で拡張しないとできません。独自のインクリメント・デクメントの定義はdial.nvimより設定項目が多いです。
デバック
-
nvim-dap
vimspectorのようにDAP(Debug Adapter Protocol)クライントをneovimに実装します。nvim-dap-virtual-textを使えば結果をvirtual textとして表示できます。また、telescopeと連携する拡張機能があります。
Linter/Formater
-
format.nvim
編集中のバッファをに対してformatを非同期で実行します。Luaで書かれている同じformatterプラグインのformatter.nvimのPRとして最初書いてましたが、アプローチを変えるため全て書き直して作成されました。
REPL
-
iron.nvim
NeovimからREPLを実行できるようにします。
Quickfix
インデント
-
indent-guides.nvim
vim-indent-guidesのようにindentに色をつけて表示します。VSCodeのindent-rainbowのような機能を実装予定です。
検索
-
nvim-hlslens
検索にヒットした行の右にvirtual textで何件目か表示します。virtual textの内容やhighlightは変更できます。
Git
-
gitsigns.nvim
vim-gitgutterのように、diffの結果を記号で行の左端に表示します。 -
git-blame.nvim
git blameをvirtual textとして表示します。 -
neogit
Emacsからgitリポジトリ操作ができるMagitのNeovim版です。Vimの概念に合わせていくつか変更する予定があります。
GitHub
-
octo.nvim
IssueとPRをNeovimから操作できます。ListIssues <repo>
でtelescopeと連携できます。 -
codeql.nvim
コードの脆弱性を発見するCodeQLを実行できます。
コメント
-
prodoc.nvim
コメント化・アノテーション追加します。 -
kommentary
コメントの切り替えを行います。
エクスプローラー
-
nvim-tree.lua
ツリー形式で表示します。ファイルの追加や削除、名前変更ができ、gitとの連携もできます。 -
lir.nvim
シンプルなエクスプロラーで、ディレクトリ表示時(e.g.e .
)にNetrw
の代わりに利用できます。 -
dirbuf.nvim
nvim-treeやvim-dirvish,vidirにインスパイアされています。 -
neofs
floating windowで表示します。
Colors
-
nvim-colorizer.lua
カラーコードのプレビューができ、外部依存関係はありません。
同じ機能を持つvim-hexokinaseはGo言語が必要です。 -
lush.nvim
colorscheme作成を支援します。色の変更をリアルタイムで反映します。
プロジェクト管理
-
nvim-projectconfig
~/.config/nvim/projects/{プロジェクト名}
(変更可能)にある、プロジェクト専用の設定ファイル(Vimscript or lua)を読み込みます。
lua require('nvim-projectconfig').load_project_config()
で設定ファイルの読み込み、lua.require("nvim-projectconfig").edit_project_config()
で設定ファイルを開きます。
ヘルプ
-
nvim-cheat.sh
cheat.shを利用して、色んなコマンドを表示します。
共同編集
-
instant.nvim
複数人で同じバッファを共有するライブ編集ができます。
コピー/ペースト
-
nvim-miniyank
kill-ringのように、yankの履歴を使えるようにします。
ターミナル
-
nvim-toggleterm.lua
neotermのように複数のターミナルウィンドウを簡単に管理できます。 -
FTerm.nvim
ターミナルをfloating windowで表示します。
アイコン
-
nvim-web-devicons
ファイルタイプのアイコンを追加するvim-deviconsのlua番 -
nvim-nonicons
Noniconsを利用したアイコンセットです。deviconとcodiconはcui用に設計されていないため、ターミナルだと見難いアイコンがあるため使用していないそうです。また、deviconはフォント間の統一性がなく、codiconにはファイルタイプのアイコンがないそうです。 -
codicons.nvim
VSCodeのcodiconを簡単に利用できるようになります。
スクロールバー
-
scrollbar.nvim
スクロールバーの見た目を変更します。
ウィンドウ
-
wintablib.nvim
ウィンドウやタブを操作する関数を提供します。- 左 or 右の全てのタブを閉じる
- 左 or 右のタブのバッファを、現在のタブで開く
- 編集中のバッファを新規タブで開く
タブは左右どちらに配置するか決めることができます。 - 全てのfloating windowを閉じる
- 上下左右のwindowを全て閉じる
マウス
-
gesture.nvim
マウスジェスチャーができるようになります。
コマンドライン
-
cmdbuf.nvim
q
=>:
で開けるコマンドラインウィンドウをバッファとして開きます。
モーション
-
hop.nvim
vim-easymotionのLua版で、1から書き直しています。 -
train.nvim
モーションを拡張します。
セッション
-
auto-session
自動でセッションを保存、読み込みを行ないます。
Markdown
-
glow.nvim
Floating windowにglowでレンダーしたMarkdownを表示します。glowを使うのでGo言語が必要です。同じ機能を提供するpreview-markdown.vimとは次が違います。- Floating windowで表示
- 対応レンダーはglowのみ
preview-markdownはmdrとmdcatにも対応しています。ただ、 glow.nvimのopen_window
内のapi.nvim_call_function("termopen", {string.format("glow %s", path)})
のglow
をmdcat
にコードを変更すればmdcat
でも動きます。 - 自動更新機能なし
preview-markdownは自動更新できますがVimのみでNeovimは対応していません。
設定
-
fey_neovim
Doom Emacsにインスパイアされた設定フレームワークで、minpacをパッケージマネージャーに使っています。
前まで表示してたもの
生活
-
weather.nvim
wttr.inを利用して、天気を表示します。
Mode
-
nvim-libmodal
このプラグインと連携するプラグインをインストールすれば、バッファやタブ管理する独自のモードを追加できます。
エクスプローラー
-
nvim-filetree
ツリー形式でファイルを表示します。
可視化
-
nvim-visual-eof.lua
EOLを⏎
などで可視化します。
ゲーム
-
vim-apm
1分間のキー操作の回数を表示します。 -
vim-be-good
Vimの基本の動きを練習するゲームができます。
Luaのプラグイン作成に役立つプラグインやドキュメント
プラグイン
-
nlua.nvim
Lua開発に役立つ機能を提供します。 -
nvim-luadev
Luaプラグイン用のREPLとdebug機能を提供します。 -
nvim-luapad
入力しているLuaのコードをリアルタイムで実行します。 -
manillua.nvim
Luaの折りたたみ表示を見やすくします。 -
lreload.nvim
Luaモジュールのhot-reloadingができます。
Library
-
plenary.nvim
Neovim専用のluaライブラリです。Luaモジュール用のpackage mangerのLuaRocksを使ってlua packageをインストールできます。 -
popup.nvim
VimのPopup APIと互換性があるAPIをNeovimに実装します。 -
vlog.nvim
Luaプラグインに簡単にログファイルを実装できます。依存性はありません。 -
neovim-plugin
プラグインのキーマップやコマンド、イベント設定をLuaのtable形式で設定できます。 -
impromptu.nvim
コマンドや関数を呼び出すためのプロンプトを簡単に作成できます。 -
sql.nvim
neovimからSQLiteを操作するwrapperです。
ドキュメント
- nvim-lua-guide
- jacobsimpson/nvim-example-lua-plugin
- How to write neovim plugins in Lua | 2n it sp. z o.o.
- Lua製Neovim pluginのテストをLuaで書く
- Lua製Neovim plugin開発でhot-reloading的な体験を得る
- Neovim Async Tutorial
- anthony-khong/nvim-education
参考資料
本文内でリンクを記載していない資料達です。
NeovimとLuaが相性が良い理由
- Developing plugins for Neovim, is there a guide or how-to? : neovim
- Neovim Development Streams! : neovim
Native Packages
- Vim 8.0 Advent Calendar 6 日目 パッケージ - Qiita
- Vim 8 時代のがんばらないプラグイン管理のすすめ - Humanity
- Vimのパッケージ機能を試してみました - Blank File
- Vim 8.0用のプラグインマネージャを作ってみた話 - Qiita
nvim-lspconfig
- Vimconf.live: Neovim Builtin LSP
- Neovim LSPSetup | Part 1
- Getting started with Nvim + LSP (Quick Start)
Discussion
いつも見てます。ありがとうございます。
prodoc.nvimのところが重複してるみたいです。以前はたしか1つ https://github.com/b3nj5m1n/kommentary だったかと
教えてくれてありがとうございます!!
修正しました。