diff options
author | Karel Kočí <cynerd@email.cz> | 2016-06-30 16:03:25 +0200 |
---|---|---|
committer | Karel Kočí <cynerd@email.cz> | 2016-06-30 16:03:25 +0200 |
commit | e573b3020c032400eed60b649a2cbf55266e6bb0 (patch) | |
tree | 8f572394ac8433529c7a8e70d160a2fbe8268b4e /vim/bundle/tlib_vim/autoload/tlib/input.vim | |
parent | b8c667bd64b3edd38d56c63c5bd1db53a23b4499 (diff) | |
download | myconfigs-e573b3020c032400eed60b649a2cbf55266e6bb0.tar.gz myconfigs-e573b3020c032400eed60b649a2cbf55266e6bb0.tar.bz2 myconfigs-e573b3020c032400eed60b649a2cbf55266e6bb0.zip |
Add current configurations from old repository
Diffstat (limited to 'vim/bundle/tlib_vim/autoload/tlib/input.vim')
-rw-r--r-- | vim/bundle/tlib_vim/autoload/tlib/input.vim | 1336 |
1 files changed, 1336 insertions, 0 deletions
diff --git a/vim/bundle/tlib_vim/autoload/tlib/input.vim b/vim/bundle/tlib_vim/autoload/tlib/input.vim new file mode 100644 index 0000000..e8f892b --- /dev/null +++ b/vim/bundle/tlib_vim/autoload/tlib/input.vim @@ -0,0 +1,1336 @@ +" @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) +" @Revision: 1366 + + +" :filedoc: +" Input-related, select from a list etc. + +" If a list is bigger than this value, don't try to be smart when +" selecting an item. Be slightly faster instead. +" See |tlib#input#List()|. +TLet g:tlib#input#sortprefs_threshold = 200 + + +" If a list contains more items, |tlib#input#List()| does not perform an +" incremental "live search" but uses |input()| to query the user for a +" filter. This is useful on slower machines or with very long lists. +TLet g:tlib#input#livesearch_threshold = 1000 + + +" Determine how |tlib#input#List()| and related functions work. +" Can be "glob", "cnf", "cnfd", "seq", or "fuzzy". See: +" glob ... Like cnf but "*" and "?" (see |g:tlib#Filter_glob#seq|, +" |g:tlib#Filter_glob#char|) are interpreted as glob-like +" |wildcards| (this is the default method) +" - Examples: +" - "f*o" matches "fo", "fxo", and "fxxxoo", but doesn't match +" "far". +" - Otherwise it is a derivate of the cnf method (see below). +" - See also |tlib#Filter_glob#New()|. +" cnfd ... Like cnf but "." is interpreted as a wildcard, i.e. it is +" expanded to "\.\{-}" +" - A period character (".") acts as a wildcard as if ".\{-}" (see +" |/\{-|) were entered. +" - Examples: +" - "f.o" matches "fo", "fxo", and "fxxxoo", but doesn't match +" "far". +" - Otherwise it is a derivate of the cnf method (see below). +" - See also |tlib#Filter_cnfd#New()|. +" cnf .... Match substrings +" - A blank creates an AND conjunction, i.e. the next pattern has to +" match too. +" - A pipe character ("|") creates an OR conjunction, either this or +" the next next pattern has to match. +" - Patterns are very 'nomagic' |regexp| with a |\V| prefix. +" - A pattern starting with "-" makes the filter exclude items +" matching that pattern. +" - Examples: +" - "foo bar" matches items that contain the strings "foo" AND +" "bar". +" - "foo|bar boo|far" matches items that contain either ("foo" OR +" "bar") AND ("boo" OR "far"). +" - See also |tlib#Filter_cnf#New()|. +" seq .... Match sequences of characters +" - |tlib#Filter_seq#New()| +" fuzzy .. Match fuzzy character sequences +" - |tlib#Filter_fuzzy#New()| +TLet g:tlib#input#filter_mode = 'glob' + + +" The highlight group to use for showing matches in the input list +" window. +" See |tlib#input#List()|. +TLet g:tlib#input#higroup = 'IncSearch' + +" When 1, automatically select the last remaining item only if the list +" had only one item to begin with. +" When 2, automatically select a last remaining item after applying +" any filters. +" See |tlib#input#List()|. +TLet g:tlib_pick_last_item = 1 + + +" :doc: +" Keys for |tlib#input#List|~ + +TLet g:tlib#input#and = ' ' +TLet g:tlib#input#or = '|' +TLet g:tlib#input#not = '-' + +" When editing a list with |tlib#input#List|, typing these numeric chars +" (as returned by getchar()) will select an item based on its index, not +" based on its name. I.e. in the default setting, typing a "4" will +" select the fourth item, not the item called "4". +" In order to make keys 0-9 filter the items in the list and make +" <m-[0-9]> select an item by its index, remove the keys 48 to 57 from +" this dictionary. +" Format: [KEY] = BASE ... the number is calculated as KEY - BASE. +" :nodefault: +TLet g:tlib#input#numeric_chars = { + \ 176: 176, + \ 177: 176, + \ 178: 176, + \ 179: 176, + \ 180: 176, + \ 181: 176, + \ 182: 176, + \ 183: 176, + \ 184: 176, + \ 185: 176, + \} + " \ 48: 48, + " \ 49: 48, + " \ 50: 48, + " \ 51: 48, + " \ 52: 48, + " \ 53: 48, + " \ 54: 48, + " \ 55: 48, + " \ 56: 48, + " \ 57: 48, + + +" :nodefault: +" The default key bindings for single-item-select list views. +" +" This variable is best customized via the variable +" g:tlib_extend_keyagents_InputList_s. If you want to use <c-j>, <c-k> +" to move the cursor up and down, add these two lines to your |vimrc| +" file: +" +" let g:tlib_extend_keyagents_InputList_s = { +" \ 10: 'tlib#agent#Down', +" \ 11: 'tlib#agent#Up' +" \ } +TLet g:tlib#input#keyagents_InputList_s = { + \ "\<PageUp>": 'tlib#agent#PageUp', + \ "\<PageDown>": 'tlib#agent#PageDown', + \ "\<Home>": 'tlib#agent#Home', + \ "\<End>": 'tlib#agent#End', + \ "\<Up>": 'tlib#agent#Up', + \ "\<Down>": 'tlib#agent#Down', + \ 9: 'tlib#agent#Complete', + \ "\<c-Up>": 'tlib#agent#UpN', + \ "\<c-Down>": 'tlib#agent#DownN', + \ "\<Left>": 'tlib#agent#ShiftLeft', + \ "\<Right>": 'tlib#agent#ShiftRight', + \ 18: 'tlib#agent#Reset', + \ 242: 'tlib#agent#Reset', + \ 17: 'tlib#agent#Input', + \ 241: 'tlib#agent#Input', + \ 27: 'tlib#agent#Exit', + \ 26: 'tlib#agent#Suspend', + \ 250: 'tlib#agent#Suspend', + \ 15: 'tlib#agent#SuspendToParentWindow', + \ "\<F1>": 'tlib#agent#Help', + \ "\<F10>": 'tlib#agent#ExecAgentByName', + \ "\<S-Esc>": 'tlib#agent#ExecAgentByName', + \ "\<bs>": 'tlib#agent#ReduceFilter', + \ "\<del>": 'tlib#agent#ReduceFilter', + \ "\<c-bs>": 'tlib#agent#PopFilter', + \ "\<m-bs>": 'tlib#agent#PopFilter', + \ "\<c-del>": 'tlib#agent#PopFilter', + \ "\<m-del>": 'tlib#agent#PopFilter', + \ "\<s-space>": 'tlib#agent#Wildcard', + \ 191: 'tlib#agent#Debug', + \ char2nr(g:tlib#input#or): 'tlib#agent#OR', + \ char2nr(g:tlib#input#and): 'tlib#agent#AND', + \ } + " \ 63: 'tlib#agent#Help', + +if exists('g:tlib_extend_keyagents_InputList_s') + let g:tlib#input#keyagents_InputList_s = extend(g:tlib#input#keyagents_InputList_s, g:tlib_extend_keyagents_InputList_s) +endif + + +" :nodefault: +TLet g:tlib#input#keyagents_InputList_m = { + \ 35: 'tlib#agent#Select', + \ "\<s-up>": 'tlib#agent#SelectUp', + \ "\<s-down>": 'tlib#agent#SelectDown', + \ 1: 'tlib#agent#SelectAll', + \ 225: 'tlib#agent#SelectAll', + \ "\<F9>": 'tlib#agent#ToggleRestrictView', + \ } +" "\<c-space>": 'tlib#agent#Select' + +if exists('g:tlib_extend_keyagents_InputList_m') + let g:tlib#input#keyagents_InputList_m = extend(g:tlib#input#keyagents_InputList_m, g:tlib_extend_keyagents_InputList_m) +endif + + + +" :nodefault: +TLet g:tlib#input#handlers_EditList = [ + \ {'key': 5, 'agent': 'tlib#agent#EditItem', 'key_name': '<c-e>', 'help': 'Edit item'}, + \ {'key': 4, 'agent': 'tlib#agent#DeleteItems', 'key_name': '<c-d>', 'help': 'Delete item(s)'}, + \ {'key': 14, 'agent': 'tlib#agent#NewItem', 'key_name': '<c-n>', 'help': 'New item'}, + \ {'key': 24, 'agent': 'tlib#agent#Cut', 'key_name': '<c-x>', 'help': 'Cut item(s)'}, + \ {'key': 3, 'agent': 'tlib#agent#Copy', 'key_name': '<c-c>', 'help': 'Copy item(s)'}, + \ {'key': 22, 'agent': 'tlib#agent#Paste', 'key_name': '<c-v>', 'help': 'Paste item(s)'}, + \ {'pick_last_item': 0}, + \ {'return_agent': 'tlib#agent#EditReturnValue'}, + \ {'help_extra': [ + \ 'Submit changes by pressing ENTER or <c-s> or <c-w><cr>', + \ 'Cancel editing by pressing <c-w>c' + \ ]}, + \ ] + + +" A dictionary KEY => {'agent': AGENT, 'key_name': KEY_NAME} to +" customize keyboard shortcuts in the list view. +TLet g:tlib#input#user_shortcuts = {} + + +" If true, define a popup menu for |tlib#input#List()| and related +" functions. +TLet g:tlib#input#use_popup = has('menu') && (has('gui_gtk') || has('gui_gtk2') || has('gui_win32')) + + +" How to format filenames: +" l ... Show basenames on the left side, separated from the +" directory names +" r ... Show basenames on the right side +TLet g:tlib#input#format_filename = 'l' + + +" If g:tlib#input#format_filename == 'r', how much space should be kept +" free on the right side. +TLet g:tlib#input#filename_padding_r = '&co / 10' + + +" If g:tlib#input#format_filename == 'l', an expression that +" |eval()|uates to the maximum display width of filenames. +TLet g:tlib#input#filename_max_width = '&co / 2' + + +" Functions related to tlib#input#List(type, ...) "{{{2 + +" :def: function! tlib#input#List(type. ?query='', ?list=[], ?handlers=[], ?default="", ?timeout=0) +" Select a single or multiple items from a list. Return either the list +" of selected elements or its indexes. +" +" By default, typing numbers will select an item by its index. See +" |g:tlib#input#numeric_chars| to find out how to change this. +" +" The item is automatically selected if the numbers typed equals the +" number of digits of the list length. I.e. if a list contains 20 items, +" typing 1 will first highlight item 1 but it won't select/use it +" because 1 is an ambiguous input in this context. If you press enter, +" the first item will be selected. If you press another digit (e.g. 0), +" item 10 will be selected. Another way to select item 1 would be to +" type 01. If the list contains only 9 items, typing 1 would select the +" first item right away. +" +" type can be: +" s ... Return one selected element +" si ... Return the index of the selected element +" m ... Return a list of selected elements +" mi ... Return a list of indexes +" +" Several pattern matching styles are supported. See +" |g:tlib#input#filter_mode|. +" +" Users can type <Tab> to complete the current filter with the longest +" match. +" +" EXAMPLES: > +" echo tlib#input#List('s', 'Select one item', [100,200,300]) +" echo tlib#input#List('si', 'Select one item', [100,200,300]) +" echo tlib#input#List('m', 'Select one or more item(s)', [100,200,300]) +" echo tlib#input#List('mi', 'Select one or more item(s)', [100,200,300]) +" +" See ../samples/tlib/input/tlib_input_list.vim (move the cursor over +" the filename and press gf) for a more elaborated example. +function! tlib#input#List(type, ...) "{{{3 + exec tlib#arg#Let([ + \ ['query', ''], + \ ['list', []], + \ ['handlers', []], + \ ['rv', ''], + \ ['timeout', 0], + \ ]) + " let handlers = a:0 >= 1 ? a:1 : [] + " let rv = a:0 >= 2 ? a:2 : '' + " let timeout = a:0 >= 3 ? a:3 : 0 + " let backchar = ["\<bs>", "\<del>"] + + if a:type =~ '^resume' + let world = b:tlib_{matchstr(a:type, ' \zs.\+')} + else + let world = tlib#World#New({ + \ 'type': a:type, + \ 'base': list, + \ 'query': query, + \ 'timeout': timeout, + \ 'rv': rv, + \ 'handlers': handlers, + \ }) + let scratch_name = tlib#list#Find(handlers, 'has_key(v:val, "scratch_name")', '', 'v:val.scratch_name') + if !empty(scratch_name) + let world.scratch = scratch_name + endif + let world.scratch_vertical = tlib#list#Find(handlers, 'has_key(v:val, "scratch_vertical")', 0, 'v:val.scratch_vertical') + call world.Set_display_format(tlib#list#Find(handlers, 'has_key(v:val, "display_format")', '', 'v:val.display_format')) + let world.initial_index = tlib#list#Find(handlers, 'has_key(v:val, "initial_index")', 1, 'v:val.initial_index') + let world.index_table = tlib#list#Find(handlers, 'has_key(v:val, "index_table")', [], 'v:val.index_table') + let world.state_handlers = filter(copy(handlers), 'has_key(v:val, "state")') + let world.post_handlers = filter(copy(handlers), 'has_key(v:val, "postprocess")') + let world.filter_format = tlib#list#Find(handlers, 'has_key(v:val, "filter_format")', '', 'v:val.filter_format') + let world.return_agent = tlib#list#Find(handlers, 'has_key(v:val, "return_agent")', '', 'v:val.return_agent') + let world.help_extra = tlib#list#Find(handlers, 'has_key(v:val, "help_extra")', '', 'v:val.help_extra') + let world.resize = tlib#list#Find(handlers, 'has_key(v:val, "resize")', '', 'v:val.resize') + let world.show_empty = tlib#list#Find(handlers, 'has_key(v:val, "show_empty")', 0, 'v:val.show_empty') + let world.pick_last_item = tlib#list#Find(handlers, 'has_key(v:val, "pick_last_item")', + \ tlib#var#Get('tlib_pick_last_item', 'bg'), 'v:val.pick_last_item') + let world.numeric_chars = tlib#list#Find(handlers, 'has_key(v:val, "numeric_chars")', + \ g:tlib#input#numeric_chars, 'v:val.numeric_chars') + let world.key_handlers = filter(copy(handlers), 'has_key(v:val, "key")') + let filter = tlib#list#Find(handlers, 'has_key(v:val, "filter")', '', 'v:val.filter') + if !empty(filter) + " let world.initial_filter = [[''], [filter]] + " let world.initial_filter = [[filter]] + " TLogVAR world.initial_filter + call world.SetInitialFilter(filter) + endif + endif + return tlib#input#ListW(world) +endf + + +" A wrapper for |tlib#input#ListW()| that builds |tlib#World#New| from +" dict. +function! tlib#input#ListD(dict) "{{{3 + return tlib#input#ListW(tlib#World#New(a:dict)) +endf + + +" :def: function! tlib#input#ListW(world, ?command='') +" The second argument (command) is meant for internal use only. +" The same as |tlib#input#List| but the arguments are packed into world +" (an instance of tlib#World as returned by |tlib#World#New|). +function! tlib#input#ListW(world, ...) "{{{3 + TVarArg 'cmd' + " let time0 = str2float(reltimestr(reltime())) " DBG + " TLogVAR time0 + let world = a:world + if world.pick_last_item >= 1 && stridx(world.type, 'e') == -1 && len(world.base) <= 1 + let rv = get(world.base, 0, world.rv) + if stridx(world.type, 'm') != -1 + return [rv] + else + return rv + endif + endif + call s:Init(world, cmd) + " TLogVAR world.state, world.sticky, world.initial_index + " let statusline = &l:statusline + " let laststatus = &laststatus + let showmode = &showmode + set noshowmode + let lastsearch = @/ + let scrolloff = &l:scrolloff + let &l:scrolloff = 0 + let @/ = '' + let dlist = [] + let post_keys = '' + " let &laststatus = 2 + + try + while !empty(world.state) && world.state !~ '^exit' && (world.show_empty || !empty(world.base)) + let post_keys = '' + " TLogDBG 'while' + " TLogVAR world.state + " let time01 = str2float(reltimestr(reltime())) " DBG + " TLogVAR time01, time01 - time0 + try + let world = s:RunStateHandlers(world) + + " if exists('b:tlib_world_event') + " let event = b:tlib_world_event + " unlet! b:tlib_world_event + " if event == 'WinLeave' + " " let world.resume_state = world.state + " let world = tlib#agent#Suspend(world, world.rv) + " break + " endif + " endif + + " let time02 = str2float(reltimestr(reltime())) " DBG + " TLogVAR time02, time02 - time0 + if world.state =~ '\<reset\>' + " TLogDBG 'reset' + " call world.Reset(world.state =~ '\<initial\>') + call world.Reset() + continue + endif + + call s:SetOffset(world) + + " let time02 = str2float(reltimestr(reltime())) " DBG + " TLogVAR time02, time02 - time0 + " TLogDBG 1 + " TLogVAR world.state + if world.state == 'scroll' + let world.prefidx = world.offset + let world.state = 'redisplay' + endif + + if world.state =~ '\<sticky\>' + let world.sticky = 1 + endif + + " TLogVAR world.filter + " TLogVAR world.sticky + if world.state =~ '\<picked\>' + " TLogVAR world.rv + throw 'picked' + elseif world.state =~ '\<pick\>' + let world.rv = world.CurrentItem() + " TLogVAR world.rv + throw 'picked' + elseif world.state =~ 'display' + if world.state =~ '^display' + " let time03 = str2float(reltimestr(reltime())) " DBG + " TLogVAR time03, time03 - time0 + if world.IsValidFilter() + + " let time1 = str2float(reltimestr(reltime())) " DBG + " TLogVAR time1, time1 - time0 + call world.BuildTableList() + " let time2 = str2float(reltimestr(reltime())) " DBG + " TLogVAR time2, time2 - time0 + " TLogDBG 2 + " TLogDBG len(world.table) + " TLogVAR world.table + " let world.list = map(copy(world.table), 'world.GetBaseItem(v:val)') + " TLogDBG 3 + let world.llen = len(world.list) + " TLogVAR world.index_table + if empty(world.index_table) + let dindex = range(1, world.llen) + let world.index_width = len(world.llen) + else + let dindex = world.index_table + let world.index_width = len(max(dindex)) + endif + " let time3 = str2float(reltimestr(reltime())) " DBG + " TLogVAR time3, time3 - time0 + if world.llen == 0 && !world.show_empty + call world.ReduceFilter() + let world.offset = 1 + " TLogDBG 'ReduceFilter' + continue + else + if world.llen == 1 + let world.last_item = world.list[0] + if world.pick_last_item >= 2 + " echom 'Pick last item: '. world.list[0] + let world.prefidx = '1' + " TLogDBG 'pick last item' + throw 'pick' + endif + else + let world.last_item = '' + endif + endif + " let time4 = str2float(reltimestr(reltime())) " DBG + " TLogVAR time4, time4 - time0 + " TLogDBG 4 + " TLogVAR world.idx, world.llen, world.state + " TLogDBG world.FilterIsEmpty() + if world.state == 'display' + if world.idx == '' && world.llen < g:tlib#input#sortprefs_threshold && !world.FilterIsEmpty() + call world.SetPrefIdx() + else + let world.prefidx = world.idx == '' ? world.initial_index : world.idx + endif + if world.prefidx > world.llen + let world.prefidx = world.llen + elseif world.prefidx < 1 + let world.prefidx = 1 + endif + endif + " let time5 = str2float(reltimestr(reltime())) " DBG + " TLogVAR time5, time5 - time0 + " TLogVAR world.initial_index, world.prefidx + " TLogDBG 5 + " TLogDBG len(world.list) + " TLogVAR world.list + let dlist = world.DisplayFormat(world.list) + " TLogVAR world.prefidx + " TLogDBG 6 + " let time6 = str2float(reltimestr(reltime())) " DBG + " TLogVAR time6, time6 - time0 + if world.offset_horizontal > 0 + call map(dlist, 'v:val[world.offset_horizontal:-1]') + endif + " let time7 = str2float(reltimestr(reltime())) " DBG + " TLogVAR time7, time7 - time0 + " TLogVAR dindex + let dlist = map(range(0, world.llen - 1), 'printf("%0'. world.index_width .'d", dindex[v:val]) .": ". dlist[v:val]') + " TLogVAR dlist + " let time8 = str2float(reltimestr(reltime())) " DBG + " TLogVAR time8, time8 - time0 + + else + + let dlist = ['Malformed filter'] + + endif + else + if world.prefidx == 0 + let world.prefidx = 1 + endif + endif + " TLogVAR world.idx, world.prefidx + + " TLogDBG 7 + " TLogVAR world.prefidx, world.offset + " TLogDBG (world.prefidx > world.offset + winheight(0) - 1) + " if world.prefidx > world.offset + winheight(0) - 1 + " let listtop = world.llen - winheight(0) + 1 + " let listoff = world.prefidx - winheight(0) + 1 + " let world.offset = min([listtop, listoff]) + " TLogVAR world.prefidx + " TLogDBG len(list) + " TLogDBG winheight(0) + " TLogVAR listtop, listoff, world.offset + " elseif world.prefidx < world.offset + " let world.offset = world.prefidx + " endif + " TLogDBG 8 + " TLogVAR world.initial_display, !tlib#char#IsAvailable() + if world.state =~ '\<update\>' || world.initial_display || !tlib#char#IsAvailable() + " TLogDBG len(dlist) + call world.DisplayList(world.Query(), dlist) + call world.FollowCursor() + let world.initial_display = 0 + " TLogDBG 9 + endif + if world.state =~ '\<hibernate\>' + let world.state = 'suspend' + else + let world.state = '' + endif + else + " if world.state == 'scroll' + " let world.prefidx = world.offset + " endif + call world.DisplayList() + if world.state == 'help' || world.state == 'printlines' + let world.state = 'display' + else + let world.state = '' + call world.FollowCursor() + endif + endif + " TAssert IsNotEmpty(world.scratch) + let world.list_wnr = winnr() + + " TLogVAR world.state, world.next_state + if !empty(world.next_state) + let world.state = world.next_state + let world.next_state = '' + endif + + if world.state =~ '\<suspend\>' + let world = tlib#agent#SuspendToParentWindow(world, world.rv) + continue + endif + + if world.state =~ '\<eval\>' + let query = matchstr(world.state, '\<eval\[\zs.\{-}\ze\]') + if empty(query) + let query = 'Waiting for input ... Press ESC to continue' + endif + if has('gui_win32') + let exec_cmd = input(query, '') + " TLogVAR exec_cmd + if exec_cmd == '' + let world.state = 'redisplay' + else + exec exec_cmd + endif + elseif has('gui_gtk') || has('gui_gtk2') + let c = s:GetModdedChar(world) + " TLogVAR c + endif + else + " TLogVAR world.timeout + let c = s:GetModdedChar(world) + " TLogVAR c, has_key(world.key_map[world.key_mode],c) + endif + " TLogVAR c + " TLogDBG string(sort(keys(world.key_map[world.key_mode]))) + + " TLogVAR world.next_agent, world.next_eval + if !empty(world.next_agent) + let nagent = world.next_agent + let world.next_agent = '' + " let world = call(nagent, [world, world.GetSelectedItems(world.CurrentItem())]) + " call s:CheckAgentReturnValue(nagent, world) + let world = s:CallAgent({'agent': nagent}, world, world.GetSelectedItems(world.CurrentItem())) + elseif !empty(world.next_eval) + let selected = world.GetSelectedItems(world.CurrentItem()) + let neval = world.next_eval + let world.next_eval = '' + exec neval + call s:CheckAgentReturnValue(neval, world) + elseif world.state != '' + " continue + elseif has_key(world.key_map[world.key_mode], c) + let sr = @/ + silent! let @/ = lastsearch + " TLogVAR c, world.key_map[world.key_mode][c] + " TLog "Agent: ". string(world.key_map[world.key_mode][c]) + let handler = world.key_map[world.key_mode][c] + " " TLogVAR handler + " let world = call(handler.agent, [world, world.GetSelectedItems(world.CurrentItem())]) + " call s:CheckAgentReturnValue(c, world) + let world = s:CallAgent(handler, world, world.GetSelectedItems(world.CurrentItem())) + silent! let @/ = sr + " continue + elseif c == 13 + throw 'pick' + elseif c == 27 + " TLogVAR c, world.key_mode + if world.key_mode != 'default' + let world.key_mode = 'default' + let world.state = 'redisplay' + else + let world.state = 'exit empty' + endif + elseif c == "\<LeftMouse>" + if v:mouse_win == world.list_wnr + let world.prefidx = world.GetLineIdx(v:mouse_lnum) + " let world.offset = world.prefidx + if empty(world.prefidx) + " call feedkeys(c, 't') + let c = s:GetModdedChar(world) + let world.state = 'help' + continue + endif + throw 'pick' + else + let post_keys = v:mouse_lnum .'gg'. v:mouse_col .'|'. c + if world.allow_suspend + let world = tlib#agent#SuspendToParentWindow(world, world.rv) + else + let world.state = 'exit empty' + endif + endif + elseif c == "\<RightMouse>" + if v:mouse_win == world.list_wnr + call s:BuildMenu(world) + let world.state = 'redisplay' + if s:PopupmenuExists() == 1 + " if v:mouse_lnum != line('.') + " endif + let world.prefidx = world.GetLineIdx(v:mouse_lnum) + let world.next_state = 'eval[Waiting for popup menu ... Press ESC to continue]' + call world.DisplayList() + if line('w$') - v:mouse_lnum < 6 + popup ]TLibInputListPopupMenu + else + popup! ]TLibInputListPopupMenu + endif + endif + else + let post_keys = v:mouse_lnum .'gg'. v:mouse_col .'|'. c + if world.allow_suspend + let world = tlib#agent#SuspendToParentWindow(world, world.rv) + else + let world.state = 'exit empty' + endif + endif + " TLogVAR world.prefidx, world.state + elseif has_key(world.key_map[world.key_mode], 'unknown_key') + let agent = world.key_map[world.key_mode].unknown_key.agent + " let world = call(agent, [world, c]) + " call s:CheckAgentReturnValue(agent, world) + let world = s:CallAgent({'agent': agent}, world, c) + elseif c >= 32 + let world.state = 'display' + let numbase = get(world.numeric_chars, c, -99999) + " TLogVAR numbase, world.numeric_chars, c + if numbase != -99999 + let world.idx .= (c - numbase) + if len(world.idx) == world.index_width + let world.prefidx = world.idx + " TLogVAR world.prefidx + throw 'pick' + endif + else + let world.idx = '' + " TLogVAR world.filter + if world.llen > g:tlib#input#livesearch_threshold + let pattern = input('Filter: ', world.CleanFilter(world.filter[0][0]) . nr2char(c)) + if empty(pattern) + let world.state = 'exit empty' + else + call world.SetFrontFilter(pattern) + echo + endif + elseif c == 124 + call insert(world.filter[0], []) + else + call world.PushFrontFilter(c) + endif + " continue + if c == 45 && world.filter[0][0] == '-' + let world.state = 'redisplay' + end + endif + else + let world.state = 'redisplay' + " let world.state = 'continue' + endif + + catch /^picked$/ + call world.ClearAllMarks() + call world.MarkCurrent(world.prefidx) + let world.state = 'exit' + + catch /^pick$/ + call world.ClearAllMarks() + call world.MarkCurrent(world.prefidx) + let world.state = '' + " TLogDBG 'Pick item #'. world.prefidx + + finally + " TLogDBG 'finally 1', world.state + if world.state =~ '\<suspend\>' + " if !world.allow_suspend + " echom "Cannot be suspended" + " let world.state = 'redisplay' + " endif + elseif !empty(world.list) && !empty(world.base) + " TLogVAR world.list + if empty(world.state) + let world.rv = world.CurrentItem() + " TLogVAR world.state, world.rv + endif + " TLogVAR "postprocess" + for handler in world.post_handlers + let state = get(handler, 'postprocess', '') + " TLogVAR handler + " TLogVAR state + " TLogVAR world.state + if state == world.state + let agent = handler.agent + let [world, world.rv] = call(agent, [world, world.rv]) + " TLogVAR world.state, world.rv + call s:CheckAgentReturnValue(agent, world) + endif + endfor + endif + " TLogDBG 'state0='. world.state + endtry + " TLogDBG 'state1='. world.state + endwh + + " TLogVAR world.state + " TLogDBG string(tlib#win#List()) + " TLogDBG 'exit while loop' + " TLogVAR world.list + " TLogVAR world.sel_idx + " TLogVAR world.idx + " TLogVAR world.prefidx + " TLogVAR world.rv + " TLogVAR world.type, world.state, world.return_agent, world.index_table, world.rv + if world.state =~ '\<\(empty\|escape\)\>' + let world.sticky = 0 + endif + if world.state =~ '\<suspend\>' + " TLogDBG 'return suspended' + " TLogVAR world.prefidx + " exec world.prefidx + return + elseif world.state =~ '\<empty\>' + " TLog "empty" + " TLogDBG 'return empty' + " TLogVAR world.type + if stridx(world.type, 'm') != -1 + return [] + elseif stridx(world.type, 'i') != -1 + return 0 + else + return '' + endif + elseif !empty(world.return_agent) + " TLogDBG 'return agent' + " TLogVAR world.return_agent + call world.CloseScratch() + " TLogDBG "return_agent ". string(tlib#win#List()) + " TAssert IsNotEmpty(world.scratch) + return call(world.return_agent, [world, world.GetSelectedItems(world.rv)]) + elseif stridx(world.type, 'w') != -1 + " TLog "return_world" + " TLogDBG 'return world' + return world + elseif stridx(world.type, 'm') != -1 + " TLog "return_multi" + " TLogDBG 'return multi' + return world.GetSelectedItems(world.rv) + elseif stridx(world.type, 'i') != -1 + " TLog "return_index" + " TLogDBG 'return index' + if empty(world.index_table) + return world.rv + else + return world.index_table[world.rv - 1] + endif + else + " TLog "return_else" + " TLogDBG 'return normal' + return world.rv + endif + + finally + call world.Leave() + + " TLogVAR statusline + " let &l:statusline = statusline + " let &laststatus = laststatus + if &showmode != showmode + let &showmode = showmode + endif + silent! let @/ = lastsearch + let &l:scrolloff = scrolloff + if s:PopupmenuExists() == 1 + silent! aunmenu ]TLibInputListPopupMenu + endif + + " TLogDBG 'finally 2' + " TLogDBG string(world.Methods()) + " TLogVAR world.state + " TLogDBG string(tlib#win#List()) + if world.state !~ '\<suspend\>' + " redraw + " TLogVAR world.sticky, bufnr("%") + if world.sticky + " TLogDBG "sticky" + " TLogVAR world.bufnr + " TLogDBG bufwinnr(world.bufnr) + if world.scratch_split > 0 + if bufwinnr(world.bufnr) == -1 + " TLogDBG "UseScratch" + call world.UseScratch() + endif + let world = tlib#agent#SuspendToParentWindow(world, world.GetSelectedItems(world.rv)) + endif + else + " TLogDBG "non sticky" + " TLogVAR world.state, world.win_wnr, world.bufnr + if world.CloseScratch() + " TLogVAR world.winview + call tlib#win#SetLayout(world.winview) + endif + endif + endif + " for i in range(0,5) + " call getchar(0) + " endfor + echo + redraw! + if !empty(post_keys) + " TLogVAR post_keys + call feedkeys(post_keys) + endif + endtry +endf + + +function! s:CallAgent(handler, world, list) abort "{{{3 + let agent = a:handler.agent + let args = [a:world, a:list] + if has_key(a:handler, 'args') + let args += a:handler.args + endif + let world = call(agent, args) + " TLogVAR world.state, world.rv + call s:CheckAgentReturnValue(agent, world) + return world +endf + +function! s:GetModdedChar(world) "{{{3 + let [char, mode] = tlib#char#Get(a:world.timeout, a:world.timeout_resolution, 1) + if char !~ '\D' && char > 0 && mode != 0 + return printf("<%s-%s>", mode, char) + else + return char + endif +endf + + +function! s:Init(world, cmd) "{{{3 + " TLogVAR a:cmd + let a:world.initial_display = 1 + if a:cmd =~ '\<sticky\>' + let a:world.sticky = 1 + endif + if a:cmd =~ '^resume' + call a:world.UseInputListScratch() + let a:world.initial_index = line('.') + if a:cmd =~ '\<pick\>' + let a:world.state = 'pick' + let a:world.prefidx = a:world.initial_index + else + call a:world.Retrieve(1) + endif + " if !empty(a:world.resume_state) + " let a:world.state = a:world.resume_state + " endif + elseif !a:world.initialized + " TLogVAR a:world.initialized, a:world.win_wnr, a:world.bufnr + let a:world.filetype = &filetype + let a:world.fileencoding = &fileencoding + call a:world.SetMatchMode(tlib#var#Get('tlib#input#filter_mode', 'wb')) + call a:world.Initialize() + if !has_key(a:world, 'key_mode') + let a:world.key_mode = 'default' + endif + " TLogVAR has_key(a:world,'key_map') + if has_key(a:world, 'key_map') + " TLogVAR has_key(a:world.key_map,a:world.key_mode) + if has_key(a:world.key_map, a:world.key_mode) + let a:world.key_map[a:world.key_mode] = extend( + \ a:world.key_map[a:world.key_mode], + \ copy(g:tlib#input#keyagents_InputList_s), + \ 'keep') + else + let a:world.key_map[a:world.key_mode] = copy(g:tlib#input#keyagents_InputList_s) + endif + else + let a:world.key_map = { + \ a:world.key_mode : copy(g:tlib#input#keyagents_InputList_s) + \ } + endif + " TLogVAR a:world.type + if stridx(a:world.type, 'm') != -1 + call extend(a:world.key_map[a:world.key_mode], g:tlib#input#keyagents_InputList_m, 'force') + endif + for key_mode in keys(a:world.key_map) + let a:world.key_map[key_mode] = map(a:world.key_map[key_mode], 'type(v:val) == 4 ? v:val : {"agent": v:val}') + endfor + " TLogVAR a:world.key_mode + if type(a:world.key_handlers) == 3 + call s:ExtendKeyMap(a:world, a:world.key_mode, a:world.key_handlers) + elseif type(a:world.key_handlers) == 4 + for [world_key_mode, world_key_handlers] in items(a:world.key_handlers) + call s:ExtendKeyMap(a:world, world_key_mode, world_key_handlers) + endfor + else + throw "tlib#input#ListW: key_handlers must be either a list or a dictionary" + endif + " TLogVAR a:world.type, a:world.key_map + if !empty(a:cmd) + let a:world.state .= ' '. a:cmd + endif + endif + " TLogVAR a:world.state, a:world.sticky +endf + + +function! s:ExtendKeyMap(world, key_mode, key_handlers) "{{{3 + for handler in a:key_handlers + let k = get(handler, 'key', '') + if !empty(k) + let a:world.key_map[a:key_mode][k] = handler + endif + endfor +endf + + +function! s:PopupmenuExists() + if !g:tlib#input#use_popup + \ || exists(':popup') != 2 + \ || !(has('gui_win32') || has('gui_gtk') || has('gui_gtk2')) + " \ || !has('gui_win32') + let rv = -1 + else + try + let rv = 1 + silent amenu ]TLibInputListPopupMenu + catch + let rv = 0 + endtry + endif + " TLogVAR rv + return rv +endf + + +function! s:BuildMenu(world) "{{{3 + if g:tlib#input#use_popup && s:PopupmenuExists() == 0 + call s:BuildItem('Pick\ selected\ item', {'key_name': '<cr>', 'eval': 'let world.state = "pick"'}) + call s:BuildItem('Cancel', {'key_name': '<esc>', 'agent': 'tlib#agent#Exit'}) + call s:BuildItem('Select', {'key_name': '#', 'agent': 'tlib#agent#Select'}) + call s:BuildItem('Select\ all', {'key_name': '<c-a>', 'agent': 'tlib#agent#SelectAll'}) + call s:BuildItem('Reset\ list', {'key_name': '<c-r>', 'agent': 'tlib#agent#Reset'}) + call s:BuildItem('-StandardEntries-', {'key': ":", 'eval': 'let world.state = "redisplay"'}) + for [key_mode, key_handlers] in items(a:world.key_map) + let keys = sort(keys(key_handlers)) + let mitems = {} + for key in keys + let handler = key_handlers[key] + let k = get(handler, 'key', '') + if !empty(k) && has_key(handler, 'help') && !empty(handler.help) + if empty(key_mode) || key_mode == 'default' + let mname = '' + else + let mname = escape(key_mode, ' .\') .'.' + endif + if has_key(handler, 'submenu') + let submenu = escape(handler.submenu, ' .\') + else + let submenu = '~' + endif + for mfield in ['menu', 'help', 'key_name', 'agent'] + if has_key(handler, mfield) + let mname .= escape(handler[mfield], ' .\') + break + endif + endfor + if !has_key(mitems, submenu) + let mitems[submenu] = {} + endif + let mitems[submenu][mname] = handler + endif + endfor + for msubname in sort(keys(mitems)) + let msubitems = mitems[msubname] + if msubname == '~' + let msubmname = '' + else + let msubmname = msubname .'.' + endif + for mname in sort(keys(msubitems)) + let msname = msubmname . mname + let handler = msubitems[mname] + call s:BuildItem(msname, handler) + " if has_key(handler, 'agent') + " call s:BuildItem(msname, {'agent': handler.agent}) + " else + " call s:BuildItem(msname, {'key': handler.key_name}) + " endif + endfor + endfor + endfor + endif +endf + + +function! s:BuildItem(menu, def) "{{{3 + if has('gui_win32') + let key_mode = 'c' + elseif has('gui_gtk') || has('gui_gtk2') + let key_mode = 'raw' + endif + for k in ['agent', 'eval', 'key_name', 'key'] + if has('gui_win32') + elseif has('gui_gtk') || has('gui_gtk') + if k == 'agent' || k == 'eval' + continue + endif + endif + try + if has_key(a:def, k) + let v = a:def[k] + if k == 'key' + if key_mode == 'c' + " echom 'DBG amenu' (']TLibInputListPopupMenu.'. a:menu) ':let c = "'. v .'"<cr>' + exec 'amenu' (']TLibInputListPopupMenu.'. a:menu) ':let c = "'. v .'"<cr>' + else + " echom 'DBG amenu' (']TLibInputListPopupMenu.'. a:menu) v + exec 'amenu' (']TLibInputListPopupMenu.'. a:menu) v + endif + elseif k == 'key_name' + if key_mode == 'c' + " echom 'DBG amenu' (']TLibInputListPopupMenu.'. a:menu) ':let c = "\'. v .'"<cr>' + exec 'amenu' (']TLibInputListPopupMenu.'. a:menu) ':let c = "\'. v .'"<cr>' + else + let key = v + " echom 'DBG amenu' (']TLibInputListPopupMenu.'. a:menu) key + exec 'amenu' (']TLibInputListPopupMenu.'. a:menu) key + endif + elseif k == 'agent' + " echom 'DBG amenu' (']TLibInputListPopupMenu.'. a:menu) ':let world.next_agent ='. string(v) .'<cr>' + exec 'amenu' (']TLibInputListPopupMenu.'. a:menu) ':let world.next_agent ='. string(v) .'<cr>' + elseif k == 'eval' + " echom 'DBG amenu' (']TLibInputListPopupMenu.'. a:menu) ':let world.next_eval ='. string(v) .'<cr>' + exec 'amenu' (']TLibInputListPopupMenu.'. a:menu) ':let world.next_eval ='. string(v) .'<cr>' + endif + return + endif + catch + endtry + endfor +endf + + +function! s:RunStateHandlers(world) "{{{3 + " Provide the variable "world" in the environment of an "exec" + " handler (ea). + let world = a:world + for handler in a:world.state_handlers + let eh = get(handler, 'state', '') + if !empty(eh) && a:world.state =~ eh + let ea = get(handler, 'exec', '') + if !empty(ea) + exec ea + else + let agent = get(handler, 'agent', '') + " let world = call(agent, [a:world, a:world.GetSelectedItems(a:world.CurrentItem())]) + " call s:CheckAgentReturnValue(agent, a:world) + let world = s:CallAgent({'agent': agent}, world, world.GetSelectedItems(world.CurrentItem())) + endif + endif + endfor + return world +endf + + +function! s:CheckAgentReturnValue(name, value) "{{{3 + if type(a:value) != 4 && !has_key(a:value, 'state') + echoerr 'Malformed agent: '. a:name + endif + return a:value +endf + + +function! s:SetOffset(world) "{{{3 + let llenw = len(a:world.base) - winheight(0) + 1 + if a:world.offset > llenw + let a:world.offset = llenw + endif + if a:world.offset < 1 + let a:world.offset = 1 + endif +endf + + +" Functions related to tlib#input#EditList(type, ...) "{{{2 + +" :def: function! tlib#input#EditList(query, list, ?timeout=0) +" Edit a list. +" +" EXAMPLES: > +" echo tlib#input#EditList('Edit:', [100,200,300]) +function! tlib#input#EditList(query, list, ...) "{{{3 + let handlers = a:0 >= 1 && !empty(a:1) ? a:1 : g:tlib#input#handlers_EditList + let default = a:0 >= 2 ? a:2 : [] + let timeout = a:0 >= 3 ? a:3 : 0 + " TLogVAR handlers + let rv = tlib#input#List('me', a:query, copy(a:list), handlers, default, timeout) + " TLogVAR rv + if empty(rv) + return a:list + else + let [success, list] = rv + return success ? list : a:list + endif +endf + + +function! tlib#input#Resume(name, pick, bufnr) "{{{3 + " TLogVAR a:name, a:pick + echo + if bufnr('%') != a:bufnr + if g:tlib#debug + echohl WarningMsg + echom "tlib#input#Resume: Internal error: Not in scratch buffer:" bufname('%') + echohl NONE + endif + let br = tlib#buffer#Set(a:bufnr) + endif + if !exists('b:tlib_'. a:name) + if g:tlib#debug + echohl WarningMsg + echom "tlib#input#Resume: Internal error: b:tlib_". a:name ." does not exist:" bufname('%') + echohl NONE + redir => varss + silent let b: + redir END + let vars = split(varss, '\n') + call filter(vars, 'v:val =~ "^b:tlib_"') + echom "DEBUG tlib#input#Resume" string(vars) + endif + else + call tlib#autocmdgroup#Init() + autocmd! TLib BufEnter <buffer> + if b:tlib_{a:name}.state =~ '\<suspend\>' + let b:tlib_{a:name}.state = 'redisplay' + else + let b:tlib_{a:name}.state .= ' redisplay' + endif + " call tlib#input#List('resume '. a:name) + let cmd = 'resume '. a:name + if a:pick >= 1 + let cmd .= ' pick' + if a:pick >= 2 + let cmd .= ' sticky' + end + endif + call tlib#input#ListW(b:tlib_{a:name}, cmd) + endif +endf + + +" :def: function! tlib#input#CommandSelect(command, ?keyargs={}) +" Take a command, view the output, and let the user select an item from +" its output. +" +" EXAMPLE: > +" command! TMarks exec 'norm! `'. matchstr(tlib#input#CommandSelect('marks'), '^ \+\zs.') +" command! TAbbrevs exec 'norm i'. matchstr(tlib#input#CommandSelect('abbrev'), '^\S\+\s\+\zs\S\+') +function! tlib#input#CommandSelect(command, ...) "{{{3 + TVarArg ['args', {}] + if has_key(args, 'retrieve') + let list = call(args.retrieve) + elseif has_key(args, 'list') + let list = args.list + else + let list = tlib#cmd#OutputAsList(a:command) + endif + if has_key(args, 'filter') + call map(list, args.filter) + endif + let type = has_key(args, 'type') ? args.type : 's' + let handlers = has_key(args, 'handlers') ? args.handlers : [] + let rv = tlib#input#List(type, 'Select', list, handlers) + if !empty(rv) + if has_key(args, 'process') + let rv = call(args.process, [rv]) + endif + endif + return rv +endf + + +" :def: function! tlib#input#Edit(name, value, callback, ?cb_args=[]) +" +" Edit a value (asynchronously) in a scratch buffer. Use name for +" identification. Call callback when done (or on cancel). +" In the scratch buffer: +" Press <c-s> or <c-w><cr> to enter the new value, <c-w>c to cancel +" editing. +" EXAMPLES: > +" fun! FooContinue(success, text) +" if a:success +" let b:var = a:text +" endif +" endf +" call tlib#input#Edit('foo', b:var, 'FooContinue') +function! tlib#input#Edit(name, value, callback, ...) "{{{3 + " TLogVAR a:value + TVarArg ['args', []] + let sargs = {'scratch': '__EDIT__'. a:name .'__', 'win_wnr': winnr()} + let scr = tlib#scratch#UseScratch(sargs) + + " :nodoc: + map <buffer> <c-w>c :call <SID>EditCallback(0)<cr> + " :nodoc: + imap <buffer> <c-w>c <c-o>call <SID>EditCallback(0)<cr> + " :nodoc: + map <buffer> <c-s> :call <SID>EditCallback(1)<cr> + " :nodoc: + imap <buffer> <c-s> <c-o>call <SID>EditCallback(1)<cr> + " :nodoc: + map <buffer> <c-w><cr> :call <SID>EditCallback(1)<cr> + " :nodoc: + imap <buffer> <c-w><cr> <c-o>call <SID>EditCallback(1)<cr> + + call tlib#normal#WithRegister('gg"tdG', 't') + call append(1, split(a:value, "\<c-j>", 1)) + " let hrm = 'DON''T DELETE THIS HEADER' + " let hr3 = repeat('"', (tlib#win#Width(0) - len(hrm)) / 2) + let s:horizontal_line = repeat('`', tlib#win#Width(0)) + " hr3.hrm.hr3 + let hd = ['Keys: <c-s>, <c-w><cr> ... save/accept; <c-w>c ... cancel', s:horizontal_line] + call append(1, hd) + call tlib#normal#WithRegister('gg"tdd', 't') + syntax match TlibEditComment /^\%1l.*/ + syntax match TlibEditComment /^```.*/ + hi link TlibEditComment Comment + exec len(hd) + 1 + if type(a:callback) == 4 + let b:tlib_scratch_edit_callback = get(a:callback, 'submit', '') + call call(get(a:callback, 'init', ''), []) + else + let b:tlib_scratch_edit_callback = a:callback + endif + let b:tlib_scratch_edit_args = args + let b:tlib_scratch_edit_scratch = sargs + " exec 'autocmd BufDelete,BufHidden,BufUnload <buffer> call s:EditCallback('. string(a:name) .')' + " echohl MoreMsg + " echom 'Press <c-s> to enter, <c-w>c to cancel editing.' + " echohl NONE +endf + + +function! s:EditCallback(...) "{{{3 + TVarArg ['ok', -1] + " , ['bufnr', -1] + " autocmd! BufDelete,BufHidden,BufUnload <buffer> + if ok == -1 + let ok = confirm('Use value') + endif + let start = getline(2) == s:horizontal_line ? 3 : 1 + let text = ok ? join(getline(start, '$'), "\n") : '' + let cb = b:tlib_scratch_edit_callback + let args = b:tlib_scratch_edit_args + let sargs = b:tlib_scratch_edit_scratch + " TLogVAR cb, args, sargs + call tlib#scratch#CloseScratch(b:tlib_scratch_edit_scratch) + call tlib#win#Set(sargs.win_wnr) + call call(cb, args + [ok, text]) +endf + + +function! tlib#input#Dialog(text, options, default) "{{{3 + if has('dialog_con') || has('dialog_gui') + let opts = join(map(a:options, '"&". v:val'), "\n") + let val = confirm(a:text, opts) + if val + let yn = a:options[val - 1] + else + let yn = a:default + endif + else + let oi = index(a:options, a:default) + if oi == -1 + let opts = printf("(%s|%s)", join(a:options, '/'), a:default) + else + let options = copy(a:options) + let options[oi] = toupper(options[oi]) + let opts = printf("(%s)", join(a:options, '/')) + endif + let yn = inputdialog(a:text .' '. opts) + endif + return yn +endf + |