ZyX_I avatar ZyX_I committed 420f07e

@aurum, @%aurum/*: Moved filter strings and completion from @aurum to @%aurum/*
(requires recent frawor changes). It makes loading as lazy as
possible
@%aurum/cache: Moved @aurum/cache to @%aurum/cache

Comments (0)

Files changed (26)

autoload/aurum.vim

 "▶1 
 scriptencoding utf-8
 execute frawor#Setup('0.1', {'@%aurum/repo': '5.4',
-            \                '@aurum/cache': '2.3',
+            \               '@%aurum/cache': '2.3',
             \            '@%aurum/cmdutils': '4.0',})
 "▶1 getcrf
 function s:F.id(val)

autoload/aurum/annotate.vim

 "▶1 
 scriptencoding utf-8
-execute frawor#Setup('1.0', {'@%aurum/cmdutils': '4.0',
+execute frawor#Setup('1.0', {'@%aurum/cmdutils': '4.3',
             \                 '@%aurum/bufvars': '0.0',
             \                    '@%aurum/edit': '1.4',
-            \                          '@aurum': '1.0',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.0',
             \                     '@/resources': '0.0',
             \                         '@/table': '0.1',})
 let s:_messages={
 "▶1 annfunc
 " TODO Investigate why wiping out annotate buffer causes consumption of next
 "      character under wine
-function s:cmd.function(opts)
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings '.
+            \'{  repo  '.s:_r.cmdutils.comp.repo.
+            \'  ?file  '.s:_r.cmdutils.comp.file.
+            \'  ?rev   '.s:_r.cmdutils.comp.rev.
+            \'}', 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \                                     [], s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(opts)
     let [hasannbuf, repo, rev, file]=s:_r.cmdutils.getrrf(a:opts, 'noafile',
                 \                                         'annotate')
     if repo is 0

autoload/aurum/branch.vim

 scriptencoding utf-8
-execute frawor#Setup('0.0', {'@aurum': '1.0',
-            \      '@%aurum/cmdutils': '4.0',})
+execute frawor#Setup('0.0', {'@%aurum/cmdutils': '4.3',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.0',})
 let s:_messages={
             \ 'bexsts': 'Error while creating branch %s for repository %s: '.
             \           'branch already exists',
         \}
-function s:cmd.function(bang, branch, opts)
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings _ '.
+            \'type "" {repo '.s:_r.cmdutils.comp.repo.'}', 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \                                     [], s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(bang, branch, opts)
     let repo=s:_r.cmdutils.checkedgetrepo(a:opts.repo)
     let force=a:bang
     if !force && index(repo.functions.getrepoprop(repo, 'brancheslist'),

autoload/aurum/cache.vim

+"▶1
+scriptencoding utf-8
+execute frawor#Setup('2.4', {'@/resources': '0.0',
+            \                  '@/options': '0.0',})
+let s:_options={
+            \'branchcachetime': {'default': 2, 'checker': 'range 0 inf'},
+            \'cscachetime':     {'default': 3, 'checker': 'range 0 inf'},
+            \'statuscachetime': {'default': 5, 'checker': 'range 0 inf'},
+            \'repocachetime':   {'default': 7, 'checker': 'range 0 inf'},
+        \}
+let s:cachebvars={}
+let s:r={}
+let s:r.allkeys=['branch', 'changeset', 'repository', 'status']
+let s:_messages={
+            \ 'nfunc': 'Argument must be a callable function reference',
+            \ 'pldef': 'Plugin has already defined one wiper function',
+            \'dbldef': 'Function %s was already added by another plugin',
+        \}
+"▶1 bufwipeout
+function s:F.bufwipeout()
+    let buf=+expand('<abuf>')
+    if has_key(s:cachebvars, buf)
+        unlet s:cachebvars[buf]
+    endif
+endfunction
+augroup AurumCacheBufVars
+    autocmd BufWipeOut,BufFilePost * :call s:F.bufwipeout()
+augroup END
+let s:_augroups+=['AurumCacheBufVars']
+"▶1 r.getcbvar ::  () + buf, cachebvars → cbvar + cachebvars?
+function s:r.getcbvar()
+    let buf=bufnr('%')
+    if !has_key(s:cachebvars, buf)
+        let s:cachebvars[buf]={}
+    endif
+    return s:cachebvars[buf]
+endfunction
+"▶1 r.get :: key, func, args, dict → val + cbvar
+function s:r.get(key, Func, args, dict)
+    let cbvar=s:r.getcbvar()
+    if !(has_key(cbvar, a:key) &&
+                \localtime()-cbvar['_time'.a:key]<cbvar['_maxtime'.a:key])
+        let cbvar[a:key]=call(a:Func, a:args, a:dict)
+        let cbvar['_time'.a:key]=localtime()
+        if !has_key(cbvar, '_maxtime'.a:key)
+            let cbvar['_maxtime'.a:key]=s:_f.getoption(a:key.'cachetime')
+        endif
+    endif
+    return cbvar[a:key]
+endfunction
+"▶1 r.del :: key → + cbvar
+function s:r.del(key)
+    let buf=bufnr('%')
+    if !has_key(s:cachebvars, buf)
+        return
+    endif
+    let cbvar=s:cachebvars[buf]
+    if has_key(cbvar, a:key)
+        unlet cbvar[a:key]
+    endif
+endfunction
+"▶1 r.wipe :: key → + cachebvars
+function s:r.wipe(key)
+    " empty() is here only to avoid possible “Using smth as a number” error
+    call map(copy(s:cachebvars), 'has_key(v:val,a:key) && '.
+                \                                  'empty(remove(v:val,a:key))')
+    call map(copy(s:wipers), 'call(v:val, [a:key], {})')
+endfunction
+"▶1 r.getinterval
+function s:r.getinterval(key)
+    return s:_f.getoption(a:key.'cachetime')
+endfunction
+"▶1 addwiper feature
+let s:wipers=[]
+let s:feature={}
+function s:feature.cons(plugdict, fdict, Func)
+    if !exists('*a:Func')
+        call s:_f.throw('nfunc')
+    elseif has_key(a:fdict, 'func')
+        call s:_f.throw('pldef', string(a:fdict.func))
+    elseif index(s:wipers, a:Func)!=-1
+        call s:_f.throw('dbldef', string(a:Func))
+    endif
+    let s:wipers+=[a:Func]
+    let a:fdict.func=a:Func
+endfunction
+function s:feature.unload(plugdict, fdict)
+    if has_key(a:fdict, 'func')
+        call filter(s:wipers, 'v:val isnot# a:fdict.func')
+    endif
+endfunction
+call s:_f.newfeature('addwiper', s:feature)
+"▶1 Post cache resource
+call s:_f.postresource('cache', s:r)
+"▶1
+call frawor#Lockvar(s:, '_pluginloaded,cachebvars,wipers')
+" vim: ft=vim ts=4 sts=4 et fmr=▶,▲

autoload/aurum/cmdutils.vim

 "▶1
 scriptencoding utf-8
-execute frawor#Setup('4.2', {'@/resources': '0.0',
+execute frawor#Setup('4.3', {'@/resources': '0.0',
             \                       '@/os': '0.0',
             \               '@%aurum/repo': '5.0',
             \               '@%aurum/edit': '1.0',
     endwhile
     return r
 endfunction
+"▶1 completion-related constants
+let s:r.comp={}
+let s:r.comp.rev    = 'type string'
+let s:r.comp.file   = 'type String'
+let s:r.comp.cmd    = 'type STRING'
+let s:r.comp.optrev = 'type STRing'
+let s:r.comp.repo   = ':":"(either(path d, match@\v^\w+%(\+\w+)*\V://\v|^\:$@))'
+let s:r.compcmds=['new', 'vnew', 'edit',
+            \     'leftabove\ vnew', 'rightbelow\ vnew',
+            \     'topleft\ vnew',   'botright\ vnew',
+            \     'aboveleft\ new',  'belowright\ new',
+            \     'topleft\ new',    'botright\ new',]
+" XXX Some code relies on the fact that all options from s:diffoptslst are
+"     numeric
+let s:r.diffopts=['git', 'reverse', 'ignorews', 'iwsamount', 'iblanks',
+            \     'numlines', 'showfunc', 'alltext', 'dates']
+let s:r.comp.diffopts=join(map(copy(s:r.diffopts),
+            \          'v:val is# "numlines" ? '.
+            \               '" ?".v:val." range 0 inf" : '.
+            \               '"!?".v:val'))
+"▶1 Completion functions
+function s:r.revlist(...)
+    let repo=aurum#repository()
+    return       repo.functions.getrepoprop(repo, 'tagslist')+
+                \repo.functions.getrepoprop(repo, 'brancheslist')+
+                \repo.functions.getrepoprop(repo, 'bookmarkslist')
+endfunction
+"▶1 gencompfunc
+let s:replaces=[
+            \['\V'.s:r.comp.rev,     'in *_r.cmdutils.revlist', 'g'],
+            \['\V'.s:r.comp.file,    '(path)',                  'g'],
+            \['\V'.s:r.comp.cmd,     'first(in _r.cmdutils.compcmds, idof cmd)',
+            \                                                   'g'],
+            \['\V'.s:r.comp.optrev,  'either(type "", in *_r.cmdutils.revlist)',
+            \                                                   'g'],
+            \]
+function s:r.gencompfunc(fwc, subs, Compile)
+    let subs=a:subs+s:replaces
+    let fwc=substitute(a:fwc, '^-onlystrings\( _\)*', '', '')
+    for args in subs
+        let fwc=call('substitute', [fwc]+args)
+    endfor
+    return {'function': call(a:Compile, [fwc, 'complete'], {})[0]}
+endfunction
 "▶1 Post cmdutils resource
 call s:_f.postresource('cmdutils', s:r)
 "▶1

autoload/aurum/commit.vim

 "▶1 
 scriptencoding utf-8
 execute frawor#Setup('1.3', {'@/resources': '0.0',
+            \                '@/functions': '0.1',
             \                  '@/options': '0.0',
             \                       '@/os': '0.0',
-            \                     '@aurum': '1.0',
+            \                      '@/fwc': '0.0',
             \             '@%aurum/status': '1.2',
-            \           '@%aurum/cmdutils': '4.0',
+            \           '@%aurum/cmdutils': '4.3',
             \            '@%aurum/bufvars': '0.0',
             \            '@%aurum/vimdiff': '1.1',
             \               '@%aurum/edit': '1.0',
-            \               '@aurum/cache': '2.1',})
+            \              '@%aurum/cache': '2.4',})
 let s:_messages={
             \'emptmsg': 'Message must contain at least one non-blank character',
             \'nocfile': 'Unsure what should be commited',
     call a:bvar.repo.functions.commit(a:bvar.repo, message, a:bvar.files,
                 \                     a:bvar.user, a:bvar.date,
                 \                     a:bvar.closebranch)
-    call map(copy(s:_r.allcachekeys), 's:_r.cache.wipe(v:val)')
+    call map(copy(s:_r.cache.allkeys), 's:_r.cache.wipe(v:val)')
     let a:bvar.did_message=1
     if has_key(a:bvar, 'sbvar')
         call a:bvar.bwfunc(a:bvar)
     call feedkeys("\<C-\>\<C-n>:bwipeout!\n\<C-l>")
 endfunction
 "▶1 commfunc
-function s:cmd.function(opts, ...)
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings '.
+            \'{  repo '.s:_r.cmdutils.comp.repo.
+            \' *?type      (either (in [modified added '.
+            \                          'removed deleted '.
+            \                          'unknown all] '.
+            \                         '~start,'.
+            \                      'match /\v^[MARDU?!]+$/))'.
+            \'  ?message   type ""'.
+            \'  ?user      type ""'.
+            \'  ?date      match /\v%(^%(\d*\d\d-)?'.
+            \                         '%(%(1[0-2]|0?[1-9])-'.
+            \                           '%(3[01]|0?[1-9]|[12]\d)))?'.
+            \                      '%(%(^|[ _])%(2[0-3]|[01]\d)'.
+            \                                 '\:[0-5]\d'.
+            \                                 '%(\:[0-5]\d)?)?$/'.
+            \' !?closebranch'.
+            \'}'.
+            \'+ '.s:_r.cmdutils.comp.file, 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \                                     [], s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(opts, ...)
     let rrfopts=copy(a:opts)
     let hasall=index(a:000, 'all')!=-1
     if a:0 && !hasall
 function s:commit.write(lines, repo, user, date, cb, files)
     let message=join(filter(copy(a:lines), 'v:val[0] isnot# "#"'), "\n")
     call a:repo.functions.commit(a:repo, message, a:files, a:user, a:date, a:cb)
-    call map(copy(s:_r.allcachekeys), 's:_r.cache.wipe(v:val)')
+    call map(copy(s:_r.cache.allkeys), 's:_r.cache.wipe(v:val)')
 endfunction
 call s:_f.newcommand(s:commit)
 "▶1 Post resource

autoload/aurum/diff.vim

 "▶1 
 scriptencoding utf-8
-execute frawor#Setup('0.0', {'@%aurum/cmdutils': '4.0',
+execute frawor#Setup('0.0', {'@%aurum/cmdutils': '4.3',
             \                '@%aurum/maputils': '0.0',
             \                 '@%aurum/bufvars': '0.0',
             \               '@%aurum/lineutils': '0.0',
             \                 '@%aurum/vimdiff': '1.0',
             \                    '@%aurum/edit': '1.2',
-            \                          '@aurum': '1.0',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.0',
             \                      '@/mappings': '0.0',
             \                            '@/os': '0.0',})
 let s:_messages={
             \'nodfile': 'Failed to get file whose section is under the cursor',
         \}
 "▶1 difffunc
-function s:cmd.function(opts, ...)
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings '.
+            \'{  repo     '.s:_r.cmdutils.comp.repo.
+            \'  ?rev1     '.s:_r.cmdutils.comp.rev.
+            \'  ?rev2     '.s:_r.cmdutils.comp.rev.
+            \'  ?changes  '.s:_r.cmdutils.comp.rev.
+            \s:_r.cmdutils.comp.diffopts.
+            \'  ?cmd      '.s:_r.cmdutils.comp.cmd.
+            \'}'.
+            \'+ '.s:_r.cmdutils.comp.file, 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \                                     [], s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(opts, ...)
     if a:0 && a:opts.repo is# ':'
         let repo=s:_r.cmdutils.checkedgetrepo(a:1)
     else
         return
     endif
     "▲2
-    let opts=filter(copy(a:opts), 'index(s:_r.diffopts, v:key)!=-1')
+    let opts=filter(copy(a:opts), 'index(s:_r.cmdutils.diffopts, v:key)!=-1')
     call s:_r.run(get(a:opts, 'cmd', 'silent edit'), 'diff', repo, rev1, rev2,
                 \ filelist, opts)
     if !has_key(a:opts, 'cmd')
 "▶1 aurum://diff
 let s:diff= {'arguments': 2,
             \ 'listargs': 1,
-            \  'options': {'num': s:_r.diffopts},
+            \  'options': {'num': s:_r.cmdutils.diffopts},
             \ 'filetype': 'diff',
             \   'mgroup': 'AuDiff',
             \}

autoload/aurum/edit.vim

 scriptencoding utf-8
 execute frawor#Setup('1.5', {'@/resources': '0.0',
             \                       '@/os': '0.0',
+            \                '@/functions': '0.1',
             \               '@%aurum/repo': '5.0',
             \          '@%aurum/lineutils': '0.0',
-            \            '@%aurum/bufvars': '0.0',
-            \                     '@aurum': '1.0',})
+            \            '@%aurum/bufvars': '0.0',})
 let s:commands={}
 let s:_messages={
             \    'ucmd': 'Unknown command: %s',
             \ 'num': '+opts[o]',
             \ 'str': 's:F.ounescape(opts[o])',
         \}
-function s:cmd.function(rw)
+let s:_aufunctions.event={}
+function s:_aufunctions.event.function(rw)
     " XXX On windows all forward slashes are transformed to backward in @%,
     "     all backward are transformed to forward in <amatch>
     let buf=expand('<abuf>')
 call s:_f.postresource('globtopat', s:F.globtopat)
 call s:_f.postresource('prevbuf',   s:F.prevbuf)
 "▶1
-call frawor#Lockvar(s:, '_pluginloaded,_r,commands')
+call frawor#Lockvar(s:, '_r,commands')
 " vim: ft=vim ts=4 sts=4 et fmr=▶,▲

autoload/aurum/file.vim

 "▶1 
 scriptencoding utf-8
-execute frawor#Setup('0.1', {'@%aurum/cmdutils': '4.1',
+execute frawor#Setup('0.1', {'@%aurum/cmdutils': '4.3',
             \                '@%aurum/maputils': '0.1',
             \                 '@%aurum/bufvars': '0.0',
             \               '@%aurum/lineutils': '0.0',
             \                 '@%aurum/vimdiff': '1.0',
             \                    '@%aurum/edit': '1.2',
-            \                          '@aurum': '1.0',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.0',
             \                            '@/os': '0.0',
             \                      '@/mappings': '0.0',})
 let s:_messages={
     call winrestview(winview)
 endfunction
 "▶1 AuFile
-function s:cmd.function(rev, file, opts)
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings '.
+            \'[:=(0)   type ""'.
+            \'[:=(0)   either (match /\L/, path fr)]]'.
+            \'{  repo   '.s:_r.cmdutils.comp.repo.
+            \' !?replace'.
+            \' !?prompt'.
+            \'  ?cmd    '.s:_r.cmdutils.comp.cmd.
+            \'}', 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \[['\V:=(0)\s\+either (\[^)]\+)', 'path', ''],
+            \ ['\V:=(0)\s\+type ""',
+            \               'either (type "" '.s:_r.cmdutils.comp.rev.')', ''],
+            \ ['\v\[(.{-})\]',                '\1',   ''],
+            \],
+            \s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(rev, file, opts)
     let opts=copy(a:opts)
     if a:rev isnot 0 && a:rev isnot ':'
         let opts.rev=a:rev

autoload/aurum/grep.vim

 scriptencoding utf-8
-execute frawor#Setup('0.0', {'@aurum': '1.0',
-            \      '@%aurum/cmdutils': '4.0',
-            \          '@%aurum/edit': '1.0',
-            \             '@/options': '0.0',})
+execute frawor#Setup('0.0', {'@%aurum/cmdutils': '4.3',
+            \                    '@%aurum/edit': '1.0',
+            \                       '@/options': '0.0',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.0',})
 let s:_messages={
             \   'nogf': 'No files found',
         \}
             \'workdirfiles': {'default': 1,
             \                  'filter': 'bool',},
         \}
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings '.
+            \'type "" '.
+            \'{     repo       '.s:_r.cmdutils.comp.repo.
+            \' ?*+2 revrange   '.join(repeat([s:_r.cmdutils.comp.rev], 2)).
+            \' ?*   revision   '.s:_r.cmdutils.comp.rev.
+            \' ?*   files      '.s:_r.cmdutils.comp.file.
+            \' ?    location   range 0 $=winnr("$")'.
+            \' ?   !workmatch'.
+            \' ?   !wdfiles'.
+            \' ?   !ignorecase '.
+            \'}', 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \                                     [], s:_f.fwc.compile)
 function s:F.setlist(opts, list)
     if has_key(a:opts, 'location')
         return setloclist(a:opts.location, a:list)
         return setqflist(a:list)
     endif
 endfunction
-function s:cmd.function(pattern, opts)
+function s:_aufunctions.cmd.function(pattern, opts)
     if has_key(a:opts, 'files') && a:opts.repo is# ':'
         let repo=s:_r.cmdutils.checkedgetrepo(a:opts.files[0])
     else

autoload/aurum/hyperlink.vim

 scriptencoding utf-8
-execute frawor#Setup('0.1', {'@aurum': '1.0',
-            \      '@%aurum/cmdutils': '4.0',
-            \             '@/options': '0.0',})
+execute frawor#Setup('0.1', {'@%aurum/cmdutils': '4.3',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.0',
+            \                       '@/options': '0.0',})
 let s:_messages={
             \'uknurl': 'Failed to process url %s of repository %s',
             \'uunsup': 'Url type “%s” is not supported for repository %s '.
             \'ldirty': 'Cannot attach line number to a dirty file %s '.
             \          'in the repository %s (dirty=having uncommited changes)',
         \}
+let s:utypes=['html', 'raw', 'annotate', 'filehist', 'bundle', 'changeset',
+            \ 'log', 'clone', 'push']
 let s:_options={
             \'hypsites': {'default': [],
             \             'checker': 'list tuple ((type ""), '.
-            \                                    'dict {?in _r.utypes  type ""'.
+            \                                    'dict {?in utypes     type ""'.
             \                                          '/\v^[ah]line$/ type ""'.
             \                                         '})'
             \            },
 endfunction
 "▶1 function
 "TODO diff ?
-function s:cmd.function(line1, line2, opts)
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings _ _'.
+            \'{   ?repo  '.s:_r.cmdutils.comp.repo.
+            \'    ?rev   '.s:_r.cmdutils.comp.rev.
+            \'    ?file  '.s:_r.cmdutils.comp.file.
+            \' !+1?line  range 1 inf'.
+            \' !+2?lines (range 1 inf)(range 1 inf)'.
+            \'    ?cmd   '.s:_r.cmdutils.comp.cmd.
+            \'    ?url   in utypes ~start'.
+            \'}', 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \                                     [], s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(line1, line2, opts)
     let opts=copy(a:opts)
     let utype=get(opts, 'url', 'html')
     "▶2 Get line or line1+line2

autoload/aurum/junk.vim

 scriptencoding utf-8
-execute frawor#Setup('0.0', {'@aurum': '1.0',
-            \      '@%aurum/cmdutils': '4.0',})
+execute frawor#Setup('0.0', {'@%aurum/cmdutils': '4.3',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.0',})
 let s:_messages={
             \'nofiles': 'No files were specified',
         \}
-function s:cmd.function(opts, ...)
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings '.
+            \'{?!forget'.
+            \' ?!ignore'.
+            \' ?!remove'.
+            \' ?!ignoreglobs'.
+            \'} + '.s:_r.cmdutils.comp.file, 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \                                     [], s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(opts, ...)
     if !a:0
         call s:_f.throw('nofiles')
     endif

autoload/aurum/log.vim

 "▶1
 scriptencoding utf-8
-execute frawor#Setup('1.1', {'@%aurum/cmdutils': '4.0',
+execute frawor#Setup('1.1', {'@%aurum/cmdutils': '4.3',
             \           '@%aurum/log/templates': '0.0',
             \               '@%aurum/lineutils': '0.0',
             \                 '@%aurum/bufvars': '0.0',
             \                    '@%aurum/edit': '1.1',
-            \                          '@aurum': '1.0',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.0',
             \                       '@/options': '0.0',
             \                         '@/table': '0.1',})
 let s:F.glog={}
 let s:F.graph={}
+let s:ignfiles=['patch', 'renames', 'copies', 'files', 'diff', 'open']
 let s:_options={
-            \'ignorefiles':    {'default': [],'checker': 'list in _r.ignfiles'},
+            \'ignorefiles':    {'default': [],'checker': 'list in ignfiles'},
             \'closelogwindow': {'default': 1,  'filter': 'bool'               },
             \'procinput':      {'default': 1, 'checker': 'range 0 2'          },
             \'loglimit':       {'default': 0, 'checker': 'range 0 inf'        },
 " iterfuncs :: {fname: { "start": startfunc, "next": nextfunc }}
 " startfunc (always) :: repo, opts, * → d
 let s:iterfuncs={}
-" XXX Check that completion and actual template lists match. This is needed to 
-"     prevent @aurum from depending on aurum/log/templates
-if sort(s:_r.template.tlist) !=# sort(s:_r.tlist)
-    call s:_f.warn('tnmatch')
-endif
 "▶1 addcols
 function s:F.addcols(special, cnum)
     let mapexpr='[v:val[0], v:val[1]+'.a:cnum.']+v:val[2:]'
     return bvar
 endfunction
 let s:_augroups+=['AuLog']
+"▶1 branchlist
+function s:F.branchlist()
+    let repo=aurum#repository()
+    return repo.functions.getrepoprop(repo, 'brancheslist')
+endfunction
 "▶1 AuLog
-function s:cmd.function(repopath, opts)
+let s:datereg='%(\d\d%(\d\d)?|[*.])'.
+            \ '%(\-%(\d\d?|[*.])'.
+            \ '%(\-%(\d\d?|[*.])'.
+            \ '%([ _]%(\d\d?|[*.])'.
+            \ '%(\:%(\d\d?|[*.]))?)?)?)?'
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings '.
+            \'['.s:_r.cmdutils.comp.repo.']'.
+            \'{ *  ?files    '.s:_r.cmdutils.comp.file.
+            \'  *  ?ignfiles in ignfiles ~start'.
+            \'     ?date     match /\v[<>]?\=?'.s:datereg.'|'.
+            \                       s:datereg.'\<\=?\>'.s:datereg.'/'.
+            \'     ?search   isreg'.
+            \'     ?user     isreg'.
+            \'     ?branch   type ""'.
+            \' ! +1?limit    range 1 inf'.
+            \'     ?revision '.s:_r.cmdutils.comp.rev.
+            \'   +2?revrange '.join(repeat([s:_r.cmdutils.comp.rev], 2)).
+            \'     ?style    in _r.template.tlist'.
+            \'     ?template idof variable'.
+            \' !   ?merges'.
+            \' !   ?patch'.
+            \' !   ?stat'.
+            \' !   ?showfiles'.
+            \' !   ?showrenames'.
+            \' !   ?showcopies'.
+            \' !   ?procinput'.
+            \' !   ?autoaddlog'.
+            \' !   ?progress'.
+            \s:_r.cmdutils.comp.diffopts.
+            \'    ?cmd      '.s:_r.cmdutils.comp.cmd.
+            \'}', 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \[['\vbranch\s+\Vtype ""', 'branch in *F.branchlist', '']],
+            \s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(repopath, opts)
     let opts=copy(a:opts)
     if has_key(opts, 'files')
         if opts.files[0] is# ':'
             \             'bool': ['merges', 'patch', 'stat', 'showfiles',
             \                      'showrenames', 'showcopies', 'procinput',
             \                      'autoaddlog'],
-            \              'num': ['limit']+s:_r.diffopts,
+            \              'num': ['limit']+s:_r.cmdutils.diffopts,
             \              'str': ['date', 'search', 'user', 'branch',
             \                      'revision', 'style', 'template',
             \                      'crrestrict'],

autoload/aurum/move.vim

 scriptencoding utf-8
-execute frawor#Setup('0.0', {'@aurum': '1.0',
-            \      '@%aurum/cmdutils': '4.0',
-            \          '@%aurum/edit': '1.0',
-            \                  '@/os': '0.0',
-            \               '@/table': '0.0',})
+execute frawor#Setup('0.0', {'@%aurum/cmdutils': '4.3',
+            \                    '@%aurum/edit': '1.0',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.0',
+            \                            '@/os': '0.0',
+            \                         '@/table': '0.0',})
 let s:_messages={
             \'nomv': 'No movable files found',
             \'_mvheader': ['Source', 'Destination'],
         \}
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings _ '.
+            \'{  repo '.s:_r.cmdutils.comp.repo.
+            \' ?!copy'.
+            \' ?!rightrepl'.
+            \' ?!leftpattern'.
+            \' ?!pretend'.
+            \'} '.
+            \'+ '.s:_r.cmdutils.comp.file, 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \                                     [], s:_f.fwc.compile)
 " :AuM          — move current file to current directory
 " :AuM dir      — move current file to given directory
 " :AuM pat  pat — act like `zmv -W': use second pat to construct new file name
 " :AuM pat+ dir — move given file(s) to given directory
 " :AuM pat+     — move given file(s) to current directory
-function s:cmd.function(bang, opts, ...)
+function s:_aufunctions.cmd.function(bang, opts, ...)
     if a:0 && !get(a:opts, 'leftpattern', 0) && a:opts.repo is# ':'
         let repo=s:_r.cmdutils.checkedgetrepo(a:1)
     else

autoload/aurum/name.vim

 scriptencoding utf-8
-execute frawor#Setup('0.0', {'@aurum': '1.0',
-            \      '@%aurum/cmdutils': '4.0',})
+execute frawor#Setup('0.0', {'@%aurum/cmdutils': '4.3',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.0',})
 let s:_messages={
             \ 'nunsup': 'Naming is not supported for repository %s',
             \'ukntype': 'Unknown label type: %s. Supported types: %s',
             \   'ldef': 'Label %s with type %s was alredy defined',
         \}
-function s:cmd.function(bang, name, opts, ...)
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings _ '.
+            \'type ""'.
+            \'{  repo '.s:_r.cmdutils.comp.repo.
+            \' ? type   type ""'.
+            \' ?!delete'.
+            \' ?!local'.
+            \'} '.
+            \'+ type ""', 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \                                     [], s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(bang, name, opts, ...)
     let repo=s:_r.cmdutils.checkedgetrepo(a:opts.repo)
     if !has_key(repo, 'labeltypes') || empty(repo.labeltypes)
         call s:_f.throw('nunsup', repo.path)

autoload/aurum/other.vim

 scriptencoding utf-8
-execute frawor#Setup('0.0', {'@aurum': '1.0',
-            \      '@%aurum/cmdutils': '4.0',
-            \                  '@/os': '0.0',})
-function s:cmd.function(bang, action, rev, url, repopath)
+execute frawor#Setup('0.0', {'@%aurum/cmdutils': '4.3',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.0',
+            \                            '@/os': '0.0',})
+let s:pushactions=['push', 'outgoing']
+let s:pullactions=['pull', 'incoming']
+let s:ppactions=s:pushactions+s:pullactions
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings _ '.
+            \'in ppactions ~ smart '.
+            \'[:":" '.s:_r.cmdutils.comp.rev.
+            \'[:":" '.s:_r.cmdutils.comp.file.
+            \'['.     s:_r.cmdutils.comp.repo.']]]', 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \                                     [], s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(bang, action, rev, url, repopath)
     let repo=s:_r.cmdutils.checkedgetrepo(a:repopath)
     if a:url isnot# ':' && stridx(a:url, '://')==-1 && isdirectory(a:url)
         let url=s:_r.os.path.realpath(a:url)
     else
         let url=a:url
     endif
-    let key=((index(s:_r.otheractions.push, a:action)==-1)?('pull'):('push'))
+    let key=((index(s:pushactions, a:action)==-1)?('pull'):('push'))
     return repo.functions[key](repo, (a:action[0] isnot# 'p'), a:bang,
                 \              ((  url is# ':')?(0):(  url)),
                 \              ((a:rev is# ':')?(0):(a:rev)))

autoload/aurum/powerline.vim

 "▶1 
 scriptencoding utf-8
-execute frawor#Setup('0.0', {'@aurum/cache': '2.3',
-            \                '@%aurum/repo': '5.0',
-            \            '@%aurum/cmdutils': '4.2',
-            \                    '@/python': '1.0',})
+execute frawor#Setup('0.0', {'@%aurum/cache': '2.3',
+            \                 '@%aurum/repo': '5.0',
+            \             '@%aurum/cmdutils': '4.2',
+            \                     '@/python': '1.0',})
 python import aurum.powerline
 "▶1 plwipe
 function s:F.plwipe(key)

autoload/aurum/record.vim

 execute frawor#Setup('0.0', {'@/options': '0.0',
             \                     '@/os': '0.0',
             \               '@/mappings': '0.0',
-            \                   '@aurum': '1.0',
-            \             '@aurum/cache': '2.1',
+            \              '@/functions': '0.1',
+            \                    '@/fwc': '0.0',
+            \            '@%aurum/cache': '2.4',
             \           '@%aurum/commit': '1.3',
-            \         '@%aurum/cmdutils': '4.0',
+            \         '@%aurum/cmdutils': '4.3',
             \        '@%aurum/lineutils': '0.0',
             \             '@%aurum/edit': '1.5',
             \          '@%aurum/bufvars': '0.0',})
     call feedkeys("\<C-\>\<C-n>:call ".
             \      "call(<SNR>".s:_sid."_Eval('s:F.runstatmap'), ".
             \           "['commit', ".expand('<abuf>')."], {})\n","n")
-    call map(copy(s:_r.allcachekeys), 's:_r.cache.wipe(v:val)')
+    call map(copy(s:_r.cache.allkeys), 's:_r.cache.wipe(v:val)')
 endfunction
 "▶1 recfunc
 " TODO investigate why closing record tab is causing next character consumption
 "      under wine
-function s:cmd.function(opts, ...)
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings '.
+            \'{  repo      '.s:_r.cmdutils.comp.repo.
+            \'  ?message     type ""'.
+            \'  ?date        type ""'.
+            \'  ?user        type ""'.
+            \' !?closebranch'.
+            \'} '.
+            \'+ '.s:_r.cmdutils.comp.file, 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \                                     [], s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(opts, ...)
     if !empty(filter(range(1, tabpagenr('$')),
                 \    'gettabvar(v:val, "aurecid") is# "AuRecordTab"'))
         call s:_f.throw('recex')

autoload/aurum/repo.vim

             \                    '@/python': '1.0',
             \           '@%aurum/lineutils': '0.0',
             \             '@%aurum/bufvars': '0.0',
-            \                      '@aurum': '1.0',
             \'@%aurum/drivers/common/utils': '1.1',})
 let s:drivers={}
 let s:repos={}
 let s:bufrepos={}
+" FIXME deduplicate data
+let s:diffopts=['git', 'reverse', 'ignorews', 'iwsamount', 'iblanks',
+            \   'numlines', 'showfunc', 'alltext', 'dates']
 let s:_options={
             \'diffopts':  {'default': {},
-            \              'checker': 'dict {numlines         range 0 inf '.
-            \                               '?in _r.diffopts  bool}'},
+            \              'checker': 'dict {numlines      range 0 inf '.
+            \                               '?in diffopts  bool}'},
         \}
 let s:_messages={
             \    'nrm': 'Failed to remove file %s from repository %s',

autoload/aurum/status.vim

 "▶1 
 scriptencoding utf-8
-execute frawor#Setup('1.2', {'@%aurum/cmdutils': '4.0',
+execute frawor#Setup('1.2', {'@%aurum/cmdutils': '4.3',
             \                    '@%aurum/edit': '1.0',
-            \                          '@aurum': '1.0',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.0',
             \                       '@/options': '0.0',
             \                     '@/resources': '0.0',})
 let s:statchars={
 endfunction
 "▶1 statfunc
 let s:defcmd='silent botright new'
-function s:cmd.function(repopath, opts)
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings '.
+            \'['.s:_r.cmdutils.comp.repo.']'.
+            \'{ *?files     '.s:_r.cmdutils.comp.file.
+            \'   ?rev       '.s:_r.cmdutils.comp.rev.
+            \'   ?wdrev     '.s:_r.cmdutils.comp.rev.
+            \'   ?changes   '.s:_r.cmdutils.comp.rev.
+            \'  *?show      (either (in [modified added '.
+            \                           'removed deleted '.
+            \                           'unknown ignored '.
+            \                           'clean all] ~start, '.
+            \                       'match /\v^[MARDUIC!?]+$/))'.
+            \'   ?cmd       '.s:_r.cmdutils.comp.cmd.
+            \'}', 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \                                     [], s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(repopath, opts)
     if has_key(a:opts, 'files') && a:repopath is# ':'
         let repo=s:_r.cmdutils.checkedgetrepo(a:opts.files[0])
     else

autoload/aurum/track.vim

 scriptencoding utf-8
-execute frawor#Setup('0.0', {'@aurum': '1.0',
-            \      '@%aurum/cmdutils': '4.0',})
-function s:cmd.function(...)
+execute frawor#Setup('0.0', {'@%aurum/cmdutils': '4.3',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.0',})
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings '.
+            \'+ '.s:_r.cmdutils.comp.file, 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \                                     [], s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(...)
     let globs=filter(copy(a:000), 'v:val isnot# ":"')
     let hascur=!(a:0 && len(globs)==a:0)
     let repo=s:_r.cmdutils.checkedgetrepo(a:0 ? a:1 : ':')

autoload/aurum/update.vim

 scriptencoding utf-8
-execute frawor#Setup('0.0', {'@aurum': '1.0',
-            \      '@%aurum/cmdutils': '4.0',})
-function s:cmd.function(bang, rev, repopath)
+execute frawor#Setup('0.0', {'@%aurum/cmdutils': '4.3',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.3',})
+let s:comp=s:_r.cmdutils.comp
+let s:fwc='-onlystrings _ [:=(0) '.s:comp.rev.' ['.s:comp.repo.']]'
+let s:_aufunctions.cmd={'@FWC': [s:fwc, 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:fwc, [], s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(bang, rev, repopath)
     let repo=s:_r.cmdutils.checkedgetrepo(a:repopath)
     if a:rev is 0
         let rev=repo.functions.gettiphex(repo)

autoload/aurum/vimdiff.vim

 "▶1 
 scriptencoding utf-8
-execute frawor#Setup('1.1', {'@%aurum/cmdutils': '4.0',
+execute frawor#Setup('1.1', {'@%aurum/cmdutils': '4.3',
             \                    '@%aurum/edit': '1.3',
-            \                          '@aurum': '1.0',
+            \                     '@/functions': '0.1',
+            \                           '@/fwc': '0.0',
             \                      '@/mappings': '0.0',
             \                     '@/resources': '0.0',
             \                       '@/options': '0.0',
 endfunction
 "▶1 :AuVimDiff
 " TODO exclude binary files from full diff
-function s:cmd.function(opts, ...)
+let s:_aufunctions.cmd={'@FWC': ['-onlystrings '.
+            \'{  repo  '.s:_r.cmdutils.comp.repo.
+            \'  ?file  '.s:_r.cmdutils.comp.file.
+            \' *?files (match /\W/)'.
+            \' !?full'.
+            \' !?untracked'.
+            \' !?onlymodified'.
+            \' !?curfile'.
+            \' !?usewin'.
+            \'}'.
+            \'+ '.s:_r.cmdutils.comp.rev, 'filter']}
+let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
+            \[['\V(match /\\W/)', '(path)', '']], s:_f.fwc.compile)
+function s:_aufunctions.cmd.function(opts, ...)
     "▶2 repo and revisions
     let full=get(a:opts, 'full', 0)
     let action=((full)?('getfiles'):('open'))
     0.4: Added |:AuHyperlink| lines.
     1.0: Splitted into a number of plugins, added aurumcmd feature and 
          a number of resources.
+    2.0: Made everything use 3-tuple function loading thus removed lots of 
+         stuff from here.
 @%aurum/edit:
     1.0: Removed setlines function (moved it to @aurum/repo).
     1.1: Added “requiresbvar” _f.newcommand option.
     4.0: Moved _r.cmdutils.update to @%aurum/maputils
     4.1: Made _r.cmdutils.getrrf recognize “getrr” action
     4.2: Made _r.cmdutils.getrrf not throw “nrepo” in case a:failmsg is zero
+    4.3: Added _r.cmdutils.gencompfunc, _r.cmdutils.revlist and 
+         _r.cmdutils.comp.
 @%aurum:
     0.1: Added |aurum#branch()| function.
-@aurum/cache:
+@%aurum/cache:
     0.1: Added _r.cache.del().
     1.0: Added _r.getcrf(), removed cachebvars export.
     2.0: Removed getcrf, added _r.cache.getcbvar.
     2.1: Added _r.cache.wipe().
     2.2: Added _r.cache.getinterval().
     2.3: Added addwiper feature.
+    2.4: Added _r.cache.allkeys.
 ftplugin/aurumlog:
     0.1: Added OpenAny and AnnotateAny mappings.
 @%aurum/drivers/common/hypsites:
 @%aurum/hyperlink:
     0.1: Added support for password in URL.
 @%aurum/maputils:
-    0.1: Added _r.maputils.getnthparentfile()
+    0.1: Added _r.maputils.getnthparentfile().
 
 vim: ft=help:tw=78
 "▶1 Setup
 scriptencoding utf-8
-execute frawor#Setup('1.0', {'@/commands': '0.0',
-            \               '@/functions': '0.0',
+execute frawor#Setup('2.0', {'@/commands': '0.0',
+            \               '@/functions': '0.1',
+            \              '@/decorators': '0.0',
             \                '@/mappings': '0.0',
-            \                     '@/fwc': '0.3',
             \            '@/autocommands': '0.0',
-            \               '@/resources': '0.0',
-            \              '@aurum/cache': '2.1',})
-"▶1 Messages
-let s:_messages={
-            \'afail': 'Failed to load aurum:// function from %s',
-            \'anofu': 'Plugin %s did not provide any functions for aurum://',
-            \'lfail': 'Failed to load Au%s’s function from %s',
-            \'nofun': 'Plugin %s did not provide any functions for Au%s',
-        \}
-"▶1 Command descriptions
-" XXX Normally I use “type ""”. Things below are used to make these parts 
-"     unique.
-let s:revarg='type string'
-let s:filearg='type String'
-let s:cmdarg='type STRING'
-"XXX AuRecord notes:
-" options message, user, date and closebranch are used by com.commit
-" documentation says that options are the same as for `:AuCommit' except for 
-" `type' option
-let s:datereg='%(\d\d%(\d\d)?|[*.])'.
-            \ '%(\-%(\d\d?|[*.])'.
-            \ '%(\-%(\d\d?|[*.])'.
-            \ '%([ _]%(\d\d?|[*.])'.
-            \ '%(\:%(\d\d?|[*.]))?)?)?)?'
-let s:patharg='either (path d, match @\v^\w+%(\+\w+)*\V://\v|^\:$@)'
-let s:nogetrepoarg=':":" ('.s:patharg.')'
-unlet s:patharg
-let s:compbranchrevarg='in *F.branchlist'
-let s:comprevarg='in *F.revlist'
-let s:compcmdarg='first (in compcmds, idof cmd)'
-" XXX Some code relies on the fact that all options from s:diffoptslst are
-"     numeric
-let s:diffoptslst=['git', 'reverse', 'ignorews', 'iwsamount', 'iblanks',
-            \      'numlines', 'showfunc', 'alltext', 'dates']
-let s:diffoptsstr=join(map(copy(s:diffoptslst),
-            \          'v:val is# "numlines" ? '.
-            \               '" ?".v:val." range 0 inf" : '.
-            \               '"!?".v:val'))
-let s:allcachekeys=['branch', 'changeset', 'repository', 'status']
-let s:cmds={
-            \'Update':    {'opts': {'bang': 1},
-            \               'fwc': '[:=(0) '.s:revarg.
-            \                      '['.s:nogetrepoarg.']',
-            \              'wipe': ['branch', 'changeset', 'status'],
-            \             },
-            \'Move':      {'opts': {'bang': 1},
-            \               'fwc': '{  repo '.s:nogetrepoarg.
-            \                      ' ?!copy'.
-            \                      ' ?!rightrepl'.
-            \                      ' ?!leftpattern'.
-            \                      ' ?!pretend'.
-            \                      '} '.
-            \                      '+ '.s:filearg,
-            \              'wipe': ['status'],
-            \             },
-            \'Junk':      { 'fwc': '{?!forget '.
-            \                       '?!ignore '.
-            \                       '?!remove '.
-            \                       '?!ignoreglobs '.
-            \                      '} + '.s:filearg,
-            \              'wipe': ['status'],
-            \             },
-            \'Track':     { 'fwc': '+ '.s:filearg,
-            \              'wipe': ['status'],
-            \             },
-            \'Hyperlink': {'opts': {'range': '%'},
-            \               'fwc': '{   ?repo '.s:nogetrepoarg.
-            \                      '    ?rev   '.s:revarg.
-            \                      '    ?file  '.s:filearg.
-            \                      ' !+1?line  range 1 inf'.
-            \                      ' !+2?lines (range 1 inf)(range 1 inf)'.
-            \                      '    ?cmd   '.s:cmdarg.
-            \                      '    ?url   in utypes ~start'.
-            \                      '}',
-            \             },
-            \'Grep':      {'fwc': 'type "" '.
-            \                     '{     repo     '.s:nogetrepoarg.
-            \                     ' ?*+2 revrange   '.s:revarg.' '.s:revarg.
-            \                     ' ?*   revision   '.s:revarg.
-            \                     ' ?*   files      '.s:filearg.
-            \                     ' ?    location   range 0 $=winnr("$")'.
-            \                     ' ?   !workmatch'.
-            \                     ' ?   !wdfiles'.
-            \                     ' ?   !ignorecase '.
-            \                     '}',
-            \             },
-            \'Branch':    {'opts': {'bang': 1},
-            \               'fwc': 'type "" '.
-            \                      '{  repo '.s:nogetrepoarg.
-            \                      '}',
-            \              'wipe': ['branch', 'changeset'],
-            \             },
-            \'Name':      {'opts': {'bang': 1},
-            \               'fwc': 'type ""'.
-            \                      '{  repo '.s:nogetrepoarg.
-            \                      ' ? type   type ""'.
-            \                      ' ?!delete'.
-            \                      ' ?!local'.
-            \                      '} '.
-            \                      '+ type ""',
-            \              'wipe': ['branch', 'changeset'],
-            \             },
-            \'Other':     {'opts': {'bang': 1},
-            \               'fwc': 'in ppactions ~ smart '.
-            \                      '[:":" '.s:revarg.
-            \                      '[:":" '.s:filearg.
-            \                      '['.s:nogetrepoarg.']]]',
-            \              'wipe': s:allcachekeys,
-            \             },
-            \'Annotate':  { 'fwc': '{  repo  '.s:nogetrepoarg.
-            \                      '  ?file  '.s:filearg.
-            \                      '  ?rev   '.s:revarg.
-            \                      '}',
-            \             },
-            \'Commit':    { 'fwc': '{  repo '.s:nogetrepoarg.
-            \                      ' *?type      (either (in [modified added '.
-            \                                                'removed deleted '.
-            \                                                'unknown all] '.
-            \                                               '~start,'.
-            \                                            'match /\v^[MARDU?!]+$/))'.
-            \                      '  ?message   type ""'.
-            \                      '  ?user      type ""'.
-            \                      '  ?date      match /\v%(^%(\d*\d\d-)?'.
-            \                                               '%(%(1[0-2]|0?[1-9])-'.
-            \                                                 '%(3[01]|0?[1-9]|[12]\d)))?'.
-            \                                            '%(%(^|[ _])%(2[0-3]|[01]\d)'.
-            \                                                       '\:[0-5]\d'.
-            \                                                       '%(\:[0-5]\d)?)?$/'.
-            \                      ' !?closebranch'.
-            \                      '}'.
-            \                      '+ '.s:filearg,
-            \              'wipe': s:allcachekeys,
-            \             },
-            \'Diff':      { 'fwc': '{  repo     '.s:nogetrepoarg.
-            \                      '  ?rev1     '.s:revarg.
-            \                      '  ?rev2     '.s:revarg.
-            \                      '  ?changes  '.s:revarg.
-            \                      s:diffoptsstr.
-            \                      '  ?cmd      '.s:cmdarg.
-            \                      '}'.
-            \                      '+ '.s:filearg,
-            \             },
-            \'File':      { 'fwc': '[:=(0)   type ""'.
-            \                      '[:=(0)   either (match /\L/, path fr)]]'.
-            \                      '{  repo '.s:nogetrepoarg.
-            \                      ' !?replace'.
-            \                      ' !?prompt'.
-            \                      '  ?cmd    '.s:cmdarg.
-            \                      '}',
-            \              'subs': [['\V:=(0)\s\+either (\[^)]\+)', 'path', ''],
-            \                       ['\V:=(0)\s\+type ""',
-            \                         'either (type "" '.s:comprevarg.')',  ''],
-            \                       ['\v\[(.{-})\]',                '\1',   ''],
-            \                      ],
-            \             },
-            \'Record':    { 'fwc': '{  repo '.s:nogetrepoarg.
-            \                      '  ?message           type ""'.
-            \                      '  ?date              type ""'.
-            \                      '  ?user              type ""'.
-            \                      ' !?closebranch'.
-            \                      '} '.
-            \                      '+ '.s:filearg,
-            \             },
-            \'Status':    { 'fwc': '['.s:nogetrepoarg.']'.
-            \                      '{ *?files     '.s:filearg.
-            \                      '   ?rev       '.s:revarg.
-            \                      '   ?wdrev     '.s:revarg.
-            \                      '   ?changes   '.s:revarg.
-            \                      '  *?show      (either (in [modified added '.
-            \                                                 'removed deleted '.
-            \                                                 'unknown ignored '.
-            \                                                 'clean all] ~start, '.
-            \                                             'match /\v^[MARDUIC!?]+$/))'.
-            \                      '   ?cmd       '.s:cmdarg.
-            \                      '}',
-            \             },
-            \'VimDiff':   { 'fwc': '{  repo  '.s:nogetrepoarg.
-            \                      '  ?file  '.s:filearg.
-            \                      ' *?files (match /\W/)'.
-            \                      ' !?full'.
-            \                      ' !?untracked'.
-            \                      ' !?onlymodified'.
-            \                      ' !?curfile'.
-            \                      ' !?usewin'.
-            \                      '}'.
-            \                      '+ '.s:revarg,
-            \              'subs': [['\V(match /\\W/)', '(path)', '']],
-            \             },
-            \'Log':       { 'fwc': '['.s:nogetrepoarg.']'.
-            \                      '{ *  ?files    '.s:filearg.
-            \                      '  *  ?ignfiles in ignfiles ~start'.
-            \                      '     ?date     match /\v[<>]?\=?'.s:datereg.'|'.
-            \                                             s:datereg.'\<\=?\>'.s:datereg.'/'.
-            \                      '     ?search   isreg'.
-            \                      '     ?user     isreg'.
-            \                      '     ?branch   type ""'.
-            \                      ' ! +1?limit    range 1 inf'.
-            \                      '     ?revision '.s:revarg.
-            \                      '   +2?revrange '.s:revarg.' '.s:revarg.
-            \                      '     ?style    in tlist'.
-            \                      '     ?template idof variable'.
-            \                      ' !   ?merges'.
-            \                      ' !   ?patch'.
-            \                      ' !   ?stat'.
-            \                      ' !   ?showfiles'.
-            \                      ' !   ?showrenames'.
-            \                      ' !   ?showcopies'.
-            \                      ' !   ?procinput'.
-            \                      ' !   ?autoaddlog'.
-            \                      ' !   ?progress'.
-            \                      s:diffoptsstr.
-            \                      '    ?cmd      '.s:cmdarg.
-            \                      '}',
-            \              'subs': [['\vbranch\s+\Vtype ""',
-            \                                'branch '.s:compbranchrevarg, '']],
-            \             },
-        \}
-unlet s:datereg s:nogetrepoarg s:compbranchrevarg
-"▶1 Related globals
-let s:utypes=['html', 'raw', 'annotate', 'filehist', 'bundle', 'changeset',
-            \ 'log', 'clone', 'push']
-call s:_f.postresource('utypes', s:utypes)
-let s:pushactions=['push', 'outgoing']
-let s:pullactions=['pull', 'incoming']
-let s:ppactions=s:pushactions+s:pullactions
-call s:_f.postresource('otheractions', {'push': s:pushactions,
-            \                           'pull': s:pullactions})
-let s:ignfiles=['patch', 'renames', 'copies', 'files', 'diff', 'open']
-call s:_f.postresource('ignfiles', s:ignfiles)
-call s:_f.postresource('diffopts', s:diffoptslst)
-let s:tlist=['default', 'compact', 'git', 'svn', 'hgdef', 'hgdescr', 'cdescr',
-            \'gitoneline', 'bzr', 'bzrshort', 'bzrline']
-call s:_f.postresource('tlist', s:tlist)
-call s:_f.postresource('allcachekeys', s:allcachekeys)
-"▶1 Completion helpers
-let s:compcmds=['new', 'vnew', 'edit',
-            \   'leftabove vnew', 'rightbelow vnew',
-            \   'topleft vnew',   'botright vnew',
-            \   'aboveleft new',  'belowright new',
-            \   'topleft new',    'botright new',]
-call map(s:compcmds, 'escape(v:val, " ")')
-function s:F.revlist(...)
-    let repo=aurum#repository()
-    return       repo.functions.getrepoprop(repo, 'tagslist')+
-                \repo.functions.getrepoprop(repo, 'brancheslist')+
-                \repo.functions.getrepoprop(repo, 'bookmarkslist')
-endfunction
-function s:F.branchlist()
-    let repo=aurum#repository()
-    return repo.functions.getrepoprop(repo, 'brancheslist')
-endfunction
-"▶1 Commands setup
-let s:plpref='autoload/aurum/'
-let s:d={}
-let s:cmdfuncs={}
-for [s:cmd, s:cdesc] in items(s:cmds)
-    let s:cdesc.opts=extend(get(s:cdesc, 'opts', {}), {'nargs': '*',
-                \                                   'complete': []})
-    "▶2 Completion substitutions
-    let s:cdesc.subs=get(s:cdesc, 'subs', [])
-    if stridx(s:cdesc.fwc, s:revarg)!=-1
-        let s:cdesc.subs+=[['\V'.s:revarg,    s:comprevarg, 'g']]
-    endif
-    if stridx(s:cdesc.fwc, s:filearg)!=-1
-        let s:cdesc.subs+=[['\V'.s:filearg,   '(path)',     'g']]
-    endif
-    if stridx(s:cdesc.fwc, s:cmdarg)!=-1
-        let s:cdesc.subs+=[['\V'.s:cmdarg,    s:compcmdarg, '' ]]
-    endif
-    "▲2
-    let s:compfwc='-onlystrings '.s:cdesc.fwc
-    for s:args in s:cdesc.subs
-        let s:compfwc=call('substitute', [s:compfwc]+s:args)
-        unlet s:args
-    endfor
-    let s:cdesc.opts.complete+=[s:compfwc]
-    unlet s:compfwc
-    " Number of arguments that should not be checked or completed
-    let s:skipcount=  has_key(s:cdesc.opts, 'bang')+
-                \   2*has_key(s:cdesc.opts, 'range')
-    let s:cdesc.fwc='-onlystrings '.repeat('_ ', s:skipcount).s:cdesc.fwc
-    unlet s:skipcount
-    let s:eplid=string((s:plpref).(tolower(s:cmd)))
-    execute      "function s:d.function(...)\n".
-                \"    if !has_key(s:cmdfuncs, ".s:eplid.")\n".
-                \"        if !has_key(s:cmddicts, ".s:eplid.")\n".
-                \"            call FraworLoad(".s:eplid.")\n".
-                \"            if !has_key(s:cmddicts, ".s:eplid.")\n".
-                \"                call s:_f.throw('lfail', '".s:cmd."', ".
-                \                                             s:eplid.")\n".
-                \"            endif\n".
-                \"        endif\n".
-                \"        if !has_key(s:cmddicts[".s:eplid."], ".
-                \                        "'function')\n".
-                \"            call s:_f.throw('nofun', ".s:eplid.", ".
-                \                                    "'".s:cmd."')\n".
-                \"        endif\n".
-                \"        let s:cmdfuncs[".s:eplid."]=s:_f.wrapfunc(".
-                \                  "extend({'@FWC': [".string(s:cdesc.fwc).", ".
-                \                                   "'filter']}, ".
-                \                         "s:cmddicts[".s:eplid."]))\n".
-                \"    endif\n".
-                \"    call call(s:cmdfuncs[".s:eplid."], a:000, {})\n".
-                \((has_key(s:cdesc, 'wipe'))?
-                \    ("    call map(".string(s:cdesc.wipe).", ".
-                \                  "'s:_r.cache.wipe(v:val)')\n"):
-                \    ("")).
-                \"endfunction"
-    unlet s:eplid
-    call s:_f.command.add('Au'.s:cmd, remove(s:d, 'function'), s:cdesc.opts)
-    unlet s:cmd s:cdesc
-endfor
-unlet s:d
-unlet s:comprevarg s:compcmdarg
-"▶1 aurumcmd feature
-let s:feature={}
-let s:cmddicts={}
-function s:feature.register(plugdict, fdict)
-    let a:plugdict.g.cmd={}
-    let s:cmddicts[a:plugdict.id]=a:plugdict.g.cmd
-endfunction
-function s:feature.unload(plugdict, fdict)
-    unlet s:cmddicts[a:plugdict.id]
-    if has_key(s:cmdfuncs, a:plugdict.id)
-        unlet s:cmdfuncs[a:plugdict.id]
+            \                    '@aurum': '2.0',})
+"▶1 aurum_cache_wipe decorator
+function s:F.aurum_cache_wipe(plugdict, fname, wipes)
+    call s:_f.require('@%aurum/cache', [2, 4], 1)
+    if a:wipes is# 'all'
+        return [0, '@@@', {'wipes':s:_r.cache.allkeys, 'wipe':s:_r.cache.wipe},
+                    \['call map(copy(@%@.wipes), "@%@.wipe(v:val)")'],
+                    \[], 1]
+    else
+        return [0, '@@@', {'wipes': a:wipes, 'wipe': s:_r.cache.wipe},
+                    \['call map(copy(@%@.wipes), "@%@.wipe(v:val)")'],
+                    \[], 1]
     endif
 endfunction
-call s:_f.newfeature('aurumcmd', s:feature)
+call s:_f.adddecorator('aurum_cache_wipe', s:F.aurum_cache_wipe)
+"XXX AuRecord notes:
+function s:F.opts(opts, cmd, ver)
+    return extend({'nargs': '*', 'usedictcompsplitfunc': 1, 'complete':
+                \{'function': ['@%aurum/'.tolower(a:cmd), a:ver, 'comp']}},
+                \a:opts)
+endfunction
+for [s:cmd, s:ver, s:opts, s:wipe] in [
+            \['Update',    [0],{'bang': 1},    ["branch","changeset","status"]],
+            \['Move',      [0],{'bang': 1},    [                     "status"]],
+            \['Junk',      [0],{},             [                     "status"]],
+            \['Track',     [0],{},             [                     "status"]],
+            \['Hyperlink', [0],{'range': '%'}, 0                              ],
+            \['Grep',      [0],{},             0                              ],
+            \['Branch',    [0],{'bang': 1},    ["branch","changeset"         ]],
+            \['Name',      [0],{'bang': 1},    ["branch","changeset"         ]],
+            \['Other',     [0],{'bang': 1},    'all'                          ],
+            \['Annotate',  [0],{},             0                              ],
+            \['Commit',    [0],{},             'all'                          ],
+            \['Diff',      [0],{},             0                              ],
+            \['File',      [0],{},             0                              ],
+            \['Record',    [0],{},             0                              ],
+            \['Status',    [0],{},             0                              ],
+            \['VimDiff',   [0],{},             0                              ],
+            \['Log',       [0],{},             0                              ],
+            \]
+    call s:_f.command.add('Au'.s:cmd,
+                \extend({'function': ['@%aurum/'.tolower(s:cmd), s:ver, 'cmd']},
+                \       (empty(s:wipe) ? {} : {'@aurum_cache_wipe': s:wipe})),
+                \s:F.opts(s:opts, s:cmd, s:ver))
+    unlet s:wipe
+endfor
+unlet s:F.opts
+unlet s:cmd s:ver s:opts
 "▶1 Global mappings
 " TODO mapping that closes status window
 call s:_f.mapgroup.add('Aurum', {
             \'Pull':      {'lhs':  'p', 'rhs': ':<C-u>AuOther pull<CR>'      },
         \}, {'mode': 'n', 'silent': 1, 'leader': '<Leader>a'})
 "▶1 Autocommands
-function s:F.aurun(...)
-    let plid='autoload/aurum/edit'
-    if !has_key(s:cmdfuncs, plid)
-        if !has_key(s:cmddicts, plid)
-            call FraworLoad(plid)
-            if !has_key(s:cmddicts, plid)
-                call s:_f.throw('afail', plid)
-            endif
-        endif
-        if !has_key(s:cmddicts[plid], 'function')
-            call s:_f.throw('anofu', plid)
-        endif
-        let s:cmdfuncs[plid]=s:cmddicts[plid].function
-    endif
-    return call(s:cmdfuncs[plid], a:000, {})
-endfunction
+let s:aurun={'function': ['@%aurum/edit', [1], 'event']}
 call s:_f.augroup.add('Aurum',
-            \[['BufReadCmd',   'aurum://*', 1, [s:F.aurun,  0]],
-            \ ['FileReadCmd',  'aurum://*', 1, [s:F.aurun,  1]],
-            \ ['SourceCmd',    'aurum://*', 1, [s:F.aurun,  2]],
-            \ ['BufWriteCmd',  'aurum://*', 1, [s:F.aurun, -1]],
-            \ ['FileWriteCmd', 'aurum://*', 1, [s:F.aurun, -2]],
+            \[['BufReadCmd',   'aurum://*', 1, [s:aurun,  0]],
+            \ ['FileReadCmd',  'aurum://*', 1, [s:aurun,  1]],
+            \ ['SourceCmd',    'aurum://*', 1, [s:aurun,  2]],
+            \ ['BufWriteCmd',  'aurum://*', 1, [s:aurun, -1]],
+            \ ['FileWriteCmd', 'aurum://*', 1, [s:aurun, -2]],
             \])
 "▶1
-call frawor#Lockvar(s:, 'cmddicts,cmdfuncs')
+call frawor#Lockvar(s:, '_r,_f')
 " vim: ft=vim ts=4 sts=4 et fmr=▶,▲

plugin/aurum/cache.vim

-"▶1
-scriptencoding utf-8
-execute frawor#Setup('2.3', {'@/resources': '0.0',
-            \                  '@/options': '0.0',})
-let s:_options={
-            \'branchcachetime': {'default': 2, 'checker': 'range 0 inf'},
-            \'cscachetime':     {'default': 3, 'checker': 'range 0 inf'},
-            \'statuscachetime': {'default': 5, 'checker': 'range 0 inf'},
-            \'repocachetime':   {'default': 7, 'checker': 'range 0 inf'},
-        \}
-let s:cachebvars={}
-let s:r={}
-let s:_messages={
-            \ 'nfunc': 'Argument must be a callable function reference',
-            \ 'pldef': 'Plugin has already defined one wiper function',
-            \'dbldef': 'Function %s was already added by another plugin',
-        \}
-"▶1 bufwipeout
-function s:F.bufwipeout()
-    let buf=+expand('<abuf>')
-    if has_key(s:cachebvars, buf)
-        unlet s:cachebvars[buf]
-    endif
-endfunction
-augroup AurumCacheBufVars
-    autocmd BufWipeOut,BufFilePost * :call s:F.bufwipeout()
-augroup END
-let s:_augroups+=['AurumCacheBufVars']
-"▶1 r.getcbvar ::  () + buf, cachebvars → cbvar + cachebvars?
-function s:r.getcbvar()
-    let buf=bufnr('%')
-    if !has_key(s:cachebvars, buf)
-        let s:cachebvars[buf]={}
-    endif
-    return s:cachebvars[buf]
-endfunction
-"▶1 r.get :: key, func, args, dict → val + cbvar
-function s:r.get(key, Func, args, dict)
-    let cbvar=s:r.getcbvar()
-    if !(has_key(cbvar, a:key) &&
-                \localtime()-cbvar['_time'.a:key]<cbvar['_maxtime'.a:key])
-        let cbvar[a:key]=call(a:Func, a:args, a:dict)
-        let cbvar['_time'.a:key]=localtime()
-        if !has_key(cbvar, '_maxtime'.a:key)
-            let cbvar['_maxtime'.a:key]=s:_f.getoption(a:key.'cachetime')
-        endif
-    endif
-    return cbvar[a:key]
-endfunction
-"▶1 r.del :: key → + cbvar
-function s:r.del(key)
-    let buf=bufnr('%')
-    if !has_key(s:cachebvars, buf)
-        return
-    endif
-    let cbvar=s:cachebvars[buf]
-    if has_key(cbvar, a:key)
-        unlet cbvar[a:key]
-    endif
-endfunction
-"▶1 r.wipe :: key → + cachebvars
-function s:r.wipe(key)
-    " empty() is here only to avoid possible “Using smth as a number” error
-    call map(copy(s:cachebvars), 'has_key(v:val,a:key) && '.
-                \                                  'empty(remove(v:val,a:key))')
-    call map(copy(s:wipers), 'call(v:val, [a:key], {})')
-endfunction
-"▶1 r.getinterval
-function s:r.getinterval(key)
-    return s:_f.getoption(a:key.'cachetime')
-endfunction
-"▶1 addwiper feature
-let s:wipers=[]
-let s:feature={}
-function s:feature.cons(plugdict, fdict, Func)
-    if !exists('*a:Func')
-        call s:_f.throw('nfunc')
-    elseif has_key(a:fdict, 'func')
-        call s:_f.throw('pldef', string(a:fdict.func))
-    elseif index(s:wipers, a:Func)!=-1
-        call s:_f.throw('dbldef', string(a:Func))
-    endif
-    let s:wipers+=[a:Func]
-    let a:fdict.func=a:Func
-endfunction
-function s:feature.unload(plugdict, fdict)
-    if has_key(a:fdict, 'func')
-        call filter(s:wipers, 'v:val isnot# a:fdict.func')
-    endif
-endfunction
-call s:_f.newfeature('addwiper', s:feature)
-"▶1 Post cache resource
-call s:_f.postresource('cache', s:r)
-"▶1
-call frawor#Lockvar(s:, '_pluginloaded,cachebvars,wipers')
-" vim: ft=vim ts=4 sts=4 et fmr=▶,▲
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.