diff options
Diffstat (limited to 'plugin')
-rw-r--r-- | plugin/command.vim | 51 | ||||
-rw-r--r-- | plugin/insert.vim | 14 | ||||
-rw-r--r-- | plugin/move.vim | 62 | ||||
-rw-r--r-- | plugin/remappings.vim | 51 |
4 files changed, 171 insertions, 7 deletions
diff --git a/plugin/command.vim b/plugin/command.vim index db18cf3..4101307 100644 --- a/plugin/command.vim +++ b/plugin/command.vim @@ -1,14 +1,53 @@ -" g: is a command to run a vim command around a text object. +" g: last command operator. " -" For example, to do a substitution inside the current block, one can do: +" Runs the last command over the given text object. " -" g:iBs/foo/bar/g<cr> +" By "last command" I mean the last command run with a range. This avoids all those pesky :w and :e +" commands. +" +" so now to join all lines in a text object one could do something like: +" +" vap:join<cr> +" +" now this command can be repeated around a different text object using g:, for example g:ab +" +" what's more is after using g:, it is dot-repeatable. +" +" Note that while this is powerful, it wil only work on line-style selections as that it a +" limitation of ex commands. noremap <silent> g: :set operatorfunc=<SID>do_command_around<cr>g@ +noremap <silent> g:: :set operatorfunc=<SID>do_command_around<cr>g@_ + +function! s:find_cmd() abort + let match_mark = "\\('.\\)\\?[0-9\\-+^$.%]*" + + let i = -1 + while 1 + let ocmd = histget(':', i) + + " Strip the leading range + let ncmd = substitute(ocmd, printf('\(%s\)\(,\(%s\)\)\?', match_mark, match_mark), "", "") + + if ncmd != ocmd + " If this command had a range, use that one. + let cmd = ncmd + break + endif + + let i -= 1 + endwhile + + return cmd +endfunction function! s:do_command_around(str) abort - let [_, lnum0, _, _] = getpos("'[") - let [_, lnum1, _, _] = getpos("']") + call setpos("'<", getpos("'[")) + call setpos("'>", getpos("']")) + + let cmd = s:find_cmd() + - call feedkeys(printf(":silent! %d,%d ", lnum0, lnum1)) + echo printf("'<,'>%s", cmd) + exec printf("'<,'>%s", cmd) endfunction diff --git a/plugin/insert.vim b/plugin/insert.vim index c6de7a2..3d27f78 100644 --- a/plugin/insert.vim +++ b/plugin/insert.vim @@ -17,6 +17,20 @@ noremap cgI <cmd>call <sid>insert_comment_count(v:count1)<cr>1c<Plug><sid>(inser onoremap <Plug><sid>(insert-comment-obj-nog) <cmd>call <sid>insert_comment_obj(0)<cr> onoremap <Plug><sid>(insert-comment-obj-g) <cmd>call <sid>insert_comment_obj(1)<cr> +onoremap <plug>(insert-here-obj) <cmd>normal! "i <esc>v" + +let s:motions = ['b', 'w', 'ib', 'ab'] + +for m in s:motions + exec "onoremap <Plug>(mot-before-" . m . ") <cmd>call g:BeforeMot(\"" . m . "\")<cr>" + exec "noremap dI" . m . " c<Plug>(mot-before-" . m . ")" +endfor + +function! g:BeforeMot(mot) abort + exec "normal! " . a:mot + exec "normal! \<esc>i \<esc>v" +endfunction + function! s:insert_comment_count(count) abort let s:count = a:count endfunction diff --git a/plugin/move.vim b/plugin/move.vim index 0ed2e7f..88680cd 100644 --- a/plugin/move.vim +++ b/plugin/move.vim @@ -1,5 +1,65 @@ onoremap <silent> a% V<cmd>call search('{') <bar> normal! %<cr> -onoremap <silent> i% <cmd>call search('{') <bar> normal! v%<bs>o<space><cr> +onoremap <silent> i% <cmd>call search() <bar> normal! v%<bs>o<space><cr> vnoremap <silent> a% <esc>V/{<cr>% vnoremap <silent> i% <esc>/{<cr>v%<bs>o<space>o + +" +" anb, anB, an<, an[ +" +" "Next" objects. These objects are like ab, aB, a<, a[, etc. but will always go to the next body +" regardless of if it is nested or not. +" +" If outside an expression, the behavior is the +" +onoremap <silent> anb <cmd>call <sid>inner_next(v:operator, 'a', '(', ')')<cr> +onoremap <silent> inb <cmd>call <sid>inner_next(v:operator, 'i', '(', ')')<cr> +vnoremap <silent> anb <cmd>call <sid>inner_next(v:operator, 'a', '(', ')')<cr> +vnoremap <silent> inb <cmd>call <sid>inner_next(v:operator, 'i', '(', ')')<cr> + +onoremap <silent> anB <cmd>call <sid>inner_next(v:operator, 'a', '{', '}')<cr> +onoremap <silent> inB <cmd>call <sid>inner_next(v:operator, 'i', '{', '}')<cr> +vnoremap <silent> anB <cmd>call <sid>inner_next(v:operator, 'a', '{', '}')<cr> +vnoremap <silent> inB <cmd>call <sid>inner_next(v:operator, 'i', '{', '}')<cr> + +onoremap <silent> an< <cmd>call <sid>inner_next(v:operator, 'a', '<', '>')<cr> +onoremap <silent> in< <cmd>call <sid>inner_next(v:operator, 'i', '<', '>')<cr> +vnoremap <silent> an< <cmd>call <sid>inner_next(v:operator, 'a', '<', '>')<cr> +vnoremap <silent> in< <cmd>call <sid>inner_next(v:operator, 'i', '<', '>')<cr> + +onoremap <silent> an[ <cmd>call <sid>inner_next(v:operator, 'a', '\[', '\]')<cr> +onoremap <silent> in[ <cmd>call <sid>inner_next(v:operator, 'i', '\[', '\]')<cr> +vnoremap <silent> an[ <cmd>call <sid>inner_next(v:operator, 'a', '\[', '\]')<cr> +vnoremap <silent> in[ <cmd>call <sid>inner_next(v:operator, 'i', '\[', '\]')<cr> + +function! s:inner_next(operator, ai, open, close) abort + let opos = getpos('.') + let i = 0 + + while i < v:count + 1 + call search(a:open) + let i += 1 + endwhile + + normal! % + if (getline('.')[col('.')-1] =~ a:open) + normal! % + endif + + if col('.') > 1 && (getline('.')[col('.')-2] =~ a:open) && a:ai == 'i' + if v:operator =~ "[cd]" + " Cheese a 0-width by inserting a space to then immediately delete for d and c operators. + exec "normal! i \<esc>v" + else + " Other operations, just reset the position to what it was before. + call setpos('.', opos) + endif + return + endif + + if a:ai == 'i' + exec "normal! \<esc>v%\<space>o\<bs>" + else + exec "normal! \<esc>v%" + endif +endfunction diff --git a/plugin/remappings.vim b/plugin/remappings.vim new file mode 100644 index 0000000..8b3133a --- /dev/null +++ b/plugin/remappings.vim @@ -0,0 +1,51 @@ + +" Remap i{",',`} and a{",',`} to search for the next string. This is more like how objects like i( and i{ work. +" +" The behavior inside the quotes should remain unchanged. +onoremap <silent> i" <cmd>call <sid>find_quote('i', '"')<cr> +onoremap <silent> a" <cmd>call <sid>find_quote('a', '"')<cr> + +onoremap <silent> i' <cmd>call <sid>find_quote('i', "'")<cr> +onoremap <silent> a' <cmd>call <sid>find_quote('a', "'")<cr> + +onoremap <silent> i` <cmd>call <sid>find_quote('i', '`')<cr> +onoremap <silent> a` <cmd>call <sid>find_quote('a', '`')<cr> + +vnoremap <silent> i" <cmd>call <sid>find_quote('i', '"')<cr> +vnoremap <silent> a" <cmd>call <sid>find_quote('a', '"')<cr> + +vnoremap <silent> i' <cmd>call <sid>find_quote('i', "'")<cr> +vnoremap <silent> a' <cmd>call <sid>find_quote('a', "'")<cr> + +vnoremap <silent> i` <cmd>call <sid>find_quote('i', '`')<cr> +vnoremap <silent> a` <cmd>call <sid>find_quote('a', '`')<cr> + +function! s:find_quote(ai, q) abort + let l = getline('.')[:col('.') - 2] + + let cnt = 0 + let skip = 0 + for c in l + if c ==# a:q && !skip + let cnt = !cnt + endif + + if c ==# '\' + let skip = 1 + else + let skip = 0 + endif + endfor + + let flags = 'W' + if cnt == 1 + let flags .= 'b' + endif + + exec "normal! \<esc>" + call search(a:q . '\zs.', flags) + exec "normal! v" . a:ai . a:q +endfunction + +" Fix silly yank behavior. +nnoremap Y y$ |