Neovimのプラグインってどうやっていれるの?

2023/11/13に公開

はじめに

NeovimはVSCodeみたいなUIにできるぞ!!という話を聞き、「俺もNeovim使いになるか...」と使い始めたが、プラグインの導入方法がよく分からず諦めた。なんて経験はありませんか?
この記事はそのような人向けに書いた記事です。この記事を読んだことで「Neovim面白そうやん」となってくだされば幸いです。

Neovimを始め方をざっくりと分類すると、

  1. ディストリビューションを利用する
  2. 1から設定をする

の2つがあると思います。

前者の「ディストリビューションを利用する」についですが、Neovimには、すでにしっかりとカスタマイズされた設定ファイルをディストリビューションとして配布しているものがあります。
具体的には、

ざっとこれらのものが挙げられます。
これらを使うことでVSCodeと似たリッチなUIが用意されており、すぐに便利な状態から使い始められるというメリットがあります。しかし、やりたい操作がどのキーマッピングに振られているのか、自分の操作している機能はどのプラグインが提供しているものか分からない等の問題があります。また、それに伴って自分の望む設定を加えることが非常に困難になってしまうという大きなデメリットを抱えています。Neovimやプラグインの設定を自分で一から書くことが簡単でないことは事実です。しかし、試行錯誤しながら自分のエディタを作りあげることがVimの醍醐味だと自分は感じており、初めからディストリビューションを使用するのはVimの楽しみの一つを奪うようなものだと思っています。

ですから、この記事では後者の「1から設定をする」を選択して進めていきます。
これにより、自分の意志でプラグインを追加し、自分の望む設定を付け加えることができます。

この記事のゴール

  • プラグインを導入
  • プラグインの設定
  • プラグインを探す

これら3つができることをゴールとしてやっていきましょう。

はじめに結論

記事が長くなってしまったので、結論を最初に書いておきます。

プラグインを導入

  • githubにあるプラグインはユーザー名/レポジトリ名あるいはURLをプラグイン追加するための関数の引数に渡す(関数はプラグインマネージャーによって異なる点には注意)
  • lua製のプラグインの多くは.setup()が必要

プラグインの設定

  • helpを読む
  • READMEを読む
  • githubで検索する

プラグインを探せる

この記事で導入するプラグインたちの紹介

VSCodeと似た機能を提供する以下のプラグインを選定しました。
王道プラグインを選んだので、設定方法が分からないときに他の人の設定を探しやすいと思います。

プラグインマネージャー

https://github.com/folke/lazy.nvim

特徴

  • 導入が簡単
  • プラグインの管理がしやすい
  • リッチなUI

ファイラー

https://github.com/nvim-tree/nvim-tree.lua

特徴

  • VSCodeで見なれているtree形式のファイラープラグイン

シンタックスハイライト

https://github.com/nvim-treesitter/nvim-treesitter

Neovimは標準でシンタックスハイライト機能を持っています。しかし、正規表現によって実装されているため、複雑な構文のハイライトを行うのが苦手です。nvim-treesitterはtreesitterというパーサ生成ツールを使ってシンタックスハイライト等の機能を提供します。treesitterの拡張プラグインを導入することで、シンタックスハイライト以外の機能を使うこともできます。

特徴

  • 画面がカラフルになる
  • シンタックスハイライト以外にも利用ができる

LSP・自動補完

https://github.com/neoclide/coc.nvim

このプラグインを使わない場合は、LSPの機能を提供するプラグインと、自動補完機能を提供するプラグインをそれぞれ導入する必要がありますが、coc.nvimではLSPの機能と自動補完機能の両方が提供されているプラグインです。

特徴

  • coc.nvimの中で追加機能をインストールできる。
  • Neovimだけではなく、なぜかvimでも動く

ファイル検索

https://github.com/nvim-telescope/telescope.nvim

現時点(2023年11月)のNeovimトピック内では一番star数の多いプラグインとなります。主にはファイルのFuzzyFind(あいまい検索)をするためのプラグインで、VSCodeのクイックオープンやコマンドパレットと似た機能を提供しています。

レポジトリには

Community driven builtin pickers, sorters and previewers.

と書かれてあるように、telescope.nvimユーザーが作った拡張プラグインが多数存在します。

特徴

  • UIをカスタマイズできる
  • 様々な拡張プラグインがある

ステータスライン

lualine.nvimVSCodeの下側に色々表示されてるやつ↓のNeovim版

!画像

特徴

  • 標準のコンポーネントや自作のコンポーネントを組み合わせることによって、見せたい情報だけを表示できる
  • 他のプラグインがコンポーネントを提供している場合がある

プラグインを導入・設定していく

最初のファイル構成

$ tree .
.
└── init.lua

プラグインマネージャー(lazy.nvim)

lazy.nvimではターミナルでcurl等のコマンドを叩く必要がなく、luaで所定のディレクトリにgit cloneコマンドを実行するコードを記載する作りになっています。
そのコードが、ここに書かれてあります。

-- init.lua
vim.loader.enable()
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({
    "git",
    "clone",
    "--filter=blob:none",
    "https://github.com/folke/lazy.nvim.git",
    "--branch=stable", -- latest stable release
    lazypath,
  })
end
vim.opt.rtp:prepend(lazypath)

このコードをinit.luaに貼り付けてください。

因みに、vim.fn.stdpath("data")は下記のディレクトリを指しています。

DATA DIRECTORY (DEFAULT) ~
                  *$XDG_DATA_HOME*              Nvim: stdpath("data")
    Unix:         ~/.local/share              ~/.local/share/nvim
    Windows:      ~/AppData/Local             ~/AppData/Local/nvim-data

lua製のプラグインの多くは入れるだけではそのプラグインを使うことができず、setupを自分で呼び出す必要があります。

vim.loader.enable()
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({
    "git",
    "clone",
    "--filter=blob:none",
    "https://github.com/folke/lazy.nvim.git",
    "--branch=stable", -- latest stable release
    lazypath,
  })
end
vim.opt.rtp:prepend(lazypath)

+require("lazy").setup({
+  { "folke/lazy.nvim" },
+})

これで再度Neovimを起動することでlazy.nvimの導入が完了します。しかし、このままではプラグインの管理ができません。
どうすればよいのかが、:h lazy.nvim.txtへ書いています。
lazyのsetup関数に対して"plugins"という引数を渡しています。これは、
folke/lazy.nvim #📂 Structuring Your Pluginsに説明があります。

Any lua file in ~/.config/nvim/lua/plugins/*.lua will be automatically merged in the main plugin spec

deepl先生訳

~/.config/nvim/lua/plugins/*.lua にある lua ファイルは、メインのプラグイン仕様に自動的にマージされます。

~/.config/nvim/lua/plugins.lua~/.config/nvim/lua/plugins/init.luaを配置する方法もありますが、今回はplugins/*にプラグイン事にluaファイルを配置する方法を取りたいと思います。
そうする理由としては、

  • プラグイン名 == ファイル名にすれば探すのが楽
  • ファイルを消すことでプラグインを消すことができる
    という点があげられます。
    大量のプラグインとその設定が一つのファイルに記述されていると非常に見通しが悪くなってしまいます。ですから、分割して配置しようということです。

git cloneしてきたlazy.nvimを、この行でruntimepathに追加しています。これでNeovimがlazy.nvimを認識してくれるようになります。

 vim.opt.rtp:prepend(lazypath)

それでは、lazy.nvimにlazy.nvim自体を管理してもらいましょう。そうすることで、自分自身ののバージョンアップに追従することができます。

プラグインの記述法はgithubに置かれているプラグインの場合は、ユーザー名/レポジトリ名を渡してあげます。まれにgithub以外のホスティングサービスで提供されている場合がありますが、そのようなときはフルパスを指定してください。

-- lua/plugins/lazy.lua
return {
  "folke/lazy.nvim"
}

lazy.nvimのsetup関数はinit.luaに記述しているため、これでプラグインマネージャーの導入は完了です。

Neovimを再起動して:Lazyを実行したときに、下記のような画面が表示されればlazy.nvimの導入は成功です。
![[Pasted image 20231113164009.png]]

設定を変更してみる

:h lazy.nvim-lazy.nvim-installationを見ると設定は、setup()の第二引数のoptsにデフォルトから変更したい設定を渡すようです。

require("lazy").setup(plugins, opts)

:h lazy.nvim-lazy.nvim-configurationを参考に自分はこのように設定を変更してみました。

-require("lazy").setup("plugins")
+require("lazy").setup("plugins",
+{
+	ui = {
+		icons = {
+			cmd = "⌘",
+			config = "🛠",
+			event = "📅",
+			ft = "📂",
+			init = "⚙",
+			keys = "🗝",
+			plugin = "🔌",
+			runtime = "💻",
+			require = "🌙",
+			source = "📄",
+			start = "🚀",
+			task = "📌",
+			lazy = "💤 ",
+		},
+	},
+	checker = {
+		enabled = true, -- プラグインのアップデートを自動的にチェック
+	},
+	diff = {
+		cmd = "delta",
+	},
+	rtp = {
+		disabled_plugins = {
+			"gzip",
+			"matchit",
+			"matchparen",
+			"netrwPlugin",
+			"tarPlugin",
+			"tohtml",
+			"tutor",
+			"zipPlugin",
+		},
+	},
+})

ファイラー(nvim-tree)

-- lua/plugins/nvim-tree.lua
return {
  "nvim-tree/nvim-tree.lua"
}

ここまで読めば、これでnvim-tree.luaが入ることが分かるかと思います。
では、setupはどこに書けばいいのでしょうか?

:h lazy.nvim-lazy.nvim-plugin-specを見てみましょう

config
fun(LazyPlugin, opts:table) or true
config is executed when the plugin loads. The
default implementation will automatically run
require(MAIN).setup(opts). Lazy uses several
heuristics to determine the plugin’s MAIN module
automatically based on the plugin’s name. See also
opts. To use the default implementation without opts
set config to true.

意訳ですが、configを渡したいならopsに渡してあげてください。何も渡さなくていいならconfigをtrueにしてください。ということです。
では、nvim-tree.luaのconfigをtrueにしてみましょう。

 -- lua/plugins/nvim-tree.lua
 return {
   "nvim-tree/nvim-tree.lua"
+  config = true,
}

ファイルを保存したときに、右下になにか通知がでると思います。これはlazy.nvimがファイルの変更を検知してくれているからです。
通知が出た後で、:Lazy installを実行してください。すると、nvim-tree.luaがインストールされます。
Alt text

Neovimを再起動して、:NvimTreeToggleを実行してみましょう。すると、左側にファイラーが表示されると思います。
Alt text

せっかくなので、lazy.nvimの機能を使って:NvimTreeToggleをキーマッピングしてみましょう。

 -- lua/plugins/nvim-tree.lua
 return {
   "nvim-tree/nvim-tree.lua"
   config = true,
   keys = {
+    {mode = "n", "<C-n>", "<cmd>NvimTreeToggle<CR>", desc = "NvimTreeをトグルする"},
   }
 }

Neovimを再起動して、<C-n>を押してみましょう。すると、先ほどと同じように左側にファイラーが表示されると思います。

シンタックスハイライト

-- lua/plugins/nvim-treesitter.lua
return {
    "nvim-treesitter/nvim-treesitter",
    opts = {},
}

次にoptsを使ってみましょう。
:h nvim-treesitter-quickstartを確認してみると、

  require'nvim-treesitter.configs'.setup {
    -- A directory to install the parsers into.
    -- If this is excluded or nil parsers are installed
    -- to either the package dir, or the "site" dir.
    -- If a custom path is used (not nil) it must be added to the runtimepath.
    parser_install_dir = "/some/path/to/store/parsers",

    -- A list of parser names, or "all"
    ensure_installed = { "c", "lua", "rust" },

    -- Install parsers synchronously (only applied to `ensure_installed`)
    sync_install = false,
...

このような記述があると思います。
今回はensure_installedとsync_installを設定してみます。

 -- lua/plugins/nvim-treesitter.lua
 return {
     "nvim-treesitter/nvim-treesitter",
-    opts = {},
+    opts = {
+        ensure_installed = { "lua", "typescript" },
+        sync_install = true,
+    }, 
 }

この調子でじゃんじゃん行きましょう。

LSP・自動補完(coc.nvim)

申し訳ございません。時間と集中力が尽きてしまい最後まで書ききれませんでした。今週中には完成版を更新します。

ファイル検索(telescope)

ステータスライン(lualine)

プラグインの探し方

設定の仕方が分からない時

  1. doc/READMEを読む
  2. githubで検索する
  3. vim-jpで聞いてみる

おわりに

後半にかけて雑になっている感は否めないので、後日修正します。

Discussion