(2024/01/27現在) この記事にはまだ正確性がありません
記事執筆後から始めた作業に於いて、 format
がおかしいと怒られ始めました
noice.nvim
、いいよね (はじまり)
(neo)vimを使用していると、よく、ターミナルの一番下の行を眺めることになるかと思います
多くの場合、 :
から始まるvimコマンドの呼び出しや /
などでの検索、
また、 echo
や echoe
などで表示されるログメッセージの類がここに表示されるためです
しかしながら、何かしらのメッセージが表示されるたびに視線を下に下げるのは非常にめんどうです
特に vimrc
を何か誤っている場合のエラーメッセージの場合、 カーソル移動をするたびにエラーが表示され 、そのたびに Enter
を連打しないとならないことがあったりするため、とてもしんどいです
しかし、 noice.nvim
はこの問題を解決してくれます
あらゆるメッセージを任意の位置の通知として表示してくれる ようになります (デフォルトだと macOS
と同じ右上)
これによって、 エラーメッセージに対するキーアクションが必要とされなくなる ため、
たとえ LSP
でエラーがたくさん出てくるような場合でも、比較的スムーズにコーディング作業をすることができます
そして私は死んだ (何があったのか?)
これによって、 エラーメッセージに対するキーアクションが必要とされなくなる ため、
たとえLSP
でエラーがたくさん出てくるような場合でも、比較的スムーズにコーディング作業をすることができます
これはちょっと罠の部分があり、エラーが大量に出るような場合、 その通知で画面が埋め尽くされる ことがよくよく発生します
そしてこの場合、 float window
を大量に生成する処理がneovimに発生します
一度に大量にインスタンスを作成すると何が起こるかは、皆さんならよくよくご存知でしょう
……何も操作ができなくなって死にます (死んだ)
vim-jpのslackで相談してしまったレベルです、つらい
問題
特定の大量発生しがちなエラーを出してしまった場合、何も作業ができなくなって死にます
e.g. LSPの
textDocument/hover
など、LSPが対応していないファイルを操作している際にhover
を呼ぶような場合
あくまで私の場合の話です
私の場合、カーソルが特定のワードに置かれた際に、1秒程度の間隔を空けて textDocument/hover
を呼ぶような設定にしているため、このようなことが発生します
前提
環境情報
- Ubuntu 22/04 LTS (on Windows11(WSL2))
- neovim v0.9.5
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.3 LTS
Release: 22.04
Codename: jammy
$ nvim -v
NVIM v0.9.5
Build type: Release
LuaJIT 2.1.1692716794
system vimrc file: "$VIM/sysinit.vim"
fall-back for $VIM: "/__w/neovim/neovim/build/nvim.AppDir/usr/share/nvim"
Run :checkhealth for more info
noice.nvim
の filter
について
製作者様にはかなり申し訳ないのですが、私にとってはちょっとわかりづらいです…
noice.nvim
の filter
のヘルプ
noice.nvim
の route
のヘルプ
以下抜粋 (2024/01/27時点)
FILTERS *noice.nvim-noice-(nice,-noise,-notice)-filters*
**Noice** uses filters to route messages to specific views.
------------------------------------------------------------------------------
Name Type Description
------------ ---------- ------------------------------------------------------
any filter[] checks that at least one of the filters matches
blocking boolean are we in blocking mode?
cleared boolean checks if the message is cleared, meaning it’s in the
history
cmdline boolean or checks if the message was generated by executing a
string cmdline. When string, then it is used as a pattern
error boolean all error-like kinds from ext_messages
event string or any of the events from ext_messages or cmdline. See :h
string[] ui-messages
find string uses lua string.find to match the pattern
has boolean checks if the message is exists, meaning it’s in the
history
kind string or any of the kinds from ext_messages. See :h ui-messages
string[]
max_height number maximum height of the message
max_length number maximum length of the message (total width of all the
lines)
max_width number maximum width of the message
min_height number minimum height of the message
min_length number minimum length of the message (total width of all the
lines)
min_width number minimum width of the message
mode string checks if vim.api.nvim_get_mode() contains the given
mode
not filter checks whether the filter matches or not
warning boolean all warning-like kinds from ext_messages
------------------------------------------------------------------------------
わからなかったポイント
FILTERS
は FILTER
ですか?
この部分
FILTERS noice.nvim-noice-(nice,-noise,-notice)-filters
と、この部分
any filter[] checks that at least one of the filters matches
FILTERS
が FILTER
の説明なのかがちょっとわかりづらかったです
特に、 any
の型が filter[]
となっているところもあり、この入れ子構造のイメージがしづらかった…
また、ドキュメント側でのこのあたりの説明がかなりさらっとしており、 any
を利用するパターンのイメージがうまくできませんでした
構造の理解
filter
はこのような構造になっていることで理解しました
-
filter
を持つテーブル構造には、ほかのキーを持たせてはならない -
any
はfilter
の配列構造を前提 としている- これがかなりわかりづらいのですが、つまり、
{ filter = {...} }
を期待しています
- これがかなりわかりづらいのですが、つまり、
-
filter
は少なくともevent
とfind
を持たないと、フィルタリングできない -
filter
にview
を指定することで、任意のビューの方法で表示してくれる- 例えば
view = "mini"
とすると、右下に小さく、通知を表示してくれます
- 例えば
コードで表すと、このような形になります
{
{
filter = {
event = "msg_show",
any = {
{ filter = { kind = "", find = "", } }
{ filter = { kind = "", find = "", } }
{ filter = { kind = "", find = "", } }
{ : }
{ : }
},
opts = { skip = true },
},
},
{
filter = {
event = "lsp",
any = {
{ filter = { kind = "", find = "", } }
{ filter = { kind = "", find = "", } }
{ filter = { kind = "", find = "", } }
{ : }
{ : }
},
view = "mini",
},
},
}
問題の解決
このような設定を書くことで、解決することができました
local suppressMessages = {
-- ※ `suppressMessage()` は後述の `appendix` の部分で説明しています
noiceWrapper("^%d+ lines .ed %d+ times?$"),
noiceWrapper("^%d+ lines yanked$"),
noiceWrapper(".*E490.*", "emsg"),
noiceWrapper("search_count"),
-- :
-- (中略)
-- :
}
local M = {
routes = {
{
filter = {
event = "msg_show",
any = suppressMessages,
opts = { skip = true },
},
},
}
}
return M
-- lazy.nvim を使用している想定です
local noice_config = require("noice-nvim-config")
return {
{
lazy = true,
"folke/noice.nvim",
event = { "VeryLazy" },
dependencies = {
"MunifTanjim/nui.nvim",
"rcarriga/nvim-notify",
"nvim-telescope/telescope.nvim",
},
opts = function(_, opts)
-- add any options here
opts.routes = noice_config.routes
opts.notify = {
enabled = true,
view = "notify",
}
opts.messages = {
-- NOTE: If you enable messages, then the cmdline is enabled automatically.
-- This is a current Neovim limitation.
enabled = true, -- enables the Noice messages UI
view = "notify", -- default view for messages
view_error = "notify", -- view for errors
view_warn = "notify", -- view for warnings
view_history = "messages", -- view for :messages
view_search = "virtualtext", -- view for search count messages. Set to `false` to disable
}
opts.redirect = {
view = "popup",
filter = { event = "msg_show" },
}
opts.presets = {
bottom_search = true, -- use a classic bottom cmdline for search
command_palette = true, -- position the cmdline and popupmenu together
long_message_to_split = true, -- long messages will be sent to a split
inc_rename = false, -- enables an input dialog for inc-rename.nvim
lsp_doc_border = false, -- add a border to hover docs and signature help
}
end,
config = function(_, opts)
require("noice").setup(opts)
-- ※ ここは `telescope` 使用される方はお好みで
--require("telescope").load_extension("notify")
end,
}
}
appendix: ユーティリティ関数の追加
こんな感じの noice-filter
のラッパーを作成しておくことで、わざわざテーブル構造を書くコストを減らしています
local function noiceWrapper(pattern, kind)
kind = kind or ""
return {
filter = {
kind = kind,
find = pattern,
},
}
end
さいごに
入れ子構造はちょっと難しいです
キーが指定されていたり、されていなかったりすると、さらに難しさに拍車がかかるような気がしています
この問題の解決のために、私は結構精神をすり減らしましたが、うまく解決できてよかったです