diff --git a/doc/yankring.txt b/doc/yankring.txt index dafcba3..5246f2e 100644 --- a/doc/yankring.txt +++ b/doc/yankring.txt @@ -1,7 +1,7 @@ *yankring.txt* For Vim version 7.0. -Author: David Fishburn July 27, 2015 -Version: 19.0 +Author: David Fishburn March 1, 2016 +Version: 20.0 For instructions on installing this file, type :help add-local-help |add-local-help| inside Vim. @@ -169,6 +169,15 @@ your |.vimrc|. option controls whether [gp] and [gP] are also mapped. Setting this option to 0 will not create these maps. > let g:yankring_paste_using_g = 1 + yankring_paste_visual_reset_default_register +< Default: 0 + Vim's help |put-Visual-mode| indicates when you visually select text + and paste Vim places the replaced text into the default register. + This means if you attempt to paste again, you have to use the + YankRing's replace feature. If in visual mode and pasting from + the default register, this option will set the default register + back to the value before the paste. > + let g:yankring_paste_visual_reset_default_register = 1 yankring_window_use_separate < Default: 1 This is a new feature as of the 2.0 release. The YankRing now uses a @@ -395,7 +404,7 @@ variables in your |vimrc|. Yanks visually select text. > yankring_del_v_key < n - normal mode - Default: d + Default: d x The visually select text is included in the YankRing and deleted. > yankring_paste_n_bkey < n - normal mode @@ -1236,6 +1245,21 @@ mapping: > ============================================================================== 7. History *yankring-history* + 20.0: Jnauary 1, 2019 + NF: YankRing uses new Vim 8.1 TextYankPost event which allows + the removal of quite a few normal mode maps. + NF: All YankRing maps now use . If a mapping already + exists Vim will report an error. Now the user will know + if there are conflicts. (tenfyzhong, pull #12) + NF: New option g:yankring_paste_visual_reset_default_register + default(0). + When in visual mode and we are pasting text from the default + register, the default register gets replaced with the + overwritten text. This option will put the contents that + were just pasted back into the default register. + This will allow you to paste multiple times in visual mode + without having to use the YankRing replace feature. + 19.0: July 27, 2015 NF: Updated documentation displayed in the YankRing window when pressing ? to explain the Insert=0 status (Oskar Kvist). diff --git a/plugin/yankring.vim b/plugin/yankring.vim index 3cc6780..7fed156 100644 --- a/plugin/yankring.vim +++ b/plugin/yankring.vim @@ -1,9 +1,9 @@ " yankring.vim - Yank / Delete Ring for Vim " --------------------------------------------------------------- -" Version: 19.0 +" Version: 20.0 " Author: David Fishburn " Maintainer: David Fishburn -" Last Modified: 2015 Jul 27 +" Last Modified: 2019 Jan 12 " Script: http://www.vim.org/scripts/script.php?script_id=1234 " Based On: Mocked up version by Yegappan Lakshmanan " http://groups.yahoo.com/group/vim/post?act=reply&messageNum=34406 @@ -19,7 +19,7 @@ if v:version < 700 finish endif -let g:loaded_yankring = 190 +let g:loaded_yankring = 200 " Turn on support for line continuations when creating the script let s:cpo_save = &cpo @@ -30,6 +30,20 @@ if v:version > 701 || ( v:version == 701 && has("patch205") ) let s:yr_has_voperator = 1 endif +let s:yr_has_textyank_autocmd = 0 +if !exists('g:yankring_default_use_textyank_autocmd') + let g:yankring_default_use_textyank_autocmd = 0 + + if has('eval') == 1 + if v:version >= 801 || ( v:version == 800 && has("patch1394") ) + " Test for the TextYankPost autocmd + let s:yr_has_textyank_autocmd = 1 + endif + endif +else + let s:yr_has_textyank_autocmd = g:yankring_default_use_textyank_autocmd +endif + if !exists('g:yankring_history_dir') let g:yankring_history_dir = expand('$HOME') else @@ -164,13 +178,18 @@ endif " Allow the user to specify what characters to use for the mappings. if !exists('g:yankring_n_keys') - " 7.1.patch205 introduces the v:operator function which was essential - " to gain the omap support. - if s:yr_has_voperator == 1 - " Use omaps for the rest of the functionality - let g:yankring_n_keys = 'Y D x X' - else - let g:yankring_n_keys = 'x yy dd yw dw ye de yE dE yiw diw yaw daw y$ d$ Y D yG dG ygg dgg' + let g:yankring_n_keys = '' + let g:yankring_n_keys = '' + " No yank / delete maps are required with Vim 8.1 + if s:yr_has_textyank_autocmd == 0 + " 7.1.patch205 introduces the v:operator function which was essential + " to gain the omap support. + if s:yr_has_voperator == 1 + " Use omaps for the rest of the functionality + let g:yankring_n_keys = 'Y D x X' + else + let g:yankring_n_keys = 'x yy dd yw dw ye de yE dE yiw diw yaw daw y$ d$ Y D yG dG ygg dgg' + endif endif endif @@ -202,6 +221,14 @@ if !exists('g:yankring_paste_using_g') let g:yankring_paste_using_g = 1 endif +" When in visual mode and pasting text, Vim automatically +" puts the replaced text into the default register. +" This option will put the default register back +" to what it was for the next paste. +if !exists('g:yankring_paste_visual_reset_default_register') + let g:yankring_paste_visual_reset_default_register = 0 +endif + if !exists('g:yankring_v_key') let g:yankring_v_key = 'y' endif @@ -243,7 +270,7 @@ if !exists('g:yankring_replace_n_nkey') endif if !exists('g:yankring_clipboard_monitor') - let g:yankring_clipboard_monitor = (has('clipboard')?1:0) + let g:yankring_clipboard_monitor = (has('clipboard') ? 1 : 0) endif if !exists('g:yankring_manual_clipboard_check') @@ -872,9 +899,16 @@ function! s:YRPop(...) endfunction +" There are a few version of YRRecord. +" YRRecord The original stores the values in the ring and does some book +" keeping checking on other registers. +" YRRecordRepeat Does the same as YRRecord, except in the event of replaying +" operations using the "." key, it restores some maps. +" YRRecordAu Uses the new Vim 8.1 feature autocmd TextYankPost to determine +" what to record and then calls the book keeping routines. +" " Adds this value to the yankring. function! YRRecord(...) - let register = '"' if a:0 > 0 " If no yank command has been supplied, assume it is @@ -889,7 +923,12 @@ function! YRRecord(...) return "" endif - let register = ((&clipboard=~'\')?'*':((&clipboard=~'\' && has('unnamedplus'))?'+':register)) + let register = ( + \ (&clipboard=~'\') ? '*' : ( + \ (&clipboard=~'\' && has('unnamedplus')) + \ ? '+' : register + \ ) + \ ) " let s:yr_prev_changenr = changenr() if register == '"' @@ -908,33 +947,12 @@ function! YRRecord(...) \ , getregtype(register) \ ) - if g:yankring_clipboard_monitor == 1 - let s:yr_prev_clipboard_plus = getreg('+') - let s:yr_prev_clipboard_star = getreg('*') - endif - - " Manage the numbered registers - if g:yankring_manage_numbered_reg == 1 - " Allow the user to define an autocmd to dynamically - " setup their connection information. - silent! doautocmd User YRSetNumberedReg - endif - - " If the yankring window is open, refresh it - call s:YRWindowUpdate() - - " Reset the past paste entry to the top of the ring. - " When the user hits replace last entry it should - " start from the top (not from the last previous - " replace) after capturing a new value in the YankRing. - let s:yr_last_paste_idx = 1 - - return "" + return YRRecordCleanup(1) endfunction " Adds this value to the yankring. -function! YRRecord3(...) +function! YRRecordRepeat(...) let register = '"' if a:0 > 0 && a:1 != '' @@ -1010,6 +1028,47 @@ function! YRRecord3(...) \ , getregtype(register) \ ) + return YRRecordCleanup(1) +endfunction + + +" Adds this value to the yankring. +function! YRRecordAu(event_dict) + " Event dictionary sample + " { + " 'regcontents': ['one', 'two', 'three', 'four'], + " 'regname': 'y', + " 'regtype': 'V', + " 'operator': 'y' + " } + let register = '"' + + if a:event_dict.regname != '' + let register = a:event_dict.regname + endif + + if register == '"' + " If the change has occurred via an omap, we must delay + " the capture of the default register until this event + " since register updates are not reflected until the + " omap function completes + let s:yr_prev_reg_unnamed = getreg('"') + let s:yr_prev_reg_small = getreg('-') + endif + + " Add item to list + " This will also account for duplicates. + call s:YRMRUAdd( 's:yr_history_list' + \ , join(a:event_dict.regcontents, "\n") + \ , a:event_dict.regtype + \ ) + + return YRRecordCleanup(0) +endfunction + + +" Housekeeping after adding something to the ring +function! YRRecordCleanup(refreshWindow) if g:yankring_clipboard_monitor == 1 let s:yr_prev_clipboard_plus = getreg('+') let s:yr_prev_clipboard_star = getreg('*') @@ -1023,7 +1082,12 @@ function! YRRecord3(...) endif " If the yankring window is open, refresh it - call s:YRWindowUpdate() + " Do it using an autocmd as this cannot be triggered + " from a different autocmd (TextYankPost) + " doautocmd YankRing User YRWindowUpdate + if a:refreshWindow == 1 + call s:YRWindowUpdate() + endif " Reset the past paste entry to the top of the ring. " When the user hits replace last entry it should @@ -1533,6 +1597,12 @@ function! s:YRPaste(replace_last_paste_selection, nextvalue, direction, ...) endif endif + if cmd_mode == 'v' && g:yankring_paste_visual_reset_default_register == 1 + " Only in visual mode store previous register contents + let replace_reg = getreg(default_register) + let replace_reg_type = getregtype(default_register) + endif + exec "normal! ". \ ((cmd_mode=='n') ? "" : "gv"). \ ((v_count > 0)?(v_count):''). @@ -1540,6 +1610,14 @@ function! s:YRPaste(replace_last_paste_selection, nextvalue, direction, ...) \ a:direction let s:yr_paste_dir = a:direction let s:yr_prev_vis_mode = ((cmd_mode=='n') ? 0 : 1) + + if cmd_mode == 'v' && g:yankring_paste_visual_reset_default_register == 1 + " If in visual mode and we are pasting text, the + " default register gets replaced with the overwritten + " text. Set it back to what is was. + call setreg(default_register, replace_reg, replace_reg_type) + endif + return endif @@ -1579,7 +1657,12 @@ function! s:YRPaste(replace_last_paste_selection, nextvalue, direction, ...) endfunction -" Handle any omaps +" Operator Maps are used by the YankRing to determine when something has +" happened that could lead to a change that should be recorded in the +" YankRing. +" Many operators are mapped (i.e. w, E, }, ], ...) +" When used for example with c, cw = change word, we trigger the YankRing +" to check the registers and store the updated values. function! YRMapsExpression(sid, motion, ...) let cmds = a:motion " echomsg "YRMapsE:".localtime() @@ -1589,7 +1672,7 @@ function! YRMapsExpression(sid, motion, ...) " If we are repeating a series of commands we must " unmap the _zap_ keys so that the user is not " prompted when a command is replayed. - " These maps must be re-instated in YRRecord3() + " These maps must be re-instated in YRRecordRepeat() " after the action of the replay is completed. call s:YRMapsDelete('remove_only_zap_keys') endif @@ -1643,13 +1726,12 @@ function! YRMapsExpression(sid, motion, ...) " let cmds = 'normal! ' . cmds " endif - " YRRecord3() will use this value to determine what operation + " YRRecordRepeat() will use this value to determine what operation " the user just initiated. let s:yr_last_motion = cmds " echomsg "YRMapsE 5:".a:motion.":'".cmds."':".s:yr_maps_created_zap return cmds - endfunction @@ -1658,7 +1740,7 @@ function! s:YRMapsMacro(bang, ...) " If we are repeating a series of commands we must " unmap the _zap_ keys so that the user is not " prompted when a command is replayed. - " These maps must be re-instated in YRRecord3() + " These maps must be re-instated in YRRecordRepeat() " after the action of the replay is completed. call s:YRMapsDelete('remove_only_zap_keys') @@ -1745,8 +1827,8 @@ function! s:YRMapsCreate(...) let n_maps = split(g:yankring_n_keys) " Loop through and prompt the user for all buffer connection parameters. for key in n_maps - " exec 'nnoremap '.key." :YRYankCount '".key."'" - " exec 'nnoremap '.key." :YRYankCount '".key."'" + " exec 'nnoremap '.key." :YRYankCount '".key."'" + " exec 'nnoremap '.key." :YRYankCount '".key."'" " Andy Wokula's suggestion exec 'nmap' key key."yrrecord" endfor @@ -1755,46 +1837,46 @@ function! s:YRMapsCreate(...) if s:yr_has_voperator == 1 nmap . YRMapsExpression("", ".") else - nnoremap . :YRYankCount '.' + nnoremap . :YRYankCount '.' endif endif if g:yankring_v_key != '' - exec 'xnoremap '.g:yankring_v_key." :YRYankRange 'v'" + exec 'xnoremap '.g:yankring_v_key." :YRYankRange 'v'" endif if g:yankring_del_v_key != '' for v_map in split(g:yankring_del_v_key) if !empty(v_map) try - exec 'xnoremap '.v_map." :YRDeleteRange 'v'" + exec 'xnoremap '.v_map." :YRDeleteRange 'v'" catch endtry endif endfor endif if g:yankring_paste_n_bkey != '' - exec 'nnoremap '.g:yankring_paste_n_bkey." :YRPaste 'P'" + exec 'nnoremap '.g:yankring_paste_n_bkey." :YRPaste 'P'" if g:yankring_paste_using_g == 1 - exec 'nnoremap g'.g:yankring_paste_n_bkey." :YRPaste 'gP'" + exec 'nnoremap g'.g:yankring_paste_n_bkey." :YRPaste 'gP'" endif endif if g:yankring_paste_n_akey != '' - exec 'nnoremap '.g:yankring_paste_n_akey." :YRPaste 'p'" + exec 'nnoremap '.g:yankring_paste_n_akey." :YRPaste 'p'" if g:yankring_paste_using_g == 1 - exec 'nnoremap g'.g:yankring_paste_n_akey." :YRPaste 'gp'" + exec 'nnoremap g'.g:yankring_paste_n_akey." :YRPaste 'gp'" endif endif if g:yankring_paste_v_bkey != '' - exec 'xnoremap '.g:yankring_paste_v_bkey." :YRPaste 'P', 'v'" + exec 'xnoremap '.g:yankring_paste_v_bkey." :YRPaste 'P', 'v'" endif if g:yankring_paste_v_akey != '' - exec 'xnoremap '.g:yankring_paste_v_akey." :YRPaste 'p', 'v'" + exec 'xnoremap '.g:yankring_paste_v_akey." :YRPaste 'p', 'v'" endif if g:yankring_replace_n_pkey != '' - exec 'nnoremap '.g:yankring_replace_n_pkey." :YRReplace '-1', P" + exec 'nnoremap '.g:yankring_replace_n_pkey." :YRReplace '-1', P" endif if g:yankring_replace_n_nkey != '' - exec 'nnoremap '.g:yankring_replace_n_nkey." :YRReplace '1', p" + exec 'nnoremap '.g:yankring_replace_n_nkey." :YRReplace '1', p" endif let g:yankring_enabled = 1 @@ -2146,7 +2228,8 @@ function! s:YRWindowUpdate() if bufwinnr(s:yr_buffer_id) != -1 call s:YRShow(0) " Switch back to the original buffer - exec orig_win_bufnr . "wincmd w" + " This could fail, if happening from within an autocmd + silent! exec orig_win_bufnr . "wincmd w" endif endfunction @@ -2689,6 +2772,12 @@ function! s:YRWinLeave() endif endfunction +function! s:YRTextYankPostAutocmd() + call YRRecordAu(v:event) + " If the yankring window is open, refresh it + " call s:YRWindowUpdate() +endfunction + function! s:YRFocusGained() " FocusGained is not available in general by console vim. " There are some terminal windows which support it though. @@ -2725,7 +2814,7 @@ function! s:YRCheckClipboard() " Only add the item to the "top" of the ring if it is " not in the ring already. if found == -1 - call YRRecord3("+") + call YRRecordRepeat("+") endif let s:yr_prev_clipboard_plus = @+ endif @@ -2740,7 +2829,7 @@ function! s:YRCheckClipboard() " Only add the item to the "top" of the ring if it is " not in the ring already. if found == -1 - call YRRecord3("*") + call YRRecordRepeat("*") endif let s:yr_prev_clipboard_star = @* endif @@ -2787,33 +2876,39 @@ function! s:YRInsertLeave() " Only add the item to the "top" of the ring if it is " not in the ring already. if found == -1 - call YRRecord3(".") + call YRRecordRepeat(".") endif let s:yr_prev_reg_insert = @. endif endif - endfunction " Deleting autocommands first is a good idea especially if we want to reload " the script without restarting vim. -" Call YRFocusGained to check if the clipboard has been updated augroup YankRing autocmd! - autocmd VimEnter * :if has('clipboard') | call YRFocusGained() | endif - autocmd WinLeave * :call YRWinLeave() - autocmd FocusGained * :if has('clipboard') | call YRFocusGained() | endif - autocmd InsertLeave * :call YRInsertLeave() - autocmd User YRSetNumberedReg :call YRSetNumberedReg() - " autocmd User YRSetNumberedReg :let i = 0 | while i <= 10 | if i > s:yr_count | break | endif | call setreg( (i), s:YRGetValElemNbr((i),'v'), s:YRGetValElemNbr((i),'t') ) | let i += 1 | endwhile + autocmd WinLeave * :call YRWinLeave() + autocmd InsertLeave * :call YRInsertLeave() + autocmd User YRSetNumberedReg :call YRSetNumberedReg() + autocmd User YRWindowUpdate :call YRWindowUpdate() augroup END +if has('clipboard') + " Call YRFocusGained to check if the clipboard has been updated + autocmd YankRing VimEnter * :call YRFocusGained() + autocmd YankRing FocusGained * :call YRFocusGained() +endif + +if s:yr_has_textyank_autocmd == 1 + " Add an additional event to the YankRing auto group + autocmd YankRing TextYankPost * :call YRTextYankPostAutocmd() +endif " copy register inoremap