Neovim 0.7がリリースされました。多くの新機能(そしてもちろんバグ修正も多数)が搭載されています。完全なリリースノートはこちらからご覧いただけますが、この記事では、いくつかの新しい追加機能についてのみご紹介します。
Neovim 0.5では、LuaがNeovimエコシステムの第一級市民として導入されました。Luaは、ユーザーの初期化ファイル、プラグイン、カラースキーム、ftpluginなど、.vim
ファイルを使用できる場所であればどこでも使用できるようになりました。基本的に、.lua
を代わりに使用できるようになりました。
しかし、当時のLua APIにはまだいくつかの欠点がありました。特に、Luaでオートコマンドを作成したり、キーマッピングをLua関数に直接バインドしたりする機能がありませんでした。これらのいずれかを実行するには、ユーザーはVimscript変換を介したラウンドトリップを含む回避策に頼る必要があり、これは少し扱いにくいものでした。
-- Using a Lua function in a key mapping prior to 0.7
local function say_hello()
print("Hello world!")
end
_G.my_say_hello = say_hello
vim.api.nvim_set_keymap("n", "<leader>H", "<Cmd>call v:lua.my_say_hello()<CR>", {noremap = true})
オートコマンドとカスタムユーザーコマンドについても同様でした。
Neovim 0.7では、Vimscript変換を必要とせずに、すべての通常の構成プリミティブ(キーマッピング、オートコマンド、ユーザーコマンドなど)をLuaで直接使用できるようになりました。これにより、キーマッピングとオートコマンドを*ローカル* Lua関数に直接バインドすることも可能になります。
-- Using a Lua function in a key mapping in 0.7
vim.api.nvim_set_keymap("n", "<leader>H", "", {
noremap = true,
callback = function()
print("Hello world!")
end,
})
-- Creating an autocommand in 0.7
vim.api.nvim_create_autocmd("BufEnter", {
pattern = "*",
callback = function(args)
print("Entered buffer " .. args.buf .. "!")
end,
desc = "Tell me when I enter a buffer",
})
-- Creating a custom user command in 0.7
vim.api.nvim_create_user_command("SayHello", function(args)
print("Hello " .. args.args)
end, {
nargs = "*",
desc = "Say hi to someone",
})
nvim_set_keymap
はLuaコールバックを最後のテーブル引数のキーとして設定する必要があるのに対し、nvim_create_user_command
はコールバック関数を位置パラメータとして直接渡すことができることに気付くかもしれません。これは、API関数が安定版リリースされた後、そのシグネチャを*変更してはならない*と規定するNeovimの厳格なAPI契約の結果です。ただし、nvim_create_user_command
は新しいAPI関数であるため、2番目の引数で文字列または関数のいずれかを受け入れることで、少し便利にすることができます。
Neovim 0.7には、新しいキーマッピングを簡単に作成するためのLua専用のコンビニエンス関数vim.keymap.set
も含まれています。
vim.keymap.set("n", "<leader>H", function() print("Hello world!") end)
vim.keymap.set
は、以下の点で nvim_set_keymap
と異なります。
noremap
を設定します。これはユーザーが99%の時間で望むものです。ヘルプドキュメントには、さらに多くの情報が含まれています。詳細については、Neovimで :h vim.keymap.set
を実行してください。
最後に、ユーザーはAPI関数 nvim_set_hl
を使用してグローバルハイライトグループを変更できるようになりました(:hi
を使用することと同等)。これにより、純粋なLuaカラースキームへの道が開かれます。
ターミナルベースのアプリケーションであるNeovimは、長い間、ターミナルエミュレータの制約を受けてきました。その1つは、多くのキーが同じようにエンコードされているため、ターミナルで実行されているアプリケーションでは区別できないことです。たとえば、<Tab>
と <C-I>
は同じ表現を使用し、<CR>
と <C-M>
も同様です。これは長い間、<C-I>
と <Tab>
を個別にマッピングできないことを意味していました。一方をマッピングすると、必然的に両方がマッピングされます。
これは長い間悩みの種であり、これに対処するための複数のソリューションが広く存在します。Neovimは、Paul Evansの libtermkey を使用しています。これは、Evans自身の fixterms の提案を利用して、修飾キーを明確な方法でエンコードします。 Neovimを制御するターミナルエミュレータがこの方法でエンコードされたキーを送信する限り、Neovimはそれらを正しく解釈できます。
Neovim 0.7は、独自の入力処理でこれらの修飾キーの組み合わせを正しく区別するようになったため、ユーザーは<Tab>
と <C-I>
などを個別にマッピングできるようになりました。さらに、Neovimは起動時にエスケープシーケンスを送信し、制御しているターミナルエミュレータに、このスタイルのキーエンコーディングをサポートしていることを知らせます。一部のターミナルエミュレータ(iTerm2、foot、tmuxなど)はこのシーケンスを使用して、異なるエンコーディングをプログラムで有効にします。
警告:これは諸刃の剣です! <Tab>
または <C-I>
(または <CR>
/<C-M>
)への既存のマッピングが機能しなくなる場合があります。ただし、修正は簡単です。マッピングを変更して、実際に使用したいキーを使用するだけです。
これらの修飾子のペアを明確にすることに加えて、これは以前は不可能だった新しいキーマッピング(<C-;>
や <C-1>
など)も有効にします。
これのサポートは、使用しているターミナルに大きく依存するため、すべてのユーザーに影響するわけではありません。
Neovim 0.7では、laststatus=3
を設定することで有効にできる、新しい「グローバル」ステータスラインが導入されました。ウィンドウごとに1つのステータスラインを持つ代わりに、グローバルステータスラインは常にNeovimを含むウィンドウの利用可能な幅全体を実行します。これにより、VCS情報や現在の作業ディレクトリなど、ウィンドウごとに変化しない情報を表示するのに役立ちます。多くのステータスラインプラグインは、すでにこの新機能を利用しています。
Neovim 0.7では、ファイルタイプ検出を行うための新しい(実験的な)方法があります。ファイルタイプ検出の簡単な入門書:Neovimを初めて起動すると、$VIMRUNTIME
ディレクトリにある filetype.vim
というファイルがソースされます。このファイルは、ファイルに関する情報(最も一般的にはファイルの名前または拡張子ですが、ファイルの内容を使用する場合もあります)に基づいてファイルのファイルタイプを推測することのみを目的とした、数百の BufRead,BufNewFile
オートコマンドを作成します。
nvim --startuptime
で起動時間をプロファイルすると、filetype.vim
がロードに最も時間がかかるファイルの1つであることに気付くでしょう。これは、非常に多くのオートコマンドを作成するにはコストがかかるためです。ファイルタイプ検出を行う別の方法は、*すべて*の新しいバッファに対して起動する単一のオートコマンドを作成し、一連のステップを通じてファイルタイプを照合することです。これが、新しい filetype.lua
の機能です。
単一のオートコマンドを使用することに加えて、filetype.lua
はテーブルベースのルックアップ構造を使用します。つまり、多くの場合、ファイルタイプの検出は一定時間で発生します。また、NeovimがLuaJIT(ほとんどの場合そうです)でコンパイルされている場合は、このファイルタイプマッチングにジャストインタイムコンパイルの利点も得られます。
この機能は、filetype.vim
でカバーされているすべてのファイルタイプと完全に一致するわけではないため、現在*オプトイン*です。ただし、非常に近いです(私は何ヶ月も問題なく排他的に使用しています)。この機能をオプトインするには、2つの方法があります。
filetype.lua
を使用しますが、filetype.vim
にフォールバックします。
let g:do_filetype_lua = 1
を init.vim
ファイルに追加します。これにより、ファイルタイプマッチングの回帰を防ぎ、ファイルタイプが常に*少なくとも*filetype.vim
と同じくらい検出されるようにします。ただし、filetype.lua
と filetype.vim
の両方の起動時間コストがかかります。
filetype.lua
のみを使用し、filetype.vim
をまったくロードしません。
let g:do_filetype_lua = 1
と let g:did_load_filetypes = 0
の両方を init.vim
に追加します。これにより、ファイルタイプマッチングに filetype.lua
のみが使用され、上記のすべてのパフォーマンス上の利点が得られますが、ファイルタイプの検出が失敗する(小さな)リスクがあります。
パフォーマンス上の利点に加えて、filetype.lua
を使用すると、カスタムファイルタイプを簡単に追加できます。新しいファイル ~/.config/nvim/filetype.lua
を作成し、vim.filetype.add
を呼び出して、新しいマッチングルールを作成するだけです。例えば
vim.filetype.add({
extension = {
foo = "fooscript",
},
filename = {
["Foofile"] = "fooscript",
},
pattern = {
["~/%.config/foo/.*"] = "fooscript",
}
})
vim.filetype.add
は、「extension」、「filename」、および「pattern」マッチングに対応する3つの(オプションの)キーを持つテーブルを取ります。各テーブルエントリの値は、文字列(その場合、ファイルタイプとして解釈されます)または関数のいずれかになります。たとえば、別のC ++スタイルのヘッダー(つまり、末尾に .h
がないヘッダー)が含まれている場合にのみファイルタイプをC ++に設定するヒューリスティックを使用して、.h
ファイルを常にC ++ヘッダーとして分類するというNeovimのデフォルトの動作をオーバーライドすることができます。
vim.filetype.add({
extension = {
h = function(path, bufnr)
if vim.fn.search("\\C^#include <[^>.]\\+>$", "nw") ~= 0 then
return "cpp"
end
return "c"
end,
},
})
私たちは毎日 filetype.lua
を filetype.vim
と完全に同等に近づけています。目標は、Neovim 0.8でデフォルトにすることです(従来の filetype.vim
をオプトアウトする機能付き)。
Neovim 0.7は、neovim-remote の機能の一部をコアエディターに取り入れています。nvim --remote
を使用して、すでに実行されているNeovimのインスタンスでファイルを開くことができるようになりました。例:
# In one shell session
nvim --listen /tmp/nvim.sock
# In another shell session, opens foo.txt in the first Nvim instance
nvim --server /tmp/nvim.sock --remote foo.txt
新しいリモート機能のユースケースの1つは、Neovim自体の中で実行されている埋め込みNeovimインスタンスを作成するのではなく、プライマリNeovimインスタンスの埋め込みターミナルエミュレータからファイルを開くことができることです。
Neovimは、楽しみのために仕事をする意欲的な個人のゆるやかに構成されたプロジェクトです。したがって、ロードマップは常に少し推測ゲームです。ただし、Neovim 0.8で*見られる可能性のある*ものがすでにいくつかあります。