From 697981eef9b9c95f48280ea1a311729ba4229af8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 5 Sep 2026 19:31:38 +0000 Subject: [PATCH 1/3] Initial plan From c71d1d04c422979a7e21ac5fb49f3ec3c7efef21 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 5 Sep 2026 19:47:03 +0000 Subject: [PATCH 2/3] Fix PHP treesitter query using invalid node type php_end_tag Co-authored-by: andymass <6655373+andymass@users.noreply.github.com> --- .github/workflows/neovim.yml | 17 +++++++++++++++++ after/queries/php/matchup.scm | 2 +- lua/treesitter-matchup/internal.lua | 17 ++++++++++++++++- test/new/test-treesitter/example.php | 13 +++++++++++++ test/new/test-treesitter/test.vim | 15 +++++++++++++++ 5 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 test/new/test-treesitter/example.php diff --git a/.github/workflows/neovim.yml b/.github/workflows/neovim.yml index 64e31f31..7d33d2d5 100644 --- a/.github/workflows/neovim.yml +++ b/.github/workflows/neovim.yml @@ -44,6 +44,19 @@ jobs: run: git clone --depth=1 https://github.com/tree-sitter/tree-sitter-ruby.git working-directory: /tmp + - name: Clone tree-sitter-php + # Pin to the tree-sitter-php revision currently locked by + # nvim-treesitter (https://github.com/nvim-treesitter/nvim-treesitter/blob/master/lockfile.json) + # since this is what most users have installed, and its grammar + # differs from the latest tree-sitter-php master (see #448). + run: | + mkdir tree-sitter-php && cd tree-sitter-php + git init -q + git remote add origin https://github.com/tree-sitter/tree-sitter-php.git + git fetch --depth=1 origin 576a56fa7f8b68c91524cdd211eb2ffc43e7bb11 + git checkout -q FETCH_HEAD + working-directory: /tmp + - name: Create default nvim runtime parser directory run: mkdir -p $HOME/.local/share/nvim/site/parser @@ -55,6 +68,10 @@ jobs: run: tree-sitter build -o $HOME/.local/share/nvim/site/parser/ruby.so working-directory: /tmp/tree-sitter-ruby + - name: Build tree-sitter-php + run: tree-sitter build -o $HOME/.local/share/nvim/site/parser/php.so + working-directory: /tmp/tree-sitter-php/php + - name: "Run test" run: | bash -c 'VIMCMD=nvim test/vader/run' diff --git a/after/queries/php/matchup.scm b/after/queries/php/matchup.scm index f35b0296..2b05fffa 100644 --- a/after/queries/php/matchup.scm +++ b/after/queries/php/matchup.scm @@ -1,6 +1,6 @@ ; PHP tags (php_tag) @open.php -(php_end_tag) @close.php +"?>" @close.php (program) @scope.php ; if diff --git a/lua/treesitter-matchup/internal.lua b/lua/treesitter-matchup/internal.lua index 2ca7984c..0c53d54d 100644 --- a/lua/treesitter-matchup/internal.lua +++ b/lua/treesitter-matchup/internal.lua @@ -11,6 +11,10 @@ local M = {} local cache = lru.new(150) +-- languages whose matchup query failed to parse (e.g. because the +-- installed parser does not define a node type used by the query); we +-- remember this so we don't try (and error) again on every cursor move +local broken_langs = {} ---@type table ---@param lang string ---@param bufnr integer @@ -65,7 +69,18 @@ end ---@param erow integer ---@return matchup.treesitter.Match[] local get_lang_matches = function(bufnr, root, lang, srow, erow) - local query = ts.query.get(lang, 'matchup') + if broken_langs[lang] then + return {} + end + + local ok, query = pcall(ts.query.get, lang, 'matchup') + if not ok then + broken_langs[lang] = true + vim.notify_once( + string.format('matchup: failed to load treesitter matchup query for %s: %s', lang, query), + vim.log.levels.WARN) + return {} + end if not query then return {} diff --git a/test/new/test-treesitter/example.php b/test/new/test-treesitter/example.php new file mode 100644 index 00000000..f0af99c6 --- /dev/null +++ b/test/new/test-treesitter/example.php @@ -0,0 +1,13 @@ + diff --git a/test/new/test-treesitter/test.vim b/test/new/test-treesitter/test.vim index 7afe5f4b..0d8ebe7b 100644 --- a/test/new/test-treesitter/test.vim +++ b/test/new/test-treesitter/test.vim @@ -32,4 +32,19 @@ call assert_equal([3, 4], getcurpos()[1:2]) norm 2% call assert_equal([1, 1], getcurpos()[1:2]) +" php (regression test for #448: matching PHP tags and if/else must not +" error out when the treesitter query references node types not defined +" by the installed parser) +silent edit example.php + +call s:assert_ts_active() + +0go +norm % +call assert_equal([13, 2], getcurpos()[1:2]) + +call cursor(4, 3) +norm % +call assert_equal([6, 8], getcurpos()[1:2]) + call matchup#test#finished() From 49613fef14e01e4e5fc004bab6c191e681a55369 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 5 Sep 2026 19:47:38 +0000 Subject: [PATCH 3/3] Clarify pcall error variable naming per review feedback Co-authored-by: andymass <6655373+andymass@users.noreply.github.com> --- lua/treesitter-matchup/internal.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lua/treesitter-matchup/internal.lua b/lua/treesitter-matchup/internal.lua index 0c53d54d..3c209f2c 100644 --- a/lua/treesitter-matchup/internal.lua +++ b/lua/treesitter-matchup/internal.lua @@ -73,14 +73,15 @@ local get_lang_matches = function(bufnr, root, lang, srow, erow) return {} end - local ok, query = pcall(ts.query.get, lang, 'matchup') + local ok, query_or_err = pcall(ts.query.get, lang, 'matchup') if not ok then broken_langs[lang] = true vim.notify_once( - string.format('matchup: failed to load treesitter matchup query for %s: %s', lang, query), + string.format('matchup: failed to load treesitter matchup query for %s: %s', lang, query_or_err), vim.log.levels.WARN) return {} end + local query = query_or_err if not query then return {}