LoginSignup
0
0

noice.nvim のfilterの設定難しすぎて死んだ

Last updated at Posted at 2024-01-27

(2024/01/27現在) この記事にはまだ正確性がありません
記事執筆後から始めた作業に於いて、 format がおかしいと怒られ始めました

noice.nvim 、いいよね (はじまり)

(neo)vimを使用していると、よく、ターミナルの一番下の行を眺めることになるかと思います

多くの場合、 : から始まるvimコマンドの呼び出しや / などでの検索、
また、 echoechoe などで表示されるログメッセージの類がここに表示されるためです

しかしながら、何かしらのメッセージが表示されるたびに視線を下に下げるのは非常にめんどうです

特に vimrc を何か誤っている場合のエラーメッセージの場合、 カーソル移動をするたびにエラーが表示され 、そのたびに Enter を連打しないとならないことがあったりするため、とてもしんどいです

しかし、 noice.nvim はこの問題を解決してくれます
あらゆるメッセージを任意の位置の通知として表示してくれる ようになります (デフォルトだと macOS と同じ右上)

これによって、 エラーメッセージに対するキーアクションが必要とされなくなる ため、
たとえ LSP でエラーがたくさん出てくるような場合でも、比較的スムーズにコーディング作業をすることができます

そして私は死んだ (何があったのか?)

これによって、 エラーメッセージに対するキーアクションが必要とされなくなる ため、
たとえ LSP でエラーがたくさん出てくるような場合でも、比較的スムーズにコーディング作業をすることができます

これはちょっと罠の部分があり、エラーが大量に出るような場合、 その通知で画面が埋め尽くされる ことがよくよく発生します
そしてこの場合、 float window を大量に生成する処理がneovimに発生します

一度に大量にインスタンスを作成すると何が起こるかは、皆さんならよくよくご存知でしょう

……何も操作ができなくなって死にます (死んだ)

image (1).png

vim-jpのslackで相談してしまったレベルです、つらい
スクリーンショット 2024-01-27 145152.png

問題

特定の大量発生しがちなエラーを出してしまった場合、何も作業ができなくなって死にます

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.nvimfilter について

製作者様にはかなり申し訳ないのですが、私にとってはちょっとわかりづらいです…

noice.nvimfilter のヘルプ
noice.nvimroute のヘルプ

以下抜粋 (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
  ------------------------------------------------------------------------------

わからなかったポイント

FILTERSFILTER ですか?

この部分

FILTERS noice.nvim-noice-(nice,-noise,-notice)-filters

と、この部分

any filter[] checks that at least one of the filters matches

FILTERSFILTER の説明なのかがちょっとわかりづらかったです
特に、 any の型が filter[] となっているところもあり、この入れ子構造のイメージがしづらかった…

また、ドキュメント側でのこのあたりの説明がかなりさらっとしており、 any を利用するパターンのイメージがうまくできませんでした

構造の理解

filter はこのような構造になっていることで理解しました

  1. filter を持つテーブル構造には、ほかのキーを持たせてはならない
  2. anyfilter配列構造を前提 としている
    • これがかなりわかりづらいのですが、つまり、 { filter = {...} } を期待しています
  3. filter は少なくとも eventfind を持たないと、フィルタリングできない
  4. filterview を指定することで、任意のビューの方法で表示してくれる
    • 例えば view = "mini" とすると、右下に小さく、通知を表示してくれます

コードで表すと、このような形になります

config.lua
{
  {
    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",
    },
  },
}

問題の解決

このような設定を書くことで、解決することができました

noice-nvim-config.lua
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
noice.init.lua
-- 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 のラッパーを作成しておくことで、わざわざテーブル構造を書くコストを減らしています

util.noice.lua
local function noiceWrapper(pattern, kind)
  kind = kind or ""
  return {
    filter = {
      kind = kind,
      find = pattern,
    },
  }
end

さいごに

入れ子構造はちょっと難しいです
キーが指定されていたり、されていなかったりすると、さらに難しさに拍車がかかるような気がしています

この問題の解決のために、私は結構精神をすり減らしましたが、うまく解決できてよかったです

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0