Compare commits

...

15 commits
v1.2 ... master

Author SHA1 Message Date
Tim Pope 65846025c1 One last fix attempt before I revert everything
References: https://github.com/tpope/vim-repeat/issues/63
2024-07-08 17:25:42 -04:00
Tim Pope 5bd4c87a14 Restore unfolding during undo
References: https://github.com/tpope/vim-repeat/issues/63
2024-07-08 10:12:33 -04:00
Tim Pope a89a4d0760 Avoid stacktrace on undo in 'nomodifiable' buffer
References: https://github.com/tpope/vim-repeat
2024-07-07 15:08:09 -04:00
Tim Pope 4bac219cc0 Drop FUNDING.yml in favor of account-level default 2024-07-07 14:24:39 -04:00
Tim Pope 8b4435c5bb Account for Vim undo double-incrementing b:changedtick
Resolves: https://github.com/tpope/vim-repeat/issues/63
Resolves: https://github.com/tpope/vim-repeat/issues/94
Resolves: https://github.com/tpope/vim-repeat/pull/95
2024-07-07 13:00:05 -04:00
Tim Pope e0466d2b24 Bump minimum Vim version to 8.0 2024-07-07 13:00:03 -04:00
Ingo Karkat 24afe922e6 Rework error return to prevent off-by-one in Ex mode
My automated tests run Vim in silent batch mode (:help -s-ex), these also cover repeat of mappings via repeat.vim. Unfortunately, the combination of feedkeys() and :execute used in the repeat.vim implementation to return a potential caught error cause the line where the repeat mapping is executed to be increased, so for me the tests fail in a really strange way. The same problem can occur if someone uses repeats in silent batch mode (e.g. through a recorded macro) - though the source of the problem would be even harder to track down there - in my test run it at least was easily reproducible.

I raised this as a potential Vim bug in https://github.com/vim/vim/issues/7153, but Bram explained that it's a side effect of Ex mode (where empty lines make the cursor go to the next line, and as repeat#run() returns the empty String on the happy path, that's an empty line being executed). Recommendation from Bram is to pass the "x" flag for immediate execution to feedkeys() (which avoids the problem). However, in the context of repeat.vim this would mean that any errors resulting from the repeat mapping invocation would have to be caught inside repeat#run(), because they would then execute within the function's context, and not after it. Also, the "x" flag would not be supported by old Vim 7.3 and earlier.

Instead, I chose to avoid the problem by replacing the :execute with a more straightforward :call (actually an :if that tests a returned Boolean success flag), so instead of the clever direct execution of the returned :echoerr command, the error message instead is retrieved from a script-local variable via a new repeat#errmsg() getter. I use this idiom in all of my plugins through a set of utility functions (5bb32fd27a/autoload/ingo/err.vim (L38-L41)), too.
So by adding a little (well encapsulated) variable and getter, this problem can be avoided without touching the sensitive feedkeys() and try...catch logic within the plugin.
2021-01-24 22:11:08 -05:00
Tim Pope c947ad2b6a Add sponsor button 2019-11-12 19:31:06 -05:00
Anton Kochkov ae361bea99 Add vim-radical in the plugins list 2019-07-29 12:17:59 -04:00
Ingo Karkat 0b9b5e742f Make an explicit register on repeat override g:repeat_reg
As with built-in commands, this allows to override the original register on repeat, e.g. "a. uses register a instead of the original one.

One limitation is that we cannot detect whether no or the default register has been given, so an override from a non-default to the default register (e.g. via "".) is not possible.
2019-04-25 22:13:50 -04:00
Ingo Karkat 5974ea07ac Documentation fix for repeat#setreg()
Need to :execute the :silent! call to avoid that the remainder of the
command line is aborted together with the call when repeat.vim is not
installed. Otherwise, <SID>MyFunction() won't be invoked, and the
mapping does nothing.
2019-04-25 21:49:34 -04:00
Ingo Karkat eb97e729be feedkeys(..., 'i') sends keys in the wrong order in Vim 7.0/1/2
The current implementation prefers feedkeys(..., 'i') and only falls back to :normal if Vim 7.4 does not have the 'i' flag and if Vim 7.3 supports :normal with count. For Vim 8.0 (and later), and also for versions between 7.0 and 7.3.99, feedkeys(..., 'i') is used. Due to the prepending action of the 'i' flag, keys must be submitted in reverse order; that's why s is submitted before r . cnt.  Vim 7.0...7.3.99 ignore the 'i' flag, though, and append the keys, which are now in the wrong order (this only matters if a register or count is given).

Add a separate conditional branch for Vim versions before 7.3.100 that uses feedkeys() in the correct order and omits the ignored 'i' flag.
2019-04-25 21:48:12 -04:00
Tim Pope 43d2678fa5 Remove outdated plugin references 2018-07-02 15:03:55 -04:00
Tim Pope 1ea8a5325b Update installation instructions 2018-07-02 15:03:36 -04:00
Tim Pope 8fe8bde4f4 Change Markdown heading style 2018-07-02 15:03:25 -04:00
2 changed files with 49 additions and 44 deletions

View file

@ -1,5 +1,4 @@
repeat.vim # repeat.vim
==========
If you've ever tried using the `.` command after a plugin map, you were If you've ever tried using the `.` command after a plugin map, you were
likely disappointed to discover it only repeated the last native command likely disappointed to discover it only repeated the last native command
@ -11,34 +10,30 @@ The following plugins support repeat.vim:
* [surround.vim](https://github.com/tpope/vim-surround) * [surround.vim](https://github.com/tpope/vim-surround)
* [speeddating.vim](https://github.com/tpope/vim-speeddating) * [speeddating.vim](https://github.com/tpope/vim-speeddating)
* [abolish.vim](https://github.com/tpope/vim-abolish)
* [unimpaired.vim](https://github.com/tpope/vim-unimpaired) * [unimpaired.vim](https://github.com/tpope/vim-unimpaired)
* [commentary.vim](https://github.com/tpope/vim-commentary)
* [vim-easyclip](https://github.com/svermeulen/vim-easyclip) * [vim-easyclip](https://github.com/svermeulen/vim-easyclip)
* [vim-radical](https://github.com/glts/vim-radical)
Adding support to a plugin is generally as simple as the following Adding support to a plugin is generally as simple as the following
command at the end of your map functions. command at the end of your map functions.
silent! call repeat#set("\<Plug>MyWonderfulMap", v:count) silent! call repeat#set("\<Plug>MyWonderfulMap", v:count)
Installation ## Installation
------------
If you don't have a preferred installation method, I recommend Install using your favorite package manager, or use Vim's built-in package
installing [pathogen.vim](https://github.com/tpope/vim-pathogen), and support:
then simply copy and paste:
cd ~/.vim/bundle mkdir -p ~/.vim/pack/tpope/start
git clone git://github.com/tpope/vim-repeat.git cd ~/.vim/pack/tpope/start
git clone https://tpope.io/vim/repeat.git
Contributing ## Contributing
------------
See the contribution guidelines for See the contribution guidelines for
[pathogen.vim](https://github.com/tpope/vim-pathogen#readme). [pathogen.vim](https://github.com/tpope/vim-pathogen#readme).
Self-Promotion ## Self-Promotion
--------------
Like repeat.vim? Follow the repository on Like repeat.vim? Follow the repository on
[GitHub](https://github.com/tpope/vim-repeat) and vote for it on [GitHub](https://github.com/tpope/vim-repeat) and vote for it on
@ -47,8 +42,7 @@ you're feeling especially charitable, follow [tpope](http://tpo.pe/) on
[Twitter](http://twitter.com/tpope) and [Twitter](http://twitter.com/tpope) and
[GitHub](https://github.com/tpope). [GitHub](https://github.com/tpope).
License ## License
-------
Copyright (c) Tim Pope. Distributed under the same terms as Vim itself. Copyright (c) Tim Pope. Distributed under the same terms as Vim itself.
See `:help license`. See `:help license`.

View file

@ -40,11 +40,11 @@
" in your mapping will look like this: " in your mapping will look like this:
" "
" nnoremap <silent> <Plug>MyMap " nnoremap <silent> <Plug>MyMap
" \ :<C-U>silent! call repeat#setreg("\<lt>Plug>MyMap", v:register)<Bar> " \ :<C-U>execute 'silent! call repeat#setreg("\<lt>Plug>MyMap", v:register)'<Bar>
" \ call <SID>MyFunction(v:register, ...)<Bar> " \ call <SID>MyFunction(v:register, ...)<Bar>
" \ silent! call repeat#set("\<lt>Plug>MyMap")<CR> " \ silent! call repeat#set("\<lt>Plug>MyMap")<CR>
if exists("g:loaded_repeat") || &cp || v:version < 700 if exists("g:loaded_repeat") || &cp || v:version < 800
finish finish
endif endif
let g:loaded_repeat = 1 let g:loaded_repeat = 1
@ -73,55 +73,66 @@ function! repeat#setreg(sequence,register)
let g:repeat_reg = [a:sequence, a:register] let g:repeat_reg = [a:sequence, a:register]
endfunction endfunction
function! s:default_register()
let values = split(&clipboard, ',')
if index(values, 'unnamedplus') != -1
return '+'
elseif index(values, 'unnamed') != -1
return '*'
else
return '"'
endif
endfunction
function! repeat#run(count) function! repeat#run(count)
let s:errmsg = ''
try try
if g:repeat_tick == b:changedtick if g:repeat_tick == b:changedtick
let r = '' let r = ''
if g:repeat_reg[0] ==# g:repeat_sequence && !empty(g:repeat_reg[1]) if g:repeat_reg[0] ==# g:repeat_sequence && !empty(g:repeat_reg[1])
if g:repeat_reg[1] ==# '=' " Take the original register, unless another (non-default, we
" unfortunately cannot detect no vs. a given default register)
" register has been supplied to the repeat command (as an
" explicit override).
let regname = v:register ==# s:default_register() ? g:repeat_reg[1] : v:register
if regname ==# '='
" This causes a re-evaluation of the expression on repeat, which " This causes a re-evaluation of the expression on repeat, which
" is what we want. " is what we want.
let r = '"=' . getreg('=', 1) . "\<CR>" let r = '"=' . getreg('=', 1) . "\<CR>"
else else
let r = '"' . g:repeat_reg[1] let r = '"' . regname
endif endif
endif endif
let c = g:repeat_count let c = g:repeat_count
let s = g:repeat_sequence let s = g:repeat_sequence
let cnt = c == -1 ? "" : (a:count ? a:count : (c ? c : '')) let cnt = c == -1 ? "" : (a:count ? a:count : (c ? c : ''))
if ((v:version == 703 && has('patch100')) || (v:version == 704 && !has('patch601'))) call feedkeys(s, 'i')
exe 'norm ' . r . cnt . s call feedkeys(r . cnt, 'ni')
else
call feedkeys(s, 'i')
call feedkeys(r . cnt, 'ni')
endif
else else
if ((v:version == 703 && has('patch100')) || (v:version == 704 && !has('patch601'))) call feedkeys((a:count ? a:count : '') . '.', 'ni')
exe 'norm! '.(a:count ? a:count : '') . '.'
else
call feedkeys((a:count ? a:count : '') . '.', 'ni')
endif
endif endif
catch /^Vim(normal):/ catch /^Vim(normal):/
return 'echoerr v:errmsg' let s:errmsg = v:errmsg
return 0
endtry endtry
return '' return 1
endfunction
function! repeat#errmsg()
return s:errmsg
endfunction endfunction
function! repeat#wrap(command,count) function! repeat#wrap(command,count)
let preserve = (g:repeat_tick == b:changedtick) let foldopen = &foldopen =~# 'undo\|all' ? 'zv' : ''
call feedkeys((a:count ? a:count : '').a:command, 'n') let preserve = g:repeat_tick == b:changedtick ? ":let g:repeat_tick = b:changedtick\r" : ''
exe (&foldopen =~# 'undo\|all' ? 'norm! zv' : '') return (a:count ? a:count : '') . a:command . preserve . foldopen
if preserve
let g:repeat_tick = b:changedtick
endif
endfunction endfunction
nnoremap <silent> <Plug>(RepeatDot) :<C-U>exe repeat#run(v:count)<CR> nnoremap <silent> <Plug>(RepeatDot) :<C-U>if !repeat#run(v:count)<Bar>echoerr repeat#errmsg()<Bar>endif<CR>
nnoremap <silent> <Plug>(RepeatUndo) :<C-U>call repeat#wrap('u',v:count)<CR> nmap <silent><expr><script> <Plug>(RepeatUndo) repeat#wrap('u',v:count)
nnoremap <silent> <Plug>(RepeatUndoLine) :<C-U>call repeat#wrap('U',v:count)<CR> nmap <silent><expr><script> <Plug>(RepeatUndoLine) repeat#wrap('U',v:count)
nnoremap <silent> <Plug>(RepeatRedo) :<C-U>call repeat#wrap("\<Lt>C-R>",v:count)<CR> nmap <silent><expr><script> <Plug>(RepeatRedo) repeat#wrap("\022",v:count)
if !hasmapto('<Plug>(RepeatDot)', 'n') if !hasmapto('<Plug>(RepeatDot)', 'n')
nmap . <Plug>(RepeatDot) nmap . <Plug>(RepeatDot)