├── LICENSE ├── README.md └── plugin └── metarepeat.vim /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 haya14busa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## vim-metarepeat 2 | 3 | vim-metarepeat provides an operator (like) mapping which runs dot repeat for 4 | every occurence matched by last pattern (@/) in range (specified by motion or 5 | textobject). 6 | 7 | neovim-metarepeat is inspired by 'Occurrence modifier, preset-occurrence, 8 | persistence-selection' feature 9 | http://qiita.com/t9md/items/0bc7eaff726d099943eb#occurrence-modifier-preset-occurrence-persistence-selection 10 | 11 | But it's not a port of these feature. In similar to vim-mode-plus terms, 12 | vim-metarepeat provides 'preset-operation-for-occurence' feature (it's just 13 | a operator + 'gn') and provides a way to apply the operation for each 14 | occurences in textobject. 15 | 16 | 17 | ![anim](https://cloud.githubusercontent.com/assets/3797062/20180056/1a0e62da-a79c-11e6-801c-84f41d188770.gif) 18 | 19 | ``` 20 | This is 1st paragraph abc. 21 | 2nd abc also include abc abc abc. 22 | 3rd abc include abc abc abc 23 | 24 | This is 2nd paragraph abc. 25 | 2nd line also include text text text. 26 | 3rd abc include abc abc abc 27 | 4th abc 28 | ``` 29 | 30 | 1. `gg0/te` (move to first `text`) 31 | 2. `*j0wgo` (insert `text` into `@/` and move to `line`, then pre-set `line` as well) 32 | 3. `cgnabc` (first operation) 33 | 4. `ggVjjjjg.` (apply operation to first 5 lines) 34 | 5. `jjg.Vj` (skip 2nd line in 2nd paragrap and apply operation to the rest of lines) 35 | 36 | (with [haya14busa/vim-asterisk](https://github.com/haya14busa/vim-asterisk)) 37 | -------------------------------------------------------------------------------- /plugin/metarepeat.vim: -------------------------------------------------------------------------------- 1 | " vim-metarepeat provides an operator (like) mapping which runs dot repeat for 2 | " every occurence matched by last pattern (@/) in range (specified by motion or 3 | " textobject). 4 | " 5 | " vim-metarepeat is inspired by 'Occurrence modifier, preset-occurrence, 6 | " persistence-selection' feature 7 | " http://qiita.com/t9md/items/0bc7eaff726d099943eb#occurrence-modifier-preset-occurrence-persistence-selection 8 | " 9 | " But it's not a port of these feature. In similar to vim-mode-plus terms, 10 | " vim-metarepeat provides 'preset-operation-for-occurence' feature (it's just 11 | " a operator + 'gn') and provides a way to apply the operation for each 12 | " occurences in textobject. 13 | " 14 | " TODO: 15 | " - highlight changed text to make changed texts clear for users? 16 | 17 | nnoremap (metarepeat) metarepeat() 18 | xnoremap (metarepeat) :call setview() call selected() 19 | 20 | let s:saveview = {} 21 | 22 | function! s:setview() abort 23 | let s:saveview = winsaveview() 24 | endfunction 25 | 26 | " s:metarepeat() is expected to be called with mapping. 27 | " It registers CursorMoved event and returns 'v'. 28 | " By using 'v' (starting visual mode) and exiting visual mode with first 29 | " CursorMoved, it emulates 'operator' behavior without breaking dot repeat. 30 | " (g@ breaks dot repeat) 31 | function! s:metarepeat() abort 32 | augroup metarepeat-move-once 33 | autocmd! 34 | autocmd CursorMoved * call s:hook_after_move() 35 | augroup END 36 | call s:setview() 37 | return 'v' 38 | endfunction 39 | 40 | function! s:hook_after_move() abort 41 | autocmd! metarepeat-move-once 42 | execute 'normal!' "\" 43 | call s:selected() 44 | endfunction 45 | 46 | " s:selected is expected to be called in normal mode and target has been 47 | " selected. 48 | function! s:selected() abort 49 | call s:metaoperate(getpos("'<"), getpos("'>"), @/) 50 | endfunction 51 | 52 | " s:metaoperate() execute dot repeat for every pattern occurence between start 53 | " and end position. 54 | " start: [bufnum, lnum, col, off] 55 | " end: [bufnum, lnum, col, off] 56 | " pattern: string 57 | function! s:metaoperate(start, end, pattern) abort 58 | call setpos('.', a:start) 59 | let first = v:true 60 | let endline = a:end[1] 61 | let endcol = a:end[2] 62 | let stopline = endline + 1 63 | while v:true 64 | let flag = (first ? 'c' : '') . 'n' 65 | let [lnum, col] = searchpos(a:pattern, flag, stopline) 66 | if (lnum ==# 0 && col ==# 0) || lnum > endline || (lnum ==# endline && col > endcol) 67 | break 68 | endif 69 | let [_, clnum, ccol, _] = getpos('.') 70 | if !(first && clnum ==# lnum && ccol ==# col) 71 | " move cursor with / instead of seachpos() to support {offset}. See :h search-offset 72 | execute 'normal!' "/\" 73 | endif 74 | normal! . 75 | let first = v:false 76 | endwhile 77 | if s:saveview !=# {} 78 | call winrestview(s:saveview) 79 | let s:saveview = {} 80 | endif 81 | endfunction 82 | 83 | " --- 84 | " support multiple preset-occurrence like feature. 85 | 86 | nnoremap (metarepeat-preset-occurence) :call append_preset_occurence() set hlsearch 87 | 88 | function! s:cword() abort 89 | return '\V\<' . escape(expand(''), '\') . '\>' 90 | endfunction 91 | 92 | function! s:append_preset_occurence() abort 93 | let re = s:cword() 94 | if has_key(b:, 'metarepeat_changedtick') && b:metarepeat_changedtick ==# b:changedtick 95 | " append 96 | let @/ = @/ . '\V\|' . re 97 | else 98 | " new 99 | let @/ = re 100 | let b:metarepeat_changedtick = b:changedtick 101 | endif 102 | endfunction 103 | 104 | " --- 105 | 106 | if get(g:, 'meterepeat#default_mapping', 1) 107 | map g. (metarepeat) 108 | nmap go (metarepeat-preset-occurence) 109 | endif 110 | --------------------------------------------------------------------------------