diff --git a/Makefile b/Makefile index 3fd83fe..2a8ebbc 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -all: fmt apply +all: fmt apply nvim-check apply: uv run ansible-playbook -i ~/.dotfiles/ansible/inventory.ini ~/.dotfiles/ansible/dotfiles.yml @@ -13,3 +13,33 @@ fmt_check: nvim-health: nvim --headless "+checkhealth" +qa + +# Smoke test: boot nvim with representative filetypes and fail on startup errors/warnings. +# Catches plugin misconfigurations (e.g. missing tree-sitter parsers, broken submodules) +# that produce warnings in :messages but pass :checkhealth. +NVIM_CHECK_FILETYPES := R py lua md +NVIM_CHECK_TMPDIR := /tmp/_nvim_check +NVIM_CHECK_TIMEOUT := 30 + +nvim-check: + @mkdir -p $(NVIM_CHECK_TMPDIR) + @fail=0; \ + for ft in $(NVIM_CHECK_FILETYPES); do \ + tmpfile="$(NVIM_CHECK_TMPDIR)/test.$$ft"; \ + msgfile="$(NVIM_CHECK_TMPDIR)/messages_$$ft.txt"; \ + touch "$$tmpfile"; \ + timeout $(NVIM_CHECK_TIMEOUT) nvim --headless \ + +"edit $$tmpfile" \ + +"sleep 3" \ + +"redir! > $$msgfile | silent messages | redir END" \ + +"qall!" 2>/dev/null || true; \ + if grep -qiE '(error|warning)' "$$msgfile" 2>/dev/null; then \ + echo "FAIL [$$ft]: startup errors detected"; \ + cat "$$msgfile"; \ + fail=1; \ + else \ + echo "PASS [$$ft]: clean startup"; \ + fi; \ + done; \ + rm -rf $(NVIM_CHECK_TMPDIR); \ + [ "$$fail" -eq 0 ] || (echo "nvim-check: some filetypes had errors" && exit 1) diff --git a/ansible/tasks/neovim.yml b/ansible/tasks/neovim.yml index 76f91ae..9f80556 100644 --- a/ansible/tasks/neovim.yml +++ b/ansible/tasks/neovim.yml @@ -46,3 +46,16 @@ - "+qa" tags: - nvim + +- name: Clone tree-sitter-rout parser source into R.nvim resources + # TODO: Remove once https://github.com/R-nvim/R.nvim/issues/466 is fixed and merged -- see + # nvim/lua/plugins/language.lua for full context. Idempotent: skipped if grammar.js exists. + ansible.builtin.shell: | + target="{{ ansible_env.HOME }}/.local/share/nvim/lazy/R.nvim/resources/tree-sitter-rout" + grammar="$target/grammar.js" + if [ ! -f "$grammar" ]; then + rm -rf "$target" + git clone https://github.com/R-nvim/tree-sitter-rout "$target" + fi + tags: + - nvim diff --git a/nvim/lua/plugins/language.lua b/nvim/lua/plugins/language.lua index ae5841a..9df596b 100644 --- a/nvim/lua/plugins/language.lua +++ b/nvim/lua/plugins/language.lua @@ -1,4 +1,22 @@ return { + { + "R-nvim/R.nvim", + -- TODO: Remove this build workaround once https://github.com/R-nvim/R.nvim/issues/466 is + -- fixed and merged to main, then advance past that commit with `:Lazy update R.nvim`. + -- The upstream bug: check_rout_parser() calls vim.uv.chdir() into resources/tree-sitter-rout + -- but early `return` on build failure skips the chdir(cwdir) restore, leaving nvim stuck in + -- the plugin directory. Root cause is that the tree-sitter-rout submodule gitlink is absent + -- from older pinned commits, so `git submodule update` is a no-op and grammar.js is missing. + -- Workaround: clone the source directly so the build succeeds and cwd is properly restored. + -- Removal check: delete this block, run `make nvim-check`, confirm PASS [R]: clean startup. + build = function() + local target = vim.fn.stdpath("data") .. "/lazy/R.nvim/resources/tree-sitter-rout" + if vim.fn.filereadable(target .. "/grammar.js") == 0 then + vim.fn.system({ "rm", "-rf", target }) + vim.fn.system({ "git", "clone", "https://github.com/R-nvim/tree-sitter-rout", target }) + end + end, + }, { "nvim-treesitter/nvim-treesitter", opts = {