From 1645d212a7a43546aa537816e6f0201b33ce0058 Mon Sep 17 00:00:00 2001 From: rito528 <39003544+rito528@users.noreply.github.com> Date: Wed, 22 Apr 2026 17:04:04 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20Neovim=20=E3=81=AE=20Treesitter=20runti?= =?UTF-8?q?me=20=E9=85=8D=E7=BD=AE=E6=96=B9=E9=87=9D=E3=82=92=E6=95=B4?= =?UTF-8?q?=E7=90=86=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 組み込み Treesitter へ移行したあとも parser runtime の配布先がぶれないように、共通 grammar は Home Manager、プロジェクト固有 grammar は template devShell に分離する。あわせて判断軸を README と repo-local skill に残し、今後の追加変更で実装と文書がずれにくい状態にする。 Co-authored-by: Codex --- .../skills/neovim-treesitter-runtime/SKILL.md | 36 +++++++++++++++ README.md | 9 ++++ config/AGENTS.md | 3 ++ config/README.md | 3 ++ config/nvim/README.md | 41 +++++++++++++++++ config/nvim/init.lua | 11 +++++ config/nvim/lua/config/treesitter.lua | 44 +++++++++++++++++++ config/nvim/lua/plugins/treesitter.lua | 30 ------------- modules/neovim.nix | 16 ++++++- templates/seichi-assist/flake.nix | 6 +++ templates/seichi-infra/flake.nix | 8 ++++ templates/seichi-portal-backend/flake.nix | 9 ++++ templates/seichi-portal-frontend/flake.nix | 9 ++++ 13 files changed, 194 insertions(+), 31 deletions(-) create mode 100644 .agents/skills/neovim-treesitter-runtime/SKILL.md create mode 100644 config/nvim/README.md create mode 100644 config/nvim/lua/config/treesitter.lua delete mode 100644 config/nvim/lua/plugins/treesitter.lua diff --git a/.agents/skills/neovim-treesitter-runtime/SKILL.md b/.agents/skills/neovim-treesitter-runtime/SKILL.md new file mode 100644 index 0000000..f90b3d7 --- /dev/null +++ b/.agents/skills/neovim-treesitter-runtime/SKILL.md @@ -0,0 +1,36 @@ +--- +name: neovim-treesitter-runtime +description: dotfiles の Neovim Treesitter parser runtime を Home Manager と templates のどちらに置くべきか判断し、必要な Nix とドキュメントを更新するためのスキル +--- + +# neovim-treesitter-runtime + +このリポジトリで Treesitter parser runtime の配置先を決めるときに使う。 + +## 判断ルール + +- `modules/neovim.nix` に置く: + - dotfiles 自身でも頻繁に使う + - 設定ファイルやドキュメントのように複数プロジェクトで横断的に編集する + - 常時グローバル配備でも責務がぶれにくい +- `templates/*/flake.nix` に置く: + - その template の主要実装言語である + - 他の template では不要である + - LSP / formatter / build tool もその shell に閉じている + +基本は「共通 grammar は Home Manager、追加 grammar は template shell」。 + +## 実装手順 + +1. 追加・変更したい grammar が共通か project 固有かを判定する +2. 共通なら `modules/neovim.nix` の `commonTreesitterRuntime` を更新する +3. project 固有なら対象 `templates/*/flake.nix` の `treesitterRuntime` を更新する +4. `config/nvim/init.lua` が `NVIM_TREESITTER_RUNTIME_GLOBAL` と `NVIM_TREESITTER_RUNTIME_PROJECT` を読む前提を壊していないか確認する +5. 判断軸に影響する変更なら `config/nvim/README.md` と必要に応じてルート `README.md` を更新する +6. `.nix` を変更したら `nixfmt` を実行する + +## 注意点 + +- template 側に共通 grammar を重複定義しない +- Home Manager 側に project 専用 grammar を増やしすぎない +- Treesitter runtime の配布先を変えるときは、実装だけでなく判断軸の文書も同時に更新する diff --git a/README.md b/README.md index 37a7b05..0f53043 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,15 @@ home-manager generations プロジェクトごとに独立した Nix 開発環境を提供するテンプレートを管理しています(`templates/` 参照)。 +Neovim の Treesitter parser runtime は 2 層で管理します。 + +- Home Manager: + - `lua`, `markdown`, `markdown_inline`, `json`, `yaml`, `toml` のような共通 grammar を配る +- template devShell: + - `rust`, `sql`, `typescript`, `javascript`, `scala`, `hcl` のような project 固有 grammar を追加する + +判断軸と実装ルールの詳細は `config/nvim/README.md` を参照してください。 + ### 自分のプロジェクトで使う場合 ```bash diff --git a/config/AGENTS.md b/config/AGENTS.md index 3922d99..291ed80 100644 --- a/config/AGENTS.md +++ b/config/AGENTS.md @@ -20,6 +20,9 @@ - home-manager 配備対象の Claude Code 向けスキル定義の正規配置 - ここにあるスキルは `~/.claude/skills` と `~/.agents/skills` に反映される前提で扱う - 詳細は `config/agents/skills/README.md` を参照する +- `config/nvim/` + - home-manager 配備対象の Neovim 設定を管理する + - Treesitter parser runtime の配置方針は `config/nvim/README.md` を参照する - `config/agents/` - AI Agent スキル定義配下の固有ルールは `config/agents/AGENTS.md` を参照する ## 3. AI Agent 関連の注意点 diff --git a/config/README.md b/config/README.md index 60a256e..67bbb0f 100644 --- a/config/README.md +++ b/config/README.md @@ -19,6 +19,9 @@ - `config/claude/` - Claude Code の設定、hooks、status line など、実際の挙動を決める設定です - 詳細は `config/claude/README.md` を参照してください +- `config/nvim/` + - home-manager によって配備される Neovim の実運用設定です + - Treesitter parser runtime の Home Manager / template の分担ルールは `config/nvim/README.md` を参照してください - `config/agents/AGENTS.md`, `config/claude/AGENTS.md` - AI Agent 関連サブディレクトリを編集するときの固有ルールです - 共通ルールに加えて、そのディレクトリで特に意識すべき観点を補います diff --git a/config/nvim/README.md b/config/nvim/README.md new file mode 100644 index 0000000..3140602 --- /dev/null +++ b/config/nvim/README.md @@ -0,0 +1,41 @@ +# config/nvim/ + +`config/nvim/` は home-manager によって `~/.config/nvim` へ配備される Neovim 設定の正本です。 + +## Treesitter の配置方針 + +このリポジトリでは Treesitter parser runtime を 2 層で管理します。 + +- `Home Manager` + - どのプロジェクトでもほぼ確実に使う共通 grammar を配る + - 例: `lua`, `markdown`, `markdown_inline`, `json`, `yaml`, `toml` +- `templates/*/flake.nix` + - その template で主に使う言語だけを追加する + - 例: `rust`, `sql`, `typescript`, `javascript`, `scala`, `hcl` + +## 判断軸 + +- グローバル配備する: + - dotfiles 自身でも頻繁に編集する + - README や設定ファイルのように複数プロジェクトで横断的に使う + - 常時有効でも責務がぶれにくい +- dev shell に閉じる: + - ある template の主要実装言語である + - 他の template では不要である + - formatter / LSP / build tool もその shell に閉じている + +迷った場合は、まず Home Manager に共通 grammar を置き、template 側には追加分だけを載せる。 + +## 実装ルール + +- 共通 grammar runtime は [modules/neovim.nix](/home/rito528/dotfiles/modules/neovim.nix:1) で `NVIM_TREESITTER_RUNTIME_GLOBAL` として配る +- project 固有 grammar runtime は `templates/*/flake.nix` の `shellHook` で `NVIM_TREESITTER_RUNTIME_PROJECT` として配る +- Neovim 側は [init.lua](/home/rito528/dotfiles/config/nvim/init.lua:1) で両方を `runtimepath` に追加する +- parser を追加・削除するときは、この判断軸と実際の template の責務が一致しているかを確認する + +## 変更時の確認 + +- `.nix` を変えたら `nixfmt` を実行する +- Home Manager 側の変更は `home-manager build --flake .#testuser` で確認する +- template 側の変更は対応する devShell が評価できることを確認する +- Treesitter の配布先を変えた場合は、この README と関連ドキュメントも更新する diff --git a/config/nvim/init.lua b/config/nvim/init.lua index fb2c5ba..0ba9ba8 100644 --- a/config/nvim/init.lua +++ b/config/nvim/init.lua @@ -28,6 +28,16 @@ vim.cmd("filetype plugin indent on") local uv = vim.uv or vim.loop local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" local lazy_init = lazypath .. "/lua/lazy/init.lua" +local treesitter_runtimes = { + vim.env.NVIM_TREESITTER_RUNTIME_GLOBAL, + vim.env.NVIM_TREESITTER_RUNTIME_PROJECT, +} + +for _, runtime in ipairs(treesitter_runtimes) do + if runtime and runtime ~= "" then + vim.opt.rtp:append(runtime) + end +end if not uv.fs_stat(lazy_init) then vim.fn.system({ @@ -51,6 +61,7 @@ vim.opt.rtp:prepend(lazypath) require("lazy").setup("plugins", { lockfile = vim.fn.stdpath("state") .. "/lazy-lock.json", }) +require("config.treesitter") vim.cmd.colorscheme("kanagawa") diff --git a/config/nvim/lua/config/treesitter.lua b/config/nvim/lua/config/treesitter.lua new file mode 100644 index 0000000..38be167 --- /dev/null +++ b/config/nvim/lua/config/treesitter.lua @@ -0,0 +1,44 @@ +local enabled_languages = { + hcl = true, + javascript = true, + json = true, + lua = true, + markdown = true, + markdown_inline = true, + rust = true, + scala = true, + sql = true, + toml = true, + typescript = true, + yaml = true, +} + +local function start_treesitter(bufnr) + local filetype = vim.bo[bufnr].filetype + local lang = vim.treesitter.language.get_lang(filetype) or filetype + + if not enabled_languages[lang] then + return + end + + if not pcall(vim.treesitter.language.add, lang) then + return + end + + pcall(vim.treesitter.start, bufnr, lang) +end + +local group = vim.api.nvim_create_augroup("builtin_treesitter", { clear = true }) + +vim.api.nvim_create_autocmd("FileType", { + group = group, + callback = function(args) + start_treesitter(args.buf) + end, +}) + +for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do + if vim.api.nvim_buf_is_loaded(bufnr) then + start_treesitter(bufnr) + end +end diff --git a/config/nvim/lua/plugins/treesitter.lua b/config/nvim/lua/plugins/treesitter.lua deleted file mode 100644 index 52f7dcf..0000000 --- a/config/nvim/lua/plugins/treesitter.lua +++ /dev/null @@ -1,30 +0,0 @@ -return { - { - "nvim-treesitter/nvim-treesitter", - build = ":TSUpdate", - event = { "BufReadPre", "BufNewFile" }, - config = function() - require("nvim-treesitter").setup({ - ensure_installed = { - "lua", - "rust", - "toml", - "typescript", - "javascript", - "json", - "markdown", - "markdown_inline", - "scala", - "hcl", - "yaml", - "sql", - }, - auto_install = true, - highlight = { - enable = true, - }, - indent = { enable = true }, - }) - end, - }, -} diff --git a/modules/neovim.nix b/modules/neovim.nix index 97f8630..ed2135f 100644 --- a/modules/neovim.nix +++ b/modules/neovim.nix @@ -1,4 +1,18 @@ -{ ... }: +{ pkgs, ... }: +let + commonTreesitterRuntime = pkgs.vimPlugins.nvim-treesitter.withPlugins ( + plugins: with plugins; [ + json + lua + markdown + markdown_inline + toml + yaml + ] + ); +in { + home.sessionVariables.NVIM_TREESITTER_RUNTIME_GLOBAL = "${commonTreesitterRuntime}"; + xdg.configFile."nvim".source = ../config/nvim; } diff --git a/templates/seichi-assist/flake.nix b/templates/seichi-assist/flake.nix index 718b48b..bf5dae8 100644 --- a/templates/seichi-assist/flake.nix +++ b/templates/seichi-assist/flake.nix @@ -8,6 +8,11 @@ let system = "x86_64-linux"; pkgs = import nixpkgs { inherit system; }; + treesitterRuntime = pkgs.vimPlugins.nvim-treesitter.withPlugins ( + plugins: with plugins; [ + scala + ] + ); in { devShells.${system}.default = pkgs.mkShell { @@ -19,6 +24,7 @@ pkgs.stdenv.cc.cc.lib ]; shellHook = '' + export NVIM_TREESITTER_RUNTIME_PROJECT="${treesitterRuntime}" export LD_LIBRARY_PATH="${pkgs.stdenv.cc.cc.lib}/lib''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" ''; }; diff --git a/templates/seichi-infra/flake.nix b/templates/seichi-infra/flake.nix index dfebda4..e8700dd 100644 --- a/templates/seichi-infra/flake.nix +++ b/templates/seichi-infra/flake.nix @@ -11,6 +11,11 @@ inherit system; config.allowUnfreePredicate = pkg: builtins.elem (nixpkgs.lib.getName pkg) [ "terraform" ]; }; + treesitterRuntime = pkgs.vimPlugins.nvim-treesitter.withPlugins ( + plugins: with plugins; [ + hcl + ] + ); in { devShells.${system}.default = pkgs.mkShell { @@ -20,6 +25,9 @@ pkgs.kubectl pkgs.kubernetes-helm ]; + shellHook = '' + export NVIM_TREESITTER_RUNTIME_PROJECT="${treesitterRuntime}" + ''; }; }; } diff --git a/templates/seichi-portal-backend/flake.nix b/templates/seichi-portal-backend/flake.nix index 9efc0fb..e68ff45 100644 --- a/templates/seichi-portal-backend/flake.nix +++ b/templates/seichi-portal-backend/flake.nix @@ -17,6 +17,12 @@ inherit system; overlays = [ rust-overlay.overlays.default ]; }; + treesitterRuntime = pkgs.vimPlugins.nvim-treesitter.withPlugins ( + plugins: with plugins; [ + rust + sql + ] + ); in { devShells.${system}.default = pkgs.mkShell { @@ -33,6 +39,9 @@ pkgs.sqlx-cli pkgs.taplo ]; + shellHook = '' + export NVIM_TREESITTER_RUNTIME_PROJECT="${treesitterRuntime}" + ''; }; }; } diff --git a/templates/seichi-portal-frontend/flake.nix b/templates/seichi-portal-frontend/flake.nix index 9f9710d..c256240 100644 --- a/templates/seichi-portal-frontend/flake.nix +++ b/templates/seichi-portal-frontend/flake.nix @@ -8,6 +8,12 @@ let system = "x86_64-linux"; pkgs = import nixpkgs { inherit system; }; + treesitterRuntime = pkgs.vimPlugins.nvim-treesitter.withPlugins ( + plugins: with plugins; [ + javascript + typescript + ] + ); in { devShells.${system}.default = pkgs.mkShell { @@ -15,6 +21,9 @@ pkgs.nodejs_22 pkgs.pnpm ]; + shellHook = '' + export NVIM_TREESITTER_RUNTIME_PROJECT="${treesitterRuntime}" + ''; }; }; }