Commits

ZyX_I committed da8cde7

@/mappings: Added possibility to specify dictionaries in `strfunc' and `func' keys

Comments (0)

Files changed (10)

                               precise results).
                       %mgid   Mapping group id.
                       %mname  Mapping name.
+
+                      You can use dictionary instead of the function reference 
+                      for the `func' key.
                    3. Function reference: like 2. with `func' set to rhs and 
                       `args' set to [].
                    3. Dictionary: requires presence of plugin/frawor/functions 
                       just as in the previous clause, though instead of taking 
                       list of arguments from the `rhs' key, it will be taken 
                       from the `args' key.
-                      Note that this is the only way to load non-oneload 
-                      plugin before invoking a mapping.
                                                             *frawor-mk-silent*
         silent     Bool, determines whether mapping will be silent (see 
                    |map-<silent>|). Default value: 0.
                    {addarg} is the additional argument to itself that will be 
                    used on next iteration (ignored if it is equal to zero).
 
+                   You can use dictionary instead of a function reference. In 
+                   this case plugin will be loaded before strfunc will be 
+                   wrapped and called (only if `rhs' is a List or 
+                   Dictionary).
+
                    Note: `passing some keys back' means using |feedkeys()| for 
                    mappings where |frawor-mk-rhs| is a String and 
                    |frawor-mk-expr| is 0 and appending result to {rhs} in 
 ==============================================================================
 8. Changelog                                                *frawor-changelog*
 
+@/mappings:
+    0.1: Added possibility to specify dictionaries in `strfunc' and `func' 
+         keys.
+
 vim: ft=help:tw=78

plugin/frawor/mappings.vim

 "▶1 Header
 scriptencoding utf-8
-execute frawor#Setup('0.0', {'plugin/frawor/options': '0.0',
+execute frawor#Setup('0.1', {'plugin/frawor/options': '0.0',
             \           'plugin/frawor/autocommands': '0.0',
             \              'plugin/frawor/resources': '0.0',}, 1)
 "▶1 Define variables
                 \   'rhsndef': 'ключ «rhs» не определён',
                 \    'middef': 'привязка с данным именем уже определена',
                 \ 'strfncall': 'неизвестная функция в значении ключа «strfunc»',
+                \    'fncall': 'неизвестная функция в значении ключа «func»',
                 \    'mapcol': 'левая часть («%s») данной привязки совпадает '.
                 \              'с левой частью привязки %s группы %s, '.
                 \              'определённой в дополнении %s',
                 \   'rhsndef': '`rhs'' key is not defined',
                 \    'middef': 'mapping with such name was already defined',
                 \ 'strfncall': '`strfunc'' key contains unknown function',
+                \    'fncall': '`func'' key contains unknown function',
                 \    'mapcol': '{lhs} (`%s'') of the mapping is just the same '.
                 \              'as {lhs} of mapping %s from group %s '.
                 \              'defined by plugin %s',
         let s:mrargs=[a:mgid, a:mapname, a:mode, a:lhs]
         return s:modeopsuf[a:mode].'g@'
     endif
+    if !has_key(map, 'loaded')
+        if !has_key(mgroup, 'plloaded')
+            if !FraworLoad(mgroup.plid)
+                call s:_f.throw('loadfail', a:mapname, a:mgid, mgroup.plid)
+            endif
+            if has_key(mgroup, 'func') && type(mgroup.func)==type({})
+                let mgroup.func=call(mgroup.wrapfunc, [mgroup.func], {})
+            endif
+            let mgroup.plloaded=1
+        endif
+        for key in filter(['strfunc', 'func'], 'has_key(map, v:val) && '.
+                    \                          'type(map[v:val])=='.type({}))
+            let map[key]=call(mgroup.wrapfunc, [map[key]], {})
+        endfor
+        let map.loaded=1
+    endif
+    let d={'func': (has_key(map, 'func')?(map.func):(mgroup.func))}
     if (map.expr==2)
-        return call(map.func, a:000+(has_key(map, 'strfunc')?
+        return call(d.func, a:000+(has_key(map, 'strfunc')?
                     \                   [s:F.getstr(map.strfunc, s:F.feedfunc)]:
                     \                   []), {})
     elseif (map.expr==3)
-        return call(map.func, a:000+map(copy(map.args), s:replaceexpr), {})
-    elseif (map.expr==4)
-        if !FraworLoad(mgroup.plid)
-            call s:_f.throw('loadfail', a:mapname, a:mgid, mgroup.plid)
-        endif
-        if !has_key(map, 'func')
-            let map.func=call(map.wrapfunc, [map.dict], {})
-            unlet map.dict map.wrapfunc
-        endif
-        let map.expr=3
-        return call(map.func, a:000+map(copy(map.args), s:replaceexpr), {})
+        return call(d.func, a:000+map(copy(map.args), s:replaceexpr), {})
     endif
 endfunction
 "▶1 opfunc        :: mtype → <expr> + ?
     endif
 endfunction
 "▶2 mapgroup.add   :: {f}, mgid, {mapid: mapdescr}[, mopts] → + s:mgroups, …
+"▶3 getfkey :: mgroup, Val, mapname, plugdict, emsgid → Val | + throw
+function s:F.getfkey(mgroup, Val, mapname, plugdict, emsgid)
+    if type(a:Val)==type({})
+        if !has_key(a:mgroup, 'wrapfunc')
+            if !exists('a:plugdict.g._f.wrapfunc')
+                call s:_f.throw('nowrapfunc', a:mapname, a:mgroup.id,
+                            \                 a:plugdict.id)
+            endif
+            let a:mgroup.wrapfunc=a:plugdict.g._f.wrapfunc
+        endif
+    else
+        if !exists('*a:Val')
+            call s:_f.throw(a:emsgid, a:mapname, a:mgroup.id, a:plugdict.id)
+        endif
+    endif
+    return a:Val
+endfunction
+"▲3
 let s:mgroups={}
 let s:mglastid=0
 let s:mapdescrdef={'silent': 0,
             let mgroup.leader=a:1.leader
         endif
         if has_key(a:1, 'func')
-            let mgroup.func=a:1.func
+            let mgroup.func=s:F.getfkey(mgroup, a:1.func, '', a:plugdict,
+                        \               'ncall')
         endif
         "▶4 string -> mapdescrdef (mode, type)
         for key in ['mode', 'type']
         endif
         "▶3 Add `strfunc' key
         if has_key(mapdescr, 'strfunc')
-            if !exists('*mapdescr.strfunc')
-                call s:_f.throw('strfncall', mapname, mgid, a:plugdict.id)
-            endif
-            let map.strfunc=mapdescr.strfunc
+            let map.strfunc=s:F.getfkey(mgroup, mapdescr.strfunc, mapname,
+                        \               a:plugdict, 'strfncall')
+        endif
+        "▶3 Add `func' key
+        if has_key(mapdescr, 'func')
+            let map.func=s:F.getfkey(mgroup, mapdescr.func, mapname, a:plugdict,
+                        \            'fncall')
         endif
         "▲3
         let evalstr='<SNR>'.s:_sid.'_Eval'
                         \                      '"'.(map.id).'", %s)'
         "▶3 map.rhs :: List
         elseif type(map.rhs)==type([])
-            "▶4 Check `func' key
-            if !exists('*mapdescr.func') && !exists('*mgroup.func')
+            "▶4 Check `func' key existence
+            if !has_key(map, 'func') && !has_key(mgroup, 'func')
                 call s:_f.throw('nofunc', mapname, mgid, a:plugdict.id)
             endif
             "▲4
             let map.expr=3
-            let map.func=get(mapdescr, 'func', get(mgroup, 'func'))
             let map.args=map.rhs
             let map.rhs=evalstr.'("s:F").maprun("'.mgroup.id.'", '.
                         \                      '"'.(map.id).'", %s)'
         "▶3 map.rhs :: Dictionary
         elseif type(map.rhs)==type({})
             "▶4 Do some checks
-            if !exists('*a:plugdict.g._f.wrapfunc')
-                call s:_f.throw('nowrapfunc', mapname, mgid, a:plugdict.id)
-            elseif has_key(mapdescr, 'args') &&
-                        \type(mapdescr.args)!=type([])
+            if has_key(mapdescr, 'args') && type(mapdescr.args)!=type([])
                 call s:_f.throw('invargs',mapname, mgid, a:plugdict.id)
             endif
             "▲4
-            let map.expr=4
-            let map.dict=map.rhs
-            let map.wrapfunc=a:plugdict.g._f.wrapfunc
+            let map.expr=3
+            let map.func=s:F.getfkey(mgroup, map.rhs, mapname, a:plugdict, '')
             let map.args=get(mapdescr, 'args', [])
             let map.rhs=evalstr.'("s:F").maprun("'.mgroup.id.'", '.
                         \                      '"'.(map.id).'", %s)'
             if empty(map.rhs)
                 let map.rhs='<Nop>'
             elseif has_key(map, 'strfunc')
+                if type(map.strfunc)==type({})
+                    let map.strfunc=call(mgroup.wrapfunc, [map.strfunc], {})
+                endif
                 let map.rhs=substitute((map.rhs), '%str',
                             \evalstr.'("s:F.getstr(s:mgroups.'.(mgroup.id).'.'.
                             \                       'maps.'.(map.id).'.strfunc'.

test/mappings-func-twoload.in

+:let &rtp.=",".escape($TESTDIR, ',\').'/rtp'
+:let g:testfile="plugin/".g:curtest.".vim"
+:source test.vim
+ab
+:call FraworUnload(g:testfile[:-5])
+:source test.vim
+ba
+:call FraworUnload(g:testfile[:-5])
+:source test.vim
+a
+:call FraworUnload(g:testfile[:-5])
+:source test.vim
+b

test/mappings-func-twoload.ok

+alpha: ('a')
+beta: ('b')
+beta: ('b')
+alpha: ('a')
+alpha: ('a')
+beta: ('b')

test/rtp/plugin/invalid-addmapgroup.25.vim

-execute frawor#Setup('0.0', {'plugin/frawor/mappings': '0.0'}, 1)
-call s:_f.mapgroup.add("Mgroup", {'test': {'rhs': {}, 'args': 0}})
+execute frawor#Setup('0.0', {'@/mappings': '0.0'}, 1)
+call s:_f.mapgroup.add('Mgroup', {'test': {'rhs': {}, 'args': []}})
 

test/rtp/plugin/mappings-func-twoload.vim

+if !exists('s:_pluginloaded')
+    execute frawor#Setup('0.0', {'@/mappings': '0.0',
+                \               '@/functions': '0.0'}, 0)
+    let s:mappings={'alpha': {'rhs': ['%lhs'], 'lhs': 'a', 'func': {}},
+                \    'beta': {'rhs': ['%lhs'], 'lhs': 'b'}}
+    let s:mapoptions={'func': {}}
+    call s:_f.mapgroup.add('MG', s:mappings, s:mapoptions)
+    finish
+elseif s:_pluginloaded
+    finish
+endif
+function s:mappings.alpha.func.function(...)
+    call WriteFile('alpha: ('.string(a:000)[1:-2].')')
+    return ''
+endfunction
+function s:mapoptions.func.function(...)
+    call WriteFile('beta: ('.string(a:000)[1:-2].')')
+    return ''
+endfunction

test/rtp/plugin/strfunc-mappings-twoload.vim

+if !exists('s:_pluginloaded')
+    execute frawor#Setup('0.0', {'@/mappings': '0.0',
+                \               '@/functions': '0.0'}, 0)
+    function MapFunc(...)
+        call WriteFile('args: ('.string(a:000)[1:-2].')')
+        return ''
+    endfunction
+    let s:_functions+=['MapFunc']
+
+    let s:strfunc={}
+    let s:function={}
+    call s:_f.mapgroup.add('Strfunc', {'1': {'rhs': ['%lhs', '%str'],
+                \                        'strfunc': s:strfunc,
+                \                           'func': function('MapFunc'),
+                \                            'lhs': 'a',},
+                \                      '2': {'rhs': s:function,
+                \                        'strfunc': s:strfunc,
+                \                           'args': ['%lhs', '%str'],
+                \                            'lhs': 'b',},
+                \                     })
+    finish
+elseif s:_pluginloaded
+    finish
+endif
+function s:strfunc.function(char, ...)
+    if a:0
+        call WriteFile('strfunc: ('.string([a:char]+a:000)[1:-2].')')
+    endif
+    if a:char=~#'^\u$'
+        return [ 1,  0,  0]
+    elseif a:char=~#'^\l$'
+        return [ 2,  0,  0]
+    elseif a:char=~#'^\s$'
+        return [ 3,  0,  0]
+    elseif a:char=~#'^\d$'
+        return [ 1,  1,  0]
+    elseif a:char is# ','
+        return [ 2,  2,  0]
+    elseif a:char is# '.'
+        return [ 3,  3,  0]
+    elseif a:char is# '-'
+        return [ 1,  0,  4]
+    elseif a:char is# ';'
+        return [ 2,  0,  5]
+    elseif a:char is# '!'
+        return [ 3,  0,  6]
+    elseif a:char is# '+'
+        return [ 1,  7,  8]
+    elseif a:char is# ':'
+        return [ 2,  9, 10]
+    elseif a:char is# '?'
+        return [ 3, 11, 12]
+    elseif a:char is# '^'
+        return [-1,  0,  0]
+    elseif a:char is# '#'
+        return [-1,  0, 13]
+    elseif a:char is# '%'
+        return [-1, 14,  0]
+    elseif a:char is# '&'
+        return [-1, 15, 16]
+    endif
+    return [0, 0, 0]
+endfunction
+let s:function.function=function('MapFunc')

test/rtp/plugin/strfunc-mappings.vim

-execute frawor#Setup('0.0', {'plugin/frawor/mappings': '0.0',
-            \               'plugin/frawor/functions': '0.0'}, 1)
+execute frawor#Setup('0.0', {'@/mappings': '0.0',
+            \               '@/functions': '0.0'}, 1)
 function s:F.strfunc(char, ...)
     if a:0
         call WriteFile('strfunc: ('.string([a:char]+a:000)[1:-2].')')
         return [ 3,  0,  0]
     elseif a:char=~#'^\d$'
         return [ 1,  1,  0]
-    elseif a:char==#','
+    elseif a:char is# ','
         return [ 2,  2,  0]
-    elseif a:char==#'.'
+    elseif a:char is# '.'
         return [ 3,  3,  0]
-    elseif a:char==#'-'
+    elseif a:char is# '-'
         return [ 1,  0,  4]
-    elseif a:char==#';'
+    elseif a:char is# ';'
         return [ 2,  0,  5]
-    elseif a:char==#'!'
+    elseif a:char is# '!'
         return [ 3,  0,  6]
-    elseif a:char==#'+'
+    elseif a:char is# '+'
         return [ 1,  7,  8]
-    elseif a:char==#':'
+    elseif a:char is# ':'
         return [ 2,  9, 10]
-    elseif a:char==#'?'
+    elseif a:char is# '?'
         return [ 3, 11, 12]
-    elseif a:char==#'^'
+    elseif a:char is# '^'
         return [-1,  0,  0]
-    elseif a:char==#'#'
+    elseif a:char is# '#'
         return [-1,  0, 13]
-    elseif a:char==#'%'
+    elseif a:char is# '%'
         return [-1, 14,  0]
-    elseif a:char==#'&'
+    elseif a:char is# '&'
         return [-1, 15, 16]
     endif
     return [0, 0, 0]
 endfunction
 function MapFunc(...)
     call WriteFile('args: ('.string(a:000)[1:-2].')')
-    return ""
+    return ''
 endfunction
 let s:_functions+=['MapFunc']
 
-call s:_f.mapgroup.add('Strfunc', {'1': {'rhs': ["%lhs", "%str"],
+call s:_f.mapgroup.add('Strfunc', {'1': {'rhs': ['%lhs', '%str'],
             \                        'strfunc': s:F.strfunc,
             \                           'func': function('MapFunc'),
             \                            'lhs': 'a',},
             \                      '2': {'rhs': {'function':
             \                                    function('MapFunc')},
             \                        'strfunc': s:F.strfunc,
-            \                           'args': ["%lhs", "%str"],
+            \                           'args': ['%lhs', '%str'],
             \                            'lhs': 'b',},
             \                      '3': {'rhs':
             \                             ':<C-u>call MapFunc(%str)<CR>',

test/strfunc-mappings-twoload.in

+:let &rtp.=",".escape($TESTDIR, ',\').'/rtp'
+:let g:testfile="plugin/".g:curtest.".vim"
+:source test.vim
+:let @/="!!!"
+AabcaAb*:call WriteFile(@/)
+odefbCd*:call WriteFile(@/)
+ojkl
+a^a#a%a&
+aU^aU#aU%aU&
+al^al#al%al&
+b^b#b%b&
+bU^bU#bU%bU&
+bl^bl#bl%bl&
+aabcdef
+aabcdef 
+a.
+a:?
+:0
+:W=== Second load ===
+:call FraworUnload(g:testfile[:-5])
+:source test.vim
+AabcaAb*:call WriteFile(@/)
+odefbCd*:call WriteFile(@/)
+ojkl
+a^a#a%a&
+aU^aU#aU%aU&
+al^al#al%al&
+b^b#b%b&
+bU^bU#bU%bU&
+bl^bl#bl%bl&
+aabcdef
+aabcdef 
+a.
+a:?

test/strfunc-mappings-twoload.ok

+args: ('a', 'Ab')
+\<abc\>
+args: ('b', 'Cd')
+\<def\>
+args: ('a', '')
+args: ('a', '')
+args: ('a', ['', 14])
+args: ('a', ['', 15])
+args: ('a', '')
+args: ('a', '')
+args: ('a', ['', 14])
+args: ('a', ['', 15])
+args: ('a', 'l')
+args: ('a', 'l')
+args: ('a', 'l')
+args: ('a', 'l')
+args: ('b', '')
+args: ('b', '')
+args: ('b', ['', 14])
+args: ('b', ['', 15])
+args: ('b', '')
+args: ('b', '')
+args: ('b', ['', 14])
+args: ('b', ['', 15])
+args: ('b', 'l')
+args: ('b', 'l')
+args: ('b', 'l')
+args: ('b', 'l')
+args: ('a', 'abcdef')
+args: ('a', 'abcdef ')
+args: ('a', ['.', 3])
+strfunc: ('?', 10)
+args: ('a', [':?', 11])
+=== Second load ===
+args: ('a', 'Ab')
+\<abcabc\>
+args: ('b', 'Cd')
+\<def\>
+args: ('a', '')
+args: ('a', '')
+args: ('a', ['', 14])
+args: ('a', ['', 15])
+args: ('a', '')
+args: ('a', '')
+args: ('a', ['', 14])
+args: ('a', ['', 15])
+args: ('a', 'l')
+args: ('a', 'l')
+args: ('a', 'l')
+args: ('a', 'l')
+args: ('b', '')
+args: ('b', '')
+args: ('b', ['', 14])
+args: ('b', ['', 15])
+args: ('b', '')
+args: ('b', '')
+args: ('b', ['', 14])
+args: ('b', ['', 15])
+args: ('b', 'l')
+args: ('b', 'l')
+args: ('b', 'l')
+args: ('b', 'l')
+args: ('a', 'abcdef')
+args: ('a', 'abcdef ')
+args: ('a', ['.', 3])
+strfunc: ('?', 10)
+args: ('a', [':?', 11])