1
0
mirror of https://github.com/amix/vimrc synced 2025-07-07 08:45:00 +08:00

gitignore sources_non_forked_cache

This commit is contained in:
Wu Tingfeng
2022-11-21 23:06:50 +08:00
parent aff5c8f75a
commit 378168c979
1752 changed files with 208511 additions and 1 deletions

View File

@ -0,0 +1,24 @@
" buf_identifier is either a buf_nr or a filename
" If any window shows the buffer move to the buffer
" If not show it in current window (by c-w s c^ you can always
" reshow the last buffer
"
" Example: buf_utils#GotoBuf("/tmp/tfile.txt", {'create': 1})
" returns: The command which was used to switch to the buffer
fun! buf_utils#GotoBuf(buf_identifier, opts)
let buf_nr = bufnr(a:buf_identifier)
if buf_nr == -1 && ( get(a:opts, 'create', 0) || has_key(a:opts, 'create_cmd'))
exec get(a:opts,'create_cmd','e').' '.fnameescape(a:buf_identifier)
return "e"
else
let win_nr = bufwinnr(buf_nr)
if win_nr == -1
exec 'b '.buf_nr
return "b"
else
exec win_nr.'wincmd w'
return "w"
endif
wincmd w"
endif
endf

View File

@ -0,0 +1,104 @@
" cached_file_contents.vim
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Last Change: 2010-01-03.
" @Revision: 0.3.0
"exec vam#DefineAndBind('s:c','g:cache_dir_options','{}')
if !exists('g:cache_dir_options') | let g:cache_dir_options = {} | endif | let s:c = g:cache_dir_options
let s:c['cache_dir'] = get(s:c, 'cache_dir', expand('$HOME').'/.vim-cache')
let s:c['scanned_files'] = get(s:c, 'scanned_files', {})
let s:scanned_files = s:c['scanned_files']
let s:define_cache_file = "let this_dir = s:c['cache_dir'].'/cached-file-contents' | let cache_file = expand(this_dir.'/'.substitute(string([func_as_string, a:file]),'[[\\]{}:/\\,''\"# ]\\+','_','g'))"
" read a file, run function to extract contents and cache the result returned
" by that function in memory. Optionally the result can be cached on disk as
" because VimL can be slow!
"
" file : the file to be read
" func: { 'func': function which will be called by funcref#Call
" , 'version' : if this version changes cache will be invalidate automatically
" , 'ftime_check': optional, default 1. if set to 0 cache isn't updated when file changes and file is in cache
" }
"
" default: what to return if file doesn't exist
" think twice about adding lines. This function is called many times.
function! cached_file_contents#CachedFileContents(file, func, ...) abort
let ignore_ftime = a:0 > 0 ? a:1 : 0
" using string for default so that is evaluated when needed only
let use_file_cache = get(a:func, 'use_file_cache', 0)
" simple kind of normalization. necessary when using file caching
" this seems to be slower:
" let file = fnamemodify(a:file, ':p') " simple kind of normalization. necessary when using file caching
" / = assume its an absolute path
" let file = a:file[0] == '/' ? a:file : expand(a:file, ':p')
let file = a:file[0] == '/' ? a:file : fnamemodify(a:file, ':p') " simple kind of normalization. necessary when using file caching
let func_as_string = string(a:func['func'])
if (!has_key(s:scanned_files, func_as_string))
let s:scanned_files[func_as_string] = {}
endif
let dict = s:scanned_files[func_as_string]
if use_file_cache && !has_key(dict, a:file)
exec s:define_cache_file
if filereadable(cache_file)
let dict[file] = eval(readfile(cache_file,'b')[0])
endif
endif
if has_key(dict, a:file)
let d = dict[a:file]
if use_file_cache
\ && (ignore_ftime || getftime(a:file) <= d['ftime'])
\ && d['version'] == a:func['version']
return dict[a:file]['scan_result']
endif
endif
let scan_result = funcref#Call(a:func['func'], [a:file] )
let dict[a:file] = {"ftime": getftime(a:file), 'version': a:func['version'], "scan_result": scan_result }
if use_file_cache
if !exists('cache_file') | exec s:define_cache_file | endif
if !isdirectory(this_dir) | call mkdir(this_dir,'p',0700) | endif
call writefile([string(dict[a:file])], cache_file)
endif
return scan_result
endfunction
fun! cached_file_contents#ClearScanCache()
let s:c['scanned_files'] = {}
" Don't run rm -fr. Ask user to run it. It cache_dir may have been set to
" $HOME ! (should nevere be the case but who knows
echoe "run manually in your shell: rm -fr ".shellescape(s:c['cache_dir'])."/*"
endf
fun! cached_file_contents#Test()
" usually you use a global option so that the function can be reused
let my_interpreting_func = {'func' : funcref#Function('return len(readfile(ARGS[0]))'), 'version': 2, 'use_file_cache':1}
let my_interpreting_func2 = {'func' : funcref#Function('return ARGS[0]') , 'version': 2, 'use_file_cache':1}
let tmp = tempname()
call writefile(['some text','2nd line'], tmp)
let r = [ cached_file_contents#CachedFileContents(tmp, my_interpreting_func)
\ , cached_file_contents#CachedFileContents(tmp, my_interpreting_func2) ]
if r != [2, tmp]
throw "test failed 1, got ".string(r)
endif
unlet r
sleep 3
" now let's change contents
call writefile(['some text','2nd line','3rd line'], tmp)
let r = cached_file_contents#CachedFileContents(tmp, my_interpreting_func)
if 3 != r
throw "test failed 2, got ".string(r)
endif
echo "test passed"
endf

View File

@ -0,0 +1,12 @@
" in sh/bash you can type export to get a list of environment variables
" This function assigns those env vars to Vim.
" Does not delete env vars yet
" Example: env_reload#ReloadEnv(system("sh -c 'export'")
fun! env_reload#ReloadEnv(bash_export_command_output)
for i in split(a:bash_export_command_output,"\n")
let m = matchlist(i, 'export \([^=]\+\)="\(.*\)"')
if empty(m) | continue | endif
" don't care about quoted values right now.
exec 'let $'.m[1].'='.string(m[2])
endfor
endf

View File

@ -0,0 +1,95 @@
" funcref.vim
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Last Change: 2010-01-03.
" @Revision: 0.1.0
" documentation see doc/funcref.txt
" usage:
" funcref#Function("filename#Function")
" optionally pass arguments:
" funcref#Function("filename#Function",{'args': [2]})
" optionally define self:
" funcref#Function("filename#Function",{'self': object})
function! funcref#Function(name,...)
let d = a:0 > 0 ? a:1 : {}
let d['faked_function_reference'] = a:name
return d
endfunction
" args : same as used for call(f,[args], self)
" f must be either
" - a string which can be evaled (use "return 'value'" to return a value)
" - a Vim function reference created by function('..')
" - a faked function reference created by funcref#Function(..)
"
" the last "self" argument can be overriden by the function reference
" You can pass arguments in a closure like style
function! funcref#Call(...)
let args = copy(a:000)
" add parameters:
if (len(args) < 2)
call add(args, [])
endif
let isDict = type(args[0]) == type({})
" prepend parameters which were passed by faked function reference:
if isDict && has_key(args[0], 'args')
let args[1] = args[0]['args']+args[1]
endif
" always pass self. this way you can call functions from dictionaries not
" refering to self
if (len(args) < 3)
call add(args, {})
endif
" the funcref overrides self:
if isDict && has_key(args[0], 'self')
let args[2] = args[0]['self']
endif
if type(a:1) == 2
" funcref: function must have been laoded
return call(function('call'), args)
elseif isDict && has_key(args[0], 'faked_function_reference')
let Fun = args[0]['faked_function_reference']
if type(Fun) == type('')
\ && (Fun[:len('return ')-1] == 'return '
\ || Fun[:len('call ')-1] == 'call '
\ || Fun[:len('if ')-1] == 'if '
\ || Fun[:len('let ')-1] == 'let '
\ || Fun[:len('echo ')-1] == 'echo '
\ || Fun[:len('exec ')-1] == 'exec '
\ || Fun[:len('debug ')-1] == 'debug ')
" it doesn't make sense to list all vim commands here
" So if you want to execute another action consider using
" funcref#Function('exec '.string('aw')) or such
" function is a String, call exec
let ARGS = args[1]
let SELF = args[2]
exec Fun
else
" pseudo function, let's load it..
if type(Fun) == 1
if !exists('*'.Fun)
" lazily load function
let file = substitute(substitute(Fun,'#[^#]*$','',''),'#','/','g')
exec 'runtime /autoload/'.file.'.vim'
endif
let Fun2 = function(Fun)
else
let Fun2 = Fun
endif
let args[0] = Fun
return call(function('call'), args)
endif
else
" no function, return the value
return args[0]
endif
endfunction

View File

@ -0,0 +1,27 @@
exec vam#DefineAndBind('s:c','g:glob_like', '{}')
" ignore vcs stuff, Don't think you want those..
let s:c['regex_ignore_directory'] = '\<\%([_.]darcs\|\.git\|.svn\|.hg\|.cvs\|.bzr\)\>'
let s:c['glob_cache'] = get(s:c, 'glob_cache', {})
let s:glob_cache = s:c['glob_cache']
fun! glob#Glob(pattern, ...)
let pattern = a:pattern
if pattern[0] == '~'
let pattern = $HOME.pattern[1:]
endif
let opts = a:0 > 0 ? a:1 : {}
" never cache current directory. You're very likely to edit files in it.
let c = getcwd()
let cachable = get(opts, 'cachable', 0) && pattern[:len(c)-1] != c
if cachable && has_key(s:glob_cache, pattern)
return s:glob_cache[pattern]
endif
" FIXME: don't recurse into \.git directory (thus reimplement glob in vimL!)
let r = filter(split(glob(pattern),"\n"),'v:val !~ '.string(s:c['regex_ignore_directory']))
if cachable | let s:glob_cache[pattern] = r | endif
return r
endf

View File

@ -0,0 +1,43 @@
" TODO refactor: create glob function
" noremap \og :call<space>glob_linux#FileByGlobCurrentDir('**/*'.input('glob open '),"\\.git\\<bar>\\.hg\\<bar>node_modules\\<bar>\\.pyc" )<cr>
" noremap \og :call<space>glob_linux#FileByGlobCurrentDir('**/*'.input('glob open '),"default" )<cr>
function! glob_linux#FileByGlobCurrentDir(glob, exclude_pattern, ...)
let opts = a:0 > 0 ? a:1 : {}
if a:exclude_pattern == "default"
let exclude_pattern = '\.git\|\.hg\|node_modules\|\.pyc'
else
let exclude_pattern = a:exclude_pattern
endif
" let files = split(glob(a:glob),"\n")
let g = a:glob
let replace = {'**': '.*','*': '[^/\]*','.': '\.'}
let g = substitute(g, '\(\*\*\|\*\|\.\)', '\='.string(replace).'[submatch(1)]','g')
let exclude = exclude_pattern == '' ? '' : ' | grep -v -e '.shellescape(exclude_pattern)
let cmd = get(opts, 'cmd_find', 'find'). ' . | grep -e '.shellescape(g).exclude
let files = split(system(cmd),"\n")
" for nom in a:excludes
" call filter(files,nom)
" endfor
if len(files) > 1000
echoe "more than ".2000." files - would be too slow. Open the file in another way"
else
if empty(files)
echoe "no file found"
elseif len(files) == 1
exec 'e '.fnameescape(files[0])
else
let g:abc=7
call tovl#ui#filter_list#ListView({
\ 'number' : 1,
\ 'selectByIdOrFilter' : 1,
\ 'Continuation' : funcref#Function('exec "e ".fnameescape(ARGS[0])'),
\ 'items' : files,
\ 'cmds' : ['wincmd J']
\ })
endif
endif
endfunction

View File

@ -0,0 +1,19 @@
" vim suffers:
exec vam#DefineAndBind('s:c','g:vim_tiny_cmd', '{}')
fun! tiny_cmd#Put(a)
let new = get(s:c,'next',0) +1
let s:c['next'] = new
let s:c[new] = a:a
return new
endf
fun! tiny_cmd#Get(nr)
return s:c[a:nr]
endf
" Get and remove item
fun! tiny_cmd#Pop(nr)
let r = s:c[a:nr] | unlet s:c[a:nr] | return r
endf

View File

@ -0,0 +1,103 @@
" old code
augroup TOVLWrite
augroup end
" =========== scratch buffer =========================================
" a scratch buffer is a temporary buffer where the user can enter some text
" It can be used to get commit messages, edit configuration options and so on
function! tovl#scratch_buffer#KeepIntactLineNr()
let i = 0
while getline(i)!= b:keepIntact && i < line('$')
let i = i+1
endwhile
if i > line('$')
return -1
else
return i
endif
endfunction
" opens a buffer and runs an action when the buffer is written
" keys:
" name : the name of the buffer
" onWrite : will be called on write
" onWrite is responsible for setlocal nomodified to indicate that
" saving has been successful
" help : callback returning additional information lines
" getContent : callback returning lines
" cmds : extra commands to be run (optional)
" (maybe you prefer adding them the default way afer the
" ScratchBuffer call. They'll be rerun on GetContents
" sp_cmd : the command to use to create the new buffer. Defaults to :e
" buftype : ...
" modifiable : 1 / 0 defaults to 1
function! tovl#scratch_buffer#ScratchBuffer(opts)
let a:opts['name'] = get(a:opts,'name', 'strach_buffer_without_name')
exec get(a:opts, 'sp_cmd', 'e').' '.escape(a:opts['name'],' ')
let b:settings = a:opts
let b:settings['modifiable'] = get(a:opts,'modifiable', 1)
setlocal buftype=acwrite
command! -buffer -nargs=0 Help call tovl#scratch_buffer#Help()
" setup write notification
au TOVLWrite BufWriteCmd <buffer> call tovl#scratch_buffer#Write()
if has_key(a:opts,'getContent')
command! -buffer -nargs=0 GetContents call tovl#scratch_buffer#GetContents()
GetContents
if !b:settings['modifiable']
setlocal nomodifiable
endif
endif
"let u=&undolevels
"setlocal undolevels=-1
"exec 'setlocal undolevels='.u
" mark buffer as not modified
setlocal nomodified
au BufReadCmd <buffer> GetContents
" run addittional commands
for cmd in get(a:opts,'cmds',[])
exec cmd
endfor
silent echo get(a:opts,'echo_help', "type :Help for help")
endfunction
" =========== utility functions ======================================
function! tovl#scratch_buffer#Write()
if has_key(b:settings, 'onWrite')
call funcref#Call(b:settings['onWrite'])
else
echo "don't know how to write. Option hasn't been passed"
endif
endfunction
function! tovl#scratch_buffer#GetContents()
setlocal modifiable
" empty buffer
%g!//d
call append(0, funcref#Call(b:settings['getContent']))
if !b:settings['modifiable']
setlocal nomodifiable
endif
for cmd in get(b:settings,'cmds',[])
exec cmd
endfor
endfunction
function! tovl#scratch_buffer#Help()
let help = ["use :e! to reload contents, ZZ or :w(q) to write and quit"
\ ,""
\ ,"Help for this scratch buffer:"
\ ,"=======================================================","",""]
\ + funcref#Call(get(b:settings, 'help', []))
call tovl#scratch_buffer#ScratchBuffer({
\ 'name' : "return Help of ".b:settings['name'],
\ 'getContent' : help
\ })
endfunction

View File

@ -0,0 +1,473 @@
" OLD CODE !
" I should contribute the multiple filter feature to tlib
" filter list displays a list of items
" you can white / black filter them by regular expressions (similar to the
" tlib TToC command
" However you can edit the filters afterwards and select the cols which should
" be shown
fun! tovl#ui#filter_list#ListTest()
call tovl#ui#filter_list#ListView({
\ 'aligned' : 1,
\ 'Continuation' : funcref#Function('echo string(ARGS[0])'),
\ 'items' : [ {"aa" : "a\nAAAAAAAAAAA", 'bb' : "bbbbbbbbbbbbb\nB" },
\ {"aa" : "2a\n2AAAAAAAAAAAA", "bb" : "2 bbbbbbbbbbbbb\n2B"},
\ {"aa" : "XXX", "bb" : "YY"} ],
\ })
endfun
fun! s:Intersection(a, b)
return filter(copy(a:a), 'index(a:b, v:val) >= 0')
endf
fun! tovl#ui#filter_list#ListTestGotoLineCurrentBuf()
let nr=1
let lines = []
for l in getline(0,line('$'))
call add(lines, {'nr': nr, 'line' :l})
let nr = nr +1
endfor
call tovl#ui#filter_list#ListView({
\ 'aligned' : 0,
\ 'keys' : ['nr','line'],
\ 'number' : 1,
\ 'selectByIdOrFilter' : 1,
\ 'Continuation' : funcref#Function('exec ARGS[0]["nr"]'),
\ 'items' : lines,
\ })
endfun
" opens a new filtered list
" keys of opts parameters:
" Continuation: This function will be called with the selected items
" items: { key : (string or dict) }
" items willl be modified. use copy(youritems) as argument to prevent
" this. An item is either a string or a dict
" (eg {'file' : .., 'line': ... , 'msg' : .. )
" keys: list of keys to be shown (optional)
" filter: list of inital filters which must be applied
" contains [ { filter: .. , keep : .. }, ] see FilterItems() below
" aligned: default 0
" sp_cmd: the command to be used to create the new buffer (default ':e')
" init : 0 / 1 (default 1): wether to show the view right now
" number: 0 /1 (default 1): number items ?
" selectByIdOrFilter: 1: start in getchar() loop so that the user can select
" the item even faster
" auto: only do this if all items fit on screen
" (recommend)
" cmds: extra cmds to be run
" cursorAt : at which item to put the cursor?
"
" If you don't like the default view you can override UpdateDisplay
"
" Usage examples of this list control:
" - db results
" - replacement of the quickfix window
" - select a buffer etc
fun! tovl#ui#filter_list#ListView(opts)
" ActivateAddons theonevimlib
let d = {}
let d.items = a:opts.items
let d.cursorAt = get(a:opts, 'cursorAt', 0)
let d.aligned = get(a:opts, 'aligned', 0)
let d.sep = ' '
let d.filter = get(a:opts, 'filter', [])
" using sp because of bd! (FIXME)
let d.sp_cmd = get(a:opts, 'sp_cmd', 'sp')
let d.allKeys = {}
let d.closeOnContinuation = get(a:opts,'closeOnContinuation',1)
" don't recommend OnSingleMatch, use OnSingleMatchCR instead
let d.continueOnSingleMatch = get(a:opts, 'continueOnSingleMatch',0)
let d.continueOnSingleMatchCR = get(a:opts, 'continueOnSingleMatchCR',1)
let d.selectByIdOrFilter = get(a:opts, 'selectByIdOrFilter', 0)
let d.linesToItems = {}
let d.number = get(a:opts, 'number', 1)
let d.cmds = get(a:opts, 'cmds', [])
let d.syn_cmds = get(a:opts, 'syn_cmds', [])
if has_key(a:opts,'keys') | let d.keys = a:opts.keys | endif
if has_key(a:opts,'Continuation') | let d.Continuation = a:opts.Continuation | endif
" cache already filtered items in case we want to view really long results
" contains [ { filter : { regex: .. , keep : .. } , items : .. , cursorAt :},
" { filter : { ... } , items: .. , cursorAt : }
let d.cached = []
" id of buffer
let d.buffer = -1
let d.modeText = ''
fun d.HelpText()
return [ "you've entered the the help of the powerful filtered view buffer",
\ "",
\ "type f to start filtering items by regex",
\ "type F to start dropping items by regex",
\ "k / K will ask you for the key to apply the filter to first",
\ "apply the filter by <cr> and press <cr> again to select item",
\ "",
\ "use :ShowAppliedFilters to list active filters",
\ "use :ToggleAlignment to toggle alignment",
\ "",
\ "TODO: Implement sorting, implement interface to change keys (displayed columns)"
\ ]
endfun
" create new scratch buffer
" preprocess items calculating line count and maxwidth for all items
fun d.NewBufferAndInit()
let self.bufferId = bufnr(bufname('%'))
for idx in range(0,len(self.items)-1)
if type(self.items[idx]) != 4
" no dict yet, make it one
let self.items[idx] = {'string_line' : self.items[idx]}
endif
let new = {}
for [k,v] in items(self.items[idx])
let lines = split(v,"\n")
let self.items[idx][k] = { 'text' : v, 'rows' : len(lines), 'cols' : max(map(copy(lines),'len(v:val)')), 'lines' : lines }
let self.allKeys[k] = 1
unlet k v
endfor
endfor
call tovl#scratch_buffer#ScratchBuffer({
\ 'help' : funcref#Function(self.HelpText,{ 'self' : self }),
\ 'sp_cmd' : self.sp_cmd,
\ 'cmds' : self.cmds
\ })
" I assume we have some kind of formatting anyway. Thus breaking lines is bad!
set nowrap
setlocal cursorline
let b:filtered_view = self
command! -buffer -nargs=0 ToggleAlignment call b:filtered_view.ToggleAlignment()
command! -buffer -nargs=0 ShowAppliedFilters call b:filtered_view.ShowAppliedFilters()
command! -buffer -nargs=0 RemoveFilters call b:filtered_view.RemoveFilters()
noremap <buffer> f :call b:filtered_view.FilterFromKeyboard(1,'')<cr>
" noremap <buffer> f :call b:filtered_view.FilterFromKeyboard(1)<cr>
noremap <buffer> F :call b:filtered_view.FilterFromKeyboard(0,'')<cr>
if has_key(self,'Continuation')
nnoremap <buffer> <cr> :call b:filtered_view.Continue()<cr>
endif
"noremap <buffer> k
"noremap <buffer> K
let [items, cursorAt] = self.FilteredItems()
" len(items) is an approximation because one item can have multiple
" lines.. However adding the lines first to check takes too much time
if self.selectByIdOrFilter == 1 || (self.selectByIdOrFilter == 'auto' && winheight('%') > len(items) )
call self.SelectByIdOrFilter()
else
" user should choose how to proceed
call self.UpdateDisplay()
endif
endfun
" user interface
fun d.ToggleAlignment()
let self.aligned = !self.aligned
call self.UpdateDisplay()
endfun
fun d.ShowAppliedFilters()
for i in self.filter | echo string(i) | endfor
endfun
fun d.RemoveFilters()
let self.filter = []
call self.UpdateDisplay()
endfun
fun d.Continue()
let item = self.CurrentItem()
call self.DoContinue(item)
endfun
fun d.DoContinue(v)
if self.closeOnContinuation | bw! | endif
call funcref#Call(self.Continuation,[a:v])
endfun
fun d.MapToOriginal(v)
if has_key(a:v, 'string_line')
return a:v.string_line.text
else
let d = {}
for [k,v] in items(a:v)
let d[k] = v.text
unlet k v
endfor
return d
endif
endfun
fun d.CurrentItem()
let idx=line('.')-len(self.headerLines)
while idx >= 0
if has_key(self.linesToItems, idx)
return self.MapToOriginal(self.FilteredItems()[0][self.linesToItems[idx]])
else
let idx = idx -1
endif
endwhile
throw "internal error, couldn't determine selected item!"
endfun
" updates the filter cache and returns the final filtered items
fun d.FilteredItems()
" update cache
let idx = 0
let [items, cursorAt] = [self.items, self.cursorAt]
for idx in range(0, len(self.filter)-1)
if idx +1 > len(self.cached) || self.cached[idx]['filter'] != self.filter[idx]
let self.cached = self.cached[:idx-1]
let [items, cursorAt] = self.FilterItem(copy(items), self.filter[idx], cursorAt)
call add(self.cached, { 'cursorAt' : cursorAt, 'items' : items, 'filter' : self.filter[idx]})
else
let ci = self.cached[idx]
let [items, cursorAt] = [ci['items'], ci['cursorAt']]
endif
endfor
return [items, cursorAt]
endfun
" calling this will return a set of lines which are expected to be the new
" buffer contents. The self.linesToItems dict is updated
fun d.UpdateDisplay()
if empty(self.filter)
let self.statusline= 'no filter applied, :Help for help'
else
let self.statusline = len(self.filter).' '.string(self.filter[-1])
endif
let self.linesToItems = {}
let [items, cursorAt] = self.FilteredItems()
"let num_width = printf('%.0f', trunc(log10(len(items))+1))
let num_width = 4
if self.aligned
" get column width.. (probably will not work with unicde characters.. I
" don't have a better solution)
let maxlens={}
for i in items
for [k,v] in items(i)
if get(maxlens,k,0) < v.cols
let maxlens[k] = v.cols
endif
endfor
endfor
endif
" format lines
let self.headerLines = [self.modeText]
let lines = copy(self.headerLines)
let lines_count = 0
if self.number
let fmt_startA = '%'.num_width.'s)'
let fmt_startB = '%'.num_width.'s'
else
let fmt_startA = '' | let fmt_startB = ''
endif
let cursorAtLine = 1 " sane default
for idx in range(0,len(items)-1)
let self.linesToItems[lines_count + 1] = idx
let i = items[idx]
let keys = has_key(self,'keys')
\ ? s:Intersection(self.keys, keys(i))
\ : keys(i)
let fmt = ''
let args = [i]
let cols = []
for k in keys
let fmt .= self.sep.'%-'.(self.aligned ? maxlens[k] : i[k]['cols']).'s'
call add(cols, i[k])
endfor
for row in range(0, max([1] + map(copy(cols),'v:val["rows"]'))-1)
let fmt_args = row == 0 ? [fmt_startA.fmt] : [fmt_startB.fmt]
if self.number
call add(fmt_args, row == 0 ? idx : '')
endif
for c in cols
call add(fmt_args, c.rows <= row ? '' : c.lines[row])
endfor
call add(lines, call('printf', fmt_args))
let lines_count += 1
endfor
if idx == cursorAt
let cursorAtLine = lines_count
endif
endfor
" update stauts line to show last applied filter
" disabled cause it causes trouble on :wincmd w
" setlocal statusline=%!b:filtered_view.statusline
" syntax
syn clear
for s in self.syn_cmds | exec s | endfor
let id = 0
" highlight filter regex in buffer as well
let syn_ids = [ 'Underlined', 'Todo', 'Error', 'Type', 'Statement' ]
for f in self.filter
if !f.keep || !has_key(f, 'regex') | continue | endif
if f.regex != ''
try
exec 'syn match '.syn_ids[id % len(syn_ids)].' '.string(f.regex)
catch /.*/
" ignore errors such as \ without following characters. Thus just
" ignore and wait for the next character
endtry
endif
let id = id +1
endfor
if len(lines) > winheight('%')
call extend(lines, self.headerLines)
endif
normal ggdG
call append(0, lines)
" place cursor
exec (cursorAtLine+1)
" move cursor into the middle of the window
normal zz
endf
" filter = keys :
" filter = string to be executed containing Val
" keep = 1 keep on match
" = 0 drop on match
" key (optional)
" cursorAt: at which item to put the cursor
" if that item is deleted it will be placed at the item above
" optional: key of dict if dict
fun d.FilterItem(items, filter, cursorAt)
let filter = 'Val =~ '.string(a:filter.regex)
let keep = a:filter.keep
let cursorAt = a:cursorAt
for idx in reverse(range(0, len(a:items)-1))
let i = a:items[idx]
if has_key(a:filter,'key')
let key = a:filter.key
if has_key(i, key)
" key given, only filter by this column
let Val = i[key]['text']
exec 'let any = '.filter
else
let any = 0
endif
else
let any = 0
" no key given, try all
for x in values(i)
let Val = x['text']
exec 'let any = '.filter
if any | break | endif
endfor
endif
if any != keep
call remove(a:items, idx)
if idx <= cursorAt
let cursorAt = cursorAt -1
endif
endif
endfor
return [a:items, cursorAt]
endfun
" if the user enters a number select by index else start filtering..
fun d.SelectByIdOrFilter()
let idx=''
let items = self.FilteredItems()[0]
try
let self.modeText = '[0-9]* : select by index| <esc>: escape getchar() loop, any char: start filtering'
call self.UpdateDisplay() | redraw
while 1
let c=getchar()
if index([13,10],c) >= 0
return self.DoContinue(self.MapToOriginal(items[idx]))
elseif index([27], c) >=0
" esc, abort
return
else
if type(c) == 0
let c = nr2char(c)
endif
if c == "\<bs>" || index(map(range(0,10),'v:val.""'),c) >= 0
if c == "\<bs>"
let idx = idx[:-2]
else
let idx .= c
endif
if idx < len(items) && idx.'0' > len(items) || idx == 0 && len(items) < 10
" only match
return self.DoContinue(self.MapToOriginal(items[idx]))
endif
else
return self.FilterFromKeyboard(1,c)
endif
endif
endwhile
finally
let self.modeText = ''
endtry
endfun
" gets a regular expresion filter by keybaord and updates the display while
" you're typing. The regex ist shown in the statusline
fun d.FilterFromKeyboard(keep, start, ...)
let self.modeText = 'press ESC to exit getchar() loop'
call self.UpdateDisplay() | redraw
try
let key_text = a:0 > 0 ? 'key : '.a:1 : ''
let filter_bak = self.filter
let filter = copy(self.filter)
let start = a:start
let filter_new = ''
while 1
if start != ''
" use c= last char to force updating display etc
let filter_new = start[:-2]
let c = start[-1:]
let start = ''
else
let c=getchar()
endif
if index([13,10],c) >= 0
" c-j or return, accept new filter
let items = self.FilteredItems()
if len(items) == 1 && has_key(self, 'Continuation') && self.continueOnSingleMatchCR
call self.DoContinue(self.MapToOriginal(items[0]))
endif
return
elseif index([27], c) >=0
" esc, abort
let self.filter = filter_bak
call self.UpdateDisplay()
return
else
if type(c) == 0
let c = nr2char(c)
endif
if c == "\<bs>"
let filter_new = filter_new[:-2]
else
let filter_new .= c
endif
let d = {'keep' : a:keep, 'regex' : filter_new }
if a:0 > 0
let d['key'] = a:1
endif
let self.filter = copy(filter_bak)
call add(self.filter, d)
let items = self.FilteredItems()
if len(items) == 1 && has_key(self, 'Continuation') && self.continueOnSingleMatch
call self.DoContinue(self.MapToOriginal(items[0]))
return
endif
call self.UpdateDisplay() | redraw
endif
endwhile
finally
let self.modeText = ''
endtry
endfun
if get(a:opts,'init',1)
call d.NewBufferAndInit()
endif
endfun