diff options
Diffstat (limited to 'vim/bundle/tlib_vim/autoload/tlib/cache.vim')
-rwxr-xr-x | vim/bundle/tlib_vim/autoload/tlib/cache.vim | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/vim/bundle/tlib_vim/autoload/tlib/cache.vim b/vim/bundle/tlib_vim/autoload/tlib/cache.vim new file mode 100755 index 0000000..0f59f34 --- /dev/null +++ b/vim/bundle/tlib_vim/autoload/tlib/cache.vim @@ -0,0 +1,360 @@ +" cache.vim +" @Author: Tom Link (micathom AT gmail com?subject=[vim]) +" @Website: http://www.vim.org/account/profile.php?user_id=4037 +" @License: GPL (see http://www.gnu.org/licenses/gpl.txt) +" @Created: 2007-06-30. +" @Last Change: 2015-11-26. +" @Revision: 35.1.243 + + +" The cache directory. If empty, use |tlib#dir#MyRuntime|.'/cache'. +" You might want to delete old files from this directory from time to +" time with a command like: > +" find ~/vimfiles/cache/ -atime +31 -type f -print -delete +TLet g:tlib_cache = '' + +" |tlib#cache#Purge()|: Remove cache files older than N days. +TLet g:tlib#cache#purge_days = 31 + +" Purge the cache every N days. Disable automatic purging by setting +" this value to a negative value. +TLet g:tlib#cache#purge_every_days = 31 + +" The encoding used for the purge-cache script. +" Default: 'enc' +TLet g:tlib#cache#script_encoding = &enc + +" Whether to run the directory removal script: +" 0 ... No +" 1 ... Query user +" 2 ... Yes +TLet g:tlib#cache#run_script = 1 + +" Verbosity level: +" 0 ... Be quiet +" 1 ... Display informative message +" 2 ... Display detailed messages +TLet g:tlib#cache#verbosity = 1 + +" A list of regexps that are matched against partial filenames of the +" cached files. If a regexp matches, the file won't be removed by +" |tlib#cache#Purge()|. +TLet g:tlib#cache#dont_purge = ['[\/]\.last_purge$'] + +" If the cache filename is longer than N characters, use +" |pathshorten()|. +TLet g:tlib#cache#max_filename = 200 + +let s:cache = {} + + +" :display: tlib#cache#Dir(?mode = 'bg') +" The default cache directory. +function! tlib#cache#Dir(...) "{{{3 + TVarArg ['mode', 'bg'] + let dir = tlib#var#Get('tlib_cache', mode) + if empty(dir) + let dir = tlib#file#Join([tlib#dir#MyRuntime(), 'cache']) + endif + return dir +endf + + +" :def: function! tlib#cache#Filename(type, ?file=%, ?mkdir=0, ?dir='') +function! tlib#cache#Filename(type, ...) "{{{3 + " TLogDBG 'bufname='. bufname('.') + let dir0 = a:0 >= 3 && !empty(a:3) ? a:3 : tlib#cache#Dir() + let dir = dir0 + if a:0 >= 1 && !empty(a:1) + let file = a:1 + else + if empty(expand('%:t')) + return '' + endif + let file = expand('%:p') + let file = tlib#file#Relative(file, tlib#file#Join([dir, '..'])) + endif + " TLogVAR file, dir + let mkdir = a:0 >= 2 ? a:2 : 0 + let file = substitute(file, '\.\.\|[:&<>]\|//\+\|\\\\\+', '_', 'g') + let dirs = [dir, a:type] + let dirf = fnamemodify(file, ':h') + if dirf != '.' + call add(dirs, dirf) + endif + let dir = tlib#file#Join(dirs) + " TLogVAR dir + let dir = tlib#dir#PlainName(dir) + " TLogVAR dir + let file = fnamemodify(file, ':t') + " TLogVAR file, dir, mkdir + let cache_file = tlib#file#Join([dir, file]) + if len(cache_file) > g:tlib#cache#max_filename + if v:version >= 704 + let shortfilename = pathshorten(file) .'_'. sha256(file) + else + let shortfilename = pathshorten(file) .'_'. tlib#hash#Adler32(file) + endif + let cache_file = tlib#cache#Filename(a:type, shortfilename, mkdir, dir0) + else + if mkdir && !isdirectory(dir) + try + call mkdir(dir, 'p') + catch /^Vim\%((\a\+)\)\=:E739:/ + if filereadable(dir) && !isdirectory(dir) + echoerr 'TLib: Cannot create directory for cache file because a file with the same name exists (please delete it):' dir + " call delete(dir) + " call mkdir(dir, 'p') + endif + endtry + endif + endif + " TLogVAR cache_file + return cache_file +endf + + +let s:timestamps = {} + + +function! s:SetTimestamp(cfile, type) "{{{3 + if !has_key(s:timestamps, a:cfile) + let s:timestamps[a:cfile] = {} + endif + let s:timestamps[a:cfile].atime = getftime(a:cfile) + let s:timestamps[a:cfile][a:type] = s:timestamps[a:cfile].atime +endf + + +function! tlib#cache#Save(cfile, dictionary, ...) "{{{3 + TVarArg ['options', {}] + let in_memory = get(options, 'in_memory', 0) + if in_memory + " TLogVAR in_memory, a:cfile, localtime() + let s:cache[a:cfile] = {'mtime': localtime(), 'data': a:dictionary} + elseif !empty(a:cfile) + " TLogVAR a:dictionary + call writefile([string(a:dictionary)], a:cfile, 'b') + call s:SetTimestamp(a:cfile, 'write') + endif +endf + + +function! tlib#cache#MTime(cfile) "{{{3 + let mtime = {'mtime': getftime(a:cfile)} + let mtime = extend(mtime, get(s:timestamps, a:cfile, {})) + return mtime +endf + + +function! tlib#cache#Get(cfile, ...) "{{{3 + TVarArg ['default', {}], ['options', {}] + let in_memory = get(options, 'in_memory', 0) + if in_memory + " TLogVAR in_memory, a:cfile + return get(get(s:cache, a:cfile, {}), 'data', default) + else + call tlib#cache#MaybePurge() + if !empty(a:cfile) && filereadable(a:cfile) + let val = readfile(a:cfile, 'b') + call s:SetTimestamp(a:cfile, 'read') + return eval(join(val, "\n")) + else + return default + endif + endif +endf + + +" :display: tlib#cache#Value(cfile, generator, ftime, ?generator_args=[], ?options={}) +" Get a cached value from cfile. If it is outdated (compared to ftime) +" or does not exist, create it calling a generator function. +function! tlib#cache#Value(cfile, generator, ftime, ...) "{{{3 + TVarArg ['args', []], ['options', {}] + let in_memory = get(options, 'in_memory', 0) + if in_memory + let not_found = !has_key(s:cache, a:cfile) + let cftime = not_found ? -1 : s:cache[a:cfile].mtime + else + let cftime = getftime(a:cfile) + endif + " TLogVAR in_memory, cftime + if cftime == -1 || (a:ftime != 0 && cftime < a:ftime) + " TLogVAR a:generator, args + let val = call(a:generator, args) + " TLogVAR val + let cval = {'val': val} + " TLogVAR cval + call tlib#cache#Save(a:cfile, cval, options) + return val + else + let val = tlib#cache#Get(a:cfile, {}, options) + if !has_key(val, 'val') + throw 'tlib#cache#Value: Internal error: '. a:cfile + else + return val.val + endif + endif +endf + + +" Call |tlib#cache#Purge()| if the last purge was done before +" |g:tlib#cache#purge_every_days|. +function! tlib#cache#MaybePurge() "{{{3 + if g:tlib#cache#purge_every_days < 0 + return + endif + let dir = tlib#cache#Dir('g') + let last_purge = tlib#file#Join([dir, '.last_purge']) + let last_purge_exists = filereadable(last_purge) + if last_purge_exists + let threshold = localtime() - g:tlib#cache#purge_every_days * g:tlib#date#dayshift + let should_purge = getftime(last_purge) < threshold + else + let should_purge = 0 " should ignore empty dirs, like the tmru one: !empty(glob(tlib#file#Join([dir, '**']))) + endif + if should_purge + if last_purge_exists + let yn = 'y' + else + let txt = "TLib: The cache directory '". dir ."' should be purged of old files.\nDelete files older than ". g:tlib#cache#purge_days ." days now?" + let yn = tlib#input#Dialog(txt, ['yes', 'no'], 'no') + endif + if yn =~ '^y\%[es]$' + call tlib#cache#Purge() + else + let g:tlib#cache#purge_every_days = -1 + if !last_purge_exists + call s:PurgeTimestamp(dir) + endif + echohl WarningMsg + echom "TLib: Please run :call tlib#cache#Purge() to clean up ". dir + echohl NONE + endif + elseif !last_purge_exists + call s:PurgeTimestamp(dir) + endif +endf + + +" Delete old files. +function! tlib#cache#Purge() "{{{3 + let threshold = localtime() - g:tlib#cache#purge_days * g:tlib#date#dayshift + let dir = tlib#cache#Dir('g') + if g:tlib#cache#verbosity >= 1 + echohl WarningMsg + echom "TLib: Delete files older than ". g:tlib#cache#purge_days ." days from ". dir + echohl NONE + endif + let files = tlib#cache#ListFilesInCache() + let deldir = [] + let newer = [] + let msg = [] + let more = &more + set nomore + try + for file in files + if isdirectory(file) + if empty(filter(copy(newer), 'strpart(v:val, 0, len(file)) ==# file')) + call add(deldir, file) + endif + else + if getftime(file) < threshold + if delete(file) + call add(msg, "TLib: Could not delete cache file: ". file) + elseif g:tlib#cache#verbosity >= 2 + call add(msg, "TLib: Delete cache file: ". file) + endif + else + call add(newer, file) + endif + endif + endfor + finally + let &more = more + endtry + if !empty(msg) && g:tlib#cache#verbosity >= 1 + echo join(msg, "\n") + endif + if !empty(deldir) + if &shell =~ 'sh\(\.exe\)\?$' + let scriptfile = 'deldir.sh' + let rmdir = 'rm -rf %s' + else + let scriptfile = 'deldir.bat' + let rmdir = 'rmdir /S /Q %s' + endif + let enc = g:tlib#cache#script_encoding + if has('multi_byte') && enc != &enc + call map(deldir, 'iconv(v:val, &enc, enc)') + endif + let scriptfile = tlib#file#Join([dir, scriptfile]) + if filereadable(scriptfile) + let script = readfile(scriptfile) + else + let script = [] + endif + let script += map(copy(deldir), 'printf(rmdir, shellescape(v:val, 1))') + let script = tlib#list#Uniq(script) + call writefile(script, scriptfile) + call inputsave() + if g:tlib#cache#run_script == 0 + if g:tlib#cache#verbosity >= 1 + echohl WarningMsg + if g:tlib#cache#verbosity >= 2 + echom "TLib: Purged cache. Need to run script to delete directories" + endif + echom "TLib: Please review and execute: ". scriptfile + echohl NONE + endif + else + try + let yn = g:tlib#cache#run_script == 2 ? 'y' : tlib#input#Dialog("TLib: About to delete directories by means of a shell script.\nDirectory removal script: ". scriptfile ."\nRun script to delete directories now?", ['yes', 'no', 'edit'], 'no') + if yn =~ '^y\%[es]$' + exec 'silent cd '. fnameescape(dir) + exec '! ' &shell shellescape(scriptfile, 1) + exec 'silent cd -' + call delete(scriptfile) + elseif yn =~ '^e\%[dit]$' + exec 'edit '. fnameescape(scriptfile) + endif + finally + call inputrestore() + endtry + endif + endif + call s:PurgeTimestamp(dir) +endf + + +function! s:PurgeTimestamp(dir) "{{{3 + let last_purge = tlib#file#Join([a:dir, '.last_purge']) + " TLogVAR last_purge + call writefile([" "], last_purge) +endf + +function! tlib#cache#ListFilesInCache(...) "{{{3 + let dir = a:0 >= 1 ? a:1 : tlib#cache#Dir('g') + if v:version > 702 || (v:version == 702 && has('patch51')) + let filess = glob(tlib#file#Join([dir, '**']), 1) + else + let filess = glob(tlib#file#Join([dir, '**'])) + endif + let files = reverse(split(filess, '\n')) + let pos0 = len(tlib#dir#CanonicName(dir)) + call filter(files, 's:ShouldPurge(strpart(v:val, pos0))') + return files +endf + + +function! s:ShouldPurge(partial_filename) "{{{3 + " TLogVAR a:partial_filename + for rx in g:tlib#cache#dont_purge + if a:partial_filename =~ rx + " TLogVAR a:partial_filename, rx + return 0 + endif + endfor + return 1 +endf + |