Commits

ZyX_I committed 10336db

Init

Comments (0)

Files changed (3)

+*frawor.txt* Vim framework
+==============================================================================
+CONTENTS                                                     *frawor-contents*
+    1. Intro                                            |frawor-intro|
+    2. Functionality provided                           |frawor-functionality|
+        2.1. Functions                                  |frawor-functions|
+        2.2. Commands                                   |frawor-commands|
+    3. Options                                          |frawor-options|
+    4. Type definitions                                 |frawor-types|
+
+==============================================================================
+1. Intro                                                        *frawor-intro*
+
+This plugin provides extensible vim framework.
+
+==============================================================================
+2. Functionality provided                               *frawor-functionality*
+
+Frawor provides the only global function |FraworRegister()| (and 
+|frawor#FraworSetup()| that is wrapper around |FraworRegister()| and just 
+hides some work) that will register your plugin in the framework thus granting 
+access to required features. Almost all features are defined in 
+plugin/frawor/*.vim files.
+
+------------------------------------------------------------------------------
+2.1. Functions                                              *frawor-functions*
+
+                                                           *frawor-f-Register*
+FraworRegister(version, file, dependencies, oneload, g, F)  *FraworRegister()*
+        Registers plugin sourced from {file} that has given {version} (see 
+        |frawor-t-version|).
+
+------------------------------------------------------------------------------
+2.2. Commands                                                *frawor-commands*
+
+==============================================================================
+3. Options                                                    *frawor-options*
+                                                             *g:fraworOptions*
+
+Without modules frawor provides only one option: |frawor-o-_donotload|. All 
+other options are defined into various modules.
+                                                  *g:fraworOptions__donotload*
+_donotload                                               *frawor-o-_donotload*
+        Prevents frawor plugin from loading. Works if either key _donotload is 
+        present in dictionary g:fraworOptions or g:fraworOptions__donotload 
+        variable is defined (its content does not matter).
+
+==============================================================================
+4. Types                                                        *frawor-types*
+
+version :: [ Integer ]                                      *frawor-t-version*
+        List of integers, all integers must not be negative.
+
+vim: ft=help:tw=78

frawor-addon-info.txt

+{
+    "name": "frawor",
+    "version": "0.0",
+    "author": "ZyX <kp-pav@yandex.ru>",
+    "maintainer": "ZyX <kp-pav@yandex.ru>",
+    "description": "Vim framework",
+    "repository": {
+        "type": "hg",
+        "url": "https://bitbucket.org/ZyX_I/frawor",
+    },
+    "dependencies": {
+    },
+}

plugin/frawor.vim

+"▶1 Header
+scriptencoding utf-8
+if exists('s:g._pluginloaded') || exists('g:fraworOptions._donotload') ||
+            \exists('g:fraworOptions__donotload')
+    finish
+endif
+"▶1 Variable initialization
+let s:F={}
+let s:g={}
+let s:g.pls={} " Plugin dictionaries
+let s:g.pltypes={}
+let s:g.features={
+            \     'index': {},
+            \    'onload': {},
+            \  'onunload': {},
+        \}
+"▶2 Messages
+if v:lang=~?'ru'
+    let s:g._messages={
+                \ '_plstatuses': ['выгружен', 'зарегестрирован', 'загружен'],
+                \'plregistered': 'Дополнение %s уже зарегистрировано '.
+                \                'в каталоге %s',
+                \   'doublereg': 'Попытка повторной регистрации %s '.
+                \                'заблокирована',
+                \  'vernotlist': 'Версия дополнения %s должна быть списком',
+                \    'vershort': 'Версия дополнения %s должна содержать '.
+                \                'не менее двух компонент',
+                \   'vernotnum': 'Все компоненты версии дополнения %s должны '.
+                \                'быть неотрицательными целыми',
+                \  'depnotdict': 'Список зависимостей дополнения %s должен '.
+                \                'являться словарём',
+                \'d_vernotlist': 'Версия зависимости %s дополнения %s должна '.
+                \                'быть списком',
+                \  'd_vershort': 'Версия зависимости %s дополнения %s должна '.
+                \                'содержать не менее одной компоненты',
+                \ 'd_vernotnum': 'Все комопоненты версии зависимости %s '.
+                \                'дополнения %s должны быть '.
+                \                'неотрицательными целыми',
+                \ 'majmismatch': 'Несовпадение основного номера версии '.
+                \                'зависимости %s дополнения %s: '.
+                \                'требовалась версия %u, но была загружена %u',
+                \  'oldversion': 'Слишком старая версия зависимости %s '.
+                \                'дополнения %s: требовалась версия %s, '.
+                \                'но была загружена %s',
+                \   'reqfailed': 'Не удалось загрузить зависимость %s '.
+                \                'дополнения %s',
+            \}
+else
+    let s:g._messages={
+                \ '_plstatuses': ['unloaded', 'registered', 'loaded'],
+                \'plregistered': 'Plugin %s was already registered '.
+                \                'in directory %s'
+                \   'doublereg': 'Refusing to register %s for the second time',
+                \  'vernotlist': 'Version argument of plugin %s is not a List',
+                \    'vershort': 'Version argument of plugin %s must have '.
+                \                'at least two components',
+                \   'vernotnum': 'All components of %s version must be '.
+                \                'nonnegative integers',
+                \  'depnotdict': 'List of %s dependencies must be a Dictionary',
+                \'d_vernotlist': 'Version must be a list in a dependency %s '.
+                \                'of a plugin %s',
+                \  'd_vershort': 'Version must contain at least one component '.
+                \                'in a dependency %s of a plugin %s',
+                \ 'd_vernotnum': 'All components of version must be '.
+                \                'nonnegative integers in a dependency %s '.
+                \                'of a plugin %s',
+                \ 'majmismatch': 'Major version mismatch for dependency %s '.
+                \                'of a plugin %s: expected %u, but got %u',
+                \  'oldversion': 'Detected too old dependency %s '.
+                \                'of a plugin %s: expected %s, but got %s',
+                \   'reqfailed': 'Failed to load dependency %s of a plugin %s',
+            \}
+endif
+"▶1 compareversions
+function s:F.compareversions(a, b)
+    let len=max([len(a:a), len(a:b)])
+    for i in range(0, len-1)
+        let a=get(a:a, i, 0)
+        let b=get(a:b, i, 0)
+        if a>b
+            return 1
+        elseif a<b
+            return -1
+        endif
+    endfor
+    return 0
+endfunction
+"▶1 parseplugpath
+function s:F.parseplugpath(file)
+    let rtps=map(split(&runtimepath, '\v%(\\@<!\\%(\\\\)*)@<!,'),
+                \'resolve(fnamemodify(substitute(substitute(v:val, '.
+                \                                          '''\\\([\\,]\)'', '.
+                \                                          '"\\1", "g"), '.
+                \                                '''\$\w\+'', '.
+                \                                '"\\=eval(submatch(0))","g"),'.
+                \                    '":p"))')
+    let file=fnamemodify(a:file, ':p')
+    let curpath=fnamemodify(file, ':h')
+    let removedcomponents=[fnamemodify(file, ':t:r')]
+    let foundrtp=""
+    let lastpath=""
+    while lastpath!=#curpath
+        let lastpath=curpath
+        let rcurpath=resolve(curpath)
+        if index(rtps, rcurpath)!=-1
+            let foundrtp=rcurpath
+            break
+        endif
+        call insert(removedcomponents, fnamemodify(curpath, ':t'))
+        let curpath=fnamemodify(curpath, ':h')
+    endwhile
+    if !empty(foundrtp)
+        return [removedcomponents, join(removedcomponents, '/'), foundrtp]
+    else
+        return ['/unknown', join(removedcomponents,'/'), '']
+    endif
+endfunction
+"▶1 newplugin
+function s:F.newplugin(version, file, dependencies, oneload, g, F)
+    "▶2 plugtype, plid, plrtp, plversion
+    if a:version is 0
+        let plugtype='/anonymous'
+        let plid=a:file
+        let plrtp=''
+        let plversion=[0, 0]
+    "▶3 Verifying plugin version
+    elseif type(a:version)!=type([])
+        call s:F._throw('vernotlist', plid)
+    elseif len(a:version)<2
+        call s:F._throw('vershort', plid)
+    elseif !empty(filter(copy(a:version),'type(v:val)!='.type(0)).' || v:val<0')
+        call s:F._throw('vernotnum', plid)
+    "▲3
+    else
+        let [plugtype, plid, plrtp]=s:F.parseplugpath(a:file)
+        let plversion=a:version
+    endif
+    "▶2 Checking for double registration
+    if has_key(s:g.pls, plid)
+        if s:g.pls[plid].runtimepath==#plrtp
+            call s:F._throw('doublereg', plid)
+        endif
+        if plugtype[0]!=#'/'
+            call s:F._warn('plregistered', plid, plrtp)
+        endif
+        let plid.='/'
+    endif
+    "▶2 Constructing plugdict
+    "▶3 Some trivial construction
+    let plugdict={
+                \        'type': plugtype,
+                \          'id': plid,
+                \ 'runtimepath': plrtp,
+                \     'version': plversion,
+                \        'file': a:file,
+                \'dependencies': {'plugin/frawor': 1},
+                \      'status': a:oneload ? 2 : 1,
+                \    'features': {},
+            \}
+    "▶3 Processing dependencies
+    if type(a:dependencies)!=type({})
+        call s:F._throw('depnotdict', plid)
+    endif
+    let d={}
+    for [dplid, d.Version] in items(a:dependencies)
+        "▶4 Verifying dependency version
+        if type(d.Version)!=type([])
+            call s:F._throw('d_vernotlist', dplid, plid)
+        elseif empty(d.Version)
+            call s:F._throw('d_vershort', dplid, plid)
+        elseif !empty(filter(copy(d.Version), 'type(v:val)!='.type(0)))
+            call s:F._throw('d_vernotnum', dplid, plid)
+        endif
+        "▲4
+        let plugdict.dependencies[dplid]=d.Version
+    endfor
+    "▶2 Adding plugdict to global variables
+    if !has_key(s:g.pltypes, plugtype)
+        let s:g.pltypes[plugtype]={plid : plugdict}
+    else
+        let s:g.pltypes[plugtype][plid]=plugdict
+    endif
+    let s:g.pls[plid]=plugdict
+    "▶2 Locking plugdict
+    lockvar! plugdict
+    unlockvar plugdict.features
+    unlockvar plugdict.status
+    "▶2 Populating features dictionary
+    for feature in values(s:g.features.index)
+        if has_key(feature, 'register')
+            let d.Result=feature.register(plugdict)
+            let plugdict.features[feature.id]=((d.Result is 0)?({}):(d.Result))
+        else
+            let plugdict.features[feature.id]={}
+        endif
+        "▶3 Locking features dictionary
+        try
+            lockvar! plugdict.features[feature.id]
+        catch /^Vim(lockvar):E743:/
+            " Ignore «variable nested too deep for (un)lock» error
+        endtry
+        "▲3
+    endfor
+endfunction
+"▶1 FraworRegister
+function FraworRegister(...)
+    return call(s:F.newplugin, a:000, {})
+endfunction
+"▶1 loadplugin
+function s:F.loadplugin(plid)
+    if !has_key(s:g.pls, a:plid)
+        execute 'runtime! '.fnameescape(a:plid)
+    endif
+    if !has_key(s:g.pls, a:plid)
+        return 0
+    endif
+    let plugdict=s:g.pls[a:plid]
+    if plugdict.status!=2
+        "▶2 Loading dependencies
+        for [dplid, d.Version] in items(plugdict.dependencies)
+            if type(d.Version)!=type([])
+                continue
+            endif
+            if s:F.loadplugin(dplid)
+                let dversion=s:g.pls[dplid].version
+                "▶3 Checking dependency version
+                if d.Version[0]!=dversion[0]
+                    call s:F._throw('majmismatch', dplid, a:plid, d.Version[0],
+                                \                                 dversion[0])
+                elseif s:F.compareversions(d.Version, dversion)<0
+                    call s:F._throw('oldversion', dplid, a:plid,
+                                \   join(d.Version[0], '.'),
+                                \   join(dversion, '.'))
+                endif
+                "▲3
+            else
+                call s:F._throw('reqfailed', dplid, a:plid)
+            endif
+        endfor
+        "▲2
+        execute 'source '.fnameescape(plugdict.file)
+    endif
+    return 1
+endfunction
+
+" vim: fmr=▶,▲ sw=4 ts=4 sts=4 et tw=80
+