Closed b4winckler closed 10 years ago
There's no built-in support. I would imagine you could individually map daa
, caa
, and any other particular dispatches up to call repeat#set('daa')
and the like.
I doubt a general solution is possible. Vim doesn't provide any introspection for what the most recent operator was. Although perhaps there's a novel approach to the problem is missing.
Thanks for the reply. Perhaps the only real solution to this problem would be to patch the Vim source code. (I was a bit surprised that .
didn't automatically work in this situation since a custom motion only performs a selection and not an actual edit.)
Anyway, I'll leave it up to you whether it is meaningful to leave this issue open or not.
While implementing the identical text object as you, @b4winckler, I noticed that you can at least make the repetition of 'daa' work by incrementing repeat_tick by 1 after calling repeat#set(). As changing of text seems to increment b:changedtick in a way I couldn't determine, 'caa' cannot be implemented that way. Otherwise it would be possible to use a separate function to repeat, where register '@.' could be inserted, if v:operator was 'c'.
I managed to implement repeat for my custom text motions¹. Here's the problem and a solution:
vim-repeat uses b:changedtick to decide if the last change in the buffer was the change registered by repeat#set(). However, in operator-pending mappings b:changedtick is not incremented by vim until the mapping has completed. A call to repeat#set() during the omap will record the value of b:changedtick before it is incremented.
@tek noticed that manually incrementing g:repeat_tick by 1 seems to work. It does work for delete operations that only change one line, but multiline changes increment b:changedtick multiple times, so this is not a general solution.
It turns out that while CursorMoved fires on normal mode movement and changes to the cursor's line, it deliberately does not fire in operator-pending mode. Thus you can register a one-time CursorMoved handler that updates g:repeat_tick after the omap completes, and repeat#run() will work just as intended:
function! RepeatSet(buf)
call repeat#set(a:buf)
augroup repeat_tick
autocmd!
autocmd CursorMoved <buffer>
\ let g:repeat_tick = b:changedtick |
\ autocmd! repeat_tick
augroup END
endfunction
onoremap <Plug>my_motion :call move_cursor() \|
\ call RepeatSet(v:operator . "\<Plug>my_motion")<CR>
Notice that we can use v:operator to get the most recent operator, so both native and custom pending operations will be repeated.
This property of CursorMoved is documented, so I think this is a valid solution. There is no need to patch vim-repeat, but it might be helpful to add this to the documentation.
¹ https://github.com/guns/vim-sexp/blob/master/plugin/sexp.vim#L97
That works, thanks a lot, @guns! Incredible. With this, I was able to implement the repeatable change-command. https://github.com/tek/vim-argh/blob/master/autoload/argh.vim#L54
No reason I can't roll this in, I suppose.
@tpope Thanks!
I have a custom motion
omap aa <Plug>AngryOuterPrefix
that I'd like to be able to repeat when typing for exampledaa
. Currently (not using repeat.vim) the result of pressing.
is that Vim deletes the same number of characters as the firstdaa
instead of deleting the actual text object defined byaa
.Is it possible to use repeat.vim to make
daa
,caa
etc. work properly with.
?