2886 lines
98 KiB
VimL
2886 lines
98 KiB
VimL
|
" yankring.vim - Yank / Delete Ring for Vim
|
||
|
" ---------------------------------------------------------------
|
||
|
" Version: 19.0
|
||
|
" Author: David Fishburn <dfishburn dot vim at gmail dot com>
|
||
|
" Maintainer: David Fishburn <dfishburn dot vim at gmail dot com>
|
||
|
" Last Modified: 2015 Jul 27
|
||
|
" 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
|
||
|
" License: GPL (Gnu Public License)
|
||
|
" GetLatestVimScripts: 1234 1 :AutoInstall: yankring.vim
|
||
|
|
||
|
if exists('g:loaded_yankring')
|
||
|
finish
|
||
|
endif
|
||
|
|
||
|
if v:version < 700
|
||
|
echomsg 'yankring: You need at least Vim 7.0'
|
||
|
finish
|
||
|
endif
|
||
|
|
||
|
let g:loaded_yankring = 190
|
||
|
|
||
|
" Turn on support for line continuations when creating the script
|
||
|
let s:cpo_save = &cpo
|
||
|
set cpo&vim
|
||
|
|
||
|
let s:yr_has_voperator = 0
|
||
|
if v:version > 701 || ( v:version == 701 && has("patch205") )
|
||
|
let s:yr_has_voperator = 1
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_history_dir')
|
||
|
let g:yankring_history_dir = expand('$HOME')
|
||
|
else
|
||
|
" let g:yankring_history_dir = expand(g:yankring_history_dir)
|
||
|
for dir in split(g:yankring_history_dir, ",")
|
||
|
if isdirectory(expand(dir))
|
||
|
let g:yankring_history_dir = expand(dir)
|
||
|
break
|
||
|
endif
|
||
|
endfor
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_buffer_name')
|
||
|
let g:yankring_buffer_name = '[YankRing]'
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_history_file')
|
||
|
let g:yankring_history_file = 'yankring_history'
|
||
|
endif
|
||
|
|
||
|
" Allow the user to override the # of yanks/deletes recorded
|
||
|
if !exists('g:yankring_max_history')
|
||
|
let g:yankring_max_history = 100
|
||
|
elseif g:yankring_max_history < 0
|
||
|
let g:yankring_max_history = 100
|
||
|
endif
|
||
|
|
||
|
" Specify the minimum length of 1 entry
|
||
|
if !exists('g:yankring_min_element_length')
|
||
|
let g:yankring_min_element_length = 1
|
||
|
endif
|
||
|
|
||
|
" Specify the maximum length of 1 entry (1MB default)
|
||
|
if !exists('g:yankring_max_element_length')
|
||
|
let g:yankring_max_element_length = 1048576
|
||
|
endif
|
||
|
|
||
|
" Warn if truncation occurs
|
||
|
if !exists('g:yankring_warn_on_truncate')
|
||
|
let g:yankring_warn_on_truncate = 1
|
||
|
endif
|
||
|
|
||
|
" Allow the user to specify if the plugin is enabled or not
|
||
|
if !exists('g:yankring_enabled')
|
||
|
let g:yankring_enabled = 1
|
||
|
endif
|
||
|
|
||
|
" Specify max display length for each element for YRShow
|
||
|
if !exists('g:yankring_max_display')
|
||
|
let g:yankring_max_display = 0
|
||
|
endif
|
||
|
|
||
|
" Check if yankring should persist between Vim instances
|
||
|
if !exists('g:yankring_persist')
|
||
|
let g:yankring_persist = 1
|
||
|
endif
|
||
|
|
||
|
" Check if yankring share 1 file between all instances of Vim
|
||
|
if !exists('g:yankring_share_between_instances')
|
||
|
let g:yankring_share_between_instances = 1
|
||
|
endif
|
||
|
|
||
|
" Specify whether the results of the ring should be displayed
|
||
|
" in a separate buffer window instead of the use of echo
|
||
|
if !exists('g:yankring_window_use_separate')
|
||
|
let g:yankring_window_use_separate = 1
|
||
|
endif
|
||
|
|
||
|
" Specifies whether the window is closed after an action
|
||
|
" is performed
|
||
|
if !exists('g:yankring_window_auto_close')
|
||
|
let g:yankring_window_auto_close = 1
|
||
|
endif
|
||
|
|
||
|
" When displaying the buffer, how many lines should it be
|
||
|
if !exists('g:yankring_window_height')
|
||
|
let g:yankring_window_height = 8
|
||
|
endif
|
||
|
|
||
|
" When displaying the buffer, how many columns should it be
|
||
|
if !exists('g:yankring_window_width')
|
||
|
let g:yankring_window_width = 30
|
||
|
endif
|
||
|
|
||
|
" When displaying the buffer, where it should be placed
|
||
|
if !exists('g:yankring_window_use_horiz')
|
||
|
let g:yankring_window_use_horiz = 1
|
||
|
endif
|
||
|
|
||
|
" When displaying the buffer, where it should be placed
|
||
|
if !exists('g:yankring_window_use_bottom')
|
||
|
let g:yankring_window_use_bottom = 1
|
||
|
endif
|
||
|
|
||
|
" When displaying the buffer, where it should be placed
|
||
|
if !exists('g:yankring_window_use_right')
|
||
|
let g:yankring_window_use_right = 1
|
||
|
endif
|
||
|
|
||
|
" If the user presses <space>, toggle the width of the window
|
||
|
if !exists('g:yankring_window_increment')
|
||
|
let g:yankring_window_increment = 50
|
||
|
endif
|
||
|
|
||
|
" Controls whether the . operator will repeat yank operations
|
||
|
" The default is based on cpoptions: |cpo-y|
|
||
|
" y A yank command can be redone with ".".
|
||
|
if !exists('g:yankring_dot_repeat_yank')
|
||
|
let g:yankring_dot_repeat_yank = (s:cpo_save=~'y'?1:0)
|
||
|
endif
|
||
|
|
||
|
" Only adds unique items to the yankring.
|
||
|
" If the item already exists, that element is set as the
|
||
|
" top of the yankring.
|
||
|
if !exists('g:yankring_ignore_duplicate')
|
||
|
let g:yankring_ignore_duplicate = 1
|
||
|
endif
|
||
|
|
||
|
" Determine whether to record inserted data
|
||
|
if !exists('g:yankring_record_insert')
|
||
|
let g:yankring_record_insert = 0
|
||
|
endif
|
||
|
|
||
|
" Vim automatically manages the numbered registers:
|
||
|
" 0 - last yanked text
|
||
|
" 1-9 - last deleted items
|
||
|
" If this option is turned on, the yankring will manage the
|
||
|
" values in them.
|
||
|
if !exists('g:yankring_manage_numbered_reg')
|
||
|
let g:yankring_manage_numbered_reg = 0
|
||
|
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'
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
" Allow the user to specify what operator pending motions to map
|
||
|
if !exists('g:yankring_o_keys')
|
||
|
" o-motions and text objects, without zap-to-char motions
|
||
|
let g:yankring_o_keys = 'b B w W e E d h j k l H M L y G ^ 0 $ , ;'
|
||
|
let g:yankring_o_keys .= ' g_ g^ gm g$ gk gj gg ge gE - + _ '
|
||
|
let g:yankring_o_keys .= ' iw iW aw aW as is ap ip a] a[ i] i[ a) a( ab i) i( ib a> a< i> i< at it a} a{ aB i} i{ iB a" a'' a` i" i'' i`'
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_zap_keys')
|
||
|
let g:yankring_zap_keys = 'f F t T / ?'
|
||
|
endif
|
||
|
|
||
|
" Allow the user to specify what operator pending motions to map
|
||
|
if !exists('g:yankring_ignore_operator')
|
||
|
let g:yankring_ignore_operator = 'g~ gu gU ! = gq g? > < zf g@'
|
||
|
endif
|
||
|
let g:yankring_ignore_operator = ' '.g:yankring_ignore_operator.' '
|
||
|
|
||
|
" Whether we should map the . operator
|
||
|
if !exists('g:yankring_map_dot')
|
||
|
let g:yankring_map_dot = 1
|
||
|
endif
|
||
|
|
||
|
" Whether we sould map the "g" paste operators
|
||
|
if !exists('g:yankring_paste_using_g')
|
||
|
let g:yankring_paste_using_g = 1
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_v_key')
|
||
|
let g:yankring_v_key = 'y'
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_del_v_key')
|
||
|
let g:yankring_del_v_key = 'd x'
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_paste_n_bkey')
|
||
|
let g:yankring_paste_n_bkey = 'P'
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_paste_n_akey')
|
||
|
let g:yankring_paste_n_akey = 'p'
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_paste_v_bkey')
|
||
|
let g:yankring_paste_v_bkey = 'P'
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_paste_v_akey')
|
||
|
let g:yankring_paste_v_akey = 'p'
|
||
|
endif
|
||
|
|
||
|
if exists('g:yankring_paste_check_default_buffer')
|
||
|
let g:yankring_paste_check_default_register = g:yankring_paste_check_default_buffer
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_paste_check_default_register')
|
||
|
let g:yankring_paste_check_default_register = 1
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_replace_n_pkey')
|
||
|
let g:yankring_replace_n_pkey = '<C-P>'
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_replace_n_nkey')
|
||
|
let g:yankring_replace_n_nkey = '<C-N>'
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_clipboard_monitor')
|
||
|
let g:yankring_clipboard_monitor = (has('clipboard')?1:0)
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_manual_clipboard_check')
|
||
|
let g:yankring_manual_clipboard_check = 0
|
||
|
if g:yankring_clipboard_monitor == 1
|
||
|
if has("gui_running")
|
||
|
" FocusGained event will take care of
|
||
|
" monitoring the clipboard.
|
||
|
let g:yankring_manual_clipboard_check = 0
|
||
|
else
|
||
|
" If the GUI is not running and the user wants to monitor the
|
||
|
" clipboard, we need to manually check for clipboard entries as
|
||
|
" the FocusGained event does not fire in console mode.
|
||
|
let g:yankring_manual_clipboard_check = 1
|
||
|
endif
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
if !exists('g:yankring_default_menu_mode')
|
||
|
let g:yankring_default_menu_mode = 3
|
||
|
endif
|
||
|
|
||
|
" Script variables for the yankring buffer
|
||
|
let s:yr_buffer_last_winnr = -1
|
||
|
let s:yr_buffer_last = -1
|
||
|
let s:yr_buffer_id = -1
|
||
|
let s:yr_search = ''
|
||
|
let s:yr_remove_omap_dot = 0
|
||
|
let s:yr_history_version = 'v2'
|
||
|
let s:yr_history_v1_nl = '@@@'
|
||
|
let s:yr_history_v1_nl_pat = '\%(\\\)\@<!@@@'
|
||
|
let s:yr_history_v2_nl = "\2" " Use double quotes for a special character
|
||
|
let s:yr_history_v2_nl_pat = "\2"
|
||
|
let s:yr_history_last_upd = 0
|
||
|
if g:yankring_persist == 1
|
||
|
let s:yr_history_file_v1 =
|
||
|
\ g:yankring_history_dir.'/'.
|
||
|
\ g:yankring_history_file.
|
||
|
\ (g:yankring_share_between_instances==1?'':'_'.v:servername).
|
||
|
\ '.txt'
|
||
|
let s:yr_history_file_v2 =
|
||
|
\ g:yankring_history_dir.'/'.
|
||
|
\ g:yankring_history_file.
|
||
|
\ (g:yankring_share_between_instances==1?'':'_'.v:servername).
|
||
|
\ '_v2.txt'
|
||
|
endif
|
||
|
|
||
|
|
||
|
" Vim window size is changed by the yankring plugin or not
|
||
|
let s:yr_winsize_chgd = 0
|
||
|
let s:yr_maps_created = 0
|
||
|
let s:yr_maps_created_zap = 0
|
||
|
let s:yr_last_motion = ''
|
||
|
|
||
|
" Enables or disables the yankring
|
||
|
function! s:YRToggle(...)
|
||
|
" Default the current state to toggle
|
||
|
let new_state = ((g:yankring_enabled == 1) ? 0 : 1)
|
||
|
|
||
|
" Allow the user to specify if enabled
|
||
|
if a:0 > 0
|
||
|
let new_state = ((a:1 == 1) ? 1 : 0)
|
||
|
endif
|
||
|
|
||
|
" YRToggle accepts an integer value to specify the state
|
||
|
if new_state == g:yankring_enabled
|
||
|
return
|
||
|
elseif new_state == 1
|
||
|
call s:YRMapsCreate()
|
||
|
call s:YRWarningMsg('YR: The YankRing is now enabled')
|
||
|
else
|
||
|
call s:YRMapsDelete()
|
||
|
call s:YRWarningMsg('YR: The YankRing is now disabled')
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
" Enables or disables the yankring
|
||
|
function! s:YRDisplayElem(disp_nbr, script_var)
|
||
|
if g:yankring_max_display == 0
|
||
|
if g:yankring_window_use_separate == 1
|
||
|
let max_display = 500
|
||
|
else
|
||
|
let max_display = g:yankring_window_width +
|
||
|
\ g:yankring_window_increment -
|
||
|
\ 12
|
||
|
endif
|
||
|
else
|
||
|
let max_display = g:yankring_max_display
|
||
|
endif
|
||
|
|
||
|
let elem = matchstr(a:script_var, '^.*\ze,.*$')
|
||
|
if s:yr_history_version == 'v1'
|
||
|
" v1
|
||
|
" let elem = substitute(elem, '\%(\\\)\@<!@@@', '\\n', 'g')
|
||
|
" v2
|
||
|
let elem = substitute(elem, s:yr_history_v1_nl_pat, '\\n', 'g')
|
||
|
let elem = substitute(elem, '\\@', '@', 'g')
|
||
|
else
|
||
|
let elem = substitute(elem, s:yr_history_v2_nl_pat, '\\n', 'g')
|
||
|
endif
|
||
|
let length = strlen(elem)
|
||
|
" Fancy trick to align them all regardless of how many
|
||
|
" digits the element # is
|
||
|
return a:disp_nbr.
|
||
|
\ strtrans(
|
||
|
\ strpart(" ",0,(6-strlen(a:disp_nbr+1))).
|
||
|
\ (
|
||
|
\ (length>max_display)?
|
||
|
\ (strpart(elem,0,max_display).
|
||
|
\ '...'):
|
||
|
\ elem
|
||
|
\ )
|
||
|
\ )
|
||
|
|
||
|
return ""
|
||
|
endfunction
|
||
|
|
||
|
" Enables or disables the yankring
|
||
|
function! s:YRShow(...)
|
||
|
" Prevent recursion
|
||
|
if exists('s:yankring_showing') && s:yankring_showing == 1
|
||
|
" call s:YRWarningMsg('YR: YRShow aborting for recursion')
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
if g:yankring_enabled == 0
|
||
|
call s:YRWarningMsg('YR: The YankRing is disabled, use YRToggle to re-enable')
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" Prevent recursion
|
||
|
let s:yankring_showing = 1
|
||
|
|
||
|
" If the GUI is not running, we need to manually check for clipboard
|
||
|
" entries as the FocusGained event does not fire in console mode.
|
||
|
if g:yankring_manual_clipboard_check == 1
|
||
|
call s:YRCheckClipboard()
|
||
|
endif
|
||
|
|
||
|
" If no parameter was provided assume the user wants to
|
||
|
" toggle the display.
|
||
|
let toggle = 1
|
||
|
if a:0 > 0
|
||
|
let toggle = matchstr(a:1, '\d\+')
|
||
|
endif
|
||
|
|
||
|
let show_registers = 0
|
||
|
if a:0 > 1 && a:2 ==# 'R'
|
||
|
let show_registers = 1
|
||
|
endif
|
||
|
|
||
|
if toggle == 1
|
||
|
if bufwinnr(s:yr_buffer_id) > -1
|
||
|
" If the YankRing window is already open close it
|
||
|
exec bufwinnr(s:yr_buffer_id) . "wincmd w"
|
||
|
" Quit the YankRing
|
||
|
call s:YRWindowAction('q', 'n')
|
||
|
|
||
|
" Switch back to the window which the YankRing
|
||
|
" window was opened from
|
||
|
if bufwinnr(s:yr_buffer_last) != -1
|
||
|
" If the buffer is visible, switch to it
|
||
|
exec s:yr_buffer_last_winnr . "wincmd w"
|
||
|
endif
|
||
|
|
||
|
" Prevent recursion
|
||
|
let s:yankring_showing = 0
|
||
|
|
||
|
return
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
" Reset the search string, since this is automatically called
|
||
|
" if the yankring window is open. A previous search must be
|
||
|
" cleared since we do not want to show new items. The user can
|
||
|
" always run the search again.
|
||
|
let s:yr_search = ""
|
||
|
|
||
|
" It is possible for registers to be changed outside of the
|
||
|
" maps of the YankRing. Perform this quick check when we
|
||
|
" show the contents (or when it is refreshed).
|
||
|
if g:yankring_paste_check_default_register == 1
|
||
|
let save_reg = 0
|
||
|
let register = ((&clipboard=~'\<unnamed\>')?'*':((&clipboard=~'\<unnamedplus\>' && has('unnamedplus'))?'+':'"'))
|
||
|
|
||
|
if &clipboard =~ '\<unnamed\>' && getreg('*') != s:yr_prev_clipboard_star
|
||
|
let save_reg = 1
|
||
|
endif
|
||
|
if has('unnamedplus') && &clipboard =~ '\<unnamedplus\>' && getreg('+') != s:yr_prev_clipboard_plus
|
||
|
let save_reg = 1
|
||
|
endif
|
||
|
if register == '"' && getreg('"') != s:yr_prev_reg_unnamed
|
||
|
let save_reg = 1
|
||
|
endif
|
||
|
|
||
|
if save_reg == 1
|
||
|
" The user has performed a yank / delete operation
|
||
|
" outside of the yankring maps. Add this
|
||
|
" value to the yankring.
|
||
|
call YRRecord(register)
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
" List is shown in order of replacement
|
||
|
" assuming using previous yanks
|
||
|
let output = "--- YankRing ---\n"
|
||
|
let output = output . (show_registers == 1 ? 'Reg ' : 'Elem')." Content\n"
|
||
|
|
||
|
if show_registers == 1
|
||
|
for reg_name in map( range(char2nr('0'), char2nr('9')) +
|
||
|
\ (range(char2nr('a'), char2nr('z')))
|
||
|
\, 'nr2char(v:val)'
|
||
|
\ )
|
||
|
let output = output . s:YRDisplayElem(reg_name, getreg(reg_name).',') . "\n"
|
||
|
endfor
|
||
|
else
|
||
|
call s:YRHistoryRead()
|
||
|
let disp_item_nr = 1
|
||
|
for elem in s:yr_history_list
|
||
|
let output = output . s:YRDisplayElem(disp_item_nr, elem) . "\n"
|
||
|
let disp_item_nr += 1
|
||
|
endfor
|
||
|
endif
|
||
|
|
||
|
if g:yankring_window_use_separate == 1
|
||
|
call s:YRWindowOpen(output)
|
||
|
else
|
||
|
echo output
|
||
|
endif
|
||
|
|
||
|
" Prevent recursion
|
||
|
let s:yankring_showing = 0
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Used in omaps if a following character is required
|
||
|
" like with motions (f,t)
|
||
|
function! s:YRGetChar()
|
||
|
let msg = "YR:Enter character:"
|
||
|
" echomsg msg
|
||
|
echo msg
|
||
|
let c = getchar()
|
||
|
if c =~ '^\d\+$'
|
||
|
let c = nr2char(c)
|
||
|
" echomsg msg.c
|
||
|
echon c
|
||
|
endif
|
||
|
return c
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Used in omaps if a following string is required
|
||
|
" like with motions (/,?)
|
||
|
" function! s:YRGetSearch()
|
||
|
" " let msg = "YR:Enter string:"
|
||
|
" " echomsg msg
|
||
|
" let str = input("YR:Enter string:")
|
||
|
" " let str = ''
|
||
|
" " while 1==1
|
||
|
" " let c = getchar()
|
||
|
" " if c =~ '^\d\+$'
|
||
|
" " let c = nr2char(c)
|
||
|
" " if c == "\<C-C>"
|
||
|
" " return c
|
||
|
" " endif
|
||
|
" " if c == "\<CR>"
|
||
|
" " break
|
||
|
" " endif
|
||
|
" " let str = str.c
|
||
|
" " echomsg msg.str
|
||
|
" " else
|
||
|
" " break
|
||
|
" " endif
|
||
|
" " endwhile
|
||
|
" return str
|
||
|
" endfunction
|
||
|
|
||
|
|
||
|
" Paste a certain item from the yankring
|
||
|
" If no parameter is provided, this function becomes interactive. It will
|
||
|
" display the list (using YRShow) and allow the user to choose an element.
|
||
|
function! s:YRGetElem(...)
|
||
|
if g:yankring_manual_clipboard_check == 1
|
||
|
call s:YRCheckClipboard()
|
||
|
endif
|
||
|
|
||
|
if s:yr_count == 0
|
||
|
call s:YRWarningMsg('YR: yankring is empty')
|
||
|
return -1
|
||
|
endif
|
||
|
|
||
|
let default_buffer = ((&clipboard=~'\<unnamed\>')?'*':((&clipboard=~'\<unnamedplus\>' && has('unnamedplus'))?'+':'"'))
|
||
|
|
||
|
let direction = 'p'
|
||
|
if a:0 > 1
|
||
|
" If the user indicated to paste above or below
|
||
|
" let direction = ((a:2 ==# 'P') ? 'P' : 'p')
|
||
|
if a:2 =~ '\<\(p\|gp\|P\|gP\)\>'
|
||
|
let direction = a:2
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
" Check to see if a specific value has been provided
|
||
|
let elem = 0
|
||
|
if a:0 > 0
|
||
|
" Ensure we get only the numeric value (trim it)
|
||
|
let elem = matchstr(a:1, '\d\+')
|
||
|
let elem = elem - 1
|
||
|
else
|
||
|
" If no parameter was supplied display the yankring
|
||
|
" and prompt the user to enter the value they want pasted.
|
||
|
call s:YRShow(0)
|
||
|
|
||
|
if g:yankring_window_use_separate == 1
|
||
|
" The window buffer is used instead of command line
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
let elem = input("Enter # to paste:")
|
||
|
|
||
|
" Ensure we get only the numeric value (trim it)
|
||
|
let elem = matchstr(elem, '\d\+')
|
||
|
|
||
|
if elem == ''
|
||
|
" They most likely pressed enter without entering a value
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
let elem = elem - 1
|
||
|
endif
|
||
|
|
||
|
if elem < 0 || elem >= s:yr_count
|
||
|
call s:YRWarningMsg("YR: Invalid choice:".elem)
|
||
|
return -1
|
||
|
endif
|
||
|
|
||
|
let default_buffer = ((&clipboard=~'\<unnamed\>')?'*':((&clipboard=~'\<unnamedplus\>' && has('unnamedplus'))?'+':'"'))
|
||
|
call setreg(default_buffer
|
||
|
\ , s:YRGetValElemNbr((elem), 'v')
|
||
|
\ , s:YRGetValElemNbr((elem), 't')
|
||
|
\ )
|
||
|
exec 'normal! "'.default_buffer.direction
|
||
|
|
||
|
" Set the previous action as a paste in case the user
|
||
|
" press . to repeat
|
||
|
call s:YRSetPrevOP('p', '', default_buffer, 'n')
|
||
|
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Starting the top of the ring it will paste x items from it
|
||
|
function! s:YRGetMultiple(reverse_order, ...)
|
||
|
if g:yankring_manual_clipboard_check == 1
|
||
|
call s:YRCheckClipboard()
|
||
|
endif
|
||
|
|
||
|
if s:yr_count == 0
|
||
|
call s:YRWarningMsg('YR: yankring is empty')
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
let max = 1
|
||
|
if a:0 == 1
|
||
|
" If the user provided a range, exit after that many
|
||
|
" have been displayed
|
||
|
let max = matchstr(a:1, '\d\+')
|
||
|
endif
|
||
|
if max > s:yr_count
|
||
|
" Default to all items if they specified a very high value
|
||
|
let max = s:yr_count
|
||
|
endif
|
||
|
|
||
|
" Base the increment on the sort order of the results
|
||
|
let increment = ((a:reverse_order==0)?(1):(-1))
|
||
|
if a:reverse_order == 0
|
||
|
let increment = 1
|
||
|
let elem = 1
|
||
|
else
|
||
|
let increment = -1
|
||
|
let elem = max
|
||
|
endif
|
||
|
|
||
|
if a:0 > 1
|
||
|
let iter = 1
|
||
|
while iter <= a:0
|
||
|
let elem = (a:{iter} - 1)
|
||
|
call s:YRGetElem(elem)
|
||
|
let iter = iter + 1
|
||
|
endwhile
|
||
|
else
|
||
|
while max > 0
|
||
|
" Paste the first item, and move on to the next.
|
||
|
call s:YRGetElem(elem)
|
||
|
let elem = elem + increment
|
||
|
let max = max - 1
|
||
|
endwhile
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Given a regular expression, check each element within
|
||
|
" the yankring, display only the matching items and prompt
|
||
|
" the user for which item to paste
|
||
|
function! s:YRSearch(...)
|
||
|
if s:yr_count == 0
|
||
|
call s:YRWarningMsg('YR: yankring is empty')
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
let s:yr_search = ""
|
||
|
" If the user provided a range, exit after that many
|
||
|
" have been displayed
|
||
|
if a:0 == 0 || (a:0 == 1 && a:1 == "")
|
||
|
let s:yr_search = input('Enter [optional] regex:')
|
||
|
else
|
||
|
let s:yr_search = a:1
|
||
|
endif
|
||
|
|
||
|
if s:yr_search == ""
|
||
|
" Show the entire yankring
|
||
|
call s:YRShow(0)
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" List is shown in order of replacement
|
||
|
" assuming using previous yanks
|
||
|
let output = "--- YankRing ---\n"
|
||
|
let output = output . "Elem Content\n"
|
||
|
let valid_choices = []
|
||
|
|
||
|
let search_result = filter(copy(s:yr_history_list), "v:val =~ '".s:yr_search."'")
|
||
|
|
||
|
let disp_item_nr = 1
|
||
|
|
||
|
for elem in s:yr_history_list
|
||
|
if elem =~ s:yr_search
|
||
|
let output = output . s:YRDisplayElem(disp_item_nr, elem) . "\n"
|
||
|
call add(valid_choices, disp_item_nr.'')
|
||
|
endif
|
||
|
let disp_item_nr += 1
|
||
|
endfor
|
||
|
|
||
|
if empty(valid_choices)
|
||
|
let output = output . "Search for [".s:yr_search."] did not match any items "
|
||
|
endif
|
||
|
|
||
|
if g:yankring_window_use_separate == 1
|
||
|
call s:YRWindowOpen(output)
|
||
|
else
|
||
|
if !empty(valid_choices)
|
||
|
echo output
|
||
|
let elem = input("Enter # to paste:")
|
||
|
|
||
|
" Ensure we get only the numeric value (trim it)
|
||
|
let elem = matchstr(elem, '\d\+')
|
||
|
|
||
|
if elem == ''
|
||
|
" They most likely pressed enter without entering a value
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
if index(valid_choices, elem) != -1
|
||
|
exec 'YRGetElem ' . elem
|
||
|
else
|
||
|
" User did not choose one of the elements that were found
|
||
|
" Remove leading ,
|
||
|
call s:YRWarningMsg( "YR: Item[" . elem . "] not found, only valid choices are[" .
|
||
|
\ join(valid_choices, ',') .
|
||
|
\ "]"
|
||
|
\ )
|
||
|
return -1
|
||
|
endif
|
||
|
|
||
|
else
|
||
|
call s:YRWarningMsg( "YR: The pattern [" .
|
||
|
\ s:yr_search .
|
||
|
\ "] does not match any items in the yankring"
|
||
|
\ )
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Resets the common script variables for managing the ring.
|
||
|
function! s:YRReset()
|
||
|
call s:YRHistoryDelete()
|
||
|
" Update the history file
|
||
|
call s:YRHistorySave()
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Clears the yankring by simply setting the # of items in it to 0.
|
||
|
" There is no need physically unlet each variable.
|
||
|
function! s:YRInit(...)
|
||
|
let s:yr_next_idx = 0
|
||
|
let s:yr_last_paste_idx = 1
|
||
|
let s:yr_count = 0
|
||
|
let s:yr_history_last_upd = 0
|
||
|
let s:yr_history_list = []
|
||
|
let s:yr_paste_dir = 'p'
|
||
|
|
||
|
" For the . op support
|
||
|
let s:yr_prev_op_code = ''
|
||
|
let s:yr_prev_op_mode = 'n'
|
||
|
let s:yr_prev_count = ''
|
||
|
let s:yr_prev_reg = ''
|
||
|
let s:yr_prev_reg_unnamed = getreg('"')
|
||
|
let s:yr_prev_reg_small = ''
|
||
|
let s:yr_prev_reg_insert = ''
|
||
|
let s:yr_prev_reg_expres = ''
|
||
|
let s:yr_prev_clipboard_star = ''
|
||
|
let s:yr_prev_clipboard_plus = ''
|
||
|
let s:yr_prev_vis_lstart = 0
|
||
|
let s:yr_prev_vis_lend = 0
|
||
|
let s:yr_prev_vis_cstart = 0
|
||
|
let s:yr_prev_vis_cend = 0
|
||
|
let s:yr_prev_changenr = 0
|
||
|
let s:yr_prev_repeating = 0
|
||
|
|
||
|
" This is used to determine if the visual selection should be
|
||
|
" reset prior to issuing the YRReplace
|
||
|
let s:yr_prev_vis_mode = 0
|
||
|
|
||
|
if a:0 == 0 && g:yankring_persist != 1
|
||
|
" The user wants the yankring reset each time Vim is started
|
||
|
call s:YRClear()
|
||
|
endif
|
||
|
|
||
|
call s:YRHistoryRead()
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Clears the yankring by simply setting the # of items in it to 0.
|
||
|
function! s:YRClear()
|
||
|
call s:YRReset()
|
||
|
call s:YRInit('DoNotClear')
|
||
|
|
||
|
" If the yankring window is open, refresh it
|
||
|
call s:YRWindowUpdate()
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Determine which register the user wants to use
|
||
|
" For example the 'a' register: "ayy
|
||
|
function! s:YRRegister()
|
||
|
" v:register can be blank in some (unknown) cases
|
||
|
" so test for this condition and return the
|
||
|
" default register
|
||
|
let user_register = ((v:register=='')?('"'):(v:register))
|
||
|
let clipboard_default = matchstr( &clipboard, '\<unnamed\w*\>' )
|
||
|
|
||
|
" clipboard can have a comma separated list of values.
|
||
|
" Depending on which order the unnamed is referenced
|
||
|
" determines which register to use.
|
||
|
" set clipboard=unnamedplus,unnamed
|
||
|
" set clipboard=unnamed,unnamedplus
|
||
|
if clipboard_default == '\<unnamed\>' && user_register == '"'
|
||
|
let user_register = '*'
|
||
|
endif
|
||
|
if has('unnamedplus') && clipboard_default == '\<unnamedplus\>' && user_register == '"'
|
||
|
let user_register = '+'
|
||
|
endif
|
||
|
return user_register
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Allows you to push a new item on the yankring. Useful if something
|
||
|
" is in the clipboard and you want to add it to the yankring.
|
||
|
" Or if you yank something that is not mapped.
|
||
|
function! s:YRPush(...)
|
||
|
let user_register = s:YRRegister()
|
||
|
|
||
|
if a:0 > 0
|
||
|
" If no yank command has been supplied, assume it is
|
||
|
" a full line yank
|
||
|
let user_register = ((a:1 == '') ? user_register : a:1)
|
||
|
endif
|
||
|
|
||
|
" If we are pushing something on to the yankring, add it to
|
||
|
" the default buffer as well so the next item pasted will
|
||
|
" be the item pushed
|
||
|
let default_buffer = ((&clipboard=~'\<unnamed\>')?'*':((&clipboard=~'\<unnamedplus\>' && has('unnamedplus'))?'+':'"'))
|
||
|
call setreg(default_buffer, getreg(user_register),
|
||
|
\ getregtype(user_register))
|
||
|
|
||
|
call s:YRSetPrevOP('', '', '', 'n')
|
||
|
call YRRecord(user_register)
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Allows you to pop off any element from the yankring.
|
||
|
" If no parameters are provided the first element is removed.
|
||
|
" If a vcount is provided, that many elements are removed
|
||
|
" from the top.
|
||
|
function! s:YRPop(...)
|
||
|
if s:yr_count == 0
|
||
|
call s:YRWarningMsg('YR: yankring is empty')
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
let v_count = 1
|
||
|
if a:0 > 1
|
||
|
let v_count = a:2
|
||
|
endif
|
||
|
|
||
|
" If the user provided a parameter, remove that element
|
||
|
" from the yankring.
|
||
|
" If no parameter was provided assume the first element.
|
||
|
let elem_index = 0
|
||
|
if a:0 > 0
|
||
|
" Get the element # from the parameter
|
||
|
let elem_index = matchstr(a:1, '\d\+')
|
||
|
let elem_index = elem_index - 1
|
||
|
endif
|
||
|
|
||
|
" If the user entered a count, then remove that many
|
||
|
" elements from the ring.
|
||
|
while v_count > 0
|
||
|
call s:YRMRUDel('s:yr_history_list', elem_index)
|
||
|
let v_count = v_count - 1
|
||
|
endwhile
|
||
|
|
||
|
" If the yankring window is open, refresh it
|
||
|
call s:YRWindowUpdate()
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Adds this value to the yankring.
|
||
|
function! YRRecord(...)
|
||
|
|
||
|
let register = '"'
|
||
|
if a:0 > 0
|
||
|
" If no yank command has been supplied, assume it is
|
||
|
" a full line yank
|
||
|
let register = ((a:1 == '') ? register : a:1)
|
||
|
endif
|
||
|
|
||
|
" v:register can be blank in some (unknown) cases
|
||
|
" if v:register == '' || v:register == '_'
|
||
|
if v:register == '_'
|
||
|
" Black hole register, ignore recording the operation
|
||
|
return ""
|
||
|
endif
|
||
|
|
||
|
let register = ((&clipboard=~'\<unnamed\>')?'*':((&clipboard=~'\<unnamedplus\>' && has('unnamedplus'))?'+':register))
|
||
|
|
||
|
" let s:yr_prev_changenr = changenr()
|
||
|
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'
|
||
|
\ , getreg(register)
|
||
|
\ , 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 ""
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Adds this value to the yankring.
|
||
|
function! YRRecord3(...)
|
||
|
let register = '"'
|
||
|
|
||
|
if a:0 > 0 && a:1 != ''
|
||
|
let register = a:1
|
||
|
else
|
||
|
" v:register can be blank in some (unknown) cases
|
||
|
" if v:register == '' || v:register == '_'
|
||
|
if v:register == '_'
|
||
|
" Black hole register, ignore recording the operation
|
||
|
return ""
|
||
|
endif
|
||
|
|
||
|
let register = s:YRRegister()
|
||
|
|
||
|
if &clipboard =~ '\<unnamed\>' && register == '*'
|
||
|
" unnamed A variant of "unnamed" flag which uses the clipboard
|
||
|
" register '*' (|quote|) for all operations except yank.
|
||
|
" Yank shall copy the text into register '*' when "unnamed"
|
||
|
" is included.
|
||
|
"
|
||
|
let register = '*'
|
||
|
|
||
|
" The + and * registers are not modified by yank operations.
|
||
|
" We do not know what operation triggered this event so do a
|
||
|
" simple check if the register values have changed.
|
||
|
" If not, check it against the " register. Use which ever
|
||
|
" one has changed.
|
||
|
if s:yr_prev_clipboard_star == '' || getreg(register) == s:yr_prev_clipboard_star
|
||
|
if getreg('"') != getreg(register)
|
||
|
let register = '"'
|
||
|
endif
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
if has('unnamedplus') && &clipboard =~ '\<unnamedplus\>' && register == '+'
|
||
|
" unnamedplus A variant of "unnamed" flag which uses the clipboard
|
||
|
" register '+' (|quoteplus|) instead of register '*' for all
|
||
|
" operations except yank. Yank shall copy the text into
|
||
|
" register '+' and also into '*' when "unnamed" is included.
|
||
|
"
|
||
|
let register = '+'
|
||
|
|
||
|
" The + and * registers are not modified by yank operations.
|
||
|
" We do not know what operation triggered this event so do a
|
||
|
" simple check if the register values have changed.
|
||
|
" If not, check it against the " register. Use which ever
|
||
|
" one has changed.
|
||
|
if s:yr_prev_clipboard_plus == '' || getreg(register) == s:yr_prev_clipboard_plus
|
||
|
if getreg('"') != getreg(register)
|
||
|
let register = '"'
|
||
|
endif
|
||
|
endif
|
||
|
endif
|
||
|
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
|
||
|
|
||
|
if s:yr_remove_omap_dot == 1
|
||
|
call s:YRMapsCreate('add_only_zap_keys')
|
||
|
endif
|
||
|
|
||
|
" Add item to list
|
||
|
" This will also account for duplicates.
|
||
|
call s:YRMRUAdd( 's:yr_history_list'
|
||
|
\ , getreg(register)
|
||
|
\ , 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 ""
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Record the operation for the dot operator
|
||
|
function! s:YRSetPrevOP(op_code, count, reg, mode)
|
||
|
let s:yr_prev_op_code = a:op_code
|
||
|
let s:yr_prev_op_mode = a:mode
|
||
|
let s:yr_prev_count = a:count
|
||
|
let s:yr_prev_changenr = changenr()
|
||
|
let s:yr_prev_reg = a:reg
|
||
|
let s:yr_prev_reg_unnamed = getreg('"')
|
||
|
let s:yr_prev_reg_small = getreg('-')
|
||
|
let s:yr_prev_reg_insert = getreg('.')
|
||
|
let s:yr_prev_vis_lstart = line("'<")
|
||
|
let s:yr_prev_vis_lend = line("'>")
|
||
|
let s:yr_prev_vis_cstart = col("'<")
|
||
|
let s:yr_prev_vis_cend = col("'>")
|
||
|
let s:yr_prev_reg_expres = histget('=', -1)
|
||
|
|
||
|
if a:mode == 'n'
|
||
|
" In normal mode, the change has already
|
||
|
" occurred, therefore we can mark the
|
||
|
" actual position of the change.
|
||
|
let s:yr_prev_chg_lstart = line("'[")
|
||
|
let s:yr_prev_chg_lend = line("']")
|
||
|
let s:yr_prev_chg_cstart = col("'[")
|
||
|
let s:yr_prev_chg_cend = col("']")
|
||
|
else
|
||
|
" If in operator pending mode, the change
|
||
|
" has not yet occurred. Therefore we cannot
|
||
|
" use the '[ and ]' markers. But we can
|
||
|
" store the current line position.
|
||
|
let s:yr_prev_chg_lstart = line(".")
|
||
|
let s:yr_prev_chg_lend = line(".")
|
||
|
let s:yr_prev_chg_cstart = col(".")
|
||
|
let s:yr_prev_chg_cend = col(".")
|
||
|
endif
|
||
|
|
||
|
" If storing the last change position (using '[, '])
|
||
|
" is not good enough, then another option is to:
|
||
|
" Use :redir on the :changes command
|
||
|
" and grab the last item. Store this value
|
||
|
" and compare it is YRDoRepeat.
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Adds this value to the yankring.
|
||
|
function! s:YRDoRepeat()
|
||
|
let dorepeat = 0
|
||
|
|
||
|
if s:yr_has_voperator == 1
|
||
|
" Let Vim handle the repeat, just capture the updates
|
||
|
" as usual.
|
||
|
return 0
|
||
|
endif
|
||
|
|
||
|
if s:yr_prev_op_code =~ '^c'
|
||
|
" You cannot repeat change operations, let Vim's
|
||
|
" standard mechanism handle these, or the user will
|
||
|
" be prompted again, instead of repeating the
|
||
|
" previous change.
|
||
|
return 0
|
||
|
endif
|
||
|
|
||
|
if g:yankring_manage_numbered_reg == 1
|
||
|
" When resetting the numbered register we are
|
||
|
" must ignore the comparison of the " register.
|
||
|
if s:yr_prev_reg_small == getreg('-') &&
|
||
|
\ s:yr_prev_reg_insert == getreg('.') &&
|
||
|
\ s:yr_prev_reg_expres == histget('=', -1) &&
|
||
|
\ s:yr_prev_vis_lstart == line("'<") &&
|
||
|
\ s:yr_prev_vis_lend == line("'>") &&
|
||
|
\ s:yr_prev_vis_cstart == col("'<") &&
|
||
|
\ s:yr_prev_vis_cend == col("'>") &&
|
||
|
\ s:yr_prev_chg_lstart == line("'[") &&
|
||
|
\ s:yr_prev_chg_lend == line("']") &&
|
||
|
\ s:yr_prev_chg_cstart == col("'[") &&
|
||
|
\ s:yr_prev_chg_cend == col("']")
|
||
|
let dorepeat = 1
|
||
|
endif
|
||
|
else
|
||
|
" Check the previously recorded value of the registers
|
||
|
" if they are the same, we need to reissue the previous
|
||
|
" yankring command.
|
||
|
" If any are different, the user performed a command
|
||
|
" command that did not involve the yankring, therefore
|
||
|
" we should just issue the standard "normal! ." to repeat it.
|
||
|
if s:yr_prev_reg_unnamed == getreg('"') &&
|
||
|
\ s:yr_prev_reg_small == getreg('-') &&
|
||
|
\ s:yr_prev_reg_insert == getreg('.') &&
|
||
|
\ s:yr_prev_reg_expres == histget('=', -1) &&
|
||
|
\ s:yr_prev_vis_lstart == line("'<") &&
|
||
|
\ s:yr_prev_vis_lend == line("'>") &&
|
||
|
\ s:yr_prev_vis_cstart == col("'<") &&
|
||
|
\ s:yr_prev_vis_cend == col("'>")
|
||
|
let dorepeat = 1
|
||
|
endif
|
||
|
if dorepeat == 1 && s:yr_prev_op_mode == 'n'
|
||
|
" Hmm, not sure why I was doing this now
|
||
|
" so I will remove it
|
||
|
" let dorepeat = 0
|
||
|
" if s:yr_prev_chg_lstart == line("'[") &&
|
||
|
" \ s:yr_prev_chg_lend == line("']") &&
|
||
|
" \ s:yr_prev_chg_cstart == col("'[") &&
|
||
|
" \ s:yr_prev_chg_cend == col("']")
|
||
|
" let dorepeat = 1
|
||
|
" endif
|
||
|
elseif dorepeat == 1 && s:yr_prev_op_mode == 'o'
|
||
|
" Hmm, not sure why I was doing this now
|
||
|
" so I will remove it
|
||
|
" let dorepeat = 0
|
||
|
" if s:yr_prev_chg_lstart == line("'[") &&
|
||
|
" \ s:yr_prev_chg_lend == line("']") &&
|
||
|
" \ s:yr_prev_chg_cstart == col("'[") &&
|
||
|
" \ s:yr_prev_chg_cend == col("']")
|
||
|
" let dorepeat = 1
|
||
|
" endif
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
" " If another change has happened that was not part of the
|
||
|
" " yankring we cannot replay it (from the yankring). Use
|
||
|
" " the standard ".".
|
||
|
" " If the previous op was a change, do not use the yankring
|
||
|
" " to repeat it.
|
||
|
" " changenr() is buffer specific, so anytime you move to
|
||
|
" " a different buffer you will definitely perform a
|
||
|
" " standard "."
|
||
|
" " Any previous op that was a change, must be replaced using "."
|
||
|
" " since we do not want the user prompted to enter text again.
|
||
|
" if s:yr_prev_changenr == changenr() && s:yr_prev_op_code !~ '^c'
|
||
|
" let dorepeat = 1
|
||
|
" endif
|
||
|
|
||
|
" If we are going to repeat check to see if the
|
||
|
" previous command was a yank operation. If so determine
|
||
|
" if yank operations are allowed to be repeated.
|
||
|
if dorepeat == 1 && s:yr_prev_op_code =~ '^y'
|
||
|
" This value be default is set based on cpoptions.
|
||
|
if g:yankring_dot_repeat_yank == 0
|
||
|
let dorepeat = 0
|
||
|
endif
|
||
|
endif
|
||
|
return dorepeat
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Manages the Vim's numbered registers
|
||
|
function! s: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
|
||
|
|
||
|
" There are a few actions that Vim automatically takes
|
||
|
" when modifying the numbered registers.
|
||
|
" Modifying register 1 - changes the named register.
|
||
|
" It is impossible to set register 2 to a value, since Vim will change it.
|
||
|
|
||
|
" This will at least preserve the default register
|
||
|
let @" = @0
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" This internal function will add and subtract values from a starting
|
||
|
" point and return the correct element number. It takes into account
|
||
|
" the circular nature of the yankring.
|
||
|
function! s:YRGetNextElem(start, iter)
|
||
|
|
||
|
let needed_elem = a:start + a:iter
|
||
|
|
||
|
" The yankring is a ring, so if an element is
|
||
|
" requested beyond the number of elements, we
|
||
|
" must wrap around the ring.
|
||
|
if needed_elem > s:yr_count
|
||
|
let needed_elem = needed_elem % s:yr_count
|
||
|
endif
|
||
|
|
||
|
if needed_elem == 0
|
||
|
" Can happen at the end or beginning of the ring
|
||
|
if a:iter == -1
|
||
|
" Wrap to the bottom of the ring
|
||
|
let needed_elem = s:yr_count
|
||
|
else
|
||
|
" Wrap to the top of the ring
|
||
|
let needed_elem = 1
|
||
|
endif
|
||
|
elseif needed_elem < 1
|
||
|
" As we step backwards through the ring we could ask for a negative
|
||
|
" value, this will wrap it around to the end
|
||
|
let needed_elem = s:yr_count
|
||
|
endif
|
||
|
|
||
|
return needed_elem
|
||
|
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Lets Vim natively perform the operation and then stores what
|
||
|
" was yanked (or deleted) into the yankring.
|
||
|
" Supports this for example - 5"ayy
|
||
|
"
|
||
|
" This is a legacy function now since the release of Vim 7.2
|
||
|
" and the use of omaps with YankRing 5.0 and above.
|
||
|
" If Vim 7.1 has patch205, then the new omaps and the v:operator
|
||
|
" variable is used instead.
|
||
|
function! s:YRYankCount(...) range
|
||
|
|
||
|
let user_register = s:YRRegister()
|
||
|
let v_count = v:count
|
||
|
|
||
|
" Default yank command to the entire line
|
||
|
let op_code = 'yy'
|
||
|
if a:0 > 0
|
||
|
" If no yank command has been supplied, assume it is
|
||
|
" a full line yank
|
||
|
let op_code = ((a:1 == '') ? op_code : a:1)
|
||
|
endif
|
||
|
|
||
|
if op_code == '.'
|
||
|
if s:YRDoRepeat() == 1
|
||
|
if s:yr_prev_op_code != ''
|
||
|
let op_code = s:yr_prev_op_code
|
||
|
let v_count = s:yr_prev_count
|
||
|
let user_register = s:yr_prev_reg
|
||
|
endif
|
||
|
else
|
||
|
" Set this flag so that YRRecord will
|
||
|
" ignore repeats
|
||
|
let s:yr_prev_repeating = 1
|
||
|
exec "normal! ."
|
||
|
return
|
||
|
endif
|
||
|
else
|
||
|
let s:yr_prev_repeating = 0
|
||
|
endif
|
||
|
|
||
|
" Supports this for example - 5"ayy
|
||
|
" A delete operation will still place the items in the
|
||
|
" default registers as well as the named register
|
||
|
exec "normal! ".
|
||
|
\ ((v_count > 0)?(v_count):'').
|
||
|
\ (user_register=='"'?'':'"'.user_register).
|
||
|
\ op_code
|
||
|
|
||
|
if user_register == '_'
|
||
|
" Black hole register, ignore recording the operation
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
call s:YRSetPrevOP(op_code, v_count, user_register, 'n')
|
||
|
|
||
|
call YRRecord(user_register)
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Handles ranges. There are visual ranges and command line ranges.
|
||
|
" Visual ranges are easy, since we pass through and let Vim deal
|
||
|
" with those directly.
|
||
|
" Command line ranges means we must yank the entire line, and not
|
||
|
" just a portion of it.
|
||
|
function! s:YRYankRange(do_delete_selection, ...) range
|
||
|
|
||
|
let user_register = s:YRRegister()
|
||
|
let default_buffer = ((&clipboard=~'\<unnamed\>')?'*':((&clipboard=~'\<unnamedplus\>' && has('unnamedplus'))?'+':'"'))
|
||
|
|
||
|
" Default command mode to normal mode 'n'
|
||
|
let cmd_mode = 'n'
|
||
|
if a:0 > 0
|
||
|
" Change to visual mode, if command executed via
|
||
|
" a visual map
|
||
|
let cmd_mode = ((a:1 == 'v') ? 'v' : 'n')
|
||
|
endif
|
||
|
|
||
|
if a:do_delete_selection == 1
|
||
|
" Save register 0
|
||
|
" Register 0 should only be changed by yank operations
|
||
|
" if we are deleting text, this could inadvertently
|
||
|
" update this register.
|
||
|
let zero_register = [0, getreg(0), getregtype('0')]
|
||
|
endif
|
||
|
|
||
|
if cmd_mode == 'v'
|
||
|
" We are yanking either an entire line, or a range
|
||
|
" We want to yank the text first (even in a delete) since
|
||
|
" the rules around which registers get updated are a bit
|
||
|
" complicated. For deletes, it depends on how large
|
||
|
" the delete is for which registers get updated.
|
||
|
exec "normal! gv".
|
||
|
\ (user_register==default_buffer?'':'"'.user_register).
|
||
|
\ 'y'
|
||
|
if a:do_delete_selection == 1
|
||
|
exec "normal! gv".
|
||
|
\ (user_register==default_buffer?'':'"'.user_register).
|
||
|
\ 'd'
|
||
|
endif
|
||
|
else
|
||
|
" In normal mode, always yank the complete line, since this
|
||
|
" command is for a range. YRYankCount is used for parts
|
||
|
" of a single line
|
||
|
if a:do_delete_selection == 1
|
||
|
exec a:firstline . ',' . a:lastline . 'delete '.user_register
|
||
|
else
|
||
|
exec a:firstline . ',' . a:lastline . 'yank ' . user_register
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
if a:do_delete_selection == 1
|
||
|
" Restore register zero
|
||
|
call call('setreg', zero_register)
|
||
|
endif
|
||
|
|
||
|
if user_register == '_'
|
||
|
" Black hole register, ignore
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
call s:YRSetPrevOP('', '', user_register, 'n')
|
||
|
call YRRecord(user_register)
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Paste from either the yankring or from a specified register
|
||
|
" Optionally a count can be provided, so paste the same value 10 times
|
||
|
function! s:YRPaste(replace_last_paste_selection, nextvalue, direction, ...)
|
||
|
if g:yankring_manual_clipboard_check == 1
|
||
|
call s:YRCheckClipboard()
|
||
|
endif
|
||
|
|
||
|
" Disabling the yankring removes the default maps.
|
||
|
" But there are some maps the user can create on their own, and
|
||
|
" these would most likely call this function. So place an extra
|
||
|
" check and display a message.
|
||
|
if g:yankring_enabled == 0
|
||
|
call s:YRWarningMsg(
|
||
|
\ 'YR: The yankring is currently disabled, use YRToggle.'
|
||
|
\ )
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
let user_register = s:YRRegister()
|
||
|
let default_register = ((&clipboard=~'\<unnamed\>')?'*':((&clipboard=~'\<unnamedplus\>' && has('unnamedplus'))?'+':'"'))
|
||
|
let default_register = '"'
|
||
|
let clipboard_default = matchstr( &clipboard, '\<unnamed\w*\>' )
|
||
|
if has('unnamedplus') && clipboard_default == '\<unnamedplus\>' && (v:register == '' || v:register == '"')
|
||
|
let default_register = '+'
|
||
|
endif
|
||
|
if clipboard_default =~ '\<unnamed\>' && (v:register == '' || v:register == '"')
|
||
|
let default_register = '*'
|
||
|
endif
|
||
|
let v_count = v:count
|
||
|
|
||
|
" Default command mode to normal mode 'n'
|
||
|
let cmd_mode = 'n'
|
||
|
if a:0 > 0
|
||
|
" Change to visual mode, if command executed via
|
||
|
" a visual map
|
||
|
let cmd_mode = ((a:1 == 'v') ? 'v' : 'n')
|
||
|
endif
|
||
|
|
||
|
if a:replace_last_paste_selection == 1
|
||
|
" Replacing the previous put
|
||
|
let start = line("'[")
|
||
|
let end = line("']")
|
||
|
|
||
|
if start != line('.')
|
||
|
call s:YRWarningMsg( 'YR: You must paste text first, before you can replace' )
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
if start == 0 || end == 0
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" If a count was provided (ie 5<C-P>), multiply the
|
||
|
" nextvalue accordingly and position the next paste index
|
||
|
" let which_elem = a:nextvalue * ((v_count > 0)?(v_count):1) * -1
|
||
|
let which_elem = matchstr(a:nextvalue, '-\?\d\+') * ((v_count > 0)?(v_count):1) * -1
|
||
|
let s:yr_last_paste_idx = s:YRGetNextElem(
|
||
|
\ s:yr_last_paste_idx, which_elem
|
||
|
\ )
|
||
|
|
||
|
let save_reg = getreg(default_register)
|
||
|
let save_reg_type = getregtype(default_register)
|
||
|
call setreg( default_register
|
||
|
\ , s:YRGetValElemNbr((s:yr_last_paste_idx-1),'v')
|
||
|
\ , s:YRGetValElemNbr((s:yr_last_paste_idx-1),'t')
|
||
|
\ )
|
||
|
|
||
|
" First undo the previous paste
|
||
|
exec "normal! u"
|
||
|
" Check if the visual selection should be reselected
|
||
|
" Next paste the correct item from the ring
|
||
|
" This is done as separate statements since it appeared that if
|
||
|
" there was nothing to undo, the paste never happened.
|
||
|
exec "normal! ".
|
||
|
\ ((s:yr_prev_vis_mode==0) ? "" : "gv").
|
||
|
\ '"'.default_register.
|
||
|
\ s:yr_paste_dir
|
||
|
call setreg(default_register, save_reg, save_reg_type)
|
||
|
call s:YRSetPrevOP('', '', '', 'n')
|
||
|
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" User has decided to bypass the yankring and specify a specific
|
||
|
" register
|
||
|
if user_register != default_register
|
||
|
" if a:replace_last_paste_selection == 1
|
||
|
" call s:YRWarningMsg( 'YR: A register cannot be specified in replace mode' )
|
||
|
" return
|
||
|
" endif
|
||
|
|
||
|
" Check for the expression register, in this special case
|
||
|
" we must copy it's evaluation into the default buffer and paste
|
||
|
if user_register == '='
|
||
|
" Save the default register since Vim will only
|
||
|
" allow the expression register to be pasted once
|
||
|
" and will revert back to the default buffer
|
||
|
let save_default_reg = @"
|
||
|
call setreg(default_register, eval(histget('=', -1)) )
|
||
|
else
|
||
|
let user_register = '"'.user_register
|
||
|
endif
|
||
|
exec "normal! ".
|
||
|
\ ((cmd_mode=='n') ? "" : "gv").
|
||
|
\ ((v_count > 0)?(v_count):'').
|
||
|
\ ((user_register=='=')?'':user_register).
|
||
|
\ a:direction
|
||
|
if user_register == '='
|
||
|
let @" = save_default_reg
|
||
|
endif
|
||
|
" In this case, we have bypassed the yankring
|
||
|
" If the user hits next or previous we want the
|
||
|
" next item pasted to be the top of the yankring.
|
||
|
let s:yr_last_paste_idx = 1
|
||
|
|
||
|
let s:yr_paste_dir = a:direction
|
||
|
let s:yr_prev_vis_mode = ((cmd_mode=='n') ? 0 : 1)
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" Try to second guess the user to make these mappings less intrusive.
|
||
|
" If the user hits paste, compare the contents of the paste register
|
||
|
" to the current entry in the yankring. If they are different, lets
|
||
|
" assume the user wants the contents of the paste register.
|
||
|
" The user could have:
|
||
|
" let @" = 'test string'
|
||
|
" would not be in the yankring as no mapping triggered this action.
|
||
|
if a:replace_last_paste_selection != 1
|
||
|
" Only check the default buffer is the user wants us to.
|
||
|
" This was necessary prior to version 4.0 since we did not
|
||
|
" capture as many items as 4.0 and above does. (A. Budden)
|
||
|
if g:yankring_paste_check_default_register == 1
|
||
|
if ( default_register == '"' && getreg(default_register) != s:yr_prev_reg_unnamed )
|
||
|
" There are only a couple of scenarios where this would happen
|
||
|
" 1. set clipboard = unnamed[plus]
|
||
|
" The user performs an action which changes the
|
||
|
" unnamed register (i.e. x - delete character)
|
||
|
" 2. Any type of direct manipulation of the registers
|
||
|
" let @" = 'something'
|
||
|
" 3. Something changed the system clipboard outside of Vim
|
||
|
if getreg('"') != s:yr_prev_reg_unnamed
|
||
|
let default_register = '"'
|
||
|
endif
|
||
|
|
||
|
" The user has performed a yank / delete operation
|
||
|
" outside of the yankring maps. First, add this
|
||
|
" value to the yankring.
|
||
|
call YRRecord(default_register)
|
||
|
elseif ( default_register == '+' &&
|
||
|
\ !empty(getreg(default_register)) &&
|
||
|
\ getreg(default_register) != s:yr_prev_clipboard_plus
|
||
|
\ )
|
||
|
|
||
|
" The user has performed a yank / delete operation
|
||
|
" outside of the yankring maps. First, add this
|
||
|
" value to the yankring.
|
||
|
call YRRecord(default_register)
|
||
|
elseif ( default_register == '*' &&
|
||
|
\ !empty(getreg(default_register)) &&
|
||
|
\ getreg(default_register) != s:yr_prev_clipboard_star
|
||
|
\ )
|
||
|
|
||
|
" The user has performed a yank / delete operation
|
||
|
" outside of the yankring maps. First, add this
|
||
|
" value to the yankring.
|
||
|
call YRRecord(default_register)
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
exec "normal! ".
|
||
|
\ ((cmd_mode=='n') ? "" : "gv").
|
||
|
\ ((v_count > 0)?(v_count):'').
|
||
|
\ '"'.default_register.
|
||
|
\ a:direction
|
||
|
let s:yr_paste_dir = a:direction
|
||
|
let s:yr_prev_vis_mode = ((cmd_mode=='n') ? 0 : 1)
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" if s:yr_count > 0 || (
|
||
|
" \ default_register != '"' &&
|
||
|
" \ empty(getreg(default_register))
|
||
|
" \ )
|
||
|
" " Nothing to paste
|
||
|
" return
|
||
|
" endif
|
||
|
|
||
|
" User hit p or P
|
||
|
" Supports this for example - 5"ayy
|
||
|
" And restores the current register
|
||
|
let save_reg = getreg(default_register)
|
||
|
let save_reg_type = getregtype(default_register)
|
||
|
let s:yr_last_paste_idx = 1
|
||
|
call setreg(default_register
|
||
|
\ , s:YRGetValElemNbr(0,'v')
|
||
|
\ , s:YRGetValElemNbr(0,'t')
|
||
|
\ )
|
||
|
exec "normal! ".
|
||
|
\ ((cmd_mode=='n') ? "" : "gv").
|
||
|
\ ((v_count > 0)?(v_count):'').
|
||
|
\ '"'.default_register.
|
||
|
\ a:direction
|
||
|
call setreg(default_register, save_reg, save_reg_type)
|
||
|
call s:YRSetPrevOP(
|
||
|
\ a:direction
|
||
|
\ , v_count
|
||
|
\ , default_register
|
||
|
\ , 'n'
|
||
|
\ )
|
||
|
let s:yr_paste_dir = a:direction
|
||
|
let s:yr_prev_vis_mode = ((cmd_mode=='n') ? 0 : 1)
|
||
|
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Handle any omaps
|
||
|
function! YRMapsExpression(sid, motion, ...)
|
||
|
let cmds = a:motion
|
||
|
" echomsg "YRMapsE:".localtime()
|
||
|
" echomsg "YRMapsE 1:".cmds.":".v:operator.":".s:yr_maps_created_zap
|
||
|
|
||
|
if (a:motion =~ '\.' && s:yr_remove_omap_dot == 1) || a: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()
|
||
|
" after the action of the replay is completed.
|
||
|
call s:YRMapsDelete('remove_only_zap_keys')
|
||
|
endif
|
||
|
|
||
|
" Check if we are in operator-pending mode
|
||
|
if a:motion =~ '\('.substitute(g:yankring_zap_keys, ' ', '\\|', 'g').'\)'
|
||
|
if a:motion =~ '\(/\|?\)'
|
||
|
let zapto = (a:0==0 ? "" : input("YR:Enter string:"))
|
||
|
if zapto != ""
|
||
|
let zapto = zapto . "\<CR>"
|
||
|
else
|
||
|
let zapto = "\<C-C>"
|
||
|
endif
|
||
|
else
|
||
|
let zapto = (a:0==0 ? "" : s:YRGetChar())
|
||
|
endif
|
||
|
|
||
|
if zapto == "\<C-C>"
|
||
|
" Abort if the user hits Control C
|
||
|
call s:YRWarningMsg( "YR:Aborting command:".v:operator.a:motion )
|
||
|
return "\<C-C>"
|
||
|
endif
|
||
|
|
||
|
let cmds = cmds . zapto
|
||
|
endif
|
||
|
|
||
|
" There are a variety of commands which do not change the
|
||
|
" registers, so these operators should be ignored when
|
||
|
" determining which operations to record
|
||
|
" Simple example is '=' which simply formats the
|
||
|
" the selected text.
|
||
|
if ' \('.escape(join(split(g:yankring_ignore_operator), '\|'), '/.*~$^[]' ).'\) ' !~ escape(v:operator, '/.*~$^[]')
|
||
|
" Check if we are performing an action that will
|
||
|
" take us into insert mode
|
||
|
if '[cCsS]' !~ escape(v:operator, '/.*~$^[]') && a:motion !~ '@'
|
||
|
" if '[cCsS]' !~ escape(v:operator, '/.*~$^[]')
|
||
|
" If we have not entered insert mode, feed the call
|
||
|
" to record the current change when the function ends.
|
||
|
" This is necessary since omaps do not update registers
|
||
|
" until the function completes.
|
||
|
" The InsertLeave event will handle the motions
|
||
|
" that place us in insert mode and record the
|
||
|
" changes when insert mode ends.
|
||
|
" let cmds .= a:sid. "yrrecord ".a:motion
|
||
|
let cmds .= a:sid. "yrrecord"
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
" This will not work since we are already executing an expression
|
||
|
" if a:motion =~ '@'
|
||
|
" let cmds = 'normal! ' . cmds
|
||
|
" endif
|
||
|
|
||
|
" YRRecord3() 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
|
||
|
|
||
|
|
||
|
" Handle macros (@).
|
||
|
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()
|
||
|
" after the action of the replay is completed.
|
||
|
call s:YRMapsDelete('remove_only_zap_keys')
|
||
|
|
||
|
" Greg Sexton indicated the use of nr2char() removes
|
||
|
" a "Press ENTER ..." prompt when executing a macro.
|
||
|
" let zapto = nr2char(getchar())
|
||
|
" let zapto = (a:0==0 ? "" : s:YRGetChar())
|
||
|
let zapto = s:YRGetChar()
|
||
|
|
||
|
if zapto == "\<C-C>"
|
||
|
" Abort if the user hits Control C
|
||
|
call s:YRWarningMsg( "YR:Aborting macro" )
|
||
|
return ""
|
||
|
endif
|
||
|
|
||
|
if zapto !~ '\(\w\|@\|:\)'
|
||
|
" Abort if the user does not specify a register
|
||
|
call s:YRWarningMsg( "YR:No register specified, aborting macro" )
|
||
|
return ""
|
||
|
endif
|
||
|
|
||
|
let v_count = v:count
|
||
|
" If no count was specified it will have a value of 0
|
||
|
" so set it to at least 1
|
||
|
let v_count = ((v_count > 0)?(v_count):'')
|
||
|
|
||
|
" let range = ''
|
||
|
" if a:firstline != a:lastline
|
||
|
" let rannge = a:firstline.','.a:lastline
|
||
|
" endif
|
||
|
|
||
|
" let cmd = range."normal! ".v_count.'@'.zapto
|
||
|
let cmd = "normal! ".v_count.'@'.zapto
|
||
|
" DEBUG
|
||
|
" echomsg cmd
|
||
|
exec cmd
|
||
|
|
||
|
call s:YRMapsCreate('add_only_zap_keys')
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Create the default maps
|
||
|
function! s:YRMapsCreate(...)
|
||
|
" 7.1.patch205 introduces the v:operator function which was
|
||
|
" essential to gain the omap support.
|
||
|
if s:yr_has_voperator == 1
|
||
|
let s:yr_remove_omap_dot = 1
|
||
|
for key in split(g:yankring_zap_keys)
|
||
|
try
|
||
|
if key != '@'
|
||
|
exec 'omap <expr>' key 'YRMapsExpression("<SID>", "'. key. '", 1)'
|
||
|
endif
|
||
|
catch
|
||
|
endtry
|
||
|
endfor
|
||
|
endif
|
||
|
|
||
|
" silent! nmap <expr> @ YRMapsExpression("<SID>", "@", "1")
|
||
|
silent! nmap @ :<C-U>YRMapsMacro<CR>
|
||
|
|
||
|
let s:yr_maps_created_zap = 1
|
||
|
|
||
|
if a:0 > 0
|
||
|
" We have only removed the _zap_ keys temporarily
|
||
|
" so abandon further changes.
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" 7.1.patch205 introduces the v:operator function which was essential
|
||
|
" to gain the omap support.
|
||
|
if s:yr_has_voperator == 1
|
||
|
let s:yr_remove_omap_dot = 1
|
||
|
" Set option to add and remove _zap_ keys when
|
||
|
" repeating commands
|
||
|
let o_maps = split(g:yankring_o_keys)
|
||
|
" Loop through and prompt the user for all buffer connection parameters.
|
||
|
for key in o_maps
|
||
|
exec 'omap <expr>' key 'YRMapsExpression("<SID>", "'. escape(key,'\"'). '")'
|
||
|
endfor
|
||
|
endif
|
||
|
|
||
|
" Iterate through a space separated list of mappings and create
|
||
|
" calls to the YRYankCount function
|
||
|
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 <silent>'.key." :<C-U>YRYankCount '".key."'<CR>"
|
||
|
" exec 'nnoremap <silent>'.key." :<C-U>YRYankCount '".key."'<CR>"
|
||
|
" Andy Wokula's suggestion
|
||
|
exec 'nmap' key key."<SID>yrrecord"
|
||
|
endfor
|
||
|
|
||
|
if g:yankring_map_dot == 1
|
||
|
if s:yr_has_voperator == 1
|
||
|
nmap <expr> . YRMapsExpression("<SID>", ".")
|
||
|
else
|
||
|
nnoremap <silent> . :<C-U>YRYankCount '.'<CR>
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
if g:yankring_v_key != ''
|
||
|
exec 'xnoremap <silent>'.g:yankring_v_key." :YRYankRange 'v'<CR>"
|
||
|
endif
|
||
|
if g:yankring_del_v_key != ''
|
||
|
for v_map in split(g:yankring_del_v_key)
|
||
|
if !empty(v_map)
|
||
|
try
|
||
|
exec 'xnoremap <silent>'.v_map." :YRDeleteRange 'v'<CR>"
|
||
|
catch
|
||
|
endtry
|
||
|
endif
|
||
|
endfor
|
||
|
endif
|
||
|
if g:yankring_paste_n_bkey != ''
|
||
|
exec 'nnoremap <silent>'.g:yankring_paste_n_bkey." :<C-U>YRPaste 'P'<CR>"
|
||
|
if g:yankring_paste_using_g == 1
|
||
|
exec 'nnoremap <silent> g'.g:yankring_paste_n_bkey." :<C-U>YRPaste 'gP'<CR>"
|
||
|
endif
|
||
|
endif
|
||
|
if g:yankring_paste_n_akey != ''
|
||
|
exec 'nnoremap <silent>'.g:yankring_paste_n_akey." :<C-U>YRPaste 'p'<CR>"
|
||
|
if g:yankring_paste_using_g == 1
|
||
|
exec 'nnoremap <silent> g'.g:yankring_paste_n_akey." :<C-U>YRPaste 'gp'<CR>"
|
||
|
endif
|
||
|
endif
|
||
|
if g:yankring_paste_v_bkey != ''
|
||
|
exec 'xnoremap <silent>'.g:yankring_paste_v_bkey." :<C-U>YRPaste 'P', 'v'<CR>"
|
||
|
endif
|
||
|
if g:yankring_paste_v_akey != ''
|
||
|
exec 'xnoremap <silent>'.g:yankring_paste_v_akey." :<C-U>YRPaste 'p', 'v'<CR>"
|
||
|
endif
|
||
|
if g:yankring_replace_n_pkey != ''
|
||
|
exec 'nnoremap <silent>'.g:yankring_replace_n_pkey." :<C-U>YRReplace '-1', P<CR>"
|
||
|
endif
|
||
|
if g:yankring_replace_n_nkey != ''
|
||
|
exec 'nnoremap <silent>'.g:yankring_replace_n_nkey." :<C-U>YRReplace '1', p<CR>"
|
||
|
endif
|
||
|
|
||
|
let g:yankring_enabled = 1
|
||
|
let s:yr_maps_created = 1
|
||
|
|
||
|
if exists('*YRRunAfterMaps')
|
||
|
" This will allow you to override the default maps if necessary
|
||
|
call YRRunAfterMaps()
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
|
||
|
" Create the default maps
|
||
|
function! s:YRMapsDelete(...)
|
||
|
|
||
|
let o_maps = split(g:yankring_zap_keys)
|
||
|
for key in o_maps
|
||
|
try
|
||
|
" Why not remove the @ map?
|
||
|
if key != '@'
|
||
|
silent! exec 'ounmap' key
|
||
|
endif
|
||
|
catch
|
||
|
endtry
|
||
|
endfor
|
||
|
|
||
|
let s:yr_maps_created_zap = 0
|
||
|
|
||
|
if a:0 > 0
|
||
|
" We have only removed the _zap_ keys temporarily
|
||
|
" so abandon further changes.
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" Iterate through a space separated list of mappings and create
|
||
|
" calls to an appropriate YankRing function
|
||
|
let n_maps = split(g:yankring_n_keys)
|
||
|
" Loop through and prompt the user for all buffer connection parameters.
|
||
|
for key in n_maps
|
||
|
try
|
||
|
silent! exec 'nunmap' key
|
||
|
catch
|
||
|
endtry
|
||
|
endfor
|
||
|
|
||
|
let o_maps = split(g:yankring_o_keys)
|
||
|
for key in o_maps
|
||
|
try
|
||
|
silent! exec 'ounmap' key
|
||
|
catch
|
||
|
endtry
|
||
|
endfor
|
||
|
|
||
|
if g:yankring_map_dot == 1
|
||
|
silent! exec "nunmap ."
|
||
|
endif
|
||
|
if g:yankring_v_key != ''
|
||
|
silent! exec 'vunmap '.g:yankring_v_key
|
||
|
endif
|
||
|
if g:yankring_del_v_key != ''
|
||
|
for v_map in split(g:yankring_del_v_key)
|
||
|
if !empty(v_map)
|
||
|
try
|
||
|
silent! exec 'vunmap '.v_map
|
||
|
catch
|
||
|
endtry
|
||
|
endif
|
||
|
endfor
|
||
|
endif
|
||
|
if g:yankring_paste_n_bkey != ''
|
||
|
silent! exec 'nunmap '.g:yankring_paste_n_bkey
|
||
|
if g:yankring_paste_using_g == 1
|
||
|
silent! exec 'nunmap g'.g:yankring_paste_n_bkey
|
||
|
endif
|
||
|
endif
|
||
|
if g:yankring_paste_n_akey != ''
|
||
|
silent! exec 'nunmap '.g:yankring_paste_n_akey
|
||
|
if g:yankring_paste_using_g == 1
|
||
|
silent! exec 'nunmap g'.g:yankring_paste_n_akey
|
||
|
endif
|
||
|
endif
|
||
|
if g:yankring_paste_v_bkey != ''
|
||
|
silent! exec 'vunmap '.g:yankring_paste_v_bkey
|
||
|
endif
|
||
|
if g:yankring_paste_v_akey != ''
|
||
|
silent! exec 'vunmap '.g:yankring_paste_v_akey
|
||
|
endif
|
||
|
if g:yankring_replace_n_pkey != ''
|
||
|
silent! exec 'nunmap '.g:yankring_replace_n_pkey
|
||
|
endif
|
||
|
if g:yankring_replace_n_nkey != ''
|
||
|
silent! exec 'nunmap '.g:yankring_replace_n_nkey
|
||
|
endif
|
||
|
|
||
|
silent! exec 'nunmap @'
|
||
|
|
||
|
let g:yankring_enabled = 0
|
||
|
let s:yr_maps_created = 0
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRGetValElemNbr( position, type )
|
||
|
let needed_elem = a:position
|
||
|
|
||
|
" The List which contains the items in the yankring
|
||
|
" history is also ordered, most recent at the top
|
||
|
let elem = s:YRMRUGet('s:yr_history_list', needed_elem)
|
||
|
|
||
|
if a:type == 't'
|
||
|
let elem = matchstr(elem, '^.*,\zs.*$')
|
||
|
else
|
||
|
let elem = matchstr(elem, '^.*\ze,.*$')
|
||
|
if s:yr_history_version == 'v1'
|
||
|
" Match three @@@ in a row as long as it is not
|
||
|
" preceded by a @@@
|
||
|
" v1
|
||
|
let elem = substitute(elem, s:yr_history_v1_nl_pat, "\n", 'g')
|
||
|
let elem = substitute(elem, '\\@', '@', 'g')
|
||
|
else
|
||
|
let elem = substitute(elem, s:yr_history_v2_nl_pat, "\n", 'g')
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
return elem
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRMRUReset( mru_list )
|
||
|
let {a:mru_list} = []
|
||
|
|
||
|
return 1
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRMRUSize( mru_list )
|
||
|
return len({a:mru_list})
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRMRUElemFormat( element, element_type )
|
||
|
let elem = a:element
|
||
|
if g:yankring_max_element_length != 0
|
||
|
let elem = strpart(a:element, 0, g:yankring_max_element_length)
|
||
|
if (g:yankring_warn_on_truncate > 0)
|
||
|
let bytes = len (a:element) - len(elem)
|
||
|
if (bytes > 0)
|
||
|
call s:YRWarningMsg("Yankring truncated its element by ".
|
||
|
\ bytes.
|
||
|
\ " bytes due to a g:yankring_max_element_length of ".
|
||
|
\ g:yankring_max_element_length
|
||
|
\ )
|
||
|
endif
|
||
|
endif
|
||
|
endif
|
||
|
if s:yr_history_version == 'v1'
|
||
|
let elem = escape(elem, '@')
|
||
|
let elem = substitute(elem, "\n", s:yr_history_v1_nl, 'g')
|
||
|
else
|
||
|
let elem = substitute(elem, "\n", s:yr_history_v2_nl, 'g')
|
||
|
endif
|
||
|
" Append the regtype to the end so we have it available
|
||
|
let elem = elem.",".a:element_type
|
||
|
|
||
|
return elem
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRMRUHas( mru_list, find_str )
|
||
|
" This function will find a string and return the element #
|
||
|
let find_idx = index({a:mru_list}, a:find_str)
|
||
|
|
||
|
return find_idx
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRMRUGet( mru_list, position )
|
||
|
" This function will return the value of the item at a:position
|
||
|
" Find the value of one element
|
||
|
let value = get({a:mru_list}, a:position, -2)
|
||
|
|
||
|
return value
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRMRUAdd( mru_list, element, element_type )
|
||
|
" Only add new items if they do not already exist in the MRU.
|
||
|
" If the item is found, move it to the start of the MRU.
|
||
|
let found = -1
|
||
|
" let elem = a:element
|
||
|
" if g:yankring_max_element_length != 0
|
||
|
" let elem = strpart(a:element, 0, g:yankring_max_element_length)
|
||
|
" endif
|
||
|
" if s:yr_history_version == 'v1'
|
||
|
" let elem = escape(elem, '@')
|
||
|
" let elem = substitute(elem, "\n", s:yr_history_v1_nl, 'g')
|
||
|
" else
|
||
|
" let elem = substitute(elem, "\n", s:yr_history_v2_nl, 'g')
|
||
|
" endif
|
||
|
" " Append the regtype to the end so we have it available
|
||
|
" let elem = elem.",".a:element_type
|
||
|
|
||
|
if strlen(a:element) < g:yankring_min_element_length
|
||
|
return 1
|
||
|
endif
|
||
|
|
||
|
let elem = s:YRMRUElemFormat(a:element, a:element_type)
|
||
|
|
||
|
" Refresh the List
|
||
|
call s:YRHistoryRead()
|
||
|
|
||
|
let found = s:YRMRUHas(a:mru_list, elem)
|
||
|
|
||
|
" Special case for efficiency, if it is first item in the
|
||
|
" List, do nothing
|
||
|
if found != 0
|
||
|
if found != -1
|
||
|
" Remove found item since we will add it to the top
|
||
|
call remove({a:mru_list}, found)
|
||
|
endif
|
||
|
call insert({a:mru_list}, elem, 0)
|
||
|
let s:yr_count = len({a:mru_list})
|
||
|
call s:YRHistorySave()
|
||
|
endif
|
||
|
|
||
|
return 1
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRMRUDel( mru_list, elem_nbr )
|
||
|
if a:elem_nbr >= 0 && a:elem_nbr < s:yr_count
|
||
|
call remove({a:mru_list}, a:elem_nbr)
|
||
|
let s:yr_count = len({a:mru_list})
|
||
|
call s:YRHistorySave()
|
||
|
endif
|
||
|
|
||
|
return 1
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRHistoryDelete()
|
||
|
let s:yr_history_list = []
|
||
|
let s:yr_count = 0
|
||
|
|
||
|
if g:yankring_persist != 1
|
||
|
return
|
||
|
endif
|
||
|
let yr_filename = s:yr_history_file_{s:yr_history_version}
|
||
|
|
||
|
if filereadable(yr_filename)
|
||
|
let rc = delete(yr_filename)
|
||
|
if rc != 0
|
||
|
call s:YRErrorMsg(
|
||
|
\ 'YRHistoryDelete: Unable to delete the yankring history file: '.
|
||
|
\ yr_filename
|
||
|
\ )
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
return 0
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRHistoryRead()
|
||
|
if g:yankring_persist != 1
|
||
|
return
|
||
|
endif
|
||
|
let refresh_needed = 1
|
||
|
let yr_history_list = []
|
||
|
let yr_filename = s:yr_history_file_{s:yr_history_version}
|
||
|
|
||
|
if filereadable(yr_filename)
|
||
|
let last_upd = getftime(yr_filename)
|
||
|
|
||
|
if s:yr_history_last_upd != 0 && last_upd <= s:yr_history_last_upd
|
||
|
let refresh_needed = 0
|
||
|
endif
|
||
|
|
||
|
if refresh_needed == 1
|
||
|
let s:yr_history_list = readfile(yr_filename)
|
||
|
let s:yr_history_last_upd = last_upd
|
||
|
let s:yr_count = len(s:yr_history_list)
|
||
|
return
|
||
|
else
|
||
|
return
|
||
|
endif
|
||
|
else
|
||
|
if s:yr_history_version == 'v2'
|
||
|
" Check to see if an upgrade is required
|
||
|
" else, let the empty yr_history_list be returned.
|
||
|
if filereadable(s:yr_history_file_v1)
|
||
|
" Perform upgrade to v2 of the history file
|
||
|
call s:YRHistoryUpgrade('v1')
|
||
|
return
|
||
|
endif
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
let s:yr_history_list = yr_history_list
|
||
|
call s:YRHistorySave()
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRHistorySave()
|
||
|
|
||
|
if len(s:yr_history_list) > g:yankring_max_history
|
||
|
" Remove items which exceed the max # specified
|
||
|
call remove(s:yr_history_list, g:yankring_max_history, (len(s:yr_history_list)-1))
|
||
|
let s:yr_count = len(s:yr_history_list)
|
||
|
endif
|
||
|
|
||
|
if g:yankring_persist != 1
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
let yr_filename = s:yr_history_file_{s:yr_history_version}
|
||
|
let rc = writefile(s:yr_history_list, yr_filename)
|
||
|
|
||
|
if rc == 0
|
||
|
let s:yr_history_last_upd = getftime(yr_filename)
|
||
|
else
|
||
|
call s:YRErrorMsg(
|
||
|
\ 'YRHistorySave: Unable to save yankring history file: '.
|
||
|
\ yr_filename
|
||
|
\ )
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRHistoryUpgrade(version)
|
||
|
if a:version == 'v1'
|
||
|
if filereadable(s:yr_history_file_v1)
|
||
|
let v1_list = readfile(s:yr_history_file_v1)
|
||
|
let v2_list = []
|
||
|
for elem in v1_list
|
||
|
" Restore from version 1
|
||
|
let elem = substitute(elem, s:yr_history_v1_nl_pat, "\n", 'g')
|
||
|
let elem = substitute(elem, '\\@', '@', 'g')
|
||
|
" Encode to version 2
|
||
|
let elem = substitute(elem, "\n", s:yr_history_v2_nl, 'g')
|
||
|
call add(v2_list, elem)
|
||
|
endfor
|
||
|
let s:yr_history_list = v2_list
|
||
|
call s:YRHistorySave()
|
||
|
call s:YRWarningMsg(
|
||
|
\ "YR:History file:".
|
||
|
\ s:yr_history_file_v1.
|
||
|
\ ' has been upgraded.'
|
||
|
\ )
|
||
|
endif
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
" YRWindowUpdate
|
||
|
" Checks if the yankring window is already open.
|
||
|
" If it is, it will refresh it.
|
||
|
function! s:YRWindowUpdate()
|
||
|
let orig_win_bufnr = bufwinnr('%')
|
||
|
|
||
|
" Switch to the yankring buffer
|
||
|
" only if it is already visible
|
||
|
if bufwinnr(s:yr_buffer_id) != -1
|
||
|
call s:YRShow(0)
|
||
|
" Switch back to the original buffer
|
||
|
exec orig_win_bufnr . "wincmd w"
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
" YRWindowStatus
|
||
|
" Displays a brief command list and option settings.
|
||
|
" It also will toggle the Help text.
|
||
|
function! s:YRWindowStatus(show_help)
|
||
|
let full_help = 0
|
||
|
let orig_win_bufnr = bufwinnr('%')
|
||
|
let yr_win_bufnr = bufwinnr(s:yr_buffer_id)
|
||
|
|
||
|
if yr_win_bufnr == -1
|
||
|
" Do not update the window status since the
|
||
|
" yankring is not currently displayed.
|
||
|
return ""
|
||
|
endif
|
||
|
" Switch to the yankring buffer
|
||
|
if orig_win_bufnr != yr_win_bufnr
|
||
|
" If the buffer is visible, switch to it
|
||
|
exec yr_win_bufnr . "wincmd w"
|
||
|
endif
|
||
|
|
||
|
let msg = 'AutoClose='.g:yankring_window_auto_close.
|
||
|
\ ';ClipboardMonitor='.g:yankring_clipboard_monitor.
|
||
|
\ ';Inserts='.g:yankring_record_insert.
|
||
|
\ ';Cmds:<enter>,[g]p,[g]P,1-9,d,r,s,a,c,i,u,R,q,<space>;Help=?'.
|
||
|
\ (s:yr_search==""?"":';SearchRegEx='.s:yr_search)
|
||
|
|
||
|
if s:yr_has_voperator == 0
|
||
|
let msg = msg . "\nYankRing has limited functionality without Vim 7.2 or higher"
|
||
|
endif
|
||
|
|
||
|
" Toggle help by checking the first line of the buffer
|
||
|
if a:show_help == 1 && getline(1) !~ 'selection'
|
||
|
let full_help = 1
|
||
|
let msg =
|
||
|
\ '" <enter> : [p]aste selection'."\n".
|
||
|
\ '" double-click : [p]aste selection'."\n".
|
||
|
\ '" [g]p : [g][p]aste selection'."\n".
|
||
|
\ '" [g]P : [g][P]aste selection'."\n".
|
||
|
\ '" 1-9 : Paste # entry from the YankRing (shortcut for speed)'."\n".
|
||
|
\ '" d : [d]elete item from the YankRing'."\n".
|
||
|
\ '" r : [p]aste selection in reverse order'."\n".
|
||
|
\ '" s : [s]earch the yankring for text'."\n".
|
||
|
\ '" u : [u]pdate display show YankRing'."\n".
|
||
|
\ '" R : [R]egisters display'."\n".
|
||
|
\ '" a : toggle [a]utoclose setting'."\n".
|
||
|
\ '" c : toggle [c]lipboard monitor setting'."\n".
|
||
|
\ '" i : toggle [i]nsert recording'."\n".
|
||
|
\ '" q : [q]uit / close the yankring window'."\n".
|
||
|
\ '" ? : Remove help text'."\n".
|
||
|
\ '" <space> : toggles the width of the window'."\n".
|
||
|
\ '" AutoClose : See yankring.txt, yankring_window_auto_close'."\n".
|
||
|
\ '" ClipboardMonitor: See yankring.txt, yankring_clipboard_monitor'."\n".
|
||
|
\ '" Inserts : See yankring.txt, yankring_record_insert'."\n".
|
||
|
\ '" YankRing Version: '.g:loaded_yankring."\n".
|
||
|
\ msg
|
||
|
endif
|
||
|
|
||
|
let saveMod = &modifiable
|
||
|
|
||
|
" Go to the top of the buffer and remove any previous status
|
||
|
" Use the blackhole register so it does not affect the yankring
|
||
|
setlocal modifiable
|
||
|
exec 0
|
||
|
silent! exec 'norm! "_d/^---'."\n"
|
||
|
call histdel("search", -1)
|
||
|
|
||
|
silent! 0put =msg
|
||
|
|
||
|
" Erase it's contents to the blackhole
|
||
|
silent! exec '%g/^\s*$/delete _'
|
||
|
call histdel("search", -1)
|
||
|
|
||
|
call cursor(1,1)
|
||
|
if full_help == 0
|
||
|
call search('^\d', 'W')
|
||
|
endif
|
||
|
|
||
|
let &modifiable = saveMod
|
||
|
|
||
|
if orig_win_bufnr != s:yr_buffer_id
|
||
|
exec orig_win_bufnr . "wincmd w"
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
" YRWindowOpen
|
||
|
" Display the Most Recently Used file list in a temporary window.
|
||
|
function! s:YRWindowOpen(results)
|
||
|
|
||
|
" Setup the cpoptions properly for the maps to work
|
||
|
" and to not set the alternate buffer
|
||
|
let old_cpoptions = &cpoptions
|
||
|
set cpoptions&vim
|
||
|
set cpoptions-=a
|
||
|
set cpoptions-=A
|
||
|
|
||
|
" Save the current buffer number. The yankring will switch back to
|
||
|
" this buffer when an action is taken.
|
||
|
let s:yr_buffer_last = bufnr('%')
|
||
|
let s:yr_buffer_last_winnr = winnr()
|
||
|
|
||
|
if bufwinnr(s:yr_buffer_id) == -1
|
||
|
if g:yankring_window_use_horiz == 1
|
||
|
if g:yankring_window_use_bottom == 1
|
||
|
let location = 'botright'
|
||
|
else
|
||
|
let location = 'topleft'
|
||
|
" Creating the new window will offset all other
|
||
|
" window numbers. Account for that so we switch
|
||
|
" back to the correct window.
|
||
|
let s:yr_buffer_last_winnr = s:yr_buffer_last_winnr + 1
|
||
|
endif
|
||
|
let win_size = g:yankring_window_height
|
||
|
else
|
||
|
" Open a horizontally split window. Increase the window size, if
|
||
|
" needed, to accommodate the new window
|
||
|
if g:yankring_window_width &&
|
||
|
\ &columns < (80 + g:yankring_window_width)
|
||
|
" Store the previous window size of the YankRing
|
||
|
let s:yr_winsize_chgd = &columns
|
||
|
" One extra column is needed to include the vertical split
|
||
|
let &columns = &columns + g:yankring_window_width + 1
|
||
|
else
|
||
|
let s:yr_winsize_chgd = 0
|
||
|
endif
|
||
|
|
||
|
if g:yankring_window_use_right == 1
|
||
|
" Open the window at the rightmost place
|
||
|
let location = 'botright vertical'
|
||
|
else
|
||
|
" Open the window at the leftmost place
|
||
|
let location = 'topleft vertical'
|
||
|
" Creating the new window will offset all other
|
||
|
" window numbers. Account for that so we switch
|
||
|
" back to the correct window.
|
||
|
let s:yr_buffer_last_winnr = s:yr_buffer_last_winnr + 1
|
||
|
endif
|
||
|
let win_size = g:yankring_window_width
|
||
|
endif
|
||
|
|
||
|
" Special consideration was involved with these sequence
|
||
|
" of commands.
|
||
|
" First, split the current buffer.
|
||
|
" Second, edit a new file.
|
||
|
" Third record the buffer number.
|
||
|
" If a different sequence is followed when the yankring
|
||
|
" buffer is closed, Vim's alternate buffer is the yanking
|
||
|
" instead of the original buffer before the yankring
|
||
|
" was shown.
|
||
|
let cmd_mod = ''
|
||
|
if v:version >= 700
|
||
|
let cmd_mod = 'keepalt '
|
||
|
endif
|
||
|
exec 'silent! ' . cmd_mod . location . ' ' . win_size . 'split '
|
||
|
|
||
|
" Using :e and hide prevents the alternate buffer
|
||
|
" from being changed.
|
||
|
exec ":e " . escape(g:yankring_buffer_name, ' ')
|
||
|
" Save buffer id
|
||
|
let s:yr_buffer_id = bufnr('%') + 0
|
||
|
else
|
||
|
" If the buffer is visible, switch to it
|
||
|
exec bufwinnr(s:yr_buffer_id) . "wincmd w"
|
||
|
endif
|
||
|
|
||
|
" Perform a double check to ensure we have entered the correct
|
||
|
" buffer since we don't want to do the %d_ in the wrong buffer!
|
||
|
if (bufnr('%') + 0) != s:yr_buffer_id
|
||
|
call s:YRWarningMsg(
|
||
|
\ "YR:Failed to change to the yankring buffer, please contact author id:".
|
||
|
\ s:yr_buffer_id.
|
||
|
\ ' last:'.s:yr_buffer_last
|
||
|
\ )
|
||
|
return -1
|
||
|
endif
|
||
|
|
||
|
" Mark the buffer as scratch
|
||
|
setlocal buftype=nofile
|
||
|
setlocal bufhidden=hide
|
||
|
setlocal noswapfile
|
||
|
setlocal nowrap
|
||
|
setlocal nonumber
|
||
|
setlocal nobuflisted
|
||
|
setlocal noreadonly
|
||
|
setlocal nospell
|
||
|
setlocal modifiable
|
||
|
if v:version >= 703
|
||
|
setlocal norelativenumber
|
||
|
endif
|
||
|
|
||
|
" set up syntax highlighting
|
||
|
syn match yankringTitle #^--- YankRing ---$#hs=s+4,he=e-4
|
||
|
syn match yankringHeaders #^Elem Content$#
|
||
|
syn match yankringItemNumber #^\d\+#
|
||
|
|
||
|
syn match yankringKey #^AutoClose.*<enter>#hs=e-6
|
||
|
syn match yankringKey #^AutoClose.*\[g\]p#hs=e-3 contains=yankringKey
|
||
|
syn match yankringKey #^AutoClose.*\[g\]P#hs=e-3 contains=yankringKey
|
||
|
syn match yankringKey #^AutoClose.*,d,#hs=e-1,he=e-1 contains=yankringKey
|
||
|
syn match yankringKey #^AutoClose.*,r,#hs=e-1,he=e-1 contains=yankringKey
|
||
|
syn match yankringKey #^AutoClose.*,s,#hs=e-1,he=e-1 contains=yankringKey
|
||
|
syn match yankringKey #^AutoClose.*,a,#hs=e-1,he=e-1 contains=yankringKey
|
||
|
syn match yankringKey #^AutoClose.*,c,#hs=e-1,he=e-1 contains=yankringKey
|
||
|
syn match yankringKey #^AutoClose.*,i,#hs=e-1,he=e-1 contains=yankringKey
|
||
|
syn match yankringKey #^AutoClose.*,u,#hs=e-1,he=e-1 contains=yankringKey
|
||
|
syn match yankringKey #^AutoClose.*,R,#hs=e-1,he=e-1 contains=yankringKey
|
||
|
syn match yankringKey #^AutoClose.*,q,#hs=e-1,he=e-1 contains=yankringKey
|
||
|
syn match yankringKey #^AutoClose.*<space>#hs=e-6 contains=yankringKey
|
||
|
syn match yankringKey #^AutoClose.*?$#hs=e contains=yankringKey
|
||
|
|
||
|
syn match yankringKey #^".*:#hs=s+1,he=e-1
|
||
|
syn match yankringHelp #^".*$# contains=yankringKey
|
||
|
|
||
|
hi link yankringTitle directory
|
||
|
hi link yankringHeaders keyword
|
||
|
hi link yankringItemNumber constant
|
||
|
hi link yankringKey identifier
|
||
|
hi link yankringHelp string
|
||
|
|
||
|
" Clear all existing maps for this buffer
|
||
|
" We should do this for all maps, but I am not sure how to do
|
||
|
" this for this buffer/window only without affecting all the
|
||
|
" other buffers.
|
||
|
mapclear <buffer>
|
||
|
" Create a mapping to act upon the yankring
|
||
|
nnoremap <buffer> <silent> <2-LeftMouse> :call <SID>YRWindowActionN('p' , 'n')<CR>
|
||
|
nnoremap <buffer> <silent> <CR> :call <SID>YRWindowActionN('p' , 'n')<CR>
|
||
|
xnoremap <buffer> <silent> <CR> :call <SID>YRWindowAction ('p' , 'v')<CR>
|
||
|
nnoremap <buffer> <silent> p :call <SID>YRWindowActionN('p' , 'n')<CR>
|
||
|
nnoremap <buffer> <silent> [p :call <SID>YRWindowActionN('[p' , 'n')<CR>
|
||
|
nnoremap <buffer> <silent> ]p :call <SID>YRWindowActionN(']p' , 'n')<CR>
|
||
|
xnoremap <buffer> <silent> p :call <SID>YRWindowAction ('p' , 'v')<CR>
|
||
|
xnoremap <buffer> <silent> [p :call <SID>YRWindowAction ('[p' , 'v')<CR>
|
||
|
xnoremap <buffer> <silent> ]p :call <SID>YRWindowAction (']p' , 'v')<CR>
|
||
|
nnoremap <buffer> <silent> P :call <SID>YRWindowActionN('P' , 'n')<CR>
|
||
|
nnoremap <buffer> <silent> [P :call <SID>YRWindowActionN('[P' , 'n')<CR>
|
||
|
nnoremap <buffer> <silent> ]P :call <SID>YRWindowActionN(']P' , 'n')<CR>
|
||
|
xnoremap <buffer> <silent> P :call <SID>YRWindowAction ('P' , 'v')<CR>
|
||
|
xnoremap <buffer> <silent> [P :call <SID>YRWindowAction ('[P' , 'v')<CR>
|
||
|
xnoremap <buffer> <silent> ]P :call <SID>YRWindowAction (']P' , 'v')<CR>
|
||
|
nnoremap <buffer> <silent> gp :call <SID>YRWindowActionN('gp' , 'n')<CR>
|
||
|
xnoremap <buffer> <silent> gp :call <SID>YRWindowAction ('gp' , 'v')<CR>
|
||
|
nnoremap <buffer> <silent> gP :call <SID>YRWindowActionN('gP' , 'n')<CR>
|
||
|
xnoremap <buffer> <silent> gP :call <SID>YRWindowAction ('gP' , 'v')<CR>
|
||
|
nnoremap <buffer> <silent> d :call <SID>YRWindowActionN('d' , 'n')<CR>
|
||
|
xnoremap <buffer> <silent> d :call <SID>YRWindowAction ('d' , 'v')<CR>
|
||
|
xnoremap <buffer> <silent> r :call <SID>YRWindowAction ('r' , 'v')<CR>
|
||
|
nnoremap <buffer> <silent> s :call <SID>YRWindowAction ('s' , 'n')<CR>
|
||
|
nnoremap <buffer> <silent> a :call <SID>YRWindowAction ('a' , 'n')<CR>
|
||
|
nnoremap <buffer> <silent> c :call <SID>YRWindowAction ('c' , 'n')<CR>
|
||
|
nnoremap <buffer> <silent> i :call <SID>YRWindowAction ('i' , 'n')<CR>
|
||
|
nnoremap <buffer> <silent> ? :call <SID>YRWindowAction ('?' , 'n')<CR>
|
||
|
nnoremap <buffer> <silent> u :call <SID>YRWindowAction ('u' , 'n')<CR>
|
||
|
nnoremap <buffer> <silent> q :call <SID>YRWindowAction ('q' , 'n')<CR>
|
||
|
nnoremap <buffer> <silent> R :call <SID>YRWindowAction ('R' , 'n')<CR>
|
||
|
nnoremap <buffer> <silent> 1 :call <SID>YRWindowAction ('q' ,'n')<CR>:call <SID>YRGetElem(1)<CR>
|
||
|
nnoremap <buffer> <silent> 2 :call <SID>YRWindowAction ('q' ,'n')<CR>:call <SID>YRGetElem(2)<CR>
|
||
|
nnoremap <buffer> <silent> 3 :call <SID>YRWindowAction ('q' ,'n')<CR>:call <SID>YRGetElem(3)<CR>
|
||
|
nnoremap <buffer> <silent> 4 :call <SID>YRWindowAction ('q' ,'n')<CR>:call <SID>YRGetElem(4)<CR>
|
||
|
nnoremap <buffer> <silent> 5 :call <SID>YRWindowAction ('q' ,'n')<CR>:call <SID>YRGetElem(5)<CR>
|
||
|
nnoremap <buffer> <silent> 6 :call <SID>YRWindowAction ('q' ,'n')<CR>:call <SID>YRGetElem(6)<CR>
|
||
|
nnoremap <buffer> <silent> 7 :call <SID>YRWindowAction ('q' ,'n')<CR>:call <SID>YRGetElem(7)<CR>
|
||
|
nnoremap <buffer> <silent> 8 :call <SID>YRWindowAction ('q' ,'n')<CR>:call <SID>YRGetElem(8)<CR>
|
||
|
nnoremap <buffer> <silent> 9 :call <SID>YRWindowAction ('q' ,'n')<CR>:call <SID>YRGetElem(9)<CR>
|
||
|
nnoremap <buffer> <silent> <space> \|:silent exec 'vertical resize '.
|
||
|
\ (
|
||
|
\ g:yankring_window_use_horiz!=1 && winwidth('.') > g:yankring_window_width
|
||
|
\ ?(g:yankring_window_width)
|
||
|
\ :(winwidth('.') + g:yankring_window_increment)
|
||
|
\ )<CR>
|
||
|
|
||
|
" Erase it's contents to the blackhole
|
||
|
silent! exec '%delete _'
|
||
|
|
||
|
" Display the status line / help
|
||
|
call s:YRWindowStatus(0)
|
||
|
exec 'normal! G'
|
||
|
|
||
|
" Display the contents of the yankring
|
||
|
silent! put =a:results
|
||
|
|
||
|
if getline('$') == ''
|
||
|
" Erase last blank line
|
||
|
silent! exec '$delete _'
|
||
|
endif
|
||
|
|
||
|
" Move the cursor to the first line with an element
|
||
|
exec 0
|
||
|
call search('^\d','W')
|
||
|
|
||
|
setlocal nomodifiable
|
||
|
"
|
||
|
" Restore the previous cpoptions settings
|
||
|
let &cpoptions = old_cpoptions
|
||
|
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRWindowActionN(op, cmd_mode)
|
||
|
let v_count = v:count
|
||
|
" If no count was specified it will have a value of 0
|
||
|
" so set it to at least 1
|
||
|
let v_count = ((v_count > 0)?(v_count):1)
|
||
|
|
||
|
if v_count > 1
|
||
|
if !exists("b:yankring_show_range_error")
|
||
|
let b:yankring_show_range_error = v_count
|
||
|
else
|
||
|
let b:yankring_show_range_error = b:yankring_show_range_error - 1
|
||
|
endif
|
||
|
|
||
|
if b:yankring_show_range_error == 1
|
||
|
call s:YRWarningMsg("YR:Use visual mode if you need to specify a count")
|
||
|
unlet b:yankring_show_range_error
|
||
|
endif
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
call s:YRWindowAction(a:op, a:cmd_mode)
|
||
|
let v_count = v_count - 1
|
||
|
|
||
|
if g:yankring_window_auto_close == 1 && v_count == 0 && a:op != 'd'
|
||
|
" If autoclose is set close the window unless
|
||
|
" you are removing items from the YankRing
|
||
|
exec 'bdelete '.s:yr_buffer_id
|
||
|
return ""
|
||
|
endif
|
||
|
|
||
|
return ""
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRWindowAction(op, cmd_mode) range
|
||
|
let default_buffer = ((&clipboard=~'\<unnamed\>')?'*':((&clipboard=~'\<unnamedplus\>' && has('unnamedplus'))?'+':'"'))
|
||
|
let opcode = a:op
|
||
|
let lines = []
|
||
|
let v_count = v:count
|
||
|
let cmd_mode = a:cmd_mode
|
||
|
let firstline = a:firstline
|
||
|
let lastline = a:lastline
|
||
|
|
||
|
if a:lastline < a:firstline
|
||
|
let firstline = a:lastline
|
||
|
let lastline = a:firstline
|
||
|
endif
|
||
|
|
||
|
if cmd_mode == 'n'
|
||
|
let v_count = 1
|
||
|
" If a count was provided (5p), we want to repeat the paste
|
||
|
" 5 times, but this also alters the a:firstline and a:lastline
|
||
|
" ranges, which while in normal mode we do not want
|
||
|
let lastline = firstline
|
||
|
endif
|
||
|
" If no count was specified it will have a value of 0
|
||
|
" so set it to at least 1
|
||
|
let v_count = ((v_count > 0)?(v_count):1)
|
||
|
|
||
|
if '\<[drP]\>' =~# opcode
|
||
|
" Reverse the order of the lines to act on
|
||
|
let begin = lastline
|
||
|
while begin >= firstline
|
||
|
call add(lines, getline(begin))
|
||
|
let begin = begin - 1
|
||
|
endwhile
|
||
|
else
|
||
|
" Process the selected items in order
|
||
|
let begin = firstline
|
||
|
while begin <= lastline
|
||
|
call add(lines, getline(begin))
|
||
|
let begin = begin + 1
|
||
|
endwhile
|
||
|
endif
|
||
|
|
||
|
if opcode ==# 'q'
|
||
|
" Close the yankring window
|
||
|
if s:yr_winsize_chgd > 0
|
||
|
" Adjust the Vim window width back to the width
|
||
|
" it was before we showed the yankring window
|
||
|
let &columns = s:yr_winsize_chgd
|
||
|
" Reset the indicator the window size was changed
|
||
|
let s:yr_winsize_chgd = 0
|
||
|
endif
|
||
|
|
||
|
" Hide the YankRing window
|
||
|
hide
|
||
|
|
||
|
if bufwinnr(s:yr_buffer_last) != -1
|
||
|
" If the buffer is visible, switch to it
|
||
|
exec s:yr_buffer_last_winnr . "wincmd w"
|
||
|
endif
|
||
|
|
||
|
return
|
||
|
elseif opcode ==# 's'
|
||
|
" Switch back to the original buffer
|
||
|
exec s:yr_buffer_last_winnr . "wincmd w"
|
||
|
|
||
|
call s:YRSearch()
|
||
|
return
|
||
|
elseif opcode ==# 'u'
|
||
|
" Switch back to the original buffer
|
||
|
exec s:yr_buffer_last_winnr . "wincmd w"
|
||
|
|
||
|
call s:YRShow(0)
|
||
|
return
|
||
|
elseif opcode ==# 'R'
|
||
|
" Switch back to the original buffer
|
||
|
exec s:yr_buffer_last_winnr . "wincmd w"
|
||
|
|
||
|
call s:YRShow(0, 'R')
|
||
|
return
|
||
|
elseif opcode ==# 'a'
|
||
|
let l:curr_line = line(".")
|
||
|
" Toggle the auto close setting
|
||
|
let g:yankring_window_auto_close =
|
||
|
\ (g:yankring_window_auto_close == 1?0:1)
|
||
|
" Display the status line / help
|
||
|
call s:YRWindowStatus(0)
|
||
|
call cursor(l:curr_line,0)
|
||
|
return
|
||
|
elseif opcode ==# 'c'
|
||
|
let l:curr_line = line(".")
|
||
|
" Toggle the clipboard monitor setting
|
||
|
let g:yankring_clipboard_monitor =
|
||
|
\ (g:yankring_clipboard_monitor == 1?0:1)
|
||
|
" Display the status line / help
|
||
|
call s:YRWindowStatus(0)
|
||
|
call cursor(l:curr_line,0)
|
||
|
return
|
||
|
elseif opcode ==# 'i'
|
||
|
let l:curr_line = line(".")
|
||
|
" Toggle the auto close setting
|
||
|
let g:yankring_record_insert =
|
||
|
\ (g:yankring_record_insert == 1?0:1)
|
||
|
" Display the status line / help
|
||
|
call s:YRWindowStatus(0)
|
||
|
call cursor(l:curr_line,0)
|
||
|
return
|
||
|
elseif opcode ==# '?'
|
||
|
" Display the status line / help
|
||
|
call s:YRWindowStatus(1)
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" Switch back to the original buffer
|
||
|
exec s:yr_buffer_last_winnr . "wincmd w"
|
||
|
|
||
|
" Intentional case insensitive comparison
|
||
|
if opcode =~? 'p'
|
||
|
let cmd = 'YRGetElem '
|
||
|
let parms = ", '".opcode."' "
|
||
|
elseif opcode ==? 'r'
|
||
|
let opcode = 'p'
|
||
|
let cmd = 'YRGetElem '
|
||
|
let parms = ", 'p' "
|
||
|
elseif opcode ==# 'd'
|
||
|
let cmd = 'YRPop '
|
||
|
let parms = ""
|
||
|
endif
|
||
|
|
||
|
" Only execute this code if we are operating on elements
|
||
|
" within the yankring
|
||
|
if '[auq?]' !~# opcode
|
||
|
while v_count > 0
|
||
|
" let iter = 0
|
||
|
" let index = 0
|
||
|
for line in lines
|
||
|
let elem = matchstr(line, '^\d\+')
|
||
|
if elem > 0
|
||
|
if elem > 0 && elem <= s:yr_count
|
||
|
" if iter > 0 && opcode =~# 'p'
|
||
|
if opcode =~# 'p'
|
||
|
" Move to the end of the last pasted item
|
||
|
" only if pasting after (not above)
|
||
|
" ']
|
||
|
endif
|
||
|
exec cmd . elem . parms
|
||
|
" let iter += 1
|
||
|
endif
|
||
|
endif
|
||
|
endfor
|
||
|
let v_count = v_count - 1
|
||
|
endwhile
|
||
|
|
||
|
if opcode ==# 'd'
|
||
|
call s:YRShow(0)
|
||
|
" Return the user to their last known position, assuming
|
||
|
" it is still available after the delete
|
||
|
if firstline < line("$")
|
||
|
call cursor(firstline,0)
|
||
|
else
|
||
|
call cursor(line("$"),0)
|
||
|
endif
|
||
|
return ""
|
||
|
endif
|
||
|
|
||
|
if g:yankring_window_auto_close == 1 && cmd_mode == 'v'
|
||
|
exec 'bdelete '.s:yr_buffer_id
|
||
|
return ""
|
||
|
endif
|
||
|
|
||
|
endif
|
||
|
|
||
|
return ""
|
||
|
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRWarningMsg(msg)
|
||
|
echohl WarningMsg
|
||
|
echomsg a:msg
|
||
|
echohl None
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRErrorMsg(msg)
|
||
|
echohl ErrorMsg
|
||
|
echomsg a:msg
|
||
|
echohl None
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRWinLeave()
|
||
|
" Track which window we are last in. We will use this information
|
||
|
" to determine where we need to paste any contents, or which
|
||
|
" buffer to return to.
|
||
|
|
||
|
if s:yr_buffer_id < 0
|
||
|
" The yankring window has never been activated
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
if winbufnr(winnr()) == s:yr_buffer_id
|
||
|
" Ignore leaving the yankring window
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
if bufwinnr(s:yr_buffer_id) != -1
|
||
|
" YankRing window is visible, so save off the previous buffer ids
|
||
|
let s:yr_buffer_last_winnr = winnr()
|
||
|
let s:yr_buffer_last = winbufnr(s:yr_buffer_last_winnr)
|
||
|
" else
|
||
|
" let s:yr_buffer_last_winnr = -1
|
||
|
" let s:yr_buffer_last = -1
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRFocusGained()
|
||
|
" FocusGained is not available in general by console vim.
|
||
|
" There are some terminal windows which support it though.
|
||
|
" This thread on vim_use covers some of it:
|
||
|
" http://groups.google.com/group/vim_use/browse_thread/thread/8dd3fb054ee922c6/59bee226473a9eea?lnk=gst&q=console+FocusGained#59bee226473a9eea
|
||
|
" http://groups.google.com/group/vim_dev/browse_thread/thread/ba58fb493a3cf4ba/dc1a22ba1e92579d?lnk=gst&q=terminal+FocusGained#dc1a22ba1e92579d
|
||
|
" Does not work:
|
||
|
" urxvt terminal
|
||
|
" Works:
|
||
|
" GTK2 GUI, on Fedora 11, both as gvim and as vim in a GNOME Terminal
|
||
|
"
|
||
|
" Simple test, create the following autocmd and gain and loose focus in
|
||
|
" the terminal:
|
||
|
" autocmd FocusLost * echomsg "focus lost"
|
||
|
" autocmd FocusGained * echomsg "focus gained"
|
||
|
call s:YRCheckClipboard()
|
||
|
|
||
|
" If the yankring window is open, refresh it
|
||
|
call s:YRWindowUpdate()
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRCheckClipboard()
|
||
|
if g:yankring_clipboard_monitor == 1
|
||
|
" If the clipboard has changed record it inside the yankring
|
||
|
" echomsg "YRCheckClipboard[".len(@*)."][".@*.']['.s:yr_prev_clipboard_star.']'
|
||
|
if has('unnamedplus') && &clipboard =~ '\<unnamedplus\>'
|
||
|
if !empty(@+) && @+ != s:yr_prev_clipboard_plus
|
||
|
let elem = s:YRMRUElemFormat(
|
||
|
\ getreg('+')
|
||
|
\ , getregtype('+')
|
||
|
\ )
|
||
|
let found = s:YRMRUHas('s:yr_history_list', elem)
|
||
|
|
||
|
" Only add the item to the "top" of the ring if it is
|
||
|
" not in the ring already.
|
||
|
if found == -1
|
||
|
call YRRecord3("+")
|
||
|
endif
|
||
|
let s:yr_prev_clipboard_plus = @+
|
||
|
endif
|
||
|
else
|
||
|
if !empty(@*) && @* != s:yr_prev_clipboard_star
|
||
|
let elem = s:YRMRUElemFormat(
|
||
|
\ getreg('*')
|
||
|
\ , getregtype('*')
|
||
|
\ )
|
||
|
let found = s:YRMRUHas('s:yr_history_list', elem)
|
||
|
|
||
|
" Only add the item to the "top" of the ring if it is
|
||
|
" not in the ring already.
|
||
|
if found == -1
|
||
|
call YRRecord3("*")
|
||
|
endif
|
||
|
let s:yr_prev_clipboard_star = @*
|
||
|
endif
|
||
|
endif
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
function! s:YRInsertLeave()
|
||
|
" The YankRing uses omaps to execute the prescribed motion
|
||
|
" and then appends to the motion a call to a YankRing
|
||
|
" function to record the contents of the changed register.
|
||
|
"
|
||
|
" We cannot append a function call to the end of a motion
|
||
|
" that results in Insert mode. For example, any command
|
||
|
" like 'cw' enters insert mode. Appending a function call
|
||
|
" after the w, simply writes out the call as if the user
|
||
|
" typed it.
|
||
|
"
|
||
|
" Using the InsertLeave event, allows us to capture the
|
||
|
" contents of any changed register after it completes.
|
||
|
|
||
|
call YRRecord(s:YRRegister())
|
||
|
|
||
|
" When performing a change (not a yank or delete)
|
||
|
" it is not possible to call <SID>yrrecord at the end
|
||
|
" of the command (or it's contents will be inserted
|
||
|
" into the buffer instead of executed).
|
||
|
" So, when using ".", we have to remove the _zap_
|
||
|
" keys and then re-add them back again after we
|
||
|
" record the updates.
|
||
|
if s:yr_remove_omap_dot == 1
|
||
|
call s:YRMapsCreate('add_only_zap_keys')
|
||
|
endif
|
||
|
|
||
|
" Check if we should record inserted text
|
||
|
if g:yankring_record_insert == 1
|
||
|
if !empty(@.) && @. != s:yr_prev_reg_insert
|
||
|
let elem = s:YRMRUElemFormat(
|
||
|
\ getreg('.')
|
||
|
\ , getregtype('.')
|
||
|
\ )
|
||
|
let found = s:YRMRUHas('s:yr_history_list', elem)
|
||
|
|
||
|
" Only add the item to the "top" of the ring if it is
|
||
|
" not in the ring already.
|
||
|
if found == -1
|
||
|
call YRRecord3(".")
|
||
|
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 <SID>YRFocusGained() | endif
|
||
|
autocmd WinLeave * :call <SID>YRWinLeave()
|
||
|
autocmd FocusGained * :if has('clipboard') | call <SID>YRFocusGained() | endif
|
||
|
autocmd InsertLeave * :call <SID>YRInsertLeave()
|
||
|
autocmd User YRSetNumberedReg :call <SID>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
|
||
|
augroup END
|
||
|
|
||
|
|
||
|
" copy register
|
||
|
inoremap <script> <SID>YRGetChar <c-r>=YRGetChar()<CR>
|
||
|
" inoremap <script> <SID>YRGetSearch <c-r>=YRGetSearch()<CR>
|
||
|
nnoremap <silent> <SID>yrrecord :call YRRecord3()<cr>
|
||
|
inoremap <silent> <SID>yrrecord <C-R>=YRRecord3()<cr>
|
||
|
|
||
|
|
||
|
" Public commands
|
||
|
command! YRClear call s:YRClear()
|
||
|
command! -nargs=0 YRMapsCreate call s:YRMapsCreate()
|
||
|
command! -nargs=0 YRMapsDelete call s:YRMapsDelete()
|
||
|
command! -range -bang -nargs=? YRDeleteRange <line1>,<line2>call s:YRYankRange(<bang>1, <args>)
|
||
|
command! -nargs=* YRGetElem call s:YRGetElem(<args>)
|
||
|
command! -bang -nargs=? YRGetMultiple call s:YRGetMultiple(<bang>0, <args>)
|
||
|
command! -count -register -nargs=* YRPaste call s:YRPaste(0,1,<args>)
|
||
|
command! -nargs=? YRPop <line1>,<line2>call s:YRPop(<args>)
|
||
|
command! -register -nargs=? YRPush call s:YRPush(<args>)
|
||
|
command! -nargs=* YRReplace call s:YRPaste(1,<f-args>)
|
||
|
command! -nargs=? YRSearch call s:YRSearch(<q-args>)
|
||
|
command! -nargs=? YRShow call s:YRShow(<args>)
|
||
|
command! -nargs=? YRToggle call s:YRToggle(<args>)
|
||
|
command! -nargs=? YRCheckClipboard call s:YRCheckClipboard(<args>)
|
||
|
command! -count -register -nargs=* YRYankCount call s:YRYankCount(<args>)
|
||
|
command! -range -bang -nargs=? YRYankRange <line1>,<line2>call s:YRYankRange(<bang>0, <args>)
|
||
|
command! -count=1 -bang -nargs=0 YRMapsMacro call s:YRMapsMacro(<bang>0, <args>)
|
||
|
|
||
|
" Menus
|
||
|
" 0: Turns the menu off.
|
||
|
if has("menu") && g:yankring_default_menu_mode != 0
|
||
|
if g:yankring_default_menu_mode == 1
|
||
|
" 1: Turns the 'Yankring' menu on with no menu shortcut.
|
||
|
let menuRoot = 'YankRing'
|
||
|
let menuPriority = ''
|
||
|
elseif g:yankring_default_menu_mode == 2
|
||
|
" 2: Turns the 'Yankring 'menu on with <alt>-y as the shortcut.
|
||
|
let menuRoot = '&YankRing'
|
||
|
let menuPriority = ''
|
||
|
elseif g:yankring_default_menu_mode == 3
|
||
|
" 3: Turns the 'Plugin -> YankRing' menu on with <alt>-y as the shortcut.
|
||
|
let menuRoot = exists("g:yankring_menu_root") ? g:yankring_menu_root : '&Plugin.&YankRing'
|
||
|
let menuPriority = exists("g:yankring_menu_priority") ? yankring_menu_priority : ''
|
||
|
else
|
||
|
" 3: Turns the 'Plugin -> YankRing' menu on with <alt>-y as the shortcut.
|
||
|
let menuRoot = '&Plugin.&YankRing'
|
||
|
let menuPriority = ''
|
||
|
endif
|
||
|
|
||
|
let leader = '\'
|
||
|
if exists('g:mapleader')
|
||
|
let leader = g:mapleader
|
||
|
endif
|
||
|
let leader = escape(leader, '\')
|
||
|
|
||
|
exec 'noremenu <script> '.menuPriority.' '.menuRoot.'.YankRing\ Window :YRShow<CR>'
|
||
|
exec 'noremenu <script> '.menuPriority.' '.menuRoot.'.YankRing\ Search :YRSearch<CR>'
|
||
|
exec 'noremenu <script> '.menuPriority.' '.menuRoot.'.Replace\ with\ Previous<TAB>'.leader.g:yankring_replace_n_pkey.' :YRReplace -1, ''P''<CR>'
|
||
|
exec 'noremenu <script> '.menuPriority.' '.menuRoot.'.Replace\ with\ Next<TAB>'.leader.g:yankring_replace_n_nkey.' :YRReplace 1, ''P''<CR>'
|
||
|
exec 'noremenu <script> '.menuPriority.' '.menuRoot.'.Clear :YRClear<CR>'
|
||
|
exec 'noremenu <script> '.menuPriority.' '.menuRoot.'.Toggle :YRToggle<CR>'
|
||
|
exec 'noremenu <script> '.menuPriority.' '.menuRoot.'.Check\ Clipboard :YRCheckClipboard<CR>'
|
||
|
endif
|
||
|
|
||
|
if g:yankring_enabled == 1
|
||
|
" Create YankRing Maps
|
||
|
call s:YRMapsCreate()
|
||
|
endif
|
||
|
|
||
|
call s:YRInit()
|
||
|
call s:YRCheckClipboard()
|
||
|
|
||
|
let &cpo = s:cpo_save
|
||
|
unlet s:cpo_save
|
||
|
|
||
|
" vim:fdm=marker:nowrap:ts=4:expandtab:
|