Post

ターミナルでVS Code的なコード閲覧環境を作る — Neovim + LazyVim入門

TL;DR

  • Neovim + LazyVim でファイルツリー・タブ・LSP・ファジー検索が最初から揃う
  • neo-tree をカスタマイズすると、ツリーでカーソル移動するだけでプレビュー表示される VS Code 的な体験が得られる
  • microhelix も試したが、プロジェクト単位のコード閲覧には Neovim が一番完成度が高い

背景

ターミナルで VS Code のようにコードを閲覧・編集したかった。いくつかのツールを試した結果:

ツール 評価 理由
bat ファイル単体なら良い プロジェクト単位の操作ができない
micro 編集は直感的 filemanager プラグインの完成度が低い
helix LSP内蔵で設定不要 ファイルツリーが未実装
Neovim + LazyVim 採用 ファイルツリー・タブ・LSP が全部入り

セットアップ

インストール

brew install neovim ripgrep fd

LazyVim の導入

# 既存設定があればバックアップ mv ~/.config/nvim ~/.config/nvim.bak 2>/dev/null # LazyVim starter をクローン git clone https://github.com/LazyVim/starter ~/.config/nvim

nvim で起動するとプラグインが自動インストールされる。

基本操作

ナビゲーション

キー 操作
Space リーダーメニュー(VS Code の Cmd+Shift+P 的)
Space + e ファイルツリー表示
Space + f + f ファイル検索(Cmd+P 的)
Space + s + g 全文検索(Cmd+Shift+F 的)
Ctrl + h 左ウィンドウ(ツリー)にフォーカス
Ctrl + l 右ウィンドウ(エディタ)にフォーカス

エディタ操作

キー 操作
i 編集モードに入る
Esc or Ctrl+c 編集モードを抜ける
Ctrl+f / Ctrl+b 1ページ下/上
Ctrl+d / Ctrl+u 半ページ下/上
g + d 定義へジャンプ
K ホバー情報
:wqa 全保存して終了
:qa 全終了(保存なし)

neo-tree カスタマイズ: VS Code 的プレビュー体験

デフォルトの neo-tree は Space + e でツリーが開閉するだけ。以下をカスタマイズした:

  1. 起動時にツリーを常時表示
  2. ツリーでカーソル移動するだけでファイル内容をプレビュー
  3. プレビュー用バッファを1つだけ使い回す(タブが増殖しない)
  4. Enter で正式にファイルを開く(プレビューから確定)
  5. Enter でフォルダも展開/折りたたみ可能

設定ファイル

~/.config/nvim/lua/plugins/neo-tree.lua:

local preview_buf = nil return { { "nvim-neo-tree/neo-tree.nvim", opts = { close_if_last_window = false, filesystem = { follow_current_file = { enabled = true }, use_libuv_file_watcher = true, }, window = { mappings = { ["<cr>"] = function(state) local node = state.tree:get_node() if node.type == "file" then preview_buf = nil vim.cmd("wincmd l") vim.cmd("edit " .. vim.fn.fnameescape(node.path)) elseif node.type == "directory" then require("neo-tree.sources.filesystem.commands").toggle_node(state) end end, }, }, }, init = function() -- 起動時にツリーを自動表示 vim.api.nvim_create_autocmd("VimEnter", { callback = function() vim.cmd("Neotree show") end, }) -- ツリー内でカーソル移動したらプレビュー表示 vim.api.nvim_create_autocmd("CursorMoved", { pattern = "neo-tree*", callback = function() local ok, manager = pcall(require, "neo-tree.sources.manager") if not ok then return end local state = manager.get_state("filesystem") if not state or not state.tree then return end local node = state.tree:get_node() if not node or node.type ~= "file" then return end local cur_win = vim.api.nvim_get_current_win() local target_win = nil for _, win in ipairs(vim.api.nvim_list_wins()) do if win ~= cur_win then target_win = win break end end if not target_win then return end local cur_buf = vim.api.nvim_win_get_buf(target_win) local cur_name = vim.api.nvim_buf_get_name(cur_buf) if cur_name == node.path then return end if preview_buf and vim.api.nvim_buf_is_valid(preview_buf) and preview_buf ~= cur_buf then pcall(vim.api.nvim_buf_delete, preview_buf, { force = true }) end vim.api.nvim_win_call(target_win, function() vim.cmd("edit " .. vim.fn.fnameescape(node.path)) end) preview_buf = vim.api.nvim_win_get_buf(target_win) end, }) end, }, }

ポイント

  • preview_buf 変数で前回のプレビューバッファを追跡し、新しいファイルを開く前に削除する。これでタブが無限に増えない
  • CursorMoved autocmd で neo-tree バッファ内のカーソル移動を検知。after_render イベントではカーソル移動を拾えない
  • Enter は node.type で分岐。ファイルなら右ペインで開き、ディレクトリなら展開/折りたたみ

まとめ

Vim のモーダル操作は慣れが必要だが、LazyVim + neo-tree カスタマイズで「ツリーからファイルを選んでプレビュー → Enter で確定」という VS Code 的なワークフローはターミナル内で実現できる。

This post is licensed under CC BY 4.0 by the author.