I know that similar things were asked here several times. I know that to repeat a motion ; works. Unless it doesn't(in case there is count for example), but then repmo.vim usually works. And I know that . works for changes.

The thing is that repmo.vim is stupid, and thus provides no solution for complicated things such as [m,[c, [M. When I tried to do so(add this motion to its list), it didn't work.

So, any solution for this that I missed? Doing norm ']m' and then @: is an option, but I don't really like it. The forward and rev capability of repmo.vim is nice.


3 Answers 3


Plugin repmo-vim by Andy Wakula

The plugin #2174 listed on https://www.vim.org/scripts is, according to the description, outdated:

2016 Nov 22 started a new script at https://github.com/Houl/vim-repmo

The new plugin on github works for me when repeating, e.g. ]m/[m and ]M/[M with ; and ,. My minimal configuration looks like using vim8 packages (vim 8.1.560 on macOS 10.12):

❯ tree
├── pack
│   └── repeat-complicated-motions
│       └── start
│           └── repmo-vim
│               ├── README.markdown
│               └── autoload
│                   └── repmo.vim
└── vimrc

5 directories, 3 files
" ~/.vim/vimrc
source $VIMRUNTIME/defaults.vim

map <expr> ; repmo#LastKey(';')|sunmap ;
map <expr> , repmo#LastRevKey(',')|sunmap ,

" Still repeat fFtT (now with counts):
noremap <expr> f repmo#ZapKey('f')|sunmap f
noremap <expr> F repmo#ZapKey('F')|sunmap F
noremap <expr> t repmo#ZapKey('t')|sunmap t
noremap <expr> T repmo#ZapKey('T')|sunmap T

" Now following can also be repeated with `;` and `,`:
for keys in [ ['[[', ']]'], ['[]', ']['], ['[m', ']m'], ['[M', ']M'], ['[c', ']c'] ]
    execute 'noremap <expr> '.keys[0]." repmo#SelfKey('".keys[0]."', '".keys[1]."')|sunmap ".keys[0]
    execute 'noremap <expr> '.keys[1]." repmo#SelfKey('".keys[1]."', '".keys[0]."')|sunmap ".keys[1]

Example java file:

public class Factorial
    public static void main(String[] args)
    {   final int NUM_FACTS = 100;                                 // ; after [m
        for(int i = 0; i < NUM_FACTS; i++)
            System.out.println( i + "! is " + factorial(i));
    }                                                              // , after ]M

    public static int factorial(int n)
    {   int result = 1;                                            // [m
        for(int i = 2; i <= n; i++)
            result *= i;                                           // CURSOR
        return result;
    }                                                              // ]M
// vim: ft=java

Also when I open a diff (e.g. with :Gdiff from vim-fugitive), repeating ]c and [c are possible.

<Plug> mappings of ftplugins

Another possible issue with [m, [M is that you have to remap them for filetypes with overwrites and you want to use the overwrites. Examples are python, vimscript, and ruby. Unfortunately, many ftplugins do not provide them as <plug> mappings which repmo-vim needs.

The ftplugin vim-pythonsense provides them as <plug> mappings:

" ~/.vim/after/ftplugin/python.vim
map <expr><buffer> ]] repmo#Key('<plug>(PythonsenseStartOfNextPythonClass)', '<plug>(PythonsenseStartOfPythonClass)')|sunmap <buffer> ]]
map <expr><buffer> [[ repmo#Key('<plug>(PythonsenseStartOfPythonClass)', '<plug>(PythonsenseStartOfNextPythonClass)')|sunmap <buffer> [[
map <expr><buffer> ][ repmo#Key('<plug>(PythonsenseEndOfPythonClass)', '<plug>(PythonsenseEndOfPreviousPythonClass)')|sunmap <buffer> ][
map <expr><buffer> [] repmo#Key('<plug>(PythonsenseEndOfPreviousPythonClass)', '<plug>(PythonsenseEndOfPythonClass)')|sunmap <buffer> []
map <expr><buffer> ]m repmo#Key('<plug>(PythonsenseStartOfNextPythonFunction)', '<plug>(PythonsenseStartOfPythonFunction)')|sunmap <buffer> ]m
map <expr><buffer> [m repmo#Key('<plug>(PythonsenseStartOfPythonFunction)', '<plug>(PythonsenseStartOfNextPythonFunction)')|sunmap <buffer> [m
map <expr><buffer> ]M repmo#Key('<plug>(PythonsenseEndOfPythonFunction)', '<plug>(PythonsenseEndOfPreviousPythonFunction)')|sunmap <buffer> ]M
map <expr><buffer> [M repmo#Key('<plug>(PythonsenseEndOfPreviousPythonFunction)', '<plug>(PythonsenseEndOfPythonFunction)')|sunmap <buffer> [M

Also the ftplugin vimtex provides them as <plug> mappings and the configuration becomes:

" ~/.vim/after/ftplugin/tex.vim
map <expr><buffer> ]] repmo#Key('<plug>(vimtex-]])', '<plug>(vimtex-[[)')|sunmap <buffer> ]]
map <expr><buffer> [[ repmo#Key('<plug>(vimtex-[[)', '<plug>(vimtex-]])')|sunmap <buffer> [[
map <expr><buffer> ][ repmo#Key('<plug>(vimtex-][)', '<plug>(vimtex-[])')|sunmap <buffer> ][
map <expr><buffer> [] repmo#Key('<plug>(vimtex-[])', '<plug>(vimtex-][)')|sunmap <buffer> []
map <expr><buffer> ]m repmo#Key('<plug>(vimtex-]m)', '<plug>(vimtex-[m)')|sunmap <buffer> ]m
map <expr><buffer> [m repmo#Key('<plug>(vimtex-[m)', '<plug>(vimtex-]m)')|sunmap <buffer> [m
map <expr><buffer> ]M repmo#Key('<plug>(vimtex-]M)', '<plug>(vimtex-[M)')|sunmap <buffer> ]M
map <expr><buffer> [M repmo#Key('<plug>(vimtex-[M)', '<plug>(vimtex-]M)')|sunmap <buffer> [M

If you want to use the ones in $VIMRUNTIME/ftplugin/{python,ruby,vim}.vim you have to rewrite them as <plug> mappings and put them into repmo#Key.

What file types are you interested in?

  • I spend like two hours trying to presuade vim to load it. It did work in one of my environment (I have gui and command line environment). But no more. I simply source it from .vimrc before anything else. Even though it is on the autoload folder it ignores it. I give up.
    – eyal karni
    Commented Dec 6, 2018 at 20:19
  • I can see that autoload was run from echoing one of the variables. But motions are not repeated. It did work earlier.
    – eyal karni
    Commented Dec 6, 2018 at 20:19
  • 1
    Hi eyal karni. Sorry to hear that you could not make it work. I have updated the question with a more explicit description of a minimal config with java code for illustration. Could you backup your vim config and work with an empty ~/.vim folder? Place everything I mentioned in my answer accordingly ($ git clone https://github.com/Houl/repmo-vim ~/.vim/pack/repeat-complicated-motions/start/repmo-vim and the vimrc should be identical). Also please post the result from :nmap [m which should be nox [m * repmo#SelfKey('[m', ']m') and your vim version 8.x.xxxx and OS.
    – Hotschke
    Commented Dec 7, 2018 at 12:28
  • 1
    Also check out How to debug a mapping? and How do I debug my vimrc file?.
    – Hotschke
    Commented Dec 7, 2018 at 12:35

I have created a small vim-remotions plugin that allows to repeat the last motion using the ; and , keys (like for the f and t motions).

By default it repeats the following motions: ]m, ]M, ]], ][, }, g;, ]b, ]l, ]q, ]t, ]g.

It use the motion as they are defined in the buffer by the filetype.

The list of motions it repeats is configurable.

It can repeat the motion and their count or only the motion.

It can repeat the motion in the direction of the initial motion (like ; and , are doing for f and t) or in the direction of the document if considered more intuitive.

Thanks to @romainl for his hints.

  • 1
    Hi Vivian. It looks like you copied this answer from another one of your answes here. In general if the same answer can apply to the same question it may be a duplicate, but in this case it looks like you are recommending your plugin. Can you please edit your answer to address the question's specifics.
    – Dom
    Commented Oct 20, 2023 at 5:06
  • 1
    Currently I use the repmo plugin , but might try yours one day :) Are they compatible?
    – eyal karni
    Commented Oct 20, 2023 at 15:54
  • 1
    I think @Dom’s point is that this answer should contain some specific address of the question. For example: « to repeat ]m after installing the plugin, just press ; », and so forth. The answer reads a bit more like an ad than a « here’s the solution to your problem »
    – D. Ben Knoble
    Commented Oct 20, 2023 at 16:22
  • 1
    I already accepted it.
    – eyal karni
    Commented Oct 21, 2023 at 20:40
  • 1
    It indeed doesnt work it seems. [d does for example (diagnostics).
    – eyal karni
    Commented Dec 2, 2023 at 2:28

After a long time it didn't really work I returned to that, slightly improving the answer by @Hotschke.

Now, in addition to what he said, for the maps that I defined myself, I first define the mappings as usual, and support for repeat is established like so (using repmo) :

nmap [a :ALEPrevious<CR>
nmap ]a :ALENext<CR>
nmap ]E <Plug>(coc-diagnostic-next)
nmap [E <Plug>(coc-diagnostic-prev)
nmap ]e <Plug>(coc-diagnostic-next-error)
nmap [e <Plug>(coc-diagnostic-prev-error)
nmap [h <Plug>(GitGutterPrevHunk)
nmap ]h <Plug>(GitGutterNextHunk)

for keys in [[']E','[E'],[']a','[a'],[']e','[e'],[']h','[h']]
    call RepRemap(keys[0],keys[1])

Needed function:

"Remaps repeat pairs
function! RepRemap(mapA,mapB)
let varA=maparg(a:mapA,'n')
let varB=maparg(a:mapB,'n')
execute "nmap <expr> " . a:mapA . " repmo#Key('".varA ."', '". varB. "')"
execute "nmap <expr> " . a:mapB . " repmo#Key('".varB ."', '". varA. "')"

Possibly using map and sunmap is better.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.