vim-metarepeat
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
" vim-metarepeat provides an operator (like) mapping which runs dot repeat for | |
" every occurence matched by last pattern (@/) in range (specified by motion or | |
" textobject). | |
" | |
" vim-metarepeat is inspired by 'Occurrence modifier, preset-occurrence, | |
" persistence-selection' feature | |
" http://qiita.com/t9md/items/0bc7eaff726d099943eb#occurrence-modifier-preset-occurrence-persistence-selection | |
" | |
" But it's not a port of these feature. In similar to vim-mode-plus terms, | |
" vim-metarepeat provides 'preset-operation-for-occurence' feature (it's just | |
" a operator + 'gn') and provides a way to apply the operation for each | |
" occurences in textobject. | |
" | |
" TODO: | |
" - highlight changed text to make changed texts clear for users? | |
nnoremap <expr> <Plug>(metarepeat) <SID>metarepeat() | |
xnoremap <Plug>(metarepeat) <Esc>:<C-u>call <SID>setview() <bar> call <SID>selected()<CR> | |
map g. <Plug>(metarepeat) | |
let s:saveview = {} | |
function! s:setview() abort | |
let s:saveview = winsaveview() | |
endfunction | |
" s:metarepeat() is expected to be called with <expr> mapping. | |
" It registers CursorMoved event and returns 'v'. | |
" By using 'v' (starting visual mode) and exiting visual mode with first | |
" CursorMoved, it emulates 'operator' behavior without breaking dot repeat. | |
" (g@ breaks dot repeat) | |
function! s:metarepeat() abort | |
augroup metarepeat-move-once | |
autocmd! | |
autocmd CursorMoved * call s:hook_after_move() | |
augroup END | |
call s:setview() | |
return 'v' | |
endfunction | |
function! s:hook_after_move() abort | |
autocmd! metarepeat-move-once | |
execute 'normal!' "\<Esc>" | |
call s:selected() | |
endfunction | |
" s:selected is expected to be called in normal mode and target has been | |
" selected. | |
function! s:selected() abort | |
call s:metaoperate(getpos("'<"), getpos("'>"), @/) | |
endfunction | |
" s:metaoperate() execute dot repeat for every pattern occurence between start | |
" and end position. | |
" start: [bufnum, lnum, col, off] | |
" end: [bufnum, lnum, col, off] | |
" pattern: [bufnum, lnum, col, off] | |
function! s:metaoperate(start, end, pattern) abort | |
call setpos('.', a:start) | |
let first = v:true | |
let endline = a:end[1] | |
let endcol = a:end[2] | |
let stopline = endline + 1 | |
while v:true | |
let flag = first ? 'c' : '' | |
let [lnum, col] = searchpos(a:pattern, flag, stopline) | |
if (lnum ==# 0 && col ==# 0) || lnum > endline || (lnum ==# endline && col > endcol) | |
break | |
endif | |
normal! . | |
let first = v:false | |
endwhile | |
if s:saveview !=# {} | |
call winrestview(s:saveview) | |
let s:saveview = {} | |
endif | |
endfunction | |
" --- | |
" support multiple preset-occurrence like feature by providing append preset | |
" occurence mapping. It only supports 'appending' because we cannot reset | |
" preset occurence after operation. | |
nnoremap <silent> <Plug>(append-preset-occurence) :<C-u>call <SID>append_preset_occurence() <bar> set hlsearch<CR> | |
nmap go <Plug>(append-preset-occurence) | |
function! s:append_preset_occurence() abort | |
let @/ = @/ . '\V\|\<' . escape(expand('<cword>'), '\') . '\>' | |
endfunction |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment