Give this a try. It remaps `@` so that `g@` (plus a dummy motion `l`) is used afterwards, thus becoming the last operator and subject to repeating with `.`. " When . repeats g@, repeat the last macro. fun! AtRepeat(_) " If no count is supplied use the one saved in s:atcount. " Otherwise save the new count in s:atcount, so it will be " applied to repeats. let s:atcount = v:count ? v:count : s:atcount " feedkeys() rather than :normal allows finishing in Insert " mode, should the macro do that. @@ is remapped, so 'opfunc' " will be correct, even if the macro changes it. call feedkeys(s:atcount.'@@') endfun fun! AtSetRepeat(_) set opfunc=AtRepeat endfun " Called by g@ being invoked directly for the first time. Sets " 'opfunc' ready for repeats with . by calling AtSetRepeat(). fun! AtInit() " Make sure setting 'opfunc' happens here, after initial playback " of the macro recording, in case 'opfunc' is set there. set opfunc=AtSetRepeat return 'g@l' endfun " Enable calling a function within the mapping for @ nno <expr> <plug>@init AtInit() " A macro could, albeit unusually, end in Insert mode. ino <expr> <plug>@init "\<c-o>".AtInit() fun! AtReg() let s:atcount = v:count1 let c = nr2char(getchar()) return '@'.c."\<plug>@init" endfun nmap <expr> @ AtReg() I've tried to handle as many corner cases as I can think of. You can repeat `@:` with `.`. Counts to `@` or `.` are retained for subsequent presses of `.`. This is tricky, and I'm not convinced that something won't break somewhere along the way. So no guarantees, warranties, or promises with this one. Personally, I'm okay having a difference between the fine-grained repeats of `.` for the last change, and the macro repeats of `@@`. **EDIT** I figured, having gone this far, that I may as well add some additional code that will allow pressing `.` immediately after recording a macro to play it back. fun! QRepeat(_) call feedkeys('@'.s:qreg) endfun fun! QSetRepeat(_) set opfunc=QRepeat endfun fun! QStop() set opfunc=QSetRepeat return 'g@l' endfun nno <expr> <plug>qstop QStop() ino <expr> <plug>qstop "\<c-o>".QStop() let s:qrec = 0 fun! QStart() if s:qrec == 1 let s:qrec = 0 return "q\<plug>qstop" endif let s:qrec = 1 let s:qreg = nr2char(getchar()) return 'q'.s:qreg endfun nmap <expr> q QStart()