aboutsummaryrefslogtreecommitdiff
path: root/autoload/paste_insert.vim
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2019-06-23 01:24:37 +1200
committerTom Ryder <tom@sanctum.geek.nz>2019-06-23 01:24:37 +1200
commit17de75eb35838c3f588f1556f53dc574d78a2faf (patch)
treeeabdd2fd591bc970f443e277622731e9ff628a9a /autoload/paste_insert.vim
parentMerge branch 'release/v0.2.0' (diff)
parentBump VERSION (diff)
downloadvim-paste-insert-17de75eb35838c3f588f1556f53dc574d78a2faf.tar.gz
vim-paste-insert-17de75eb35838c3f588f1556f53dc574d78a2faf.zip
Merge branch 'release/v0.3.0'v0.3.0
* release/v0.3.0: Revert "Clear event table only once so user can... Flesh out documentation a lot Flesh out comment a little Don't fill out .buffer property if already set Catch specific mapping errors Add lots of comments Clear event table only once so user can use it Clarify explanation of map settings a bit More sophisticated map caching Get normal mode map specifically for cancel Support mapping cancel keys, add Esc as default
Diffstat (limited to 'autoload/paste_insert.vim')
-rw-r--r--autoload/paste_insert.vim130
1 files changed, 113 insertions, 17 deletions
diff --git a/autoload/paste_insert.vim b/autoload/paste_insert.vim
index 277f333..fe9e482 100644
--- a/autoload/paste_insert.vim
+++ b/autoload/paste_insert.vim
@@ -43,29 +43,125 @@ function! paste_insert#() abort
endfunction
-" Key that cancels the pending paste in normal mode, defaults to CTRL-C
-let s:cancel = get(g:, 'paste_insert_cancel', '<C-C>')
+" Keys that cancel the pending paste in normal mode, defaults to Ctrl-C and
+" Escape
+let s:cancel = get(g:, 'paste_insert_cancel', ['<C-C>', '<Esc>'])
-" Start the paste: save cancel key's prior function, remap it, set 'paste'
+" Cache for the prior functions of those keys, in case the user has already
+" mapped them
+let s:maps = {}
+
+" Function to abstract over shortcomings in Vim older than 7.3.032 in yielding
+" incomplete map information; return as much as we can in the same structure
+" as Vim after this patchlevel does with the {dict} parameter TRUE;
+" unfortunately, this is just the mapping's right hand side. We should be
+" able to figure out the <buffer> flag too, but that's it. The documentation
+" for this plugin points out this unfortunate caveat, and suggests
+" a workaround.
+"
+function! s:MapArg(key, mode) abort
+ if v:version > 703 || v:version == 703 && has('patch-32')
+ return maparg(a:key, a:mode, 0, 1)
+ else
+ let rhs = maparg(a:key, a:mode)
+ if rhs ==# ''
+ return {}
+ else
+ return { 'rhs': rhs }
+ endif
+ endif
+endfunction
+
+" Start the paste: save each cancel key's prior function, remap it, set
+" 'paste'
function! s:Start() abort
- let s:maparg = maparg(s:cancel)
- let command = join([
- \ 'nnoremap'
- \,s:cancel
- \,':<C-U>doautocmd paste_insert User Cancel<CR>'
- \])
- execute command
+
+ " Collect and remove existing mappings for this key, replacing with a global
+ " map that cancels the pending paste operation
+ "
+ for key in s:cancel
+ let maps = []
+
+ " We might need to stop partway through this
+ try
+
+ " Collect first mapping, perhaps a buffer-local mapping, since maparg()
+ " yields those first
+ let map = s:MapArg(key, 'n')
+ if !empty(map)
+ call add(maps, s:MapArg(key, 'n'))
+ endif
+ execute 'nunmap <buffer> '.key
+
+ " Since we got here, the `:nunmap <buffer>` command must have worked,
+ " and there might be one more global map to collect
+ let map = s:MapArg(key, 'n')
+ if !empty(map)
+ call add(maps, s:MapArg(key, 'n'))
+ endif
+ execute 'nunmap '.key
+
+ catch /^Vim\%((\a\+)\)\=:E31:/ " No such mapping
+ " Ignore it
+ endtry
+
+ " If we collected two mappings, the first one must have been buffer-local,
+ " and Vim before 7.3.032 won't have told us that, so we'll flag it now
+ "
+ if len(maps) == 2 && !has_key(maps[0], 'buffer')
+ let maps[0]['buffer'] = 1
+ endif
+
+ " Add the collected maps to this key's cache
+ let s:maps[key] = maps
+
+ " Set up our map to cancel the pending paste
+ execute 'nnoremap '.key
+ \.' :<C-U>doautocmd paste_insert User Cancel<CR>'
+ endfor
+
+ " Let's go!
set paste
+
endfunction
" Stop the paste: unset 'paste', restore prior function of cancel key
function! s:Stop() abort
+
+ " Let's stop!
set nopaste
- let command = join(
- \ s:maparg !=# ''
- \ ? ['nnoremap', s:cancel, s:maparg]
- \ : ['nunmap', s:cancel]
- \)
- execute command
- unlet s:maparg
+
+ " Now we need to remove our temporary maps, and restore the user's
+ for key in s:cancel
+
+ " Start by getting read of our map; there should now be none at all
+ execute 'nunmap '.key
+
+ " Iterate through any cached maps for this key
+ for map in reverse(s:maps[key])
+
+ " Start building the command to restore the mapping; assume this is
+ " a nonrecursive map unless flagged otherwise
+ let command = !has_key(map, 'noremap') || map['noremap']
+ \ ? ['nnoremap']
+ \ : ['nmap']
+
+ " Restore any flags for the mapping as we know them
+ for flag in ['buffer', 'expr', 'nowait', 'silent']
+ if has_key(map, flag) && map[flag]
+ call add(command, '<'.flag.'>')
+ endif
+ endfor
+
+ " Add the key and right hand
+ call extend(command, [key, map['rhs']])
+ execute join(command)
+
+ endfor
+
+ " Clear the map cache for this key, now that we've restored them
+ unlet s:maps[key]
+
+ endfor
+
endfunction