├── LICENSE ├── README.md └── plugin └── markmultiple.vim /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012 Alfredo Di Napoli 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | Vim, arguably the best text-editor in the world. 22 | 23 | Inspired from magnars' mark-multiple plugin. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | vim-markmultiple 2 | ================ 3 | 4 | An emacs-like mark multiple plugin, inspired from this plugin: 5 | 6 | [mark-multiple.el](https://github.com/magnars/mark-multiple.el) 7 | 8 | ## Usage 9 | **Ctrl-n** to activate and to go to the next match. 10 | When you are tired, simply change the word under the cursor the usual way. 11 | 12 | ## Customization 13 | You can put this inside your .vimrc to customize which keybinding you want associate to 14 | vim-markmultiple. In the example, we are using Control + m: 15 | 16 | ``` 17 | let g:mark_multiple_trigger = "" 18 | ``` 19 | 20 | [Watch the screencast!](http://www.youtube.com/watch?v=deGhhILp2PY&feature=youtu.be) 21 | 22 | ## Why highlighted words remain on screen? 23 | Because you "Interrupted" the marking process without actually substituting 24 | nothing. If this happens, simply call ```MarkMultipleClean()``` 25 | 26 | 27 | ## Installation 28 | Like any Pathogen bundle. 29 | 30 | ## Contributes 31 | Yes, please. Pull requests welcome. 32 | -------------------------------------------------------------------------------- /plugin/markmultiple.vim: -------------------------------------------------------------------------------- 1 | if exists("g:loaded_mark_multiple") || &cp 2 | finish 3 | endif 4 | 5 | let g:loaded_mark_multiple = 1 6 | let s:matches = [] 7 | let s:keepcpo = &cpo 8 | set cpo&vim 9 | 10 | if !exists("g:mark_multiple_started") 11 | let g:mark_multiple_started = 0 12 | endif 13 | 14 | if !exists("g:mark_multiple_searching") 15 | let g:mark_multiple_searching = 0 16 | endif 17 | 18 | 19 | if !exists("g:mark_multiple_in_normal_mode") 20 | let g:mark_multiple_in_normal_mode = 0 21 | endif 22 | 23 | 24 | if !exists("g:mark_multiple_in_visual_mode") 25 | let g:mark_multiple_in_visual_mode = 1 26 | endif 27 | 28 | 29 | if !exists("g:mark_multiple_current_chars_on_the_line") 30 | let g:mark_multiple_current_chars_on_the_line = col('$') 31 | endif 32 | 33 | 34 | 35 | " Leave space for user customization. 36 | if !exists("g:mark_multiple_trigger") 37 | let g:mark_multiple_trigger = "" 38 | endif 39 | 40 | 41 | if g:mark_multiple_trigger != '' 42 | :execute "nnoremap ". g:mark_multiple_trigger ." :call MarkMultiple()" 43 | :execute "xnoremap ". g:mark_multiple_trigger ." :call MarkMultiple()" 44 | endif 45 | au InsertLeave * call MarkMultipleSubstitute() 46 | 47 | 48 | fun! s:ClearMatches() 49 | let matches_to_delete = s:matches 50 | let s:matches = [] 51 | for match in matches_to_delete 52 | call matchdelete(match) 53 | endfor 54 | endfun 55 | 56 | fun! MarkMultiple() 57 | if GetWordUnderTheCursor() == "" 58 | let g:mark_multiple_started = 0 59 | else 60 | if g:mark_multiple_in_normal_mode 61 | call MarkMultipleNormal() 62 | endif 63 | 64 | if g:mark_multiple_in_visual_mode 65 | call MarkMultipleVisual() 66 | endif 67 | endif 68 | endfunction 69 | 70 | 71 | fun! MarkMultipleVisual() 72 | 73 | if !g:mark_multiple_started 74 | let g:mark_multiple_starting_curpos = getpos(".") 75 | let g:mark_multiple_current_chars_on_the_line = col('$') 76 | let g:mark_multiple_curpos = g:mark_multiple_starting_curpos 77 | endif 78 | 79 | let g:mark_multiple_started = 1 80 | let g:mark_multiple_current_chars_on_the_line = col('$') 81 | let g:mark_multiple_word = GetWordUnderTheCursor() 82 | call MarkMultipleSetCursor() 83 | call SelectWord() 84 | call HighlightWord() 85 | call MarkMultipleSwapModes() 86 | endfunction 87 | 88 | 89 | " This ensures the cursor is properly set. 90 | fun! MarkMultipleSetCursor() 91 | 92 | 93 | " If we are iterating through words, 94 | " leave to Vim the matching stuff 95 | if !g:mark_multiple_searching 96 | 97 | let original_position = getpos('.') 98 | 99 | " New algorithm, it relies as much as possible on visual selection 100 | " of a word. 101 | normal! vw 102 | normal! b 103 | if getpos('.')[2] < original_position[2] 104 | :execute "normal! \e" 105 | endif 106 | endif 107 | 108 | let g:mark_multiple_curpos = getpos('.') 109 | endfun 110 | 111 | fun! HighlightWord() 112 | let line_to_match = g:mark_multiple_curpos[1] 113 | let col_start = g:mark_multiple_curpos[2] - 1 114 | let col_end = g:mark_multiple_curpos[2] + len(g:mark_multiple_word) 115 | let pattern = '\%'.line_to_match.'l\%>'.col_start.'c\%<'.col_end.'c' 116 | let new_match = matchadd('Search', pattern) 117 | call add(s:matches, new_match) 118 | endfun 119 | 120 | 121 | fun! MarkMultipleSwapModes() 122 | let g:mark_multiple_in_normal_mode = !g:mark_multiple_in_normal_mode 123 | let g:mark_multiple_in_visual_mode = !g:mark_multiple_in_visual_mode 124 | endfunction 125 | 126 | 127 | fun! MarkMultipleNormal() 128 | if g:mark_multiple_started 129 | let g:mark_multiple_searching = 1 130 | "Go to the next word 131 | call setpos('.', g:mark_multiple_curpos) 132 | 133 | "Search for the next word, but disable search highlighting 134 | normal! * 135 | nohlsearch 136 | endif 137 | 138 | call MarkMultipleSwapModes() 139 | endfunction 140 | 141 | 142 | fun! MarkMultipleSubstitute() 143 | 144 | if g:mark_multiple_started 145 | 146 | "Protect against invalid subs. 147 | let valid_sub = MarkMultipleValidSubstitution(col('$')) 148 | if !valid_sub 149 | let new_word = "" 150 | else 151 | let new_word = GetWordUnderTheCursor() 152 | endif 153 | 154 | let start = g:mark_multiple_starting_curpos[1] 155 | let end = g:mark_multiple_curpos[1] 156 | silent! execute start .','. end . 's/\V' . expand(g:mark_multiple_word) . '/' . expand(new_word) .'/g' 157 | let g:mark_multiple_started = 0 158 | let g:mark_multiple_searching = 0 159 | 160 | "Restore cursor under the last matched 161 | call setpos('.', g:mark_multiple_curpos) 162 | 163 | "Clear highlighting 164 | call s:ClearMatches() 165 | endif 166 | endfunction 167 | 168 | 169 | " Call this to clear all the highlightings 170 | fun! MarkMultipleClean() 171 | call s:ClearMatches() 172 | let g:mark_multiple_started = 0 173 | let g:mark_multiple_searching = 0 174 | let g:mark_multiple_in_normal_mode = 0 175 | let g:mark_multiple_in_visual_mode = 1 176 | endfunction 177 | 178 | 179 | fun! MarkMultipleValidSubstitution(chars_on_the_line) 180 | 181 | "Exploit the length of the prev line to determine if 182 | "something was changed 183 | let prev_chars = g:mark_multiple_current_chars_on_the_line 184 | if a:chars_on_the_line <= (prev_chars - len(g:mark_multiple_word)) 185 | return 0 186 | endif 187 | 188 | return 1 189 | endfunction 190 | 191 | 192 | fun! GetWordUnderTheCursor() 193 | return expand("") 194 | endfunction 195 | 196 | 197 | fun! SelectWord() 198 | silent! normal! zO 199 | normal! viw 200 | endfunction 201 | 202 | let &cpo = s:keepcpo 203 | unlet s:keepcpo 204 | 205 | " vim: et sw=4 206 | --------------------------------------------------------------------------------