この記事シリーズについて
Neovim の補完エンジンを nvim-cmp から blink.cmp に移行する過程で、SKK 日本語入力プラグイン skkeleton との協調動作にかなり苦戦しました。
blink.compat(旧 nvim-cmp ソースの互換レイヤー)経由で cmp-skkeleton を使う方法では、候補は出るのに <CR> で確定してもひらがなのまま反映されない、という不具合が解消できず、最終的に skkeleton 用の補完ソースを blink.cmp ネイティブで書き直すことになりました。
この過程で得た知見を、次の4パートに分けて紹介します。
- (本記事) 全体構成と環境構築
- skkeleton 用ネイティブ blink.cmp ソースの実装
- skkeleton 本体が blink.cmp を認識しない問題との格闘
- 周辺の作り込み(スニペット統合・コマンドライン補完)
設定ファイル一式はこちらに公開しています。
環境
- プラグインマネージャー: lazy.nvim
-
補完エンジン: blink.cmp(
version = "1.*"固定)+ blink.compat(calc / emoji / latex_symbols / spell / rg 用の互換レイヤー) -
SKK 補完: 自作のネイティブ blink.cmp ソース(
blink.compatは経由しない) - 対象バージョン: Neovim v0.12 以降
- OS: Manjaro Linux (x86_64)
- 移行の変遷: wbthomason/packer.nvim → folke/lazy.nvim →(補完エンジンのみ)hrsh7th/nvim-cmp → saghen/blink.cmp
なぜ blink.cmp に移行したか
nvim-cmp は長らく安定して使ってきましたが、blink.cmp は Rust 製のファジーマッチャーによる高速な候補表示が魅力で、プラグインマネージャーを packer.nvim から lazy.nvim に移行したタイミングで補完エンジンも刷新することにしました。
ただし移行は単純な差し替えでは済みませんでした。calc / emoji / latex_symbols / spell / rg のように blink.cmp にネイティブ実装がないソースは blink.compat 経由で旧 nvim-cmp 用ソースをそのまま使う一方、skkeleton だけは blink.compat 経由だと最後まで正しく動かせず、ネイティブソースを自作する結果になりました。この顛末は Part 2および Part 3 で詳しく扱います。
ディレクトリ構成
~/.config/nvim/
├── init.lua # エントリーポイント
└── lua/
├── plugins/ # プラグイン定義(lazy.nvim)
│ ├── 01-base.lua # 操作補助・快適化
│ ├── 02-colorschemes.lua # カラースキーム
│ ├── 03-ui.lua # UI 関連
│ ├── 04-treesitter.lua # Treesitter
│ ├── 05-telescope.lua # Telescope
│ ├── 06-lsp.lua # LSP・補完(blink.cmp)
│ ├── 07-markdown.lua # Markdown・Typst・LaTeX
│ ├── 08-migemo.lua # Migemo 検索
│ ├── 09-notify-skk.lua # Noice・SKK
│ └── 10-lisp.lua # Common Lisp 開発環境(conjure)
└── my/ # カスタム設定
├── autocommand.lua
├── keymap.lua
└── cmp/
├── blink.lua # blink.cmp 設定本体
├── keymap.lua # blink.cmp トグルキーマップ
├── LuaSnipCustom.lua # カスタムスニペット
├── regex_source.lua # 正規表現補完ソース(cmdline 専用)
├── skkeleton_source.lua # skkeleton 補完ソース(ネイティブ実装)
├── skkeleton_cmp_shim.lua # skkeleton に blink.cmp を認識させるシム
└── luasnip_source.lua # LuaSnip トリガー文字列を出すソース
補完まわりの実装は lua/my/cmp/ 配下に集約しています。特に skkeleton_source.lua と skkeleton_cmp_shim.lua の2ファイルが、このシリーズの本題です。
セットアップ手順
初回インストール
# 1. 設定を配置
git clone git@github.com:nabehan/nvim-config-blink-skkeleton.git ~/.config/nvim
# 2. nvim を起動(lazy.nvim が自動でプラグインをインストール・同期)
nvim
blink.cmp は Rust 製フュージーマッチャーのプリビルドバイナリを GitHub Releases から取得するため、初回起動時にネットワーク接続が必要です。fuzzy.implementation = "prefer_rust_with_warning" を指定しているので、取得に失敗した場合は自動的に純 Lua 実装にフォールバックします。
初回起動後の追加作業
noice.nvim でコマンドラインの正規表現ハイライトを有効にするため、以下を実行します。
:TSInstall regex
補完ソースの全体像(先取り)
詳細は Part 2 以降に譲りますが、lua/my/cmp/blink.lua で定義しているソース構成の全体像だけ先に示しておきます。
common = skkeleton / snippets(LuaSnip) / lsp / path / calc / emoji / latex_symbols / buffer
writing_sources = common + spell ← markdown / text / typst
prog_sources = common + rg + spell ← プログラミング / スクリプト言語
それ以外 = common のみ
skkeleton はこの中で唯一「compat 経由ではなくネイティブ実装」という特別枠になっています。次回はその理由と実装の中身を掘り下げます。
次回予告
Part 2 では、skkeleton_source.lua の実装 —— denops#request を直接呼んで候補を取得する方法や、textEdit.range をバイトオフセットで自前計算する理由、そして最初にハマった「確定してもバッファに反映されない」問題の真因について書く予定です。