Commits

ZyX_I committed 70b326b

core: Made it possible for different plugins to define two features with the same name

  • Participants
  • Parent commits bccfcbd

Comments (0)

Files changed (2)

File plugin/frawor.vim

                 \                'не может являться названием возможности',
                 \     'featreg': 'Ошибка регистрации возможности %s '.
                 \                'дополнения %s: возможность с таким именем '.
-                \                'уже зарегестрирована дополнением %s',
+                \                'уже зарегестрирована данным дополнением',
                 \ 'foptsnotdct': 'Ошибка регистрации возможности %s '.
                 \                'дополнения %s: описание возможности '.
                 \                'не является словарём',
                 \                'is not a valid feature ID',
                 \     'featreg': 'Error while registering feature %s '.
                 \                'of a plugin %s: feature with such ID was '.
-                \                'already registered by plugin %s',
+                \                'already registered by this plugin',
                 \ 'foptsnotdct': 'Error while registering feature %s '.
                 \                'of a plugin %s: description argument '.
                 \                'is not a Dictionary',
     " behavior must be kept in order to work with resolve()
     let curpath=fnamemodify(file, ':h')
     let removedcomponents=[fnamemodify(file, ':t:r')]
-    let foundrtp=""
-    let lastpath=""
+    let foundrtp=''
+    let lastpath=''
     let adddirs=[]
     while lastpath isnot# curpath
         let lastpath=curpath
                 \                          'processed) : '.
                 \           'eval(a:expr)')
 endfunction
-"▶1 createconsfunc  :: fid, consargs, suf → function
-function s:F.createconsfunc(fid, consargs, suf)
+"▶1 createconsfunc  :: efid, fname, consargs, suf → function
+function s:F.createconsfunc(efid, fname, consargs, suf)
     let r={}
     execute  "function r.F(...)\n".
-                \'    return call(s:features.'.a:fid.'.cons'.a:suf.', '.
-                \                '['.printf(a:consargs, a:fid)."]+a:000, {})\n".
+                \'    return call(s:features['.a:efid.'].cons'.a:suf.', '.
+                \                '['.printf(a:consargs,a:fname)."]+a:000,{})\n".
                 \'endfunction'
     return r.F
 endfunction
 function s:F.createcons(plugdict, shadowdict, feature)
     if type(a:feature.cons)==type({})
         return s:F.recdictmap(deepcopy(a:feature.cons),
-                    \'s:F.createconsfunc('.string(a:feature.id).', '.
-                    \                    string(a:shadowdict.consargs).', '.
-                    \                   '".".join(path+[v:key], "."))')
+                    \'s:F.createconsfunc('.string(a:feature.escapedid).', '.
+                    \                      string(a:feature.name).', '.
+                    \                      string(a:shadowdict.consargs).', '.
+                    \                    '".".join(path+[v:key], "."))')
     else
-        return s:F.createconsfunc(a:feature.id, a:shadowdict.consargs, "")
+        return s:F.createconsfunc(a:feature.escapedid, a:feature.name,
+                    \             a:shadowdict.consargs, '')
     endif
 endfunction
 "▶1 addcons         :: plugdict + s:f.cons → + p:_f
     let shadowdict=s:shadow[a:plugdict.id]
     for feature in sort(values(s:f.cons), function('s:FeatComp'))
         if has_key(a:plugdict.dependencies, feature.plid)
-            let a:plugdict.g._f[feature.id]=s:F.createcons(a:plugdict, shadowdict,
-                        \                                feature)
+            let a:plugdict.g._f[feature.name]=s:F.createcons(a:plugdict,
+                        \                                    shadowdict,
+                        \                                    feature)
         endif
     endfor
 endfunction
 " " Can't add s:FeatComp to _functions because it is required for unloadplugin 
 " " to  work and thus should not be removed by unloadpre event
 " let function('s:FeatComp')=function('s:FeatComp')
+"▶1 getfeatures     :: plugdict, {: feature} → [feature]
+function s:F.getfeatures(plugdict, featuresdict)
+    return sort(filter(values(a:featuresdict),
+                \      'has_key(a:plugdict.dependencies, v:val.plid) ||'.
+                \      'has_key(v:val, "ignoredeps")'),
+                \function('s:FeatComp'))
+endfunction
 "▶1 runfeatures     :: plugdict, fkey + shadowdict, +s:f → plugdict + shadowdict
 function s:F.runfeatures(plugdict, key)
     let fdicts=s:shadow[a:plugdict.id].features
-    for feature in sort(values(s:f[a:key]), function('s:FeatComp'))
-        if has_key(a:plugdict.dependencies, feature.plid) ||
-                    \has_key(feature, 'ignoredeps')
-            " XXX can't use feature[a:key](a:plugdict) due to the vim bug
-            call call(feature[a:key], [a:plugdict, fdicts[feature.id]], {})
+    let fnames={}
+    for feature in s:F.getfeatures(a:plugdict, s:f[a:key])
+        if has_key(fnames, feature.name)
+            continue
         endif
+        let fnames[feature.name]=feature
+        call call(feature[a:key], [a:plugdict, fdicts[feature.name]], {})
     endfor
     " XXX required in order not to copy list
     return a:plugdict
 "▶1 initfeatures    :: plugdict + shadowdict → + shadowdict
 function s:F.initfeatures(plugdict)
     let fdicts=s:shadow[a:plugdict.id].features
-    for feature in sort(values(s:features), function('s:FeatComp'))
-        if has_key(a:plugdict.dependencies, feature.plid) ||
-                    \has_key(feature, 'ignoredeps')
-            let fdict={}
-            let fdicts[feature.id]=fdict
-            if has_key(feature, 'init')
-                call extend(fdict, deepcopy(feature.init))
-            endif
-            if has_key(feature, 'register')
-                call feature.register(a:plugdict, fdict)
-            endif
+    for feature in s:F.getfeatures(a:plugdict, s:features)
+        if has_key(fdicts, feature.name)
+            continue
+        endif
+        let fdict={}
+        let fdicts[feature.name]=fdict
+        if has_key(feature, 'init')
+            call extend(fdict, deepcopy(feature.init))
+        endif
+        if has_key(feature, 'register')
+            call feature.register(a:plugdict, fdict)
         endif
     endfor
 endfunction
 function s:F.addfeature(plugdict, feature, ...)
     let shadowdict=s:shadow[a:plugdict.id]
     "▶2 `init' and `register' keys
-    if !has_key(shadowdict.features, a:feature.id)
+    if !has_key(shadowdict.features, a:feature.name)
         let fdict={}
-        let shadowdict.features[a:feature.id]=fdict
+        let shadowdict.features[a:feature.name]=fdict
         if has_key(a:feature, 'init')
             call extend(fdict, deepcopy(a:feature.init))
         endif
         endif
     endif
     "▶2 `cons' key
-    if has_key(a:feature,'cons') && !has_key(a:plugdict.g._f, a:feature.id)
+    if has_key(a:feature,'cons') && !has_key(a:plugdict.g._f, a:feature.name)
                 \&& has_key(a:plugdict.dependencies, a:feature.plid)
-        let a:plugdict.g._f[a:feature.id]=s:F.createcons(a:plugdict, shadowdict,
-                    \                                  a:feature)
+        let a:plugdict.g._f[a:feature.name]=s:F.createcons(a:plugdict,
+                    \                                      shadowdict,
+                    \                                      a:feature)
     endif
     "▶2 `load' key
-    if has_key(a:feature, 'load') && !has_key(shadowdict.loadedfs, a:feature.id)
+    if has_key(a:feature, 'load') && !has_key(shadowdict.loadedfs,
+                \                             a:feature.name)
                 \&& ((a:0 && a:1) || a:plugdict.status==2)
-        call a:feature.load(a:plugdict, shadowdict.features[a:feature.id])
-        let shadowdict.loadedfs[a:feature.id]=1
+        call a:feature.load(a:plugdict, shadowdict.features[a:feature.name])
+        let shadowdict.loadedfs[a:feature.name]=1
     endif
     "▲2
     return a:feature
             endfor
             "▲2
             "▶2 Running features
-            for feature in sort(values(s:features), function('s:FeatComp'))
-                if has_key(plugdict.dependencies, feature.plid) ||
-                            \has_key(feature, 'ignoredeps')
-                    call s:F.addfeature(plugdict, feature, 1)
-                endif
+            for feature in s:F.getfeatures(plugdict, s:features)
+                call s:F.addfeature(plugdict, feature, 1)
             endfor
             "▲2
             if !plugdict.oneload
         " XXX runfeature returns v:val
         call map(ordered, 's:F.runfeatures(v:val, "unloadpre")')
         for plugdict in ordered
-            call s:F.runfeatures(plugdict, "unload")
+            call s:F.runfeatures(plugdict, 'unload')
             if exists('*plugdict.g._unload')
                 call plugdict.g._unload()
             endif
     return call(s:F.unloadplugin, a:000, {})
 endfunction
 let s:_functions+=['FraworUnload']
-"▶1 isfunc          :: funcref, key, fid, plid → + throw
-function s:F.isfunc(Func, key, fid, plid)
+"▶1 isfunc          :: funcref, key, fname, plid → + throw
+function s:F.isfunc(Func, key, fname, plid)
     if type(a:Func)!=2
-        call s:_f.throw('nfref', a:fid, a:plid, a:key)
+        call s:_f.throw('nfref', a:fname, a:plid, a:key)
     elseif !exists('*a:Func')
-        call s:_f.throw('ncall', a:fid, a:plid, a:key)
+        call s:_f.throw('ncall', a:fname, a:plid, a:key)
     elseif stridx(a:key, '.')!=-1 && a:key!~#'^cons\%(\.\w\+\)\+$'
-        call s:_f.throw('invkey', a:fid, a:plid, a:key)
+        call s:_f.throw('invkey', a:fname, a:plid, a:key)
     endif
 endfunction
-"▶1 features.newfeature.cons :: {f}, fid, fopts → + s:features, shadowdict, …
-let s:features.newfeature={
+"▶1 features.newfeature.cons   :: {f}, fid, fopts → + s:features, shadowdict, …
+let s:newfeature={
             \'plid': 'plugin/frawor',
-            \  'id': 'newfeature',
+            \'name': 'newfeature',
             \'init': {},
         \}
-let s:f.cons.newfeature=s:features.newfeature
-let s:f.load.newfeature=s:features.newfeature
-let s:f.unload.newfeature=s:features.newfeature
-function s:features.newfeature.cons(plugdict, fdict, fid, fopts)
+let s:newfeature.id=s:newfeature.plid.'/'.s:newfeature.name
+let s:newfeature.escapedid=string(s:newfeature.id)
+function s:newfeature.cons(plugdict, fdict, fid, fopts)
     "▶2 Check arguments
-    if type(a:fid)!=type("")
+    if type(a:fid)!=type('')
         call s:_f.throw('fidnotstr', a:plugdict.id)
     elseif empty(a:fid) || a:fid=~#'\W'
         call s:_f.throw('fidinvstr', a:plugdict.id, a:fid)
-    elseif has_key(s:features, a:fid)
-        call s:_f.throw('featreg', a:fid, a:plugdict.id,
-                    \              s:features[a:fid].plid)
+    elseif has_key(a:fdict, a:fid)
+        call s:_f.throw('featreg', a:fid, a:plugdict.id)
     elseif type(a:fopts)!=type({})
         call s:_f.throw('foptsnotdct', a:fid, a:plugdict.id)
     endif
     "▲2
     let feature={
                 \'plid': a:plugdict.id,
-                \  'id': a:fid,
+                \'name': a:fid,
+                \  'id': a:plugdict.id.'/'.a:fid,
             \}
+    let feature.escapedid=substitute(string(feature.id), '\n', '''."\n".''','g')
     "▶2 Adding keys that hold functions
     let addedsomething=0
     for key in s:featfunckeys
                     call s:F.recdictmap(deepcopy(a:fopts[key]),
                                 \'s:F.isfunc(v:val, '.
                                 \           '"cons.".join(path+[v:key], "."), '.
-                                \            string(feature.id).', '.
+                                \            string(feature.name).', '.
                                 \            string(feature.plid).')')
                 else
-                    call s:F.isfunc(a:fopts[key], key, feature.id, feature.plid)
+                    call s:F.isfunc(a:fopts[key], key, feature.name,
+                                \   feature.plid)
                 endif
             else
-                call s:F.isfunc(a:fopts[key], key, feature.id, feature.plid)
+                call s:F.isfunc(a:fopts[key], key, feature.name, feature.plid)
             endif
             let feature[key]=a:fopts[key]
             let s:f[key][feature.id]=feature
     endfor
     "▶3 Must have added something
     if !addedsomething
-        call s:_f.throw('nofeatkeys', feature.id, feature.plid)
+        call s:_f.throw('nofeatkeys', feature.name, feature.plid)
     endif
     "▶2 Adding `ignoredeps'
     if has_key(a:fopts, 'ignoredeps')
     "▶2 Adding `init'
     if has_key(a:fopts, 'init')
         if type(a:fopts.init)!=type({})
-            call s:_f.throw('initndct', feature.id, a:plugdict.id)
+            call s:_f.throw('initndct', feature.name, a:plugdict.id)
         endif
         let feature.init=a:fopts.init
         let s:f.register[feature.id]=feature
     endif
     "▲2
-    let a:fdict[feature.id]=feature
+    let a:fdict[feature.name]=feature
     let s:features[feature.id]=feature
     "▶2 Running addfeature()
     call map(((has_key(feature, 'ignoredeps'))?
                 \'s:F.addfeature(v:val, feature)')
 endfunction
 "▶1 features.newfeature.unload :: {f} → + s:features, shadowdict, s:f
-function s:features.newfeature.unload(plugdict, fdict)
+function s:newfeature.unload(plugdict, fdict)
     for feature in values(a:fdict)
         if has_key(feature, 'ignoredeps')
             for shadowdict in values(s:shadow)
-                if has_key(shadowdict.features, feature.id)
-                    unlet shadowdict.features[feature.id]
+                if has_key(shadowdict.features, feature.name)
+                    unlet shadowdict.features[feature.name]
                 endif
-                if has_key(shadowdict.loadedfs, feature.id)
-                    unlet shadowdict.loadedfs[feature.id]
+                if has_key(shadowdict.loadedfs, feature.name)
+                    unlet shadowdict.loadedfs[feature.name]
                 endif
             endfor
         endif
         endfor
     endfor
 endfunction
+let s:features[s:newfeature.id]=s:newfeature
+let s:f.cons[s:newfeature.id]=s:newfeature
+let s:f.load[s:newfeature.id]=s:newfeature
+let s:f.unload[s:newfeature.id]=s:newfeature
 "▶1 Plugin registration
 call s:F.newplugin([0, 0], s:Eval('+matchstr(expand("<sfile>"), ''\d\+'')'),
             \      expand('<sfile>:p'), {}, 1, s:)
-let s:shadow[s:_frawor.id].features.newfeature.newfeature=
-            \                                           s:features.newfeature
+let s:shadow[s:_frawor.id].features.newfeature.newfeature=s:newfeature
+unlet s:newfeature
 "▶1 warn feature    :: {f}, msgid, … + p:_messages → message + echomsg
 function s:F.warn(plugdict, fdict, msgid, ...)
     if !has_key(a:plugdict.g, '_messages')
 "▶1
 call frawor#Lockvar(s:, 'dependents,features,f,selfdeps,loading,shadow,pls,'.
             \           'rtpcache,dircache')
-" TODO feature redefinition
+lockvar 1 f
 " vim: fmr=▶,▲ sw=4 ts=4 sts=4 et tw=80

File test/rtp/plugin/invalid-newfeature.3.vim

 execute frawor#Setup('0.0', {}, 1)
-call s:_f.newfeature('throw', {})
+call s:_f.newfeature('abc', {'cons': function('string')})
+call s:_f.newfeature('abc', {'cons': function('string')})