tpope / vim-repeat

repeat.vim: enable repeating supported plugin maps with "."
http://www.vim.org/scripts/script.php?script_id=2136
2.58k stars 81 forks source link

Can't repeat surround.vim action with . after undoing with u #94

Closed michelesr closed 2 weeks ago

michelesr commented 1 year ago

Steps to reproduce:

  1. use a surround.vim action such as csi"
  2. try to repeat with . multiple times (it works)
  3. now press u to undo last repeat
  4. press . again: now repeat doesn't work correctly, and it's likely to repeat last vim native atomic operation
troiganto commented 1 year ago

I just stumbled over this issue myself and I think I found the problem: it's a race condition between the plugin and feedkeys().

In this line, vim-repeat feeds the undo command into the vim typeahead buffer via feedkeys(). The function documents that it does not wait until the appended command has actually been handled, but instead it returns immediately.

Once returned, the plugin updates g:repeat_tick to the latest change value in this line. Only after that does vim handle the undo command, which updates the buffer tick again and brings it out of sync with g:repeat_tick. Thus, the plugin no longer knows that its command is still up-to-date.

There are two solutions to this issue. One is to pass the mode 'nx' instead of 'n' to feedkeys(). The x tells it to immediately empty the typeahead buffer and only return when that is done. This way, when g:repeat_tick is updated, it actually receives the latest value.

The other solution works on older vim versions as well and requires to add a single-use autocmd TextChanged <buffer> let g:repeat_tick = b:changedtick after the feedkeys() call. It's been implemented in this PR.