じゃあ、おうちで学べる

本能を呼び覚ますこのコードに、君は抗えるか

Neovimのイベントタイミングガイド

はじめに

Neovimでの設定やプラグイン開発において、適切なタイミングでコードを実行することは非常に重要です。このガイドでは、Neovimの主要なイベントについて、実用的な例を交えながら解説します。

1. 起動時のイベント系統

Neovimの起動プロセスで最も重要なイベントはVimEnterです。これは全ての初期化処理(vimrcの読み込み、プラグインの初期化など)が完了した後に発火します:

vim.api.nvim_create_autocmd("VimEnter", {
  callback = function()
    -- プラグインの初期化
    -- カラースキームの設定
    -- ステータスラインの設定など
  end,
})

2. バッファ操作のイベント系統

バッファの作成から読み込みまでの主要なイベント:

  1. BufNew: バッファ作成直後
  2. BufAdd: バッファリストへの追加時
  3. BufReadPre: ファイル読み込み前
  4. BufReadPost: ファイル読み込み後
  5. BufEnter: バッファアクティブ化時
vim.api.nvim_create_autocmd("BufReadPost", {
  pattern = "*",
  callback = function()
    -- ファイル読み込み後の処理
    -- 最後のカーソル位置の復元など
  end,
})

3. 編集モードのイベント系統

テキスト編集に関連する主要なイベント:

  1. InsertEnter: 挿入モード開始時
  2. TextChangedI: 挿入モードでテキスト変更時
  3. InsertLeave: 挿入モード終了時
  4. TextChanged: ノーマルモードでテキスト変更時
vim.api.nvim_create_autocmd("InsertEnter", {
  pattern = "*",
  callback = function()
    -- 挿入モード開始時の設定
    -- 相対行番号の無効化など
  end,
})

4. ファイル保存のイベント系統

ファイル保存時の処理フロー:

  1. BufWritePre: 保存前
  2. BufWrite: 保存処理中
  3. BufWritePost: 保存後
vim.api.nvim_create_autocmd("BufWritePre", {
  pattern = "*",
  callback = function()
    -- 保存前の自動整形
    -- 末尾の空白除去など
  end,
})

5. 終了時のイベント系統

Neovim終了時の処理順序:

  1. QuitPre: 終了コマンド実行時
  2. VimLeavePre: 終了処理開始前
  3. VimLeave: 最終終了処理時
vim.api.nvim_create_autocmd("VimLeavePre", {
  callback = function()
    -- セッション保存
    -- 未保存バッファの保存など
  end,
})

実践的なサンプルコード

以下は、よくある設定パターンの例です:

-- ファイルタイプ別の設定
vim.api.nvim_create_autocmd("FileType", {
  pattern = {"python", "lua", "rust"},
  callback = function()
    local settings = {
      python = { indent = 4, expandtab = true },
      lua = { indent = 2, expandtab = true },
      rust = { indent = 4, expandtab = true }
    }
    local ft = vim.bo.filetype
    if settings[ft] then
      vim.bo.shiftwidth = settings[ft].indent
      vim.bo.expandtab = settings[ft].expandtab
    end
  end,
})

-- 自動保存の設定
vim.api.nvim_create_autocmd({"InsertLeave", "TextChanged"}, {
  pattern = "*",
  callback = function()
    if vim.bo.modified and vim.bo.buftype == "" then
      vim.cmd("silent! write")
    end
  end,
})

-- 最後のカーソル位置を復元
vim.api.nvim_create_autocmd("BufReadPost", {
  pattern = "*",
  callback = function()
    local last_pos = vim.fn.line("'\"")
    if last_pos > 0 and last_pos <= vim.fn.line("$") then
      vim.cmd('normal! g`"')
    end
  end,
})

注意点

  • イベントは適切な順序で処理される必要があります
  • 重い処理は非同期で行うことを推奨します
  • パターンマッチングを活用して、必要なファイルタイプのみで実行するようにします
  • vim.schedule()を使用して、UIブロッキングを避けます

参考文献