aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugin/insert.vim191
1 files changed, 175 insertions, 16 deletions
diff --git a/plugin/insert.vim b/plugin/insert.vim
index c6de7a2..3caca81 100644
--- a/plugin/insert.vim
+++ b/plugin/insert.vim
@@ -1,26 +1,76 @@
-" Other operators for entering insert mode.
-
-" Like 'I', but skip past the first v:count1 WORDs. Useful for when one wants
-" the 'I' behavior to respect comments.
-"
-" If there are fewer than v:count1 WORDs in the line, then append to the end of
-" the line.
-"
-" Have to cheese this a little bit to get the redo (.) operator to work with it.
-" This is done by making a "sort-of" 0-width text object that exists where the
-" change should happen.
-"
-" If the 'g' is present, that acts similar to gI -- it does not skip
-" whitespace and starts insertion directly after the v:count1'th word.
-noremap cI <cmd>call <sid>insert_comment_count(v:count1)<cr>1c<Plug><sid>(insert-comment-obj-nog)
-noremap cgI <cmd>call <sid>insert_comment_count(v:count1)<cr>1c<Plug><sid>(insert-comment-obj-g)
+if !exists('g:field_marshal_insert_include_bindings')
+ let g:field_marshal_insert_include_bindings = 1
+endif
+
+if g:field_marshal_insert_include_bindings
+ " Like 'I', but skip past the first v:count1 WORDs. Useful for when one wants
+ " the 'I' behavior to respect comments.
+ "
+ " If there are fewer than v:count1 WORDs in the line, then append to the end of
+ " the line.
+ "
+ " Have to cheese this a little bit to get the redo (.) operator to work with it.
+ " This is done by making a "sort-of" 0-width text object that exists where the
+ " change should happen.
+ "
+ " If the 'g' is present, that acts similar to gI -- it does not skip
+ " whitespace and starts insertion directly after the v:count1'th word.
+ noremap cI <Plug>(insert-after-comment)
+ noremap cgI <Plug>(insert-after-comment-g)
+
+ " Insert before/after a motion.
+ "
+ " Zi - takes a text object, moves to the beginning of that text object and
+ " places the user in INSERT mode.
+ "
+ " Za - takes a text object, moves to the end of that text object and places
+ " the user in INSERT mode.
+ "
+ " Some of this functionality can be replicated using <C-R><C-P> in insert
+ " mode. For example, suffixing the current word with 'ed' can be
+ " accomplished with either:
+ "
+ " Zaeed<esc>
+ "
+ " or
+ "
+ " ce^R^P"ed<esc>
+ "
+ " or Prefixing with sub can be accomplished with
+ "
+ " Zibsub<esc>
+ "
+ " or
+ "
+ " cbsub^R^P"<esc>
+ "
+ " However the traditional ^R^P" solution is not very pretty and prone to
+ " typeos.
+ "
+ " This also means that certain motions are now redundant and can be
+ " emulated. For example:
+ "
+ " I === Zi^
+ " gI === Zi0
+ " A === Za$
+ "
+ "
+ noremap Zi <Plug>(insert-before-motion)
+ noremap Za <Plug>(append-after-motion)
+endif
+
+noremap <Plug>(insert-after-comment) <cmd>call <sid>insert_comment_count(v:count1)<cr>1c<Plug><sid>(insert-comment-obj-nog)
+noremap <Plug>(insert-after-comment-g)> <cmd>call <sid>insert_comment_count(v:count1)<cr>1c<Plug><sid>(insert-comment-obj-g)
+
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>
+" Set the count for the insert comment command.
function! s:insert_comment_count(count) abort
let s:count = a:count
endfunction
+" The function which will set the insert comment.
function! s:insert_comment_obj(g, ...) abort
if v:operator == 'c'
let end = 0
@@ -59,3 +109,112 @@ function! s:insert_comment_obj(g, ...) abort
else
endif
endfunction
+
+noremap <silent> <Plug>(insert-before-motion) <cmd>call <sid>save_state('i')
+ \<bar>call <sid>start_recording()
+ \<bar>set operatorfunc=<sid>recordop<cr>g@
+noremap <silent> <Plug>(append-after-motion) <cmd>call <sid>save_state('a')
+ \<bar>call <sid>start_recording()
+ \<bar>set operatorfunc=<sid>recordop<cr>g@
+onoremap <silent> <Plug>(insert-about-obj) <cmd>call <sid>insert_before_recorded()<cr>
+nnoremap <silent> <Plug>(insert-about-obj) <cmd>call <sid>insert_before_recorded()<cr>
+
+" Save the 'l' register. This is the register used for recording the text
+" motion.
+let s:savereg = []
+let s:savepos = []
+let s:instype = ''
+
+" Not many people use the 'z' register, right?
+let s:reg_to_clobber = 'z'
+" if exists('&urf')
+" " Neovim has Rahm's multibyte register extension patch. Pick an arbitrary
+" " unicode character which is probably not used very often to clobber.
+" let s:reg_to_clobber = '∫'
+" endif
+
+function! s:start_recording()
+ exec "normal! q" . s:reg_to_clobber
+endfunction
+
+function! s:save_state(instype)
+ " Unfortunately macros kinda break this feature. While I think I might be able
+ " to patch together a fix to make them work, I figure that I'll see if there's
+ " any real need to implement it.
+ if reg_recording() != ''
+ normal! q
+ endif
+
+ let s:savereg = [getreg(s:reg_to_clobber, 1, 1), getregtype(s:reg_to_clobber)]
+ let s:savepos = getpos('.')
+ let s:instype = a:instype
+endfunction
+
+noremap <plug>(ñóþ) <nop>
+
+" Save the motion postions, for use with g@.
+function s:save_object(t) abort
+ let s:object = {
+ \ "type": a:t,
+ \ "start": getpos("'["),
+ \ "end": getpos("']")
+ \ }
+endfunction
+
+function! s:insert_before_recorded() abort
+ " A limitation of normal! is that it can't start with a space, so use a NOP
+ " instead.
+ if s:recorded =~ '^\s'
+ let s:recorded = "\<plug>(ñóþ)" . s:recorded
+ endif
+
+ " Something of a hack. If the motion starts with i or a, it is probably a
+ " text object.
+ "
+ " I think there's probably a better way to handle this, butth
+ if s:recorded =~ '^[ia]'
+ " Without Rahm's patched Neovim, custom text objects will not work. This is
+ " because while the redo buffer is saved and restored when calling a user
+ " function, repeat_cmdline is not, and thus the g@ command clobbers the
+ " repeat_cmdline which breaks the redobuff. Ergo the first Zi will work,
+ " but subsequent repititions with the dot operator will not work.
+ set operatorfunc=s:save_object
+ exec "normal g@" . s:recorded
+
+ if s:instype == 'a'
+ call setpos(".", s:object.end)
+ if s:object.type == 'line'
+ normal! $
+ endif
+ else
+ call setpos(".", s:object.start)
+ if s:object.type == 'line'
+ normal! 0
+ endif
+ endif
+ else
+ exec "normal " . s:recorded
+ endif
+
+ if s:instype == 'a'
+ exec "normal! \<esc>a \<esc>v"
+ else
+ exec "normal! \<esc>i \<esc>v"
+ endif
+endfunction
+
+" Record the operator
+function! s:recordop(...) abort
+ " Stop recording
+ normal! q
+ " Save the recorded amount
+ let s:recorded=getreg(s:reg_to_clobber)
+ " Restore the register
+ call setreg(s:reg_to_clobber, s:savereg[0], s:savereg[1])
+ " Restore the position
+ call setpos('.', s:savepos)
+
+ " Called <Plug>(insert-about-obj). This is the part that can be repeated.
+ call feedkeys("c\<Plug>(insert-about-obj)")
+endfunction
+