mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-02-03 06:00:05 +08:00
215 lines
5.4 KiB
VimL
215 lines
5.4 KiB
VimL
"=============================================================================
|
|
" FILE: neoyank.vim
|
|
" AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
|
|
" License: MIT license
|
|
"=============================================================================
|
|
|
|
" Variables
|
|
let s:VERSION = '2.0'
|
|
|
|
let s:yank_histories = {}
|
|
let s:yank_histories_old = {}
|
|
|
|
" the last modified time of the yank histories file.
|
|
let s:yank_histories_file_mtime = 0
|
|
|
|
let s:prev_registers = {}
|
|
let s:prev_yankpost_event = {}
|
|
|
|
let s:is_windows = has('win16') || has('win32') || has('win64') || has('win95')
|
|
function! s:set_default(var, val, ...) abort
|
|
if !exists(a:var) || type({a:var}) != type(a:val)
|
|
let alternate_var = get(a:000, 0, '')
|
|
unlet! {a:var}
|
|
|
|
let {a:var} = exists(alternate_var) ?
|
|
\ {alternate_var} : a:val
|
|
endif
|
|
endfunction
|
|
function! s:substitute_path_separator(path) abort
|
|
return s:is_windows ? substitute(a:path, '\\', '/', 'g') : a:path
|
|
endfunction
|
|
let s:base = expand(($XDG_CACHE_HOME != '' ?
|
|
\ $XDG_CACHE_HOME . '/neoyank' : '~/.cache/neoyank'), 1)
|
|
|
|
call s:set_default(
|
|
\ 'g:neoyank#file',
|
|
\ s:substitute_path_separator(s:base.'/history_yank'))
|
|
|
|
call s:set_default('g:neoyank#limit', 100)
|
|
|
|
call s:set_default('g:neoyank#length', 10000)
|
|
|
|
function! neoyank#default_register_from_clipboard()
|
|
if &clipboard == 'unnamed'
|
|
return "*"
|
|
elseif &clipboard == 'unnamedplus'
|
|
return "+"
|
|
else
|
|
return '"'
|
|
endif
|
|
endfunction
|
|
|
|
call s:set_default(
|
|
\ 'g:neoyank#save_registers',
|
|
\ [neoyank#default_register_from_clipboard()])
|
|
|
|
|
|
function! neoyank#update() abort
|
|
call neoyank#_append()
|
|
endfunction
|
|
|
|
function! neoyank#_append() abort
|
|
call neoyank#_load()
|
|
|
|
for register in g:neoyank#save_registers
|
|
call s:add_register(register,
|
|
\ [getreg(register), getregtype(register)])
|
|
endfor
|
|
|
|
call neoyank#_save()
|
|
endfunction
|
|
function! neoyank#_yankpost() abort
|
|
if v:event == s:prev_yankpost_event
|
|
return
|
|
endif
|
|
for register in g:neoyank#save_registers
|
|
call s:add_register(register,
|
|
\ [getreg(register), getregtype(register)])
|
|
endfor
|
|
let s:prev_yankpost_event = v:event
|
|
endfunction
|
|
|
|
function! neoyank#_get_yank_histories() abort
|
|
return s:yank_histories
|
|
endfunction
|
|
|
|
function! neoyank#_save() abort
|
|
if g:neoyank#file == ''
|
|
\ || s:is_sudo()
|
|
\ || (exists('g:neoyank#disable_write') && g:neoyank#disable_write)
|
|
\ || s:yank_histories ==# s:yank_histories_old
|
|
return
|
|
endif
|
|
|
|
call s:writefile(g:neoyank#file,
|
|
\ [s:VERSION, s:vim2json(s:yank_histories)])
|
|
let s:yank_histories_file_mtime =
|
|
\ getftime(g:neoyank#file)
|
|
let s:yank_histories_old = copy(s:yank_histories)
|
|
endfunction
|
|
function! neoyank#_load() abort
|
|
if !filereadable(g:neoyank#file)
|
|
\ || s:yank_histories_file_mtime == getftime(g:neoyank#file)
|
|
return
|
|
endif
|
|
|
|
let file = readfile(g:neoyank#file)
|
|
|
|
" Version check.
|
|
if empty(file) || len(file) != 2 || file[0] !=# s:VERSION
|
|
return
|
|
endif
|
|
|
|
try
|
|
let yank_histories = s:json2vim(file[1])
|
|
catch
|
|
unlet! yank_histories
|
|
let yank_histories = {}
|
|
endtry
|
|
if type(yank_histories) != type({})
|
|
unlet! yank_histories
|
|
let yank_histories = {}
|
|
endif
|
|
|
|
for register in g:neoyank#save_registers
|
|
if !has_key(s:yank_histories, register)
|
|
let s:yank_histories[register] = []
|
|
endif
|
|
let s:yank_histories[register] =
|
|
\ get(yank_histories, register, []) + s:yank_histories[register]
|
|
call s:uniq(register)
|
|
endfor
|
|
|
|
let s:yank_histories_file_mtime =
|
|
\ getftime(g:neoyank#file)
|
|
endfunction
|
|
|
|
function! s:add_register(name, reg) abort
|
|
" Append register value.
|
|
if !has_key(s:yank_histories, a:name)
|
|
let s:yank_histories[a:name] = []
|
|
endif
|
|
|
|
if get(s:yank_histories[a:name], 0, []) ==# a:reg
|
|
" Skip same register value.
|
|
return
|
|
endif
|
|
|
|
let len_history = len(a:reg[0])
|
|
" Ignore too long yank.
|
|
if len_history < 2 || len_history > g:neoyank#length
|
|
\ || a:reg[0] =~ '[\x00-\x08\x10-\x1a\x1c-\x1f]\{3,}'
|
|
return
|
|
endif
|
|
|
|
" Error check
|
|
try
|
|
call s:vim2json(a:reg)
|
|
catch
|
|
return
|
|
endtry
|
|
|
|
let s:prev_registers[a:name] = a:reg
|
|
|
|
call insert(s:yank_histories[a:name], a:reg)
|
|
call s:uniq(a:name)
|
|
endfunction
|
|
|
|
function! s:uniq(name) abort
|
|
let history = s:uniq_by(s:yank_histories[a:name], 'v:val')
|
|
if g:neoyank#limit < len(history)
|
|
let history = history[ : g:neoyank#limit - 1]
|
|
endif
|
|
let s:yank_histories[a:name] = history
|
|
endfunction
|
|
|
|
function! s:is_sudo() abort
|
|
return $SUDO_USER != '' && $USER !=# $SUDO_USER
|
|
\ && $HOME !=# expand('~'.$USER)
|
|
\ && $HOME ==# expand('~'.$SUDO_USER)
|
|
endfunction
|
|
|
|
" Removes duplicates from a list.
|
|
function! s:uniq_by(list, f) abort
|
|
let list = map(copy(a:list), printf('[v:val, %s]', a:f))
|
|
let i = 0
|
|
let seen = {}
|
|
while i < len(list)
|
|
let key = string(list[i][1])
|
|
if has_key(seen, key)
|
|
call remove(list, i)
|
|
else
|
|
let seen[key] = 1
|
|
let i += 1
|
|
endif
|
|
endwhile
|
|
return map(list, 'v:val[0]')
|
|
endfunction
|
|
|
|
function! s:writefile(path, list) abort
|
|
let path = fnamemodify(a:path, ':p')
|
|
if !isdirectory(fnamemodify(path, ':h'))
|
|
call mkdir(fnamemodify(path, ':h'), 'p')
|
|
endif
|
|
|
|
call writefile(a:list, path)
|
|
endfunction
|
|
|
|
function! s:vim2json(expr) abort
|
|
return exists('*json_encode') ? json_encode(a:expr) : string(a:expr)
|
|
endfunction
|
|
function! s:json2vim(expr) abort
|
|
sandbox return (exists('*json_encode') ? json_decode(a:expr) : eval(a:expr))
|
|
endfunction
|