Neovim ニュース #12 - Neovim 0.7の新機能

2022年4月

原文: https://gpanders.com/blog/whats-new-in-neovim-0-7

Neovim 0.7がリリースされました。多くの新機能(そしてもちろんバグ修正も多数)が搭載されています。完全なリリースノートはこちらからご覧いただけますが、この記事では、いくつかの新しい追加機能についてのみご紹介します。

目次

Lua がどこにでも!

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 と異なります。

  • 3番目の引数として、文字列またはLua関数のいずれかを受け入れることができます。
  • デフォルトで 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情報や現在の作業ディレクトリなど、ウィンドウごとに変化しない情報を表示するのに役立ちます。多くのステータスラインプラグインは、すでにこの新機能を利用しています。

filetype.lua

Neovim 0.7では、ファイルタイプ検出を行うための新しい(実験的な)方法があります。ファイルタイプ検出の簡単な入門書:Neovimを初めて起動すると、$VIMRUNTIME ディレクトリにある filetype.vim というファイルがソースされます。このファイルは、ファイルに関する情報(最も一般的にはファイルの名前または拡張子ですが、ファイルの内容を使用する場合もあります)に基づいてファイルのファイルタイプを推測することのみを目的とした、数百の BufRead,BufNewFile オートコマンドを作成します。

nvim --startuptime で起動時間をプロファイルすると、filetype.vim がロードに最も時間がかかるファイルの1つであることに気付くでしょう。これは、非常に多くのオートコマンドを作成するにはコストがかかるためです。ファイルタイプ検出を行う別の方法は、*すべて*の新しいバッファに対して起動する単一のオートコマンドを作成し、一連のステップを通じてファイルタイプを照合することです。これが、新しい filetype.lua の機能です。

単一のオートコマンドを使用することに加えて、filetype.lua はテーブルベースのルックアップ構造を使用します。つまり、多くの場合、ファイルタイプの検出は一定時間で発生します。また、NeovimがLuaJIT(ほとんどの場合そうです)でコンパイルされている場合は、このファイルタイプマッチングにジャストインタイムコンパイルの利点も得られます。

この機能は、filetype.vim でカバーされているすべてのファイルタイプと完全に一致するわけではないため、現在*オプトイン*です。ただし、非常に近いです(私は何ヶ月も問題なく排他的に使用しています)。この機能をオプトインするには、2つの方法があります。

  1. filetype.lua を使用しますが、filetype.vim にフォールバックします。

    let g:do_filetype_lua = 1init.vim ファイルに追加します。これにより、ファイルタイプマッチングの回帰を防ぎ、ファイルタイプが常に*少なくとも*filetype.vim と同じくらい検出されるようにします。ただし、filetype.luafiletype.vim の両方の起動時間コストがかかります。

  2. filetype.lua のみを使用し、filetype.vim をまったくロードしません。

    let g:do_filetype_lua = 1let 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.luafiletype.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インスタンスの埋め込みターミナルエミュレータからファイルを開くことができることです。

0.8に向けて

Neovimは、楽しみのために仕事をする意欲的な個人のゆるやかに構成されたプロジェクトです。したがって、ロードマップは常に少し推測ゲームです。ただし、Neovim 0.8で*見られる可能性のある*ものがすでにいくつかあります。

ニュース

その他のアップデートは、ニュースアーカイブをご覧ください。RSSフィードもあります。

Neovimとは何ですか?

Neovimは、拡張性使いやすさのために設計されたVimベースのテキストエディタであり、新しいアプリケーションと貢献を促進します。

ディスカッション

チームとチャットするには、#neovim:matrix.org またはirc.libera.chatの#neovimにアクセスしてください。