├── .gitignore ├── .travis.yml ├── Gemfile ├── Rakefile ├── VimFlavor ├── autoload └── operator │ └── replace.vim ├── doc └── operator-replace.txt ├── plugin └── operator │ └── replace.vim └── t ├── basics.vim ├── register.vim └── selection.vim /.gitignore: -------------------------------------------------------------------------------- 1 | .vim-flavor 2 | Gemfile.lock 3 | VimFlavor.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.1.5 4 | script: rake ci 5 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'vim-flavor', '~> 2.0' 4 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | 3 | task :ci => [:dump, :test] 4 | 5 | task :dump do 6 | sh 'vim --version' 7 | end 8 | 9 | task :test do 10 | sh 'bundle exec vim-flavor test' 11 | end 12 | -------------------------------------------------------------------------------- /VimFlavor: -------------------------------------------------------------------------------- 1 | flavor 'kana/vim-operator-user', '~> 0.1' 2 | 3 | group :development do 4 | flavor 'kana/vim-textobj-line' 5 | end 6 | 7 | # vim: filetype=ruby 8 | -------------------------------------------------------------------------------- /autoload/operator/replace.vim: -------------------------------------------------------------------------------- 1 | " operator-replace - Operator to replace text with register content 2 | " Version: 0.0.5 3 | " Copyright (C) 2009-2015 Kana Natsuno 4 | " License: MIT license {{{ 5 | " Permission is hereby granted, free of charge, to any person obtaining 6 | " a copy of this software and associated documentation files (the 7 | " "Software"), to deal in the Software without restriction, including 8 | " without limitation the rights to use, copy, modify, merge, publish, 9 | " distribute, sublicense, and/or sell copies of the Software, and to 10 | " permit persons to whom the Software is furnished to do so, subject to 11 | " the following conditions: 12 | " 13 | " The above copyright notice and this permission notice shall be included 14 | " in all copies or substantial portions of the Software. 15 | " 16 | " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | " OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | " IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | " CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | " TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | " SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | " }}} 24 | " Interface "{{{1 25 | function! operator#replace#do(motion_wise) "{{{2 26 | let visual_command = s:visual_command_from_wise_name(a:motion_wise) 27 | 28 | let put_command = (s:deletion_moves_the_cursor_p( 29 | \ a:motion_wise, 30 | \ getpos("']")[1:2], 31 | \ len(getline("']")), 32 | \ [line('$'), len(getline('$'))] 33 | \ ) 34 | \ ? 'p' 35 | \ : 'P') 36 | 37 | if !s:is_empty_region(getpos("'["), getpos("']")) 38 | let original_selection = &g:selection 39 | let &g:selection = 'inclusive' 40 | execute 'normal!' '`['.visual_command.'`]"_d' 41 | let &g:selection = original_selection 42 | end 43 | execute 'normal!' '"'.operator#user#register().put_command 44 | return 45 | endfunction 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | " Misc. "{{{1 55 | " s:deletion_moves_the_cursor_p(motion_wise) "{{{2 56 | function! s:deletion_moves_the_cursor_p(motion_wise, 57 | \ motion_end_pos, 58 | \ motion_end_last_col, 59 | \ buffer_end_pos) 60 | let [buffer_end_line, buffer_end_col] = a:buffer_end_pos 61 | let [motion_end_line, motion_end_col] = a:motion_end_pos 62 | 63 | if a:motion_wise ==# 'char' 64 | return ((a:motion_end_last_col == motion_end_col) 65 | \ || (buffer_end_line == motion_end_line 66 | \ && buffer_end_col <= motion_end_col)) 67 | elseif a:motion_wise ==# 'line' 68 | return buffer_end_line == motion_end_line 69 | elseif a:motion_wise ==# 'block' 70 | return 0 71 | else 72 | echoerr 'E2: Invalid wise name:' string(a:wise_name) 73 | return 0 74 | endif 75 | endfunction 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | function! s:is_empty_region(begin, end) "{{{2 85 | " Whenever 'operatorfunc' is called, '[ is always placed before '] even if 86 | " a backward motion is given to g@. But there is the only one exception. 87 | " If an empty region is given to g@, '[ and '] are set to the same line, but 88 | " '[ is placed after ']. 89 | return a:begin[1] == a:end[1] && a:end[2] < a:begin[2] 90 | endfunction 91 | 92 | 93 | 94 | 95 | function! s:visual_command_from_wise_name(wise_name) "{{{2() 96 | if a:wise_name ==# 'char' 97 | return 'v' 98 | elseif a:wise_name ==# 'line' 99 | return 'V' 100 | elseif a:wise_name ==# 'block' 101 | return "\" 102 | else 103 | echoerr 'E1: Invalid wise name:' string(a:wise_name) 104 | return 'v' " fallback 105 | endif 106 | endfunction 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | " __END__ "{{{1 116 | " vim: foldmethod=marker 117 | -------------------------------------------------------------------------------- /doc/operator-replace.txt: -------------------------------------------------------------------------------- 1 | *operator-replace.txt* Operator to replace text with register content 2 | 3 | Version 0.0.5 4 | Script ID: 2782 5 | Copyright (C) 2009-2015 Kana Natsuno 6 | License: MIT license {{{ 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the 9 | "Software"), to deal in the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included 16 | in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | }}} 26 | 27 | CONTENTS *operator-replace-contents* 28 | 29 | Introduction |operator-replace-introduction| 30 | Interface |operator-replace-interface| 31 | Key Mappings |operator-replace-key-mappings| 32 | Examples |operator-replace-examples| 33 | Bugs |operator-replace-bugs| 34 | Changelog |operator-replace-changelog| 35 | 36 | 37 | 38 | 39 | ============================================================================== 40 | INTRODUCTION *operator-replace-introduction* 41 | 42 | *operator-replace* is a Vim plugin to provide an operator to replace 43 | a specified text with register content. This is shortcut for several types of 44 | operations such as "d{motion}P" and "c{motion}{register}". 45 | 46 | 47 | Requirements: 48 | - Vim 7.2 or later 49 | - |operator-user| 0.1.0 or later 50 | https://github.com/kana/vim-operator-user 51 | 52 | Latest version: 53 | https://github.com/kana/vim-operator-replace 54 | 55 | 56 | 57 | 58 | ============================================================================== 59 | INTERFACE *operator-replace-interface* 60 | 61 | ------------------------------------------------------------------------------ 62 | KEY MAPPINGS *operator-replace-key-mappings* 63 | 64 | ["x](operator-replace){motion} *(operator-replace)* 65 | Replace text that {motion} moves over with register x. 66 | 67 | 68 | 69 | 70 | ============================================================================== 71 | EXAMPLES *operator-replace-examples* 72 | 73 | (A) At first, you have to map arbitrary key sequences to 74 | |(operator-replace)| like the following: 75 | > 76 | map _ (operator-replace) 77 | < 78 | 79 | (B) Suppose that you edit a buffer with the following content: 80 | (note that "^" indicates the cursor position) 81 | > 82 | (herb oil pepper) salt water 83 | ^ 84 | < 85 | If you yank "sugar" into register x, now you can replace any text with the 86 | yanked text. For example: 87 | 88 | To replace the 2nd word: 89 | > 90 | w"x_iw 91 | < 92 | To replace inside the parens: 93 | > 94 | "x_ib 95 | < 96 | To replace the cursor line: 97 | > 98 | "x__ 99 | < 100 | 101 | 102 | 103 | 104 | ============================================================================== 105 | BUGS *operator-replace-bugs* 106 | 107 | - Combinations of wises of {motion} and register content are not considered 108 | well, especially with blockwise ones. 109 | 110 | - See also |operator-user-bugs|. 111 | 112 | 113 | 114 | 115 | ============================================================================== 116 | CHANGELOG *operator-replace-changelog* 117 | 118 | 0.0.5 2015-02-25T00:48:14+09:00 *operator-replace-changelog-0.0.5* 119 | - Fix a bug that any register given to |(operator-replace)| is 120 | ignored if the operator is combined with any custom text object 121 | defined by |textobj-user|. 122 | - |operator-user| 0.1.0 or later is now required. 123 | 124 | 0.0.4 2013-03-05T22:30:01+09:00 *operator-replace-changelog-0.0.4* 125 | - Fix to delete a proper range of text for environments which 126 | 'selection' is set to "exclusive". 127 | 128 | 0.0.3 2012-11-29T20:19:45+09:00 *operator-replace-changelog-0.0.3* 129 | - Fix to correctly handle empty region. For example, 130 | |(operator-replace)| with |it| on text such as "
" 131 | did not work correctly. 132 | 133 | 0.0.2 2012-03-24T14:14:37+09:00 *operator-replace-changelog-0.0.2* 134 | - Refine the internal structure. 135 | 136 | 0.0.1 2009-09-16T07:59:40+09:00 *operator-replace-changelog-0.0.1* 137 | - Fix edge case bugs. Now replaacing at the end of line or the end of 138 | buffer work as you expect. 139 | 140 | 0.0.0 2009-09-06T10:13:20+09:00 *operator-replace-changelog-0.0.0* 141 | - Initial version. 142 | 143 | 144 | 145 | 146 | ============================================================================== 147 | vim:tw=78:ts=8:ft=help:norl:fen:fdl=0:fdm=marker: 148 | -------------------------------------------------------------------------------- /plugin/operator/replace.vim: -------------------------------------------------------------------------------- 1 | " operator-replace - Operator to replace text with register content 2 | " Version: 0.0.5 3 | " Copyright (C) 2009-2015 Kana Natsuno 4 | " License: MIT license {{{ 5 | " Permission is hereby granted, free of charge, to any person obtaining 6 | " a copy of this software and associated documentation files (the 7 | " "Software"), to deal in the Software without restriction, including 8 | " without limitation the rights to use, copy, modify, merge, publish, 9 | " distribute, sublicense, and/or sell copies of the Software, and to 10 | " permit persons to whom the Software is furnished to do so, subject to 11 | " the following conditions: 12 | " 13 | " The above copyright notice and this permission notice shall be included 14 | " in all copies or substantial portions of the Software. 15 | " 16 | " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | " OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | " IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | " CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | " TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | " SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | " }}} 24 | 25 | if exists('g:loaded_operator_replace') 26 | finish 27 | endif 28 | 29 | 30 | 31 | 32 | call operator#user#define('replace', 'operator#replace#do') 33 | 34 | 35 | 36 | 37 | let g:loaded_operator_replace = 1 38 | 39 | " __END__ 40 | " vim: foldmethod=marker 41 | -------------------------------------------------------------------------------- /t/basics.vim: -------------------------------------------------------------------------------- 1 | runtime! plugin/operator/*.vim 2 | 3 | 4 | 5 | 6 | describe 'Named key mappings' 7 | it 'is available in proper modes' 8 | let lhs = '(operator-replace)' 9 | Expect maparg(lhs, 'c') ==# '' 10 | Expect maparg(lhs, 'i') ==# '' 11 | Expect maparg(lhs, 'n') =~# 'operator#replace#' 12 | Expect maparg(lhs, 'o') ==# 'g@' 13 | Expect maparg(lhs, 'v') =~# 'operator#replace#' 14 | end 15 | end 16 | 17 | 18 | 19 | 20 | describe '(operator-replace) with block {motion}' 21 | " FIXME: NIY - but what result I expect for this case? 22 | end 23 | 24 | 25 | 26 | 27 | describe '(operator-replace) with char {motion}' 28 | before 29 | tabnew 30 | let @" = 'qux' 31 | let @s = 'waldo' 32 | put ='foo bar baz' 33 | end 34 | 35 | after 36 | tabclose! 37 | end 38 | 39 | it 'works fine with block {register} content' 40 | SKIP 'FIXME: NIY - but what result I expect for this case?' 41 | end 42 | 43 | it 'works fine with char {register} content (1)' 44 | " {operator}{characterwise-motion} without register designation 45 | execute 'normal' "\(operator-replace)e" 46 | Expect getline('.') ==# 'qux bar baz' 47 | Expect [getreg('"'), getregtype('"')] ==# ['qux', 'v'] 48 | Expect [getreg('s'), getregtype('s')] ==# ['waldo', 'v'] 49 | end 50 | 51 | it 'works fine with char {register} content (2)' 52 | " {characterwise-Visual}{operator} without register designation 53 | execute 'normal' "ve\(operator-replace)" 54 | Expect getline('.') ==# 'qux bar baz' 55 | Expect [getreg('"'), getregtype('"')] ==# ['qux', 'v'] 56 | Expect [getreg('s'), getregtype('s')] ==# ['waldo', 'v'] 57 | end 58 | 59 | it 'works fine with char {register} content (3)' 60 | " {operator}{characterwise-motion} with register designation 61 | execute 'normal' "\"s\(operator-replace)e" 62 | Expect getline('.') ==# 'waldo bar baz' 63 | Expect [getreg('"'), getregtype('"')] ==# ['qux', 'v'] 64 | Expect [getreg('s'), getregtype('s')] ==# ['waldo', 'v'] 65 | end 66 | 67 | it 'works fine with char {register} content (4)' 68 | " {characterwise-Visual}{operator} with register designation 69 | execute 'normal' "ve\"s\(operator-replace)" 70 | Expect getline('.') ==# 'waldo bar baz' 71 | Expect [getreg('"'), getregtype('"')] ==# ['qux', 'v'] 72 | Expect [getreg('s'), getregtype('s')] ==# ['waldo', 'v'] 73 | end 74 | 75 | it 'works fine with char {register} content (5)' 76 | " {operator}{characterwise-motion} including the end of buffer 77 | execute 'normal' "\"s\(operator-replace)$" 78 | Expect getline('.') ==# 'waldo' 79 | Expect [getreg('"'), getregtype('"')] ==# ['qux', 'v'] 80 | Expect [getreg('s'), getregtype('s')] ==# ['waldo', 'v'] 81 | end 82 | 83 | it 'works fine with char {register} content (6)' 84 | " {characterwise-Visual}{operator} including the end of buffer 85 | execute 'normal' "v$\"s\(operator-replace)" 86 | Expect getline('.') ==# 'waldo' 87 | Expect [getreg('"'), getregtype('"')] ==# ['qux', 'v'] 88 | Expect [getreg('s'), getregtype('s')] ==# ['waldo', 'v'] 89 | end 90 | 91 | it 'works fine with line {register} content' 92 | SKIP 'FIXME: NIY - but what result I expect for this case?' 93 | end 94 | end 95 | 96 | 97 | 98 | 99 | describe '(operator-replace) with line {motion}' 100 | before 101 | tabnew 102 | put ='foo foo foo' 103 | put ='bar bar bar' 104 | put ='baz baz baz' 105 | 1 delete _ 106 | 2 107 | let @" = "qux\n" 108 | let @s = "waldo\n" 109 | end 110 | 111 | after 112 | tabclose! 113 | end 114 | 115 | it 'works fine with block {register} content' 116 | SKIP 'FIXME: NIY - but what result I expect for this case?' 117 | end 118 | 119 | it 'works fine with char {register} content' 120 | SKIP 'FIXME: NIY - but what result I expect for this case?' 121 | end 122 | 123 | it 'works fine with line {register} content (1)' 124 | " {operator}{linewise-motion} without register designation 125 | execute 'normal' "\(operator-replace)\(operator-replace)" 126 | Expect getline(1) ==# 'foo foo foo' 127 | Expect getline(2) ==# 'qux' 128 | Expect getline(3) ==# 'baz baz baz' 129 | Expect line('$') == 3 130 | Expect [getreg('"'), getregtype('"')] ==# ["qux\n", 'V'] 131 | Expect [getreg('s'), getregtype('s')] ==# ["waldo\n", 'V'] 132 | end 133 | 134 | it 'works fine with line {register} content (2)' 135 | " {linewise-Visual}{operator} without register designation 136 | execute 'normal' "Vw\(operator-replace)" 137 | Expect getline(1) ==# 'foo foo foo' 138 | Expect getline(2) ==# 'qux' 139 | Expect getline(3) ==# 'baz baz baz' 140 | Expect line('$') == 3 141 | Expect [getreg('"'), getregtype('"')] ==# ["qux\n", 'V'] 142 | Expect [getreg('s'), getregtype('s')] ==# ["waldo\n", 'V'] 143 | end 144 | 145 | it 'works fine with line {register} content (3)' 146 | " {operator}{linewise-motion} with register designation 147 | execute 'normal' "\"s\(operator-replace)\(operator-replace)" 148 | Expect getline(1) ==# 'foo foo foo' 149 | Expect getline(2) ==# 'waldo' 150 | Expect getline(3) ==# 'baz baz baz' 151 | Expect line('$') == 3 152 | Expect [getreg('"'), getregtype('"')] ==# ["qux\n", 'V'] 153 | Expect [getreg('s'), getregtype('s')] ==# ["waldo\n", 'V'] 154 | end 155 | 156 | it 'works fine with line {register} content (4)' 157 | " {linewise-Visual}{operator} with register designation 158 | execute 'normal' "Ve\"s\(operator-replace)" 159 | Expect getline(1) ==# 'foo foo foo' 160 | Expect getline(2) ==# 'waldo' 161 | Expect getline(3) ==# 'baz baz baz' 162 | Expect line('$') == 3 163 | Expect [getreg('"'), getregtype('"')] ==# ["qux\n", 'V'] 164 | Expect [getreg('s'), getregtype('s')] ==# ["waldo\n", 'V'] 165 | end 166 | 167 | it 'works fine with line {register} content (5)' 168 | " {operator}{linewise-motion} including the end of buffer 169 | execute 'normal' "\(operator-replace)j" 170 | Expect getline(1) ==# 'foo foo foo' 171 | Expect getline(2) ==# 'qux' 172 | Expect line('$') == 2 173 | Expect [getreg('"'), getregtype('"')] ==# ["qux\n", 'V'] 174 | Expect [getreg('s'), getregtype('s')] ==# ["waldo\n", 'V'] 175 | end 176 | 177 | it 'works fine with line {register} content (6)' 178 | " {linewise-Visual}{operator} including the end of buffer 179 | execute 'normal' "Vk\(operator-replace)" 180 | Expect getline(1) ==# 'qux' 181 | Expect getline(2) ==# 'baz baz baz' 182 | Expect line('$') == 2 183 | Expect [getreg('"'), getregtype('"')] ==# ["qux\n", 'V'] 184 | Expect [getreg('s'), getregtype('s')] ==# ["waldo\n", 'V'] 185 | end 186 | end 187 | 188 | 189 | 190 | 191 | describe '(operator-replace) with empty region' 192 | before 193 | tabnew 194 | end 195 | 196 | after 197 | tabclose! 198 | end 199 | 200 | it 'replaces a given empty region with a register content' 201 | let @" = 'foo' 202 | 203 | normal! o
---
204 | execute 'normal' "\(operator-replace)it" 205 | Expect getline('.') ==# '
foo
' 206 | 207 | normal! o
-
208 | execute 'normal' "\(operator-replace)it" 209 | Expect getline('.') ==# '
foo
' 210 | 211 | normal! o
212 | execute 'normal' "\(operator-replace)it" 213 | Expect getline('.') ==# '
foo
' 214 | 215 | normal! o
xyz
216 | execute 'normal' "0fz\(operator-replace)Fx" 217 | Expect getline('.') ==# '
fooz
' 218 | end 219 | end 220 | -------------------------------------------------------------------------------- /t/register.vim: -------------------------------------------------------------------------------- 1 | runtime! plugin/operator/*.vim 2 | runtime! plugin/textobj/*.vim 3 | 4 | describe '(operator-replace)' 5 | before 6 | new 7 | 0 put =' foo bar baz ' 8 | let @" = '"""' 9 | let @a = 'aaa' 10 | map _ (operator-replace) 11 | end 12 | 13 | after 14 | close! 15 | end 16 | 17 | context 'with a built-in text object' 18 | it 'uses a given register' 19 | Expect getline('.') ==# ' foo bar baz ' 20 | normal! fa 21 | normal "a_iw 22 | Expect getline('.') ==# ' foo aaa baz ' 23 | end 24 | end 25 | 26 | context 'with a custom text object' 27 | it 'uses a given register' 28 | Expect getline('.') ==# ' foo bar baz ' 29 | normal "a_il 30 | Expect getline('.') ==# ' aaa ' 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /t/selection.vim: -------------------------------------------------------------------------------- 1 | runtime! plugin/operator/*.vim 2 | 3 | describe '(operator-replace)' 4 | before 5 | new 6 | 7 | function! b:.go(selection) 8 | let original_selection = &g:selection 9 | let &g:selection = a:selection 10 | 11 | put ='abcd' 12 | let @" = 'xyz' 13 | execute 'normal' "viw\(operator-replace)e" 14 | Expect getline('.') ==# 'xyz' 15 | 16 | let &g:selection = original_selection 17 | endfunction 18 | end 19 | 20 | after 21 | close! 22 | end 23 | 24 | it 'works properly with &selection == "inclusive"' 25 | call b:.go('inclusive') 26 | end 27 | 28 | it 'works properly with &selection == "exclusive"' 29 | call b:.go('exclusive') 30 | end 31 | end 32 | --------------------------------------------------------------------------------