Vim沼: AIコーディング用Neovimセットアップ
!
本記事は devas.life の日本語訳です
どうもTAKUYAです。本稿では、AIエージェント(Claude Code)を使用してNeovimをセットアップする手順について説明します。
動画版はこちら:
youtube.com
dotfilesはこちら:
craftzdog/dotfiles
構成サマリー
この記事で紹介するセットアップの全体像です。
スペックは9つのステップに分かれています。
ステップ
内容
主なプラグイン・機能
0. 前提条件
Neovim、CLIツール、フォント、Git
Neovim 0.12、Nerd Font
1. 基盤
ファイル構成、オプション、メッセージ、基本のキーマップ
vim.pack、ui2、tiny-cmdline.nvim
2. 見た目
カラースキーム、アイコン、タブライン、ステータスライン
solarized-osaka、mini.icons、自作タブライン、lualine、incline.nvim、snacks.nvim
3. ナビゲーション
ピッカー、ファイルエクスプローラー
snacks.nvimのピッカー、oil.nvim
4. シンタックス
構文ハイライト、TODOと色の表示
nvim-treesitter、todo-comments.nvim、nvim-highlight-colors
5. コード支援
言語サーバー、補完、括弧、フォーマット
Mason、nvim-lspconfig、blink.cmp、mini.pairs、conform.nvim
6. Git
サイン、差分、lazygit、リンク
gitsigns.nvim、mini.diff(フォーク)、codediff.nvim、lazygit、gitlinker.nvim
7. AI
インラインの補完候補
copilot.lua
8. エージェントコーディング
パスやコードブロックをエージェント用にコピー
自作のキーマップ
ファイル構成:
~/.config/nvim
├── init.lua
├── after/lsp/<name>.lua # サーバーごとのLSP設定
└── lua/craftzdog/
├── utils/ # 共通のヘルパー
├── config/ # options, keymaps, autocmds, commands, workarounds
└── plugins/ # init.lua、グループごとの設定、keymaps.lua
LazyVimを卒業した
2023年に紹介した前回のセットアップでは、プラグインのメンテナンスを避けるためにLazyVimを使っていて、とても快適でした。
LazyVimコミュニティのおかげで、プラグインを簡単に最新に保てて、設定も気軽にいじれました。
でも、カスタマイズすればするほど不安定になっていきました。
LazyVimを更新するたびにエラーを直すのが、ちょっと面倒だったんです。
一方で最近のNeovimでは、以前はプラグインが必要だった機能がたくさん組み込まれました:
vim.pack: 組み込みのプラグインマネージャー
vim.lsp.enableとafter/lsp/<name>.lua: ほぼボイラープレートなしでLSPを設定できる
ui2: 新しいメッセージUI
:restart: Neovimを再起動してセッションを復元する
そこで、これらをベースに新しくセットアップを作ることにしました。
エージェントコーディングのためのNeovim
Agentic Codingが普及し、僕もすっかりエージェント中心の開発ワークフローになりました。
最近はNeovimを、手でコードを書くためというより、主にコードレビューのために使っています。
正直、ワークフローの変化がとても速いので、いつまでこの構成でNeovimを使い続けるかはわかりません。しかしながら、現状のセットアップをシェアしてその変化を楽しむのも一興だと思いました。
設定を自然言語で書く
今はNeovimの設定をいじるのがとても簡単です。やりたいことをエージェントに伝えるだけだからです。
そこでLuaを書く代わりに、設定の スペック(仕様書) を英語でInkdropに書き、MCPサーバー経由でエージェントにステップごとに渡しました。
スペックノート
スペックには「どうやるか」ではなく、「何がしたいか」と「なぜか」を書きます。
Luaのコードはエージェントが考えます。
ワークフロー
スペックのステップを1つ書く。
そのステップだけを実装するようエージェントに頼む。
:restartでNeovimを再起動し、自分で動作を確認する。
差分をレビューしてコミットする。
エージェントへのプロンプト
エージェントには次のルールを伝えました:
スペックを読み、指定したステップだけを実装する。それ以外は何も足さない。
作業結果は軽くチェックする:
Neovimがエラーなしで起動する: nvim --headless +qa
新しいキーマップが存在する: :verbose map <key>
テスト用のプロジェクトを作ったり、UIを操作したりしない。動作は再起動後に自分で確認する。
設定のリロード
ZRに:restartを割り当てています。
Neovimが同じターミナル内で再起動し、ウィンドウ、タブ、バッファを復元します。
先に:waで保存しておきます。未保存のバッファがあると再起動できません。
:restart +qall!なら未保存の変更を破棄して再起動します。
プラグインを追加するステップの後は、vim.packがインストールの確認を出すので承認します。
再起動で終了してしまうので、エージェントはNeovim内の:terminalではなく、別のターミナル分割で動かします。
以下が、ステップごとのスペック全体です。
自由にコピーして自分のエージェントに渡し、好みに合わせて調整してください。
0. 前提条件
0.1 Neovim
Neovim 0.12以上。
この設定は0.12で入った組み込み機能(vim.pack、vim.lsp.enable、ui2メッセージUI)に依存しています。
0.2 CLIツール
ツール
用途
git
vim.packがプラグインのクローンに使う
tree-sitter CLI + Cコンパイラ
nvim-treesitterのmainブランチはパーサーをローカルでビルドする
curlとtar
パーサーとblink.cmpのバイナリのダウンロード
Node.js + npm
Masonはほとんどの言語サーバーをnpm経由でインストールする
ripgrepとfd
テキスト検索とファイル検索のバックエンド
lazygitとgit-delta
Git UIとその差分表示
0.3 フォント
Nerd Font。僕はPlemolJP Console NFを使っています。
タブライン、ステータスライン、補完メニュー、ファイルエクスプローラーにアイコンが出るので、普通のフォントだと四角(豆腐)になります。
0.4 Git
設定フォルダはGitリポジトリにする。
.gitignoreにnvim-pack-lock.jsonを入れる。
1. 基盤
1.0 セッションを始める
まず、スペックの場所をエージェントに伝えました:
I'd like to make a neovim setup. I'm going to write a spec in this note: <link to the spec>
When you are ready, say so
エージェントの最初の返答
1.1 構成
~/.config/nvim: 設定のルートフォルダ
init.lua: 起動を速くするためvim.loaderを有効にし、次のファイルを順に直接requireする:
craftzdog.utils(グローバル変数Craftzdogに代入)
craftzdog.config.options、.keymaps、.autocmds、.commands、.workarounds
craftzdog.plugins
lua/craftzdog/: 自分の設定はここに置く
utils/: 共通のヘルパー
init.lua: ヘルパーモジュールのテーブルを返す。最初は空。
後のステップでutils/editor.luaのようなモジュールを追加し、editorとして公開する。
config/: Neovim本体の設定。上に挙げた名前ごとに1ファイル
plugins/
init.lua: 1回のvim.pack.addですべてのプラグインをインストールし、各グループのファイルをrequireする
プラグインのグループごとに隣にファイルを作り(例: ui.lua)、require("<plugin>").setup({ ... })で設定する。
keymaps.lua: プラグインを使うキーマップはすべてここ。すべてのプラグインの設定が終わってから読むよう、最後にrequireする。グループのファイルにはキーマップを書かない。
Luaファイルはタブでインデントし、stylua(デフォルト設定)で整形する。
生成されたファイルツリー
1.2 リーダーキーと基本設定
リーダーとローカルリーダーはSpace。
マウスはオフ。キーボードのみ。
クリップボードはunnamedplus。ヤンクとペーストがシステムのクリップボードを通る。
インデントはスペース2つ:
tabstop、shiftwidth、softtabstopはすべて2
expandtabとsmartindentはオン
-を単語の一部として扱うので、foo-barは1単語になる。
CSSのクラス名やケバブケースの名前に合う。
1.3 バッファの見た目
ハイブリッド行番号: number + relativenumberをオンにして、カーソル行には実際の行番号を表示する。
cursorlineはオン。折り返しなし、scrolloffは10、sidescrolloffは8。
signcolumnは常に表示。
Gitや診断のマークが出てもテキストがずれない。
cmdheightは0、ステータスラインはグローバルに1本(laststatus 3)。
縦のスペースを最大限使う。
すべてのフローティングウィンドウの枠を角丸に(winborder)。
ポップアップメニュー: 最大10行、少し透過(pumheight 10、pumblend 10)。
対応する括弧を一瞬ハイライト(showmatch オン、matchtime 2)。
titleをオンにして、ターミナルのタブにファイル名を表示する。
差分の空き領域を斜線╱で埋める。
ハイブリッド行番号
1.4 検索、ファイル、アンドゥ
ignorecase + smartcaseをオン: 大文字を入力するまでは大文字・小文字を区別しない。
pathに**を追加して、:findがサブフォルダも検索するようにする。
:の補完:
wildmodeはlongest:full,full
wildignoreで/node_modules/、.o、.obj、.pyc、.class、*.jarを除外
swapfileとwritebackupはオフ。
永続アンドゥ(undofile オン)の保存先は~/.cache/nvim/undodir。
ファイルを閉じてもアンドゥできる。スワップファイルは邪魔なだけ。
タイミングをキビキビさせる: updatetime 300、timeoutlen 500、ttimeoutlen 0。
CursorHoldイベントが早くなり、キーシーケンスが遅延なく確定する。
試してみる:
init.luaで/craftzdog、次に/Craftzdog
:find opt<Tab>
init.luaを編集して:wq、開き直してからu
1.5 分割と折りたたみ
新しい分割は下と右に開く。
折りたたみはTreesitterから作り、foldlevelは99。
最初はすべて展開された状態で、構文単位で折りたたむこともできる。
試してみる:
:split、:vsplit
:e $VIMRUNTIME/lua/vim/keymap.luaを開き、関数の中でzc / zo
zM / zR
折りたたまれた関数
1.6 メッセージ
メッセージはNeovim 0.12の実験的機能ui2で表示します。config/options.luaの最後で有効にします。
短いメッセージ: 画面の隅にポップアップ(最大で画面の高さの30%)し、5秒で消える。
長い出力(エラー、:ls、:verbose、シェルコマンド、進捗): 最大で画面の半分までのスクロールできるページャーに表示。
検索件数、検索パターン、補完、:の補完リスト、確認プロンプトはコマンドラインに残す。
自分で入力したコマンドの出力は、種類にかかわらずコマンドラインに表示する。
次のキーを押すまで、画面の下部に広がって表示される。
Enterでページャーに移る。
tiny-cmdline.nvimで、:のコマンドラインを左右中央・上から20%の位置にフローティングボックスとして表示します。設定はplugins/ui.luaに書きます。
cmdheightが0なのでコマンドラインを出す場所が必要で、視線がもともとある上の方が見やすい。
試してみる:
:echo "hi"
:lua print("hi")
:foo
:!ls
:verbose set ts?
フローティングのコマンドライン
lsの出力
1.7 autocmd
ヤンクしたテキストを一瞬ハイライトする。
アクティブなウィンドウにだけcursorlineを表示する。
ヤンクのハイライト
1.8 基本のキーマップ
キー
動作
備考
x
ヤンクせずに削除
<leader>d、<leader>c、<leader>p
ヤンクレジスタを変えずに削除・変更・ペースト
周りを編集しても、ヤンクしたテキストが残る。
dw
単語を後方にヤンクせず削除
- / -
数値を増減
<C-a>
全選択
te
新しいタブを開く
Tab / Shift-Tab
タブを切り替える
ss / sv
分割
ホームポジションで短くウィンドウを操作できる。
sh sj sk sl
ウィンドウ間を移動
ホームポジションで短くウィンドウを操作できる。
<C-m>
ジャンプリストを前に進む
ターミナルでは<C-i>がTabと同じキーで、Tabはタブ切り替えに使っているため。
<leader>o / <leader>O
コメントを継続せずに下/上に行を挿入(o<Esc>^Da)
ssとsvで分割
1.9 隠れバッファを閉じる
<leader>bdで、未保存のものを除くすべての隠れバッファを閉じる。
2. 見た目
2.1 カラースキーム
solarized-osaka、vividスタイル、背景は透過。
ターミナルのブラーが透けて見え、配色がGhosttyのテーマと揃う。
カラースキーム適用前
カラースキーム適用後
2.2 アイコン
mini.icons。nvim-web-deviconsのモックも兼ねる。
すべてのプラグインでアイコンの出どころを1つにする。
2.3 タブライン
プラグインを使わず、utils/tabline.luaに自作のタブラインを書きます。
タブが2つ以上のときだけ表示する。
各タブには、アクティブなウィンドウのファイル名とアイコンを、左右3スペースずつの余白付きで、斜めの区切りの間に表示する。
両端が下に向かって外側に傾くので、各タブは下が広い台形になる:
色はsolarized-osakaのパレットから:
アクティブなタブ: yellowの背景に太字のbase4の文字
非アクティブなタブ: base02の背景にbase0の文字
アイコンはタブの文字色に合わせる。
区切りは透過背景にタブの色。最後のタブの後ろの空き領域も同じ。
20文字より長い名前は、17文字に切って…を付ける。
未保存のタブはアイコンの前に[+]を表示する。
ターミナルは[Terminal]、空のバッファは[No Name]と表示し、アイコンは付けない。
タブライン
2.4 ステータスライン
lualine。グローバルに1本、テーマはauto。
セクション
内容
a
モード
b
Gitブランチ
c
プロジェクトルート名(cwdと違う場合のみ)、ファイルタイプのアイコン、整形したパス
x
マクロ記録中のレジスタ、診断、Gitの差分数
y
進捗
z
行:列
プロジェクトルートは、上の階層に向かって.git、lua、package.json、Makefile、Cargo.toml、go.mod、pyproject.tomlを探して決める。
カーソル移動時と、マクロの記録開始・終了時に更新する。
記録中の表示が、非表示のコマンドラインの代わりになる。
完成イメージ:
結果:
ステータスライン
2.5 ウィンドウのラベル
incline.nvimで、各ウィンドウの右上にアイコン付きのファイル名タグを表示する。未保存なら[+]も付ける。
ステータスラインがグローバルに1本なので、分割したそれぞれのウィンドウにどのファイルかを示す必要がある。
カーソルがタグの行に来たら、タグを隠す。
inclineのラベル
2.6 Snacks
snacks.nvimで、通知、インデントガイド、statuscolumn、単語のハイライトを提供します。
後のステップで、ピッカーやlazygit連携など、さらに機能を有効にしていきます。
Words: カーソル下の単語をすべてハイライトする。]] / [[で出現箇所を移動。
言語サーバーが必要なので、ステップ5.1の後から動く。
スムーズスクロールはオフ。
スクロールは即座に反応してほしい。
vim.notify
インデントガイド
3. ナビゲーション
3.1 ピッカー
snacks.nvimのピッカー。
キー
動作
備考
;f
隠しファイルも含めてファイルを検索
.github/や.env.exampleのようなドットファイルも、実際のプロジェクトの一部。
;r
隠しファイルも含めてライブgrep
;;
最後のピッカーを開き直す
\
開いているバッファの一覧
すでにそのバッファを表示しているウィンドウがあれば、そこにジャンプする。
;e
診断の一覧
;n
通知の履歴
;h
Gitのハンクの一覧
ファイルピッカー
ライブgrep
3.2 ファイルエクスプローラー
oil.nvimでnetrwを置き換え、隠しファイルも表示します。
ディレクトリがバッファになっているので、ファイルの名前変更・移動・削除は、テキストを編集して:wするだけ。
列: アイコン、パーミッション、サイズ、更新日時。
ファイル名を変更すると、LSPにimportの更新を頼み、その編集を自動で保存する。
タブライン(2.3)では、oilのタブはディレクトリ(~/foo)をアイコンなしで表示する。
20文字より長いパスは左側を切り、…と末尾の17文字にする。
キー
動作
備考
sf
ライブプレビュー付きの中央フローティングでoilを開く
最大200列幅、角丸。
h
親ディレクトリに移動
q
oilを閉じる
プレビュー付きのoilフローティング
oilの列
4. シンタックス
4.1 Treesitter
nvim-treesitterのmainブランチ。
38個のパーサーを入れる:
astro, bash, c, cmake, cpp, css, diff, fish, gitignore, go, graphql, html, http, java, javascript, jsdoc, json, lua, luadoc, luap, markdown, markdown_inline, php, printf, python, query, regex, rust, scss, sql, svelte, toml, tsx, typescript, vim, vimdoc, xml, yaml
FileTypeのautocmdで、パーサーがあればハイライトとTreesitterのインデントを開始する。
PackChangedイベントで:TSUpdateを実行する。
パーサーがプラグインのバージョンと同期した状態に保たれる。
PackChangedフック
Inspect
4.2 ちょっとしたハイライト
todo-comments.nvimでTODOやFIXMEなどをハイライト。設定はデフォルト。
nvim-highlight-colorsで、hex、rgb、hsl、ANSI、CSS変数の色を背景色として表示。Tailwindはオフ。
色が二重に塗られないよう、NeovimのLSPのdocument colorsはオフにする。
TODOとFIXME
色の表示
5. コード支援
5.1 言語サーバー
Mason + mason-tool-installerで起動時にインストールし、自動更新はしません:
サーバー: lua-language-server, vtsls, eslint-lsp, oxlint, tailwindcss-language-server, css-lsp, rust-analyzer, copilot-language-server
フォーマッター: prettier, prettierd, oxfmt, stylua, shfmt
デフォルト設定はnvim-lspconfigから。
vim.lsp.enableで有効にするサーバー: eslint, oxlint, lua_ls, cssls, vtsls, tailwindcss, rust_analyzer
すべてのサーバーでファイル名変更(didRename / willRename)をサポートする。
Mason
単語のハイライト
5.2 診断の見た目
下線で表示し、入力中は更新せず、重大度順に並べる。
インラインのテキスト: ● メッセージ。ソースは複数あるときだけ表示する。
ガターのアイコンは共通のアイコンセットから。
たとえば、TSXファイルでconst x: number = 'a'と入力すると:
エラーに下線が引かれ、インラインに● Type 'string' is not assignable…、ガターにアイコンが出る。
この行には「never read」のヒントもあるが、重大度順なのでガターにはエラーのアイコンが出る。
oxlintも未使用のxを指摘するので、各メッセージにソース(ts、oxc)が表示される。
診断
5.3 サーバーごとの設定
サーバーごとの設定はafter/lsp/<name>.luaに書きます。
Neovim 0.12が自動でマージしてくれるので、セットアップのボイラープレートは不要です。
vtsls:
ワークスペースのTypeScriptを使い、ファイル移動時にimportを更新する。
サーバー側のあいまい検索と、関数呼び出しの補完。
インレイヒントは短く: 変数の型は出さず、最大30文字。
lua_ls: Neovimのランタイムを認識し、引数の型ヒントを表示し、うるさいチェックをいくつか黙らせる。
cssls: 空のルールを無視する。
oxlint: oxlint --lspで起動する。
lua_lsのチェックについて質問するClaude
5.4 補完
blink.cmp、バージョン^1、enterプリセット: Enterで確定。
5.1のすべての言語サーバーに、blink.cmpの補完のcapabilitiesも渡す。
関数の後に括弧を自動で付ける。ドキュメントは200ms後にポップアップ。
メニューの項目はTreesitterで色付けし、種類のアイコンは共通のアイコンセットから。
ゴーストテキストはオフ。
Copilotがすでにインラインで候補を出すので、ゴーストテキストが2つあるとぶつかる。
コマンドラインでは、:コマンドのときだけメニューが自動で開き、何も事前選択しない。
補完メニュー
5.5 括弧のペア
mini.pairsをデフォルト設定で、挿入モードとコマンドモードで使う。
5.6 フォーマット
conform.nvimで、保存時に1000msのタイムアウトでフォーマットし、なければLSPにフォールバックします。
ファイルタイプ
フォーマッター
js, ts, jsx, tsx, json, css, scss, less, html, markdown, mdx, yaml
oxfmt、prettierd、prettierの順(最初に使えるもの)
lua
stylua
sh
shfmt
fish
fish_indent
oxfmtは、プロジェクトに.oxfmtrc.jsonやVite+のvite.config.tsのようなoxfmtの設定があるときだけ動く。
prettierを使うプロジェクトは、そのままprettierでフォーマットされる。
:ToggleFormatterで、現在のバッファの保存時フォーマットをオフ/オンし、通知を出す。
このコマンドはconfig/commands.luaに置く。
ConformInfo
5.7 LSPのキーマップ
キー
動作
備考
gd
定義へ移動
gD、gy、grと同じくピッカー経由。
gD
宣言へ移動
gy
型定義へ移動
gr
参照の一覧
gI
TypeScriptではソース定義、他の言語では実装へ移動
.d.tsを飛ばして実際のコードに行ける。
;c
呼び出し元の一覧
K
ホバードキュメントを表示
gK / <C-k>(挿入モード)
シグネチャヘルプを表示
<C-j>
次の診断へジャンプしてフローティング表示
<leader>ca
コードアクションを表示
<leader>cr
シンボル名を変更
<leader>cR
importを更新しつつファイル名を変更
<leader>f
今すぐフォーマット
<leader>cl
LSPの情報を表示
参照のピッカー
ホバードキュメント
6. Git
今は主にエージェントが書いたコードをレビューしているので、セットアップの中でここが一番よく使う部分です。
6.1 サインとblame
gitsigns.nvimをデフォルト設定で。
キー
動作
備考
<leader>gb
行のblame
<leader>gB
バッファのblame
<leader>go
その行を最後に変更したコミット時点のファイルを新しいタブで開く
エディタを離れずに、昔の変更の文脈を確認できる。
<leader>gs
バッファをステージ。ステージするものがなければアンステージ
<leader>gh
ハンクをステージ/アンステージ
Gitのサイン
blameのフローティング
6.2 差分のオーバーレイ
mini.diffを自分のフォーク(craftzdog/mini.diff、feat/groupingブランチ)から使います。
このフォークでは、git diffの表示と同じように、変更をハンク単位でまとめる。
キー
動作
<leader>gd
オーバーレイの切り替え
]c / [c
ハンク間を移動
mini.diffのオーバーレイ
6.3 差分ビュー
codediff.nvimで、左右に並べた差分と履歴を見ます。
エージェントがコードベースに大量の変更を入れたときに使います。
エクスプローラー: ツリー表示、幅50列、カーソル移動に合わせてファイルを開き、行の増減(+/-)を表示。
コンパクトモード: 変更箇所と前後8行だけを表示し、折りたたみを左右のペインで同期。
キー
動作
<leader>dv
差分ビューの切り替え
<leader>dh
現在のファイルの履歴を表示
<leader>dH
リポジトリの履歴を表示
codediffのエクスプローラー
6.4 Lazygit
;gで、snacks.nvim経由でlazygitをフローティングで開きます。テーマを同期し、アクティブな枠線はWarningMsgの色にします。
ファイル上でeを押すと、lazygitを閉じ、起動元のウィンドウでファイルを開きます。$NVIMとnvim --server --remoteを使います。
;gは現在のウィンドウを覚えておく。
eはlazygitを終了し、--remote-sendでそのウィンドウにフォーカスしてからファイルを開くので、カーソルがファイルに移る。
新しいタブでも、入れ子のNeovimでもない。Neovimの外では、単にnvim <file>を実行する。
編集コマンドはfishの構文で書く。
lazygit自体の設定はNeovimの設定の外、~/.config/lazygit/config.ymlにあります。snacks.nvimが同期したテーマと一緒に読み込みます。内容は:
差分はdelta --dark --paging=never --syntax-theme="Solarized (dark)"で表示。
マウスイベントと自動fetchはオフ。
ファイルパネルのCで、commitizen(git cz)でコミット。
lazygitのフローティング
6.5 リンク
gitlinker.nvim: :GitLinkで、現在の行(または選択範囲)のGitHubのURLをコピー。
7. AI
7.1 Copilot
copilot.lua。自動トリガーをオンにし、Markdownとhelpでも有効にします。
メモやドキュメントでも、コードと同じくらい候補が役に立つ。
最初に一度:Copilot authが必要。
macOSでは、ターミナルでOptionをAltとして扱う設定が必要。
キーは挿入モードで使います:
キー
動作
<C-l>
候補を確定
Alt-l
1単語だけ確定
Alt-Shift-l
1行だけ確定
Alt-] / Alt-[
候補を切り替え
<C-]>
候補を消す
8. エージェントコーディング
Neovimからエージェントにコンテキストを渡すための、小さなヘルパーです。
8.1 エージェント用にパスをコピー
キー
動作
備考
<leader>yf
現在のファイルのcwdからの相対パスを#L<行番号>付きでコピー
例: lua/craftzdog/config/options.lua#L12
<leader>yp
同じ形式で絶対パスをコピー
どちらも、コピーしたテキストを通知で表示する。
パスをエージェントのプロンプトに貼れば、該当する行を正確に指せる。
パスをコピーした通知
8.2 ヘルパーのキーマップ
キー
動作
備考
<leader>cc(ビジュアル)
選択範囲を、filename="…"とline=…属性付きのMarkdownコードブロックとしてコピー
Inkdropのコードブロック属性と同じ形式。言語名は短縮形(tsx、jsx、ts、js)。
<leader>j
プロジェクトのpackage.jsonを中央の80%のフローティングで開く。qかEscで閉じる。
Inkdropに貼り付けたコードブロック
実践例: 新しいセットアップで小さなアプリを作る
このセットアップを普段どう使っているかを見せるために、小さなアプリを作りました。この設定のキーマップをすべて載せた、1ページのチートシートです。
Inkdropのノート駆動エージェントコーディングのワークフローに沿って進めました。
タスクごとにノートを1つ作り、自分とエージェントの共有の場所として使います。
僕が要件を書き、残りの計画はエージェントが埋めます。
1. アプリの雛形を作る
~/Developments/devaslife/keymap-cheatsheetにWakuのアプリを作りました:
npm create waku@latest
Wakuアプリの雛形作成
2. 計画ノートに要件を書く
新しいノートを作り、Cmd+Tで組み込みのImplementation planノートテンプレートを適用しました。
テンプレートの最初には、自分で書くRequirements(要件)とRelated notes(関連ノート)のセクションがある。
残りはエージェント用の骨組み: 要件の言い換え、現状、決定事項、フェーズ、リスク、ステータス、結果。
エージェントへの指示は> # !Instructionsと> # !Exampleのブロックに書かれている。
Inkdropは作成したノートからこれらを取り除き、エージェントは元のテンプレートから読む。
テンプレートから作った新しいノート
要件はたった2行と、スペックのノートへのリンクだけです:
Requirements
- Build a one-page keymap cheatsheet for my neovim setup
- It renders a simple table for each keymap
Related notes
- [Set up Neovim](inkdrop://note/…)
要件と関連ノート
3. エージェントに計画を埋めてもらう
ノートのリンクをコピーして、Claude Codeに渡しました:
fill out [Create a keymap cheatsheet for Neovim setup](inkdrop://note/eOuwoieG)
Claude Codeはfill-out-templateスキルを使い、InkdropのMCPサーバー経由でノートを読んで更新します。
計画を埋めるClaude
計画を書く前に、スペックのノートと実際のLuaの設定の両方を読んでいました。
すべてのキーマップの定義場所をfile:lineの形で一覧にした。
スペックと設定の食い違いを見つけた。
例: ファイル検索のキーが、スペックでは;fではなく:fと誤記されていた。
スペックより設定の方を信頼すると判断した。
そのうえで、僕にしか決められないことを質問してきました:
決定事項
質問
僕の答え
データの出どころ
ページはキーマップをどこから取得する?
手で整理した、型付きのTSデータファイル
対象範囲
スペックの表だけか、設定でマップしているキーすべてか?
マップしているキーすべて
スターターのUI
スターターのヘッダーとフッターを残す?
削除して、/の1ページだけにする
質問するClaude
僕の答えをDecisions Needed(決定事項)に記録し、作業を3つのフェーズに分けました:
キーマップのデータ
ページと表のコンポーネント
スターターの残骸を削除
埋まった計画
コードをレビューするより、計画をレビューする方がずっと楽なので、注意力はここに注ぎます。
4. 実装する
Claude Codeに実装を頼むと、3つのフェーズすべてを1分18秒で実装しました。
進むにつれて、ノートのStatusセクションで各フェーズにチェックを付けていきます。
実装完了
チートシートは7セクション・59キーで、ダークモードにも対応しています。
キーマップのチートシート
5. Neovimでコードをレビューする
ここでセットアップのGitの部分が活躍します:
;g: lazygitで、差分全体にざっと目を通す
<leader>dv: codediffで、変更されたファイルを1つずつ左右に並べて見る
<leader>gd: mini.diffのオーバーレイで、ファイル内の変更を見る
lazygitで差分をレビュー
mini.diffでレビュー
レビューの後、プロジェクトをpnpmに切り替えてコミットしました。
6. 結果を記録する
最後に、動いているページのスクリーンショットをClaude Codeに貼りました。
するとノートのOutcome(結果)とFollow-up(フォローアップ)のセクションを埋めてくれます。
結果を記録したノート
これでノートには、何をなぜ作ったのかが残ります。スペックの誤記を直すというフォローアップも含めてです。完成したノートはこちら: Create a keymap cheatsheet for Neovim setup
まとめ
今やコードを書くコストはほぼゼロなので、設定を自然言語のスペックとして書くのはとても自然に感じました。僕の場合は英語と日本語です。
スペックは読みやすく、各設定の横に「なぜ」が残ります。そして、やりたいことをエージェントに伝えるだけで、いつでもセットアップを作り直したり調整したりできます。
スペックは全部上に載せたので、ぜひコピーして自分好みにしてみてください。皆さんのNeovimセットアップの参考になれば嬉しいです。読んで・観てくれてありがとうございました!
Mentions
Vim沼: AIコーディング用Neovimセットアップ ! 本記事は devas.life の日本語訳です どうもTAKUYAです。本稿では、AIエージェント(Claude Code)を使用してNeovimをセットアップする手順について説明します。 動画版はこちら: youtube.com dotfilesはこちら: craftzdog/dotfiles 構成サマリー この記事で紹介するセットアップの全体像です。 スペックは9つのステップに分かれています。 ステップ 内容 主なプラグイン・機能 0. 前提条件 Neovim、CLIツール、フォント、Git Neovim 0.12、Nerd Font 1. 基盤 ファイル構成、オプション、メッセージ、基本のキーマップ vim.pack、ui2、tiny-cmdline.nvim 2. 見た目 カラースキーム、アイコン、タブライン、ステータスライン solarized-osaka、mini.icons、自作タブライン、lualine、incline.nvim、snacks.nvim 3. ナビゲーション ピッカー、ファイルエクスプローラー snacks.nvimのピッカー、oil.nvim 4. シンタックス 構文ハイライト、TODOと色の表示 nvim-treesitter、todo-comments.nvim、nvim-highlight-colors 5. コード支援 言語サーバー、補完、括弧、フォーマット Mason、nvim-lspconfig、blink.cmp、mini.pairs、conform.nvim 6. Git サイン、差分、lazygit、リンク gitsigns.nvim、mini.diff(フォーク)、codediff.nvim、lazygit、gitlinker.nvim 7. AI インラインの補完候補 copilot.lua 8. エージェントコーディング パスやコードブロックをエージェント用にコピー 自作のキーマップ ファイル構成: ~/.config/nvim ├── init.lua ├── after/lsp/<name>.lua # サーバーごとのLSP設定 └── lua/craftzdog/ ├── utils/ # 共通のヘルパー ├── config/ # options, keymaps, autocmds, commands, workarounds └── plugins/ # init.lua、グループごとの設定、keymaps.lua LazyVimを卒業した 2023年に紹介した前回のセットアップでは、プラグインのメンテナンスを避けるためにLazyVimを使っていて、とても快適でした。 LazyVimコミュニティのおかげで、プラグインを簡単に最新に保てて、設定も気軽にいじれました。 でも、カスタマイズすればするほど不安定になっていきました。 LazyVimを更新するたびにエラーを直すのが、ちょっと面倒だったんです。 一方で最近のNeovimでは、以前はプラグインが必要だった機能がたくさん組み込まれました: vim.pack: 組み込みのプラグインマネージャー vim.lsp.enableとafter/lsp/<name>.lua: ほぼボイラープレートなしでLSPを設定できる ui2: 新しいメッセージUI :restart: Neovimを再起動してセッションを復元する そこで、これらをベースに新しくセットアップを作ることにしました。 エージェントコーディングのためのNeovim Agentic Codingが普及し、僕もすっかりエージェント中心の開発ワークフローになりました。 最近はNeovimを、手でコードを書くためというより、主にコードレビューのために使っています。 正直、ワークフローの変化がとても速いので、いつまでこの構成でNeovimを使い続けるかはわかりません。しかしながら、現状のセットアップをシェアしてその変化を楽しむのも一興だと思いました。 設定を自然言語で書く 今はNeovimの設定をいじるのがとても簡単です。やりたいことをエージェントに伝えるだけだからです。 そこでLuaを書く代わりに、設定の スペック(仕様書) を英語でInkdropに書き、MCPサーバー経由でエージェントにステップごとに渡しました。 スペックノート スペックには「どうやるか」ではなく、「何がしたいか」と「なぜか」を書きます。 Luaのコードはエージェントが考えます。 ワークフロー スペックのステップを1つ書く。 そのステップだけを実装するようエージェントに頼む。 :restartでNeovimを再起動し、自分で動作を確認する。 差分をレビューしてコミットする。 エージェントへのプロンプト エージェントには次のルールを伝えました: スペックを読み、指定したステップだけを実装する。それ以外は何も足さない。 作業結果は軽くチェックする: Neovimがエラーなしで起動する: nvim --headless +qa 新しいキーマップが存在する: :verbose map <key> テスト用のプロジェクトを作ったり、UIを操作したりしない。動作は再起動後に自分で確認する。 設定のリロード ZRに:restartを割り当てています。 Neovimが同じターミナル内で再起動し、ウィンドウ、タブ、バッファを復元します。 先に:waで保存しておきます。未保存のバッファがあると再起動できません。 :restart +qall!なら未保存の変更を破棄して再起動します。 プラグインを追加するステップの後は、vim.packがインストールの確認を出すので承認します。 再起動で終了してしまうので、エージェントはNeovim内の:terminalではなく、別のターミナル分割で動かします。 以下が、ステップごとのスペック全体です。 自由にコピーして自分のエージェントに渡し、好みに合わせて調整してください。 0. 前提条件 0.1 Neovim Neovim 0.12以上。 この設定は0.12で入った組み込み機能(vim.pack、vim.lsp.enable、ui2メッセージUI)に依存しています。 0.2 CLIツール ツール 用途 git vim.packがプラグインのクローンに使う tree-sitter CLI + Cコンパイラ nvim-treesitterのmainブランチはパーサーをローカルでビルドする curlとtar パーサーとblink.cmpのバイナリのダウンロード Node.js + npm Masonはほとんどの言語サーバーをnpm経由でインストールする ripgrepとfd テキスト検索とファイル検索のバックエンド lazygitとgit-delta Git UIとその差分表示 0.3 フォント Nerd Font。僕はPlemolJP Console NFを使っています。 タブライン、ステータスライン、補完メニュー、ファイルエクスプローラーにアイコンが出るので、普通のフォントだと四角(豆腐)になります。 0.4 Git 設定フォルダはGitリポジトリにする。 .gitignoreにnvim-pack-lock.jsonを入れる。 1. 基盤 1.0 セッションを始める まず、スペックの場所をエージェントに伝えました: I'd like to make a neovim setup. I'm going to write a spec in this note: <link to the spec> When you are ready, say so エージェントの最初の返答 1.1 構成 ~/.config/nvim: 設定のルートフォルダ init.lua: 起動を速くするためvim.loaderを有効にし、次のファイルを順に直接requireする: craftzdog.utils(グローバル変数Craftzdogに代入) craftzdog.config.options、.keymaps、.autocmds、.commands、.workarounds craftzdog.plugins lua/craftzdog/: 自分の設定はここに置く utils/: 共通のヘルパー init.lua: ヘルパーモジュールのテーブルを返す。最初は空。 後のステップでutils/editor.luaのようなモジュールを追加し、editorとして公開する。 config/: Neovim本体の設定。上に挙げた名前ごとに1ファイル plugins/ init.lua: 1回のvim.pack.addですべてのプラグインをインストールし、各グループのファイルをrequireする プラグインのグループごとに隣にファイルを作り(例: ui.lua)、require("<plugin>").setup({ ... })で設定する。 keymaps.lua: プラグインを使うキーマップはすべてここ。すべてのプラグインの設定が終わってから読むよう、最後にrequireする。グループのファイルにはキーマップを書かない。 Luaファイルはタブでインデントし、stylua(デフォルト設定)で整形する。 生成されたファイルツリー 1.2 リーダーキーと基本設定 リーダーとローカルリーダーはSpace。 マウスはオフ。キーボードのみ。 クリップボードはunnamedplus。ヤンクとペーストがシステムのクリップボードを通る。 インデントはスペース2つ: tabstop、shiftwidth、softtabstopはすべて2 expandtabとsmartindentはオン -を単語の一部として扱うので、foo-barは1単語になる。 CSSのクラス名やケバブケースの名前に合う。 1.3 バッファの見た目 ハイブリッド行番号: number + relativenumberをオンにして、カーソル行には実際の行番号を表示する。 cursorlineはオン。折り返しなし、scrolloffは10、sidescrolloffは8。 signcolumnは常に表示。 Gitや診断のマークが出てもテキストがずれない。 cmdheightは0、ステータスラインはグローバルに1本(laststatus 3)。 縦のスペースを最大限使う。 すべてのフローティングウィンドウの枠を角丸に(winborder)。 ポップアップメニュー: 最大10行、少し透過(pumheight 10、pumblend 10)。 対応する括弧を一瞬ハイライト(showmatch オン、matchtime 2)。 titleをオンにして、ターミナルのタブにファイル名を表示する。 差分の空き領域を斜線╱で埋める。 ハイブリッド行番号 1.4 検索、ファイル、アンドゥ ignorecase + smartcaseをオン: 大文字を入力するまでは大文字・小文字を区別しない。 pathに**を追加して、:findがサブフォルダも検索するようにする。 :の補完: wildmodeはlongest:full,full wildignoreで/node_modules/、.o、.obj、.pyc、.class、*.jarを除外 swapfileとwritebackupはオフ。 永続アンドゥ(undofile オン)の保存先は~/.cache/nvim/undodir。 ファイルを閉じてもアンドゥできる。スワップファイルは邪魔なだけ。 タイミングをキビキビさせる: updatetime 300、timeoutlen 500、ttimeoutlen 0。 CursorHoldイベントが早くなり、キーシーケンスが遅延なく確定する。 試してみる: init.luaで/craftzdog、次に/Craftzdog :find opt<Tab> init.luaを編集して:wq、開き直してからu 1.5 分割と折りたたみ 新しい分割は下と右に開く。 折りたたみはTreesitterから作り、foldlevelは99。 最初はすべて展開された状態で、構文単位で折りたたむこともできる。 試してみる: :split、:vsplit :e $VIMRUNTIME/lua/vim/keymap.luaを開き、関数の中でzc / zo zM / zR 折りたたまれた関数 1.6 メッセージ メッセージはNeovim 0.12の実験的機能ui2で表示します。config/options.luaの最後で有効にします。 短いメッセージ: 画面の隅にポップアップ(最大で画面の高さの30%)し、5秒で消える。 長い出力(エラー、:ls、:verbose、シェルコマンド、進捗): 最大で画面の半分までのスクロールできるページャーに表示。 検索件数、検索パターン、補完、:の補完リスト、確認プロンプトはコマンドラインに残す。 自分で入力したコマンドの出力は、種類にかかわらずコマンドラインに表示する。 次のキーを押すまで、画面の下部に広がって表示される。 Enterでページャーに移る。 tiny-cmdline.nvimで、:のコマンドラインを左右中央・上から20%の位置にフローティングボックスとして表示します。設定はplugins/ui.luaに書きます。 cmdheightが0なのでコマンドラインを出す場所が必要で、視線がもともとある上の方が見やすい。 試してみる: :echo "hi" :lua print("hi") :foo :!ls :verbose set ts? フローティングのコマンドライン lsの出力 1.7 autocmd ヤンクしたテキストを一瞬ハイライトする。 アクティブなウィンドウにだけcursorlineを表示する。 ヤンクのハイライト 1.8 基本のキーマップ キー 動作 備考 x ヤンクせずに削除 <leader>d、<leader>c、<leader>p ヤンクレジスタを変えずに削除・変更・ペースト 周りを編集しても、ヤンクしたテキストが残る。 dw 単語を後方にヤンクせず削除 - / - 数値を増減 <C-a> 全選択 te 新しいタブを開く Tab / Shift-Tab タブを切り替える ss / sv 分割 ホームポジションで短くウィンドウを操作できる。 sh sj sk sl ウィンドウ間を移動 ホームポジションで短くウィンドウを操作できる。 <C-m> ジャンプリストを前に進む ターミナルでは<C-i>がTabと同じキーで、Tabはタブ切り替えに使っているため。 <leader>o / <leader>O コメントを継続せずに下/上に行を挿入(o<Esc>^Da) ssとsvで分割 1.9 隠れバッファを閉じる <leader>bdで、未保存のものを除くすべての隠れバッファを閉じる。 2. 見た目 2.1 カラースキーム solarized-osaka、vividスタイル、背景は透過。 ターミナルのブラーが透けて見え、配色がGhosttyのテーマと揃う。 カラースキーム適用前 カラースキーム適用後 2.2 アイコン mini.icons。nvim-web-deviconsのモックも兼ねる。 すべてのプラグインでアイコンの出どころを1つにする。 2.3 タブライン プラグインを使わず、utils/tabline.luaに自作のタブラインを書きます。 タブが2つ以上のときだけ表示する。 各タブには、アクティブなウィンドウのファイル名とアイコンを、左右3スペースずつの余白付きで、斜めの区切りの間に表示する。 両端が下に向かって外側に傾くので、各タブは下が広い台形になる: 色はsolarized-osakaのパレットから: アクティブなタブ: yellowの背景に太字のbase4の文字 非アクティブなタブ: base02の背景にbase0の文字 アイコンはタブの文字色に合わせる。 区切りは透過背景にタブの色。最後のタブの後ろの空き領域も同じ。 20文字より長い名前は、17文字に切って…を付ける。 未保存のタブはアイコンの前に[+]を表示する。 ターミナルは[Terminal]、空のバッファは[No Name]と表示し、アイコンは付けない。 タブライン 2.4 ステータスライン lualine。グローバルに1本、テーマはauto。 セクション 内容 a モード b Gitブランチ c プロジェクトルート名(cwdと違う場合のみ)、ファイルタイプのアイコン、整形したパス x マクロ記録中のレジスタ、診断、Gitの差分数 y 進捗 z 行:列 プロジェクトルートは、上の階層に向かって.git、lua、package.json、Makefile、Cargo.toml、go.mod、pyproject.tomlを探して決める。 カーソル移動時と、マクロの記録開始・終了時に更新する。 記録中の表示が、非表示のコマンドラインの代わりになる。 完成イメージ: 結果: ステータスライン 2.5 ウィンドウのラベル incline.nvimで、各ウィンドウの右上にアイコン付きのファイル名タグを表示する。未保存なら[+]も付ける。 ステータスラインがグローバルに1本なので、分割したそれぞれのウィンドウにどのファイルかを示す必要がある。 カーソルがタグの行に来たら、タグを隠す。 inclineのラベル 2.6 Snacks snacks.nvimで、通知、インデントガイド、statuscolumn、単語のハイライトを提供します。 後のステップで、ピッカーやlazygit連携など、さらに機能を有効にしていきます。 Words: カーソル下の単語をすべてハイライトする。]] / [[で出現箇所を移動。 言語サーバーが必要なので、ステップ5.1の後から動く。 スムーズスクロールはオフ。 スクロールは即座に反応してほしい。 vim.notify インデントガイド 3. ナビゲーション 3.1 ピッカー snacks.nvimのピッカー。 キー 動作 備考 ;f 隠しファイルも含めてファイルを検索 .github/や.env.exampleのようなドットファイルも、実際のプロジェクトの一部。 ;r 隠しファイルも含めてライブgrep ;; 最後のピッカーを開き直す \ 開いているバッファの一覧 すでにそのバッファを表示しているウィンドウがあれば、そこにジャンプする。 ;e 診断の一覧 ;n 通知の履歴 ;h Gitのハンクの一覧 ファイルピッカー ライブgrep 3.2 ファイルエクスプローラー oil.nvimでnetrwを置き換え、隠しファイルも表示します。 ディレクトリがバッファになっているので、ファイルの名前変更・移動・削除は、テキストを編集して:wするだけ。 列: アイコン、パーミッション、サイズ、更新日時。 ファイル名を変更すると、LSPにimportの更新を頼み、その編集を自動で保存する。 タブライン(2.3)では、oilのタブはディレクトリ(~/foo)をアイコンなしで表示する。 20文字より長いパスは左側を切り、…と末尾の17文字にする。 キー 動作 備考 sf ライブプレビュー付きの中央フローティングでoilを開く 最大200列幅、角丸。 h 親ディレクトリに移動 q oilを閉じる プレビュー付きのoilフローティング oilの列 4. シンタックス 4.1 Treesitter nvim-treesitterのmainブランチ。 38個のパーサーを入れる: astro, bash, c, cmake, cpp, css, diff, fish, gitignore, go, graphql, html, http, java, javascript, jsdoc, json, lua, luadoc, luap, markdown, markdown_inline, php, printf, python, query, regex, rust, scss, sql, svelte, toml, tsx, typescript, vim, vimdoc, xml, yaml FileTypeのautocmdで、パーサーがあればハイライトとTreesitterのインデントを開始する。 PackChangedイベントで:TSUpdateを実行する。 パーサーがプラグインのバージョンと同期した状態に保たれる。 PackChangedフック Inspect 4.2 ちょっとしたハイライト todo-comments.nvimでTODOやFIXMEなどをハイライト。設定はデフォルト。 nvim-highlight-colorsで、hex、rgb、hsl、ANSI、CSS変数の色を背景色として表示。Tailwindはオフ。 色が二重に塗られないよう、NeovimのLSPのdocument colorsはオフにする。 TODOとFIXME 色の表示 5. コード支援 5.1 言語サーバー Mason + mason-tool-installerで起動時にインストールし、自動更新はしません: サーバー: lua-language-server, vtsls, eslint-lsp, oxlint, tailwindcss-language-server, css-lsp, rust-analyzer, copilot-language-server フォーマッター: prettier, prettierd, oxfmt, stylua, shfmt デフォルト設定はnvim-lspconfigから。 vim.lsp.enableで有効にするサーバー: eslint, oxlint, lua_ls, cssls, vtsls, tailwindcss, rust_analyzer すべてのサーバーでファイル名変更(didRename / willRename)をサポートする。 Mason 単語のハイライト 5.2 診断の見た目 下線で表示し、入力中は更新せず、重大度順に並べる。 インラインのテキスト: ● メッセージ。ソースは複数あるときだけ表示する。 ガターのアイコンは共通のアイコンセットから。 たとえば、TSXファイルでconst x: number = 'a'と入力すると: エラーに下線が引かれ、インラインに● Type 'string' is not assignable…、ガターにアイコンが出る。 この行には「never read」のヒントもあるが、重大度順なのでガターにはエラーのアイコンが出る。 oxlintも未使用のxを指摘するので、各メッセージにソース(ts、oxc)が表示される。 診断 5.3 サーバーごとの設定 サーバーごとの設定はafter/lsp/<name>.luaに書きます。 Neovim 0.12が自動でマージしてくれるので、セットアップのボイラープレートは不要です。 vtsls: ワークスペースのTypeScriptを使い、ファイル移動時にimportを更新する。 サーバー側のあいまい検索と、関数呼び出しの補完。 インレイヒントは短く: 変数の型は出さず、最大30文字。 lua_ls: Neovimのランタイムを認識し、引数の型ヒントを表示し、うるさいチェックをいくつか黙らせる。 cssls: 空のルールを無視する。 oxlint: oxlint --lspで起動する。 lua_lsのチェックについて質問するClaude 5.4 補完 blink.cmp、バージョン^1、enterプリセット: Enterで確定。 5.1のすべての言語サーバーに、blink.cmpの補完のcapabilitiesも渡す。 関数の後に括弧を自動で付ける。ドキュメントは200ms後にポップアップ。 メニューの項目はTreesitterで色付けし、種類のアイコンは共通のアイコンセットから。 ゴーストテキストはオフ。 Copilotがすでにインラインで候補を出すので、ゴーストテキストが2つあるとぶつかる。 コマンドラインでは、:コマンドのときだけメニューが自動で開き、何も事前選択しない。 補完メニュー 5.5 括弧のペア mini.pairsをデフォルト設定で、挿入モードとコマンドモードで使う。 5.6 フォーマット conform.nvimで、保存時に1000msのタイムアウトでフォーマットし、なければLSPにフォールバックします。 ファイルタイプ フォーマッター js, ts, jsx, tsx, json, css, scss, less, html, markdown, mdx, yaml oxfmt、prettierd、prettierの順(最初に使えるもの) lua stylua sh shfmt fish fish_indent oxfmtは、プロジェクトに.oxfmtrc.jsonやVite+のvite.config.tsのようなoxfmtの設定があるときだけ動く。 prettierを使うプロジェクトは、そのままprettierでフォーマットされる。 :ToggleFormatterで、現在のバッファの保存時フォーマットをオフ/オンし、通知を出す。 このコマンドはconfig/commands.luaに置く。 ConformInfo 5.7 LSPのキーマップ キー 動作 備考 gd 定義へ移動 gD、gy、grと同じくピッカー経由。 gD 宣言へ移動 gy 型定義へ移動 gr 参照の一覧 gI TypeScriptではソース定義、他の言語では実装へ移動 .d.tsを飛ばして実際のコードに行ける。 ;c 呼び出し元の一覧 K ホバードキュメントを表示 gK / <C-k>(挿入モード) シグネチャヘルプを表示 <C-j> 次の診断へジャンプしてフローティング表示 <leader>ca コードアクションを表示 <leader>cr シンボル名を変更 <leader>cR importを更新しつつファイル名を変更 <leader>f 今すぐフォーマット <leader>cl LSPの情報を表示 参照のピッカー ホバードキュメント 6. Git 今は主にエージェントが書いたコードをレビューしているので、セットアップの中でここが一番よく使う部分です。 6.1 サインとblame gitsigns.nvimをデフォルト設定で。 キー 動作 備考 <leader>gb 行のblame <leader>gB バッファのblame <leader>go その行を最後に変更したコミット時点のファイルを新しいタブで開く エディタを離れずに、昔の変更の文脈を確認できる。 <leader>gs バッファをステージ。ステージするものがなければアンステージ <leader>gh ハンクをステージ/アンステージ Gitのサイン blameのフローティング 6.2 差分のオーバーレイ mini.diffを自分のフォーク(craftzdog/mini.diff、feat/groupingブランチ)から使います。 このフォークでは、git diffの表示と同じように、変更をハンク単位でまとめる。 キー 動作 <leader>gd オーバーレイの切り替え ]c / [c ハンク間を移動 mini.diffのオーバーレイ 6.3 差分ビュー codediff.nvimで、左右に並べた差分と履歴を見ます。 エージェントがコードベースに大量の変更を入れたときに使います。 エクスプローラー: ツリー表示、幅50列、カーソル移動に合わせてファイルを開き、行の増減(+/-)を表示。 コンパクトモード: 変更箇所と前後8行だけを表示し、折りたたみを左右のペインで同期。 キー 動作 <leader>dv 差分ビューの切り替え <leader>dh 現在のファイルの履歴を表示 <leader>dH リポジトリの履歴を表示 codediffのエクスプローラー 6.4 Lazygit ;gで、snacks.nvim経由でlazygitをフローティングで開きます。テーマを同期し、アクティブな枠線はWarningMsgの色にします。 ファイル上でeを押すと、lazygitを閉じ、起動元のウィンドウでファイルを開きます。$NVIMとnvim --server --remoteを使います。 ;gは現在のウィンドウを覚えておく。 eはlazygitを終了し、--remote-sendでそのウィンドウにフォーカスしてからファイルを開くので、カーソルがファイルに移る。 新しいタブでも、入れ子のNeovimでもない。Neovimの外では、単にnvim <file>を実行する。 編集コマンドはfishの構文で書く。 lazygit自体の設定はNeovimの設定の外、~/.config/lazygit/config.ymlにあります。snacks.nvimが同期したテーマと一緒に読み込みます。内容は: 差分はdelta --dark --paging=never --syntax-theme="Solarized (dark)"で表示。 マウスイベントと自動fetchはオフ。 ファイルパネルのCで、commitizen(git cz)でコミット。 lazygitのフローティング 6.5 リンク gitlinker.nvim: :GitLinkで、現在の行(または選択範囲)のGitHubのURLをコピー。 7. AI 7.1 Copilot copilot.lua。自動トリガーをオンにし、Markdownとhelpでも有効にします。 メモやドキュメントでも、コードと同じくらい候補が役に立つ。 最初に一度:Copilot authが必要。 macOSでは、ターミナルでOptionをAltとして扱う設定が必要。 キーは挿入モードで使います: キー 動作 <C-l> 候補を確定 Alt-l 1単語だけ確定 Alt-Shift-l 1行だけ確定 Alt-] / Alt-[ 候補を切り替え <C-]> 候補を消す 8. エージェントコーディング Neovimからエージェントにコンテキストを渡すための、小さなヘルパーです。 8.1 エージェント用にパスをコピー キー 動作 備考 <leader>yf 現在のファイルのcwdからの相対パスを#L<行番号>付きでコピー 例: lua/craftzdog/config/options.lua#L12 <leader>yp 同じ形式で絶対パスをコピー どちらも、コピーしたテキストを通知で表示する。 パスをエージェントのプロンプトに貼れば、該当する行を正確に指せる。 パスをコピーした通知 8.2 ヘルパーのキーマップ キー 動作 備考 <leader>cc(ビジュアル) 選択範囲を、filename="…"とline=…属性付きのMarkdownコードブロックとしてコピー Inkdropのコードブロック属性と同じ形式。言語名は短縮形(tsx、jsx、ts、js)。 <leader>j プロジェクトのpackage.jsonを中央の80%のフローティングで開く。qかEscで閉じる。 Inkdropに貼り付けたコードブロック 実践例: 新しいセットアップで小さなアプリを作る このセットアップを普段どう使っているかを見せるために、小さなアプリを作りました。この設定のキーマップをすべて載せた、1ページのチートシートです。 Inkdropのノート駆動エージェントコーディングのワークフローに沿って進めました。 タスクごとにノートを1つ作り、自分とエージェントの共有の場所として使います。 僕が要件を書き、残りの計画はエージェントが埋めます。 1. アプリの雛形を作る ~/Developments/devaslife/keymap-cheatsheetにWakuのアプリを作りました: npm create waku@latest Wakuアプリの雛形作成 2. 計画ノートに要件を書く 新しいノートを作り、Cmd+Tで組み込みのImplementation planノートテンプレートを適用しました。 テンプレートの最初には、自分で書くRequirements(要件)とRelated notes(関連ノート)のセクションがある。 残りはエージェント用の骨組み: 要件の言い換え、現状、決定事項、フェーズ、リスク、ステータス、結果。 エージェントへの指示は> # !Instructionsと> # !Exampleのブロックに書かれている。 Inkdropは作成したノートからこれらを取り除き、エージェントは元のテンプレートから読む。 テンプレートから作った新しいノート 要件はたった2行と、スペックのノートへのリンクだけです: Requirements - Build a one-page keymap cheatsheet for my neovim setup - It renders a simple table for each keymap Related notes - [Set up Neovim](inkdrop://note/…) 要件と関連ノート 3. エージェントに計画を埋めてもらう ノートのリンクをコピーして、Claude Codeに渡しました: fill out [Create a keymap cheatsheet for Neovim setup](inkdrop://note/eOuwoieG) Claude Codeはfill-out-templateスキルを使い、InkdropのMCPサーバー経由でノートを読んで更新します。 計画を埋めるClaude 計画を書く前に、スペックのノートと実際のLuaの設定の両方を読んでいました。 すべてのキーマップの定義場所をfile:lineの形で一覧にした。 スペックと設定の食い違いを見つけた。 例: ファイル検索のキーが、スペックでは;fではなく:fと誤記されていた。 スペックより設定の方を信頼すると判断した。 そのうえで、僕にしか決められないことを質問してきました: 決定事項 質問 僕の答え データの出どころ ページはキーマップをどこから取得する? 手で整理した、型付きのTSデータファイル 対象範囲 スペックの表だけか、設定でマップしているキーすべてか? マップしているキーすべて スターターのUI スターターのヘッダーとフッターを残す? 削除して、/の1ページだけにする 質問するClaude 僕の答えをDecisions Needed(決定事項)に記録し、作業を3つのフェーズに分けました: キーマップのデータ ページと表のコンポーネント スターターの残骸を削除 埋まった計画 コードをレビューするより、計画をレビューする方がずっと楽なので、注意力はここに注ぎます。 4. 実装する Claude Codeに実装を頼むと、3つのフェーズすべてを1分18秒で実装しました。 進むにつれて、ノートのStatusセクションで各フェーズにチェックを付けていきます。 実装完了 チートシートは7セクション・59キーで、ダークモードにも対応しています。 キーマップのチートシート 5. Neovimでコードをレビューする ここでセットアップのGitの部分が活躍します: ;g: lazygitで、差分全体にざっと目を通す <leader>dv: codediffで、変更されたファイルを1つずつ左右に並べて見る <leader>gd: mini.diffのオーバーレイで、ファイル内の変更を見る lazygitで差分をレビュー mini.diffでレビュー レビューの後、プロジェクトをpnpmに切り替えてコミットしました。 6. 結果を記録する 最後に、動いているページのスクリーンショットをClaude Codeに貼りました。 するとノートのOutcome(結果)とFollow-up(フォローアップ)のセクションを埋めてくれます。 結果を記録したノート これでノートには、何をなぜ作ったのかが残ります。スペックの誤記を直すというフォローアップも含めてです。完成したノートはこちら: Create a keymap cheatsheet for Neovim setup まとめ 今やコードを書くコストはほぼゼロなので、設定を自然言語のスペックとして書くのはとても自然に感じました。僕の場合は英語と日本語です。 スペックは読みやすく、各設定の横に「なぜ」が残ります。そして、やりたいことをエージェントに伝えるだけで、いつでもセットアップを作り直したり調整したりできます。 スペックは全部上に載せたので、ぜひコピーして自分好みにしてみてください。皆さんのNeovimセットアップの参考になれば嬉しいです。読んで・観てくれてありがとうございました!
Windows + WSL2にHerdr Appをセットアップする はじめに Herdr Appは、ターミナルやコーディングエージェントをまとめて扱えるデスクトップアプリです。今回はWindowsにアプリを入れ、SSH経由でWSL2(Ubuntu)上の開発環境を使います。 1. WSL2を準備する WSL2、Ubuntu、SSH、開発用CLIのセットアップは、次のOrca記事と同じです。手順はそちらを参照してください。Orca本体のインストールと接続設定は不要です。 zenn.dev WindowsからUbuntuへSSH接続できる状態まで準備し、公開鍵認証も設定しておきます。 ! 今回の環境では、Herdr AppからのSSH接続はパスワード認証ではうまくいかず、公開鍵認証を使う必要がありました。リンク先の「公開鍵認証で接続する」まで設定してください。 2. WindowsにHerdr Appをインストールする WindowsのPowerShellで、公式のインストールコマンドを実行します(Windows x64向け)。 irm releases.herdr.dev | iex インストール後、スタートメニューからHerdrを起動します。 3. WSL2へ接続する Windows側の C:\Users<Windowsのユーザー名>.ssh\config に接続先を追加します。既存の設定がある場合は末尾へ追記してください。 Host wsl HostName localhost User <Ubuntuのユーザー名> Port 22 IdentityFile ~/.ssh/id_ed25519_orca_wsl IdentitiesOnly yes IdentityFileには、Orca記事で作成したWindows側の秘密鍵を指定しています。別の鍵を使う場合は変更してください。 PowerShellで接続を確認します。 ssh wsl Ubuntuへ接続できたら exit で戻ります。 接続先でターミナルを動かすため、Ubuntu側にも herdr-core が必要です。Ubuntuのターミナルで、公式のインストールコマンドを実行します。 curl -fsSL releases.herdr.dev | sh インストーラーからPATHの追加を案内された場合は反映してください。 Herdr Appの Settings → Machines またはサイドバーの Add machine から、SSHの接続先 wsl を追加します。SSH設定からのホスト選択に対応しています。詳しくは公式READMEの接続手順を参照してください。 4. Ubuntu上でエージェントを起動する 追加した wsl のスペースを開き、ターミナルで作業ディレクトリへ移動します。 cd ~/projects/<リポジトリ名> uname -a Linuxの情報が表示されることを確認し、インストール済みのエージェントを起動します。例えばClaude Codeなら次のとおりです。 claude これで、WindowsのHerdr AppからUbuntu上のプロジェクトを操作できます。 スペース・タブ・ペインの基本操作は公式README、エージェントを使った設定変更の例は公式ガイドを参照してください。操作コマンドとショートカットは Ctrl+Shift+P のコマンドパレットで確認できます。 補足:Windowsのブラウザーを開く WSL側のCLIからWindowsの既定ブラウザーを開くには、wslviewを使います。Ubuntuでインストールします。 sudo apt update sudo apt install -y wslu Ubuntuの ~/.bashrc に次を追記します。 export BROWSER=wslview Herdr Appで開いたUbuntuのターミナルで設定を反映し、ブラウザーが開くことを確認してください。 source ~/.bashrc "$BROWSER" example.com BROWSER を参照するCLIは、この設定でWindowsのブラウザーを利用できます。起動済みのCLIには設定が反映されないため、設定後に起動し直してください。 補足:日本語のフォント幅 日本語の表示では、フォント幅がおかしく見える箇所があります。 日本語の文字間隔が不自然に広がっている例 次の投稿では、JetBrains Monoと日本語を統合したフォント UDEV Gothic を使うと表示が落ち着いたと報告されています。フォントのフォールバック時の文字幅計算に問題がある可能性も挙げられていますが、原因は推測です。日本語の表示が崩れる場合は、UDEV Gothicへの変更を試してみてください。本記事の環境での改善効果は未確認です。 x.com
ghostty の font を気分転換に変えたら、なんか週明けから エーアイ の文字をちゃんと読めるようになった。 yuru7/PlemolJP
@lartex_0x59 Moralerspace Radonっていうフォントです! yuru7/moralerspace