From 2dd5ac29ec6cdaa4ee7a45314d29559d2294cac0 Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Tue, 13 Sep 2022 18:16:30 -0600 Subject: assortment of stuff --- plugin/command.vim | 51 +++++++++++++++++++++++++++++++++++++----- plugin/insert.vim | 14 ++++++++++++ plugin/move.vim | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++- plugin/remappings.vim | 51 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 171 insertions(+), 7 deletions(-) create mode 100644 plugin/remappings.vim (limited to 'plugin') 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 +" 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 +" +" 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 g: :set operatorfunc=do_command_aroundg@ +noremap g:: :set operatorfunc=do_command_aroundg@_ + +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 call insert_comment_count(v:count1)1c(inser onoremap (insert-comment-obj-nog) call insert_comment_obj(0) onoremap (insert-comment-obj-g) call insert_comment_obj(1) +onoremap (insert-here-obj) normal! "i v" + +let s:motions = ['b', 'w', 'ib', 'ab'] + +for m in s:motions + exec "onoremap (mot-before-" . m . ") call g:BeforeMot(\"" . m . "\")" + exec "noremap dI" . m . " c(mot-before-" . m . ")" +endfor + +function! g:BeforeMot(mot) abort + exec "normal! " . a:mot + exec "normal! \i \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 a% Vcall search('{') normal! % -onoremap i% call search('{') normal! v%o +onoremap i% call search() normal! v%o vnoremap a% V/{% vnoremap i% /{v%oo + +" +" 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 anb call inner_next(v:operator, 'a', '(', ')') +onoremap inb call inner_next(v:operator, 'i', '(', ')') +vnoremap anb call inner_next(v:operator, 'a', '(', ')') +vnoremap inb call inner_next(v:operator, 'i', '(', ')') + +onoremap anB call inner_next(v:operator, 'a', '{', '}') +onoremap inB call inner_next(v:operator, 'i', '{', '}') +vnoremap anB call inner_next(v:operator, 'a', '{', '}') +vnoremap inB call inner_next(v:operator, 'i', '{', '}') + +onoremap an< call inner_next(v:operator, 'a', '<', '>') +onoremap in< call inner_next(v:operator, 'i', '<', '>') +vnoremap an< call inner_next(v:operator, 'a', '<', '>') +vnoremap in< call inner_next(v:operator, 'i', '<', '>') + +onoremap an[ call inner_next(v:operator, 'a', '\[', '\]') +onoremap in[ call inner_next(v:operator, 'i', '\[', '\]') +vnoremap an[ call inner_next(v:operator, 'a', '\[', '\]') +vnoremap in[ call inner_next(v:operator, 'i', '\[', '\]') + +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 \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! \v%\o\" + else + exec "normal! \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 i" call find_quote('i', '"') +onoremap a" call find_quote('a', '"') + +onoremap i' call find_quote('i', "'") +onoremap a' call find_quote('a', "'") + +onoremap i` call find_quote('i', '`') +onoremap a` call find_quote('a', '`') + +vnoremap i" call find_quote('i', '"') +vnoremap a" call find_quote('a', '"') + +vnoremap i' call find_quote('i', "'") +vnoremap a' call find_quote('a', "'") + +vnoremap i` call find_quote('i', '`') +vnoremap a` call find_quote('a', '`') + +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! \" + call search(a:q . '\zs.', flags) + exec "normal! v" . a:ai . a:q +endfunction + +" Fix silly yank behavior. +nnoremap Y y$ -- cgit