1. ZyX_I
  2. frawor

Commits

ZyX_I  committed d70afb3

@frawor: Added require feature (mostly untested) and depadd feature key (untested)
@/resources: Added addresource.depadd key

  • Participants
  • Parent commits c39a6d3
  • Branches default

Comments (0)

Files changed (11)

File doc/frawor.txt

View file
  • Ignore whitespace
         `Frawor:{plid}:{msgid}:{message}' where {message} is a value returned 
         by |frawor-f-warn|. Semicolon and backslash in {plid} and {msgid} will 
         be escaped.
+require : function ({plid}, {dversion}, {throw}) → 0..2     *frawor-f-require*
+        Loads plugin {plid} and makes it dependency of the caller, also 
+        running all its features. {throw} argument determines what should be 
+        done if frawor failed to load requested plugin: if it is 1, then 
+        `Frawor:plugin/frawor:reqfailed' exception will be thrown, otherwise 
+        0 will be returned. 2 is returned when requested dependency was 
+        already added and 1 indicates that dependency was successfully loaded.
 newfeature : function ({fid}, {fopts})                   *frawor-f-newfeature*
            + unload
         Registers plugin feature with id {fid} ({fid} must contain only 
                                                          *frawor-fk-unloadpre*
         unloadpre  Just like unload, but function will be called when plugin 
                    is queued for unloading, but nothing was yet unloaded.
+                                                            *frawor-fk-depadd*
+        depadd     Reference to a function that will be called when dependency 
+                   was added using |frawor-f-require| feature. Receives 
+                   |frawor-t-plugdict|, feature dictionary and plugin id of 
+                   the added dependency as its arguments.
                                                         *frawor-fk-ignoredeps*
         ignoredeps If this key is present, then register, load, unload and 
                    unloadpre keys will be called for all plugins even if they 
            passed by references, so it won't have any affect when you share 
            strings, numbers or function references.
 
-addresource : load + s:_r                               *frawor-f-addresource*
+addresource : load, depadd + s:_r                       *frawor-f-addresource*
         Automatically adds resources that are defined by plugins listed in 
         dependencies to s:_r dictionary. It is |frawor-fk-ignoredeps| feature, 
         so you don't need anything to get it working.
 Only API changes are listed here. See commit log in order to get other 
 changes.
 
+@frawor:
+    0.1: Added |frawor-f-require| and |frawor-fk-depadd|
 @/mappings:
     0.1: Added possibility to specify dictionaries in `strfunc' and `func' 
          keys.

File plugin/frawor.vim

View file
  • Ignore whitespace
 let s:pls={} " Plugin dictionaries
 let s:loading={}
 let s:features={}
+let s:plfeatures={}
 let s:shadow={}
-let s:featfunckeys=['cons', 'load', 'unload', 'unloadpre', 'register']
+let s:featfunckeys=['cons', 'load', 'unload', 'unloadpre', 'register', 'depadd']
 let s:featordered={'all': []}
 let s:dependents={}
 "▶2 Messages
                 \'invunloadarg': 'Неверный тип аргумента FraworUnload',
                 \       'npref': 'Использование приставки «%s» здесь '.
                 \                'не разрешено',
+                \    'plidnstr': 'Ошибка добавления зависимости '.
+                \                'дополнения %s: имя дополнения '.
+                \                'должно являться непустой строкой',
+                \'invplversion': 'Ошибка добавления зависимости %s '.
+                \                'дополнения %s: версия дополнения должна '.
+                \                'быть непустым списком '.
+                \                'целых неотрицательных чисел',
+                \  'thrownbool': 'Ошибка добавления зависимости %s '.
+                \                'дополнения %s: последний аргумент '.
+                \                'должен быть нулём или единицей',
             \}
 else
     let s:_messages={
                 \   'notloaded': 'Plugin %s is not loaded',
                 \'invunloadarg': 'Wrong type of FraworUnload argument',
                 \       'npref': 'Prefix `%s'' is not allowed here',
+                \    'plidnstr': 'Error while adding dependency to plugin %s: '.
+                \                'plugin name should be a non-empty string',
+                \'invplversion': 'Error while adding dependency %s '.
+                \                'to plugin %s: plugin version should be '.
+                \                'a non-empty list of non-negative integers',
+                \  'thrownbool': 'Error while adding dependency %s '.
+                \                'to plugin %s: last argument should be '.
+                \                'either 0 or 1',
             \}
 endif
 "▶1 s:Eval
                 \ 'has_key(a:plugdict.dependencies, v:val.plid) ||'.
                 \ 'has_key(v:val, "ignoredeps")')
 endfunction
-"▶1 runfeatures     :: plugdict, fkey + shadowdict, + … → plugdict + shadowdict
-function s:F.runfeatures(plugdict, key)
+"▶1 runfeatures     :: plugdict, fkey[, …] + shadowdict → plugdict + shadowdict
+function s:F.runfeatures(plugdict, key, ...)
     let fdicts=s:shadow[a:plugdict.id].features
     let fnames={}
     for feature in filter(s:F.getfeatures(a:plugdict, a:key),
                 \         '!has_key(fnames, v:val.name)')
         let fnames[feature.name]=feature
-        call call(feature[a:key], [a:plugdict, fdicts[feature.name]], {})
+        call call(feature[a:key], [a:plugdict, fdicts[feature.name]]+a:000, {})
     endfor
     " XXX required in order not to copy list
     return a:plugdict
     "▲2
     let a:fdict[feature.name]=feature
     let s:features[feature.id]=feature
+    let s:plfeatures[a:plugdict.id]=a:fdict
     let s:featordered={'all': sort(values(s:features), function('s:FeatComp'))}
     "▶2 Running addfeature()
     call map(((has_key(feature, 'ignoredeps'))?
 function s:newfeature.unload(plugdict, fdict)
     if !empty(a:fdict)
         let s:featordered={'all': s:featordered.all}
+        unlet s:plfeatures[a:plugdict.id]
     endif
     for feature in values(a:fdict)
         if has_key(feature, 'ignoredeps')
 let s:features[s:newfeature.id]=s:newfeature
 let s:featordered.all+=[s:newfeature]
 "▶1 Plugin registration
-call s:F.newplugin([0, 0], s:Eval('+matchstr(expand("<sfile>"), ''\d\+'')'),
+call s:F.newplugin([0, 1], s:Eval('+matchstr(expand("<sfile>"), ''\d\+'')'),
             \      expand('<sfile>:p'), {}, 1, s:)
 let s:shadow[s:_frawor.id].features.newfeature.newfeature=s:newfeature
 unlet s:newfeature
     throw call(s:F.warn, [a:plugdict, a:fdict, a:msgid]+a:000, {})
 endfunction
 call s:_f.newfeature('throw', {'cons': s:F.throw})
+"▶1 require feature :: {f}, plid, version, throw → + plugdict
+function s:F.require(plugdict, fdict, dplid, dversion, throw)
+    "▶2 Check arguments
+    if type(a:dplid)!=type('') || empty(a:dplid)
+        call s:_f.throw('plidnstr', a:plugdict.id)
+    elseif type(a:dversion)!=type([]) || empty(a:dversion) ||
+                \!empty(filter(copy(a:dversion), 'type(v:val)!='.type(0)))
+        call s:_f.throw('invplversion', a:dplid, a:plugdict.id)
+    elseif type(a:throw)!=type(0)
+        call s:_f.throw('thrownbool', a:dplid, a:plugdict.id)
+    endif
+    "▲2
+    let dplid=s:F.expandplid(a:dplid)
+    if has_key(a:plugdict.dependencies, dplid)
+        return 2
+    endif
+    let shadowdict=s:shadow[a:plugdict.id]
+    "▶2 Add dependency
+    unlockvar 1 a:plugdict.dependencies
+    let a:plugdict.dependencies[dplid]=copy(a:dversion)
+    lockvar 1 a:plugdict.dependencies
+    lockvar! a:plugdict.dependencies[dplid]
+    if !has_key(s:dependents, dplid)
+        let s:dependents[dplid]={}
+    endif
+    let s:dependents[dplid][a:plugdict.id]=1
+    "▶2 Load dependency if required
+    let olddstatus=0
+    let doload=1
+    if has_key(s:pls, dplid)
+        let olddstatus=s:pls[dplid].status
+        let doload=(olddstatus!=2)
+    endif
+    if doload && !s:F.loadplugin(dplid)
+        if a:throw
+            call s:_f.throw('reqfailed', dplid, a:plugdict.id)
+        else
+            unlockvar 1 a:plugdict.dependencies
+            call remove(a:plugdict.dependencies, dplid)
+            lockvar 1 a:plugdict.dependencies
+            return 0
+        endif
+        if !olddstatus
+            call s:F.runfeatures(a:plugdict, 'depadd')
+            return 1
+        endif
+    endif
+    "▲2
+    let dfeatures=s:plfeatures[dplid]
+    let fdicts=s:shadow[a:plugdict.id].features
+    for feature in filter(values(dfeatures), '!has_key(fdicts, v:val.name)')
+        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
+        if a:plugdict.status==2
+            if has_key(feature, 'load')
+                call feature.load(a:plugdict, fdict)
+            endif
+        endif
+    endfor
+    call s:F.runfeatures(a:plugdict, 'depadd', dplid)
+    return 1
+endfunction
+call s:_f.newfeature('require', {'cons': s:F.require})
 "▶1
 call frawor#Lockvar(s:, 'dependents,features,featordered,loading,shadow,pls,'.
-            \           'rtpcache,dircache,deplen')
+            \           'rtpcache,dircache,deplen,plfeatures')
 lockvar 1 f
 " vim: fmr=▶,▲ sw=4 ts=4 sts=4 et tw=80

File plugin/frawor/resources.vim

View file
  • Ignore whitespace
 call s:_f.newfeature('postresource', {'cons': s:F.postresource,
             \                       'unload': s:F.delresources,})
 "▶1 addresource feature
-function s:F.addresource(plugdict, fdict)
+let s:addresource={'ignoredeps': 1}
+function s:addresource.load(plugdict, fdict)
     let r={}
     call map(map(filter(keys(a:plugdict.dependencies),
                 \'has_key(s:plugresources, v:val)'),
                 \            '{v:val.name : v:val.copyfunc(v:val.resource)})")')
     let a:plugdict.g._r=r
 endfunction
-call s:_f.newfeature('addresource', {'load': s:F.addresource, 'ignoredeps': 1,})
+function s:addresource.depadd(plugdict, fdict, dplid)
+    if !has_key(a:plugdict.g, '_r') || type(a:plugdict.g._r)!=type({})
+        return
+    endif
+    let r=a:plugdict.g._r
+    if has_key(s:plugresources, a:dplid)
+        call map(values(s:plugresources[a:dplid]),
+                    \'extend(r, {v:val.name : v:val.copyfunc(v:val.resource)})')
+    endif
+endfunction
+call s:_f.newfeature('addresource', s:addresource)
 "▶1
 call frawor#Lockvar(s:, 'plugresources')
 " vim: fmr=▶,▲ sw=4 ts=4 sts=4 et tw=80

File test/double-load.ok

View file
  • Ignore whitespace
 registered plugin/double-load.2
-features: newfeature throw warn
+features: newfeature require throw warn
 registered plugin/double-load
-features: newfeature throw warn
+features: newfeature require throw warn
 feature-load: plugin/double-load
 loaded plugin/double-load
-features: newfeature testfeature throw warn
+features: newfeature require testfeature throw warn
 loaded plugin/double-load.2
-features: doublefeature newfeature throw warn
+features: doublefeature newfeature require throw warn
 registered plugin/double-load.2
-features: doublefeature newfeature throw warn
+features: doublefeature newfeature require throw warn
 loaded plugin/double-load.2
-features: doublefeature newfeature throw warn
+features: doublefeature newfeature require throw warn

File test/plid-expansion.ok

View file
  • Ignore whitespace
 plugin/plid-expansion/exptest
 autoload/exptest
 ftplugin/exptest
-['newfeature', 'postresource', 'throw', 'warn']
+['newfeature', 'postresource', 'require', 'throw', 'warn']

File test/recursive-dependent-with-features.ok

View file
  • Ignore whitespace
 +++ plugin/recursive-dependent-with-features
-plugin/recursive-dependent-with-features: newfeature throw warn write1
+plugin/recursive-dependent-with-features: newfeature require throw warn write1
 ---
 +++ plugin/recursive-dependent-with-features.2
-plugin/recursive-dependent-with-features.2: newfeature throw warn write1 write2
-plugin/recursive-dependent-with-features.2: newfeature throw warn write1 write2
+plugin/recursive-dependent-with-features.2: newfeature require throw warn write1 write2
+plugin/recursive-dependent-with-features.2: newfeature require throw warn write1 write2
 ---
 +++ plugin/recursive-dependent-with-features.3
-plugin/recursive-dependent-with-features.3: newfeature throw warn write1 write2
-plugin/recursive-dependent-with-features.3: newfeature throw warn write1 write2
+plugin/recursive-dependent-with-features.3: newfeature require throw warn write1 write2
+plugin/recursive-dependent-with-features.3: newfeature require throw warn write1 write2
 ---
 >>> .3: messages
 plugin/frawor:recdep

File test/register-feature-list.ok

View file
  • Ignore whitespace
 newfeature
+require
 throw
 warn

File test/require-feature.in

View file
  • Ignore whitespace
+:let &rtp.=",".escape($TESTDIR, ',\').'/rtp'
+:let g:testfile="plugin/".g:curtest.".vim"
+:source test.vim

File test/require-feature.ok

View file
  • Ignore whitespace
+newfeature
+require
+throw
+warn
+feature-load: plugin/require-feature
+require: 1
+newfeature
+require
+testfeature
+throw
+warn
+require: 0
+plugin/frawor:reqfailed

File test/rtp/plugin/require-feature.vim

View file
  • Ignore whitespace
+execute frawor#Setup('0.0', {'@frawor': '0.1'})
+function s:F.main()
+    call WriteFile('require: '.s:_f.require('@plugin-with-feature', [0, 0], 0))
+    call WriteFile(sort(keys(s:_f)))
+    call WriteFile('require: '.s:_f.require('@xxx-unexistent-plugin', [0, 0], 0))
+    call WriteFile('require: '.s:_f.require('@xxx-unexistent-plugin', [0, 0], 1))
+endfunction
+call WriteFile(sort(keys(s:_f)))
+call s:F.main()

File test/version-mismatch.ok

View file
  • Ignore whitespace
 newfeature
+require
 throw
 warn
 plugin/major-version-mismatch: plugin/frawor:majmismatch