aboutsummaryrefslogtreecommitdiff
path: root/plugin
diff options
context:
space:
mode:
authorJosh Rahm <rahm@google.com>2022-09-13 18:16:30 -0600
committerJosh Rahm <rahm@google.com>2022-09-13 18:16:30 -0600
commit2dd5ac29ec6cdaa4ee7a45314d29559d2294cac0 (patch)
tree24ef10b2f3dea8a6d5b2740b1b78831a15e89b55 /plugin
parent79b37fdd282f616714876b97e484d8dcc8a488ab (diff)
downloadfieldmarshal.vim-stuff.tar.gz
fieldmarshal.vim-stuff.tar.bz2
fieldmarshal.vim-stuff.zip
assortment of stuffstuff
Diffstat (limited to 'plugin')
-rw-r--r--plugin/command.vim51
-rw-r--r--plugin/insert.vim14
-rw-r--r--plugin/move.vim62
-rw-r--r--plugin/remappings.vim51
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$