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

Change behavior when repeating last move from builtin_f_expr and builtin_t_expr

Open gabrielrov opened this issue 1 year ago • 2 comments

Is your feature request related to a problem? Please describe. When using repeat_last_moveon operation pending mode, after triggeringbuiltin_f_expr or builtin_t_expr, it operates on one character less that it would be expected to.

Taking this snippet as an exemple:

vim.keymap.set({ 'n', 'x', 'o' }, ';', ts_repeat_move.repeat_last_move)

If the user presses f(, returns to the first character and presses d;, it would result on:

({ 'n', 'x', 'o' }, ';', ts_repeat_move.repeat_last_move)

t(_d; would result on:

t({ 'n', 'x', 'o' }, ';', ts_repeat_move.repeat_last_move)

Describe the solution you'd like For f(_d;, it would be expected to behave, as:

{ 'n', 'x', 'o' }, ';', ts_repeat_move.repeat_last_move)

and for t(_d;:

({ 'n', 'x', 'o' }, ';', ts_repeat_move.repeat_last_move)

Additional context This diverges from the way it works in core nvim and is inconsistent with F, T, and visual selection behavior.

As far as i can tell, this is only reproducible when repeating moves from builtin_f_expr and builtin_t_expr on operation pending mode, not with builtin_F_expr and builtin_T_expr.

gabrielrov avatar Oct 09 '24 03:10 gabrielrov

Because d; is not equal to d:norm! ;<cr>. Can be fixed with expr (this patch is used on main branch, but I'm not sure if this functionality would still be kept in future):

diff --git a/lua/nvim-treesitter-textobjects/repeatable_move.lua b/lua/nvim-treesitter-textobjects/repeatable_move.lua
index f4aa09b..4d8b3ff 100644
--- a/lua/nvim-treesitter-textobjects/repeatable_move.lua
+++ b/lua/nvim-treesitter-textobjects/repeatable_move.lua
@@ -27,34 +27,19 @@ M.make_repeatable_move = function(move_fn)
 end
 
 ---@param opts_extend TSTextObjects.MoveOpts?
----@return boolean
+---@return string?
 M.repeat_last_move = function(opts_extend)
-  if M.last_move then
-    local opts ---@type table
-    if opts_extend ~= nil then
-      opts = vim.tbl_deep_extend("force", {}, M.last_move.opts, opts_extend)
-    else
-      opts = M.last_move.opts
-    end
-
-    if M.last_move.func == "f" or M.last_move.func == "t" then
-      if opts.forward then
-        vim.cmd.normal { vim.v.count1 .. ";", bang = true }
-      else
-        vim.cmd.normal { vim.v.count1 .. ",", bang = true }
-      end
-    elseif M.last_move.func == "F" or M.last_move.func == "T" then
-      if opts.forward then
-        vim.cmd.normal { vim.v.count1 .. ",", bang = true }
-      else
-        vim.cmd.normal { vim.v.count1 .. ";", bang = true }
-      end
-    else
-      M.last_move.func(opts, unpack(M.last_move.additional_args))
-    end
-    return true
+  if not M.last_move then
+    return
+  end
+  local opts = vim.tbl_deep_extend("force", M.last_move.opts, opts_extend or {})
+  if M.last_move.func == "f" or M.last_move.func == "t" then
+    return opts.forward and ";" or ","
+  elseif M.last_move.func == "F" or M.last_move.func == "T" then
+    return opts.forward and "," or ";"
+  else
+    return M.last_move.func(opts, unpack(M.last_move.additional_args))
   end
-  return false
 end
 
 M.repeat_last_move_opposite = function()
vim.keymap.set({ 'n', 'x', 'o' }, ';', function() return require 'nvim-treesitter-textobjects.repeatable_move'.repeat_last_move_next() end, { expr = true })
vim.keymap.set({ 'n', 'x', 'o' }, ',', function() return require 'nvim-treesitter-textobjects.repeatable_move'.repeat_last_move_opposite() end, { expr = true })

phanen avatar Oct 17 '24 09:10 phanen

@phanen Could you open a PR for your fix? Your solution seems good to me.

kiyoon avatar Oct 17 '24 10:10 kiyoon

Closed by #707

kiyoon avatar Oct 22 '24 05:10 kiyoon