nvim-treesitter-textobjects icon indicating copy to clipboard operation
nvim-treesitter-textobjects copied to clipboard

[main]: `parameter.inner`: selected smaller range than expected

Open przepompownia opened this issue 1 year ago • 5 comments

Sometimes inner parameter selection ignores the current scope and selects the first parameter in the nested scope instead.

To Reproduce Steps to reproduce the behavior: init.lua:

local thisInitFile = debug.getinfo(1).source:match('@?(.*)')
local cwd = vim.fs.dirname(thisInitFile)
local appname = vim.env.NVIM_APPNAME or 'nvim'

vim.env.XDG_CONFIG_HOME = cwd
vim.env.XDG_DATA_HOME = vim.fs.joinpath(cwd, '.xdg', 'data')
vim.env.XDG_STATE_HOME = vim.fs.joinpath(cwd, '.xdg', 'state')
vim.env.XDG_CACHE_HOME = vim.fs.joinpath(cwd, '.xdg', 'cache')
vim.fn.mkdir(vim.fs.joinpath(vim.env.XDG_CACHE_HOME, appname), 'p')
local stdPathConfig = vim.fn.stdpath('config')

vim.opt.runtimepath:prepend(stdPathConfig)
vim.opt.packpath:prepend(stdPathConfig)

local function gitClone(url, installPath, branch)
  if vim.fn.isdirectory(installPath) ~= 0 then
    return
  end

  local command = {'git', 'clone', '--', url, installPath}
  if branch then
    table.insert(command, 3, '--branch')
    table.insert(command, 4, branch)
  end

  vim.notify(('Cloning %s dependency into %s...'):format(url, installPath), vim.log.levels.INFO, {})
  local sysObj = vim.system(command, {}):wait()
  if sysObj.code ~= 0 then
    error(sysObj.stderr)
  end
  vim.notify(sysObj.stdout)
  vim.notify(sysObj.stderr, vim.log.levels.WARN)
end

local pluginsPath = vim.fs.joinpath(cwd, 'nvim/pack/plugins/opt')
vim.fn.mkdir(pluginsPath, 'p')
pluginsPath = vim.uv.fs_realpath(pluginsPath)

--- @type table<string, {url:string, branch: string?}>
local plugins = {
  ['nvim-treesitter-textobjects'] = {url = 'https://github.com/nvim-treesitter/nvim-treesitter-textobjects', branch = 'main'},
}

for name, repo in pairs(plugins) do
  local installPath = vim.fs.joinpath(pluginsPath, name)
  gitClone(repo.url, installPath, repo.branch)
  vim.cmd.packadd({args = {name}, bang = true})
end

vim.keymap.set({'x', 'o'}, 'ip', function ()
  require 'nvim-treesitter-textobjects.select'.select_textobject('@parameter.inner', 'textobjects')
end)
vim.go.hlsearch = false

local function foo()
  vim.print(1, tonumber('1'), {'x'})
end

vim.api.nvim_feedkeys(vim.keycode('/tonumber<CR>'), 'n', false)
  1. nvim --clean -u init.lua init.lua
  2. type vip (for me '1' is selected)
  3. escape visual mode, go to space before {x} and type vip again (for me 'x' is selected).

Expected behavior Selected:

  • tonumber('1') in step 2.
  • {'x'} in step 3.

Output of :checkhealth vim.treesitter

vim.treesitter: require("vim.treesitter.health").check()
  • Nvim runtime ABI version: 14
  • OK Parser: c ABI: 14, path: .../nvim-from-src/lib/nvim/parser/c.so
  • OK Parser: lua ABI: 14, path: .../nvim-from-src/lib/nvim/parser/lua.so
  • OK Parser: markdown ABI: 14, path: .../nvim-from-src/lib/nvim/parser/markdown.so
  • OK Parser: markdown_inline ABI: 14, path: .../nvim-from-src/lib/nvim/parser/markdown_inline.so
  • OK Parser: query ABI: 14, path: .../nvim-from-src/lib/nvim/parser/query.so
  • OK Parser: vim ABI: 14, path: .../nvim-from-src/lib/nvim/parser/vim.so
  • OK Parser: vimdoc ABI: 14, path: .../nvim-from-src/lib/nvim/parser/vimdoc.so
  • Can load WASM parsers: false

Output of nvim --version

v0.11.0-dev-941+gcd8e15e33

przepompownia avatar Oct 09 '24 19:10 przepompownia

The master branch works as expected.

But when I try your script to reproduce, the command vip gives the following error:

E5108: Error executing lua: ...r-textobjects/lua/nvim-treesitter-textobjects/shared.lua:91: attempt t
o index a nil value
stack traceback:
        ...r-textobjects/lua/nvim-treesitter-textobjects/shared.lua:91: in function 'fn'
        ...r-textobjects/lua/nvim-treesitter-textobjects/shared.lua:39: in function 'get_query_matche
s'
        ...r-textobjects/lua/nvim-treesitter-textobjects/shared.lua:167: in function 'fn'
        ...r/share/nvim/runtime/lua/vim/treesitter/languagetree.lua:491: in function 'for_each_tree'
        ...r-textobjects/lua/nvim-treesitter-textobjects/shared.lua:164: in function 'get_capture_ran
ges_recursively'
        ...r-textobjects/lua/nvim-treesitter-textobjects/shared.lua:359: in function 'textobject_at_p
oint'
        ...r-textobjects/lua/nvim-treesitter-textobjects/select.lua:155: in function 'select_textobje
ct'
        /data/data/com.termux/files/usr/tmp/init.lua:51: in function 
Press ENTER or type command to continue

nvim --version

NVIM v0.10.2
Build type: Release
LuaJIT 2.1.1727870382

Juhan280 avatar Oct 14 '24 11:10 Juhan280

@Juhan280 I doubt that the main branch is intended to be compatible with Nvim 0.10.*, although calling iter_matches with {all = true} (default in master on Nvim) allows at least to avoid the error (not checked if it works in general and whether it makes any sense).

przepompownia avatar Oct 14 '24 20:10 przepompownia

From the :InspectTree perspective the query https://github.com/nvim-treesitter/nvim-treesitter-textobjects/blob/aad2c8e6b029ada30621e67780801420ee9debe9/queries/lua/textobjects.scm#L84-L87 looks good:

Image

przepompownia avatar Oct 14 '24 21:10 przepompownia

https://github.com/nvim-treesitter/nvim-treesitter-textobjects/blob/aad2c8e6b029ada30621e67780801420ee9debe9/lua/nvim-treesitter-textobjects/shared.lua#L228-L242

Image

Having vim.print(1, tonumber('1')) as the only line we get false from is_in_range({0, 11, 0, 26}, 0, 26).

I tried

diff --git a/lua/nvim-treesitter-textobjects/shared.lua b/lua/nvim-treesitter-textobjects/shared.lua
index 69a804c..69bd750 100644
--- a/lua/nvim-treesitter-textobjects/shared.lua
+++ b/lua/nvim-treesitter-textobjects/shared.lua
@@ -236,7 +236,7 @@ local function is_in_range(range, row, col)
   end
   local is_before_end_col_if_needed = true
   if end_row == row then
-    is_before_end_col_if_needed = col <= end_col
+    is_before_end_col_if_needed = col - 1 <= end_col
   end
   return is_in_rows and is_after_start_col_if_needed and is_before_end_col_if_needed
 end

but it breaks selection when the cursor is on the closing brace in vim.keymap.set({'x', 'o'}, 'ip', function () end) (I haven't check yet how matched ranges look in that case).

przepompownia avatar Oct 14 '24 23:10 przepompownia

I am facing similar issue after switching from master to main.

print(abc, list(x = 1L))

Having the cursor on list typing vip is selecting x = 1L instead of list(x = 1L). Any solutions?

PMassicotte avatar Jul 04 '25 17:07 PMassicotte