"Change in textobject" has odd behavior
jrwrigh opened this issue · comments
Describe the bug
When running "change in textobject" (ie. cif
), there is odd/undesired behavior. For example, I can no longer delete characters as I type, running successive ci{f,a,c}
will start to change different parts of the buffer, and autocompletion (like in nvim-cmp
) has equally odd behavior (see hrsh7th/nvim-cmp#1414 for gif and details)
To Reproduce
I have created this minimal reproducer config:
Minimal Reproducer config
vim.cmd [[set runtimepath=$VIMRUNTIME]]
vim.cmd [[set packpath=/tmp/nvim/site]]
local package_root = '/tmp/nvim/site/pack'
local install_path = package_root .. '/packer/start/packer.nvim'
local function load_plugins()
require('packer').startup {
{
'wbthomason/packer.nvim',
{
'nvim-telescope/telescope.nvim',
requires = {
'nvim-lua/plenary.nvim',
{ 'nvim-telescope/telescope-fzf-native.nvim', run = 'make' },
},
},
{ 'nvim-treesitter/nvim-treesitter', config = function()
require('nvim-treesitter.configs').setup {
ensure_installed = { 'c'},
textobjects = {
select = {
enable = true,
lookahead = true, -- Automatically jump forward to textobj, similar to targets.vim
keymaps = {
-- You can use the capture groups defined in textobjects.scm
['af'] = '@function.outer',
['if'] = '@function.inner',
['ac'] = '@class.outer',
['ic'] = '@class.inner',
['aa'] = '@parameter.outer',
['ia'] = '@parameter.inner',
},
},
},
}
end
},
{ 'nvim-treesitter/nvim-treesitter-textobjects' },
-- ADD PLUGINS THAT ARE _NECESSARY_ FOR REPRODUCING THE ISSUE
},
config = {
package_root = package_root,
compile_path = install_path .. '/plugin/packer_compiled.lua',
display = { non_interactive = true },
},
}
end
_G.load_config = function()
require('telescope').setup()
require('telescope').load_extension('fzf')
-- ADD INIT.LUA SETTINGS THAT ARE _NECESSARY_ FOR REPRODUCING THE ISSUE
end
if vim.fn.isdirectory(install_path) == 0 then
print("Installing Telescope and dependencies.")
vim.fn.system { 'git', 'clone', '--depth=1', 'https://github.com/wbthomason/packer.nvim', install_path }
end
load_plugins()
require('packer').sync()
vim.cmd [[autocmd User PackerComplete ++once echo "Ready!" | lua load_config()]]
and this example c file:
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello, World!");
return 0;
}
Here's is a gif demonstrating the behavior (with screenkeys, so it should be self-documenting):
Expected behavior
A clear and concise description of what you expected to happen.
Output of :checkhealth nvim-treesitter
nvim-treesitter: require("nvim-treesitter.health").check()
========================================================================
## Installation
- OK: `tree-sitter` found 0.20.7 (parser generator, only needed for :TSInstallFromGrammar)
- OK: `node` found v19.3.0 (only needed for :TSInstallFromGrammar)
- OK: `git` executable found.
- OK: `cc` executable found. Selected from { vim.NIL, "cc", "gcc", "clang", "cl", "zig" }
Version: cc (GCC) 12.2.0
- OK: Neovim was compiled with tree-sitter runtime ABI version 14 (required >=13). Parsers must be compatible with runtime ABI.
## OS Info:
{
machine = "x86_64",
release = "5.14.21-2-MANJARO",
sysname = "Linux",
version = "#1 SMP PREEMPT Sun Nov 21 22:43:47 UTC 2021"
}
## Parser/Features H L F I J
- c ✓ ✓ ✓ ✓ ✓
Legend: H[ighlight], L[ocals], F[olds], I[ndents], In[j]ections
+) multiple parsers found, only one will be used
x) errors found in the query, try to run :TSUpdate {lang}
Output of nvim --version
$ nvim --version
NVIM v0.8.1
Build type: Release
LuaJIT 2.1.0-beta3
Compiled by builduser
Features: +acl +iconv +tui
See ":help feature-compile"
system vimrc file: "$VIM/sysinit.vim"
fall-back for $VIM: "/usr/share/nvim"
Run :checkhealth for more info
Some more interesting evidence. Installing treesitter playground to inspect the tree during the changes:
You can see that the first argument to the function is correctly located initially (parameter_declaration [1, 9] - [1, 17]
). However, after doing the the cia
, TS node changes to parameter_declaration [1, 13] - [1, 13]
, which has zero width. I'm not sure whether this is a treesitter bug from upstream, or something to do with this plugin. Regardless, this is probably causing the issues with the successive change commands.
Thanks for reporting. I could reproduce some of the stuff you described. For me, it seems to be okay with function and class but it's a problem when there's some trailing content (argument, conditional inner).
Also I can reproduce nvim-cmp
showing duplicates of previous selection as well.
I don't know why yet.. I need to check if older commits were okay.
I can only reproduce if the change is within a line (not multi-line) and I don't need the reproduction config file. I can just reproduce with my config.
@theHamsta I tried with a8c86f4 and it still has the same issue, so it's not because of the curse of using lua function (I remember recently I changed the vimscript to lua function for select)
Could it be the upstream treesitter bug?
@theHamsta I confirmed that it's a bug from update_selection
in nvim-treesitter/ts_utils.lua
.
Using gv
to update selection seems to cause problems.
-- Simple text object that selects 3 characters.
-- Implemented in 3 different ways
-- `ciq` works well.
vim.keymap.set({ "o" }, "iq", function()
vim.cmd [[normal! vhol]]
end)
-- This is nvim-treesitter's implementation using gv. Minimal reproducible copy.
-- It has the bug (try `cir`)
function update_selection()
local cursor = vim.api.nvim_win_get_cursor(0)
vim.api.nvim_buf_set_mark(0, "<", cursor[1], cursor[2] - 1, {})
vim.api.nvim_buf_set_mark(0, ">", cursor[1], cursor[2] + 1, {})
vim.api.nvim_cmd({ cmd = "normal", bang = true, args = { "gv" } }, {})
end
vim.keymap.set({ "o" }, "ir", update_selection)
-- The suggested fix that doesn't use `gv`
-- `ciy` works well.
function update_selection_fix()
local cursor = vim.api.nvim_win_get_cursor(0)
vim.cmd "normal! v"
vim.api.nvim_win_set_cursor(0, { cursor[1], cursor[2] - 1 })
vim.cmd "normal! o"
vim.api.nvim_win_set_cursor(0, { cursor[1], cursor[2] + 1 })
end
vim.keymap.set({ "o" }, "iy", update_selection_fix)
@theHamsta I confirmed that it's a bug from
update_selection
innvim-treesitter/ts_utils.lua
. Usinggv
to update selection seems to cause problems.-- Simple text object that selects 3 characters. -- Implemented in 3 different ways -- `ciq` works well. vim.keymap.set({ "o" }, "iq", function() vim.cmd [[normal! vhol]] end) -- This is nvim-treesitter's implementation using gv. Minimal reproducible copy. -- It has the bug (try `cir`) function update_selection() local cursor = vim.api.nvim_win_get_cursor(0) vim.api.nvim_buf_set_mark(0, "<", cursor[1], cursor[2] - 1, {}) vim.api.nvim_buf_set_mark(0, ">", cursor[1], cursor[2] + 1, {}) vim.api.nvim_cmd({ cmd = "normal", bang = true, args = { "gv" } }, {}) end vim.keymap.set({ "o" }, "ir", update_selection) -- The suggested fix that doesn't use `gv` -- `ciy` works well. function update_selection_fix() local cursor = vim.api.nvim_win_get_cursor(0) vim.cmd "normal! v" vim.api.nvim_win_set_cursor(0, { cursor[1], cursor[2] - 1 }) vim.cmd "normal! o" vim.api.nvim_win_set_cursor(0, { cursor[1], cursor[2] + 1 }) end vim.keymap.set({ "o" }, "iy", update_selection_fix)
I can't tell much about this code. I was originally written by @kyazdani42 and then dozen times updated to resolve different issues. We should really add unittest about the quirks that we fix in the past so that we don't regress. Especially, since the code is very cryptic. Whatever works is fine for me.
Wasn't it using v
and o
before and we changed it to gv
😅 ?
I don't know how it has been changed, I never really touched that part of the code. I only remember that it used to be normal gv
and it changed to normal! gv
And yeah need to definitely add more kinds of tests as my testing currently only checks the selection range
@theHamsta I see, it was nvim-treesitter/nvim-treesitter#4015
@phgz It looks it the fix introduced another bug. Also I can't really reproduce the flickering UI either. Is it possible to test if you still face the same issues if you use https://github.com/kiyoon/nvim-treesitter/tree/fix/update-selection-change-mode ?
I used vim.api.nvim_win_set_cursor
instead of vim.fn.setpos
which may have fixed some issues we had earlier
I should be able to check it later today.
I should be able to check it later today.
Thank you!
Sorry for the delay. I've tested it and it seems to be good. Nothing suspect detected. It was originally to fix the vim.keymap.set
thing, but it now seems ok apparently, so all good!
@phgz Really appreciate taking your time on the weekends to test this!