Commits

ZyX_I  committed b127e02

Replaced all direct `{command} fnameescape('aurum://...')' calls with s:_r.run() or `{command} fnameescape(s:_r.fname(...))'

  • Participants
  • Parent commits 239c019

Comments (0)

Files changed (17)

File ftplugin/aurumannotate.vim

             \             '@aurum/bufvars': '0.0',
             \             '@aurum/vimdiff': '0.0',
             \            '@aurum/annotate': '0.0',
-            \            '@aurum/cmdutils': '0.0',
+            \                '@aurum/edit': '0.0',
             \                 '@/mappings': '0.0',
             \                       '@/os': '0.0',})
 let s:_messages={
     let bvar=s:_r.bufvars[buf]
     let hex=bvar.revisions[line('.')-1]
     let file=bvar.files[line('.')-1]
-    let epath=s:_r.cmdutils.escape(bvar.repo.path)
     let hasannbuf = has_key(bvar, 'annbuf') && bufwinnr(bvar.annbuf)!=-1
     "▶2 Various *diff actions
     if a:action[-4:] is# 'diff'
                 endif
             else
                 try
-                    let file1='aurum://file:'.epath.':'.rev1.':'.
-                                \           s:_r.cmdutils.escape(file)
-                    let existed=bufexists(file1)
-                    execute 'silent edit' fnameescape(file1)
+                    let existed=s:_r.run('silent edit', 'file', bvar.repo, rev1,
+                                \        file)
                 catch /\V\^Frawor:\[^:]\+:nofile:/
                     call s:_f.throw('nofile', file, rev1)
                 endtry
                 setlocal bufhidden=wipe
                 unlet existed
             endif
-            call s:_r.vimdiff.split('aurum://file:'.epath.':'.rev2.':'.
-                        \                         s:_r.cmdutils.escape(file), -1)
+            call s:_r.vimdiff.split(s:_r.fname('file',bvar.repo,rev2,file), -1)
             if empty(rev1)
                 wincmd p
             endif
             else
                 let dfile=file
             endif
-            let f='aurum://diff:'.epath.':'.rev1.':'.rev2.':'.
-                        \       ((a:0&&a:1)?(''):(s:_r.cmdutils.escape(dfile)))
-            let existed=bufexists(f)
-            execute 'silent edit' fnameescape(f)
+            let existed=s:_r.run('silent edit', 'diff', bvar.repo, rev1, rev2,
+                        \        ((a:0 && a:1)?(''):(dfile)))
         endif
     "▶2 `open' action
     elseif a:action is# 'open'
             endif
         endif
         if hasannbuf
-            execute 'silent edit '.
-                        \fnameescape('aurum://annotate:'.epath.':'.hex.':'.
-                        \                              s:_r.cmdutils.escape(file))
+            call s:_r.run('silent edit', 'annotate', bvar.repo, hex, file)
             setlocal scrollbind
             let abuf=bufnr('%')
             let newbvar=s:_r.bufvars[abuf]
             execute bufwinnr(bvar.annbuf).'wincmd w'
         endif
-        let file='aurum://file:'.epath.':'.hex.':'.s:_r.cmdutils.escape(file)
-        let existed=bufexists(file)
-        execute 'silent edit' fnameescape(file)
+        let existed=s:_r.run('silent edit', 'file', bvar.repo, hex, file)
         setlocal scrollbind
         if hasannbuf
             call s:_r.annotate.setannbuf(newbvar, abuf, bufnr('%'))
         if rev is# hex
             return
         endif
-        execute 'silent edit' fnameescape('aurum://annotate:'.epath.':'.rev.':'.
-                    \                           s:_r.cmdutils.escape(bvar.file))
+        call s:_r.run('silent edit', 'annotate', bvar.repo, rev, bvar.file)
         setlocal scrollbind
         let abuf=bufnr('%')
         let newbvar=s:_r.bufvars[abuf]
             vertical resize 42
             wincmd p
         endif
-        let file='aurum://file:'.epath.':'.rev.':'.
-                    \          s:_r.cmdutils.escape(bvar.file)
-        let existed=bufexists(file)
-        execute 'silent edit' fnameescape(file)
+        let existed=s:_r.run('silent edit', 'file', bvar.repo, rev, bvar.file)
         setlocal scrollbind
         call s:_r.annotate.setannbuf(newbvar, abuf, bufnr('%'))
     endif

File ftplugin/aurumlog.vim

 execute frawor#Setup('0.0', {'@aurum/cmdutils': '0.0',
             \                 '@aurum/bufvars': '0.0',
             \                    '@aurum/repo': '0.0',
+            \                    '@aurum/edit': '0.0',
             \                           '@/os': '0.0',
             \                     '@/mappings': '0.0',})
 let s:_messages={
             \'nocontents': 'Log is empty',
         \}
+let s:ignkeys=['crrestrict', 'filepats', 'revs', 'cmd', 'repo']
 "▶1 bisect :: [a], function + self → a
 function s:F.bisect(list, function)
     let llist=len(a:list)
     else
         let spname=s:F.findCurSpecial(bvar, hex, blockstart[0])
     endif
-    let epath=s:_r.cmdutils.escape(bvar.repo.path)
     let cs=bvar.repo.changesets[hex]
-    let opts=s:_r.cmdutils.encodeopts(bvar.opts)
+    let crrcond=((has_key(bvar.opts, 'crrestrict'))?
+                \   (string(bvar.opts.crrestrict).' isnot# v:key &&'):
+                \   (''))
+    let opts=filter(copy(bvar.opts), crrcond.'index(s:ignkeys, v:key)==-1')
     "▶2 Commit actions based on current special
     "▶3 branch: add `branch' filter
     if spname is# 'branch'
-        let cmd='edit '.fnameescape('aurum://log:'.epath.':'.opts.
-                    \               'branch:'.s:_r.cmdutils.escape(cs.branch).
-                    \               ',crrestrict:branch')
+        let cmd='edit '.fnameescape(s:_r.fname('log', bvar.repo,
+                    \                          extend(copy(opts),
+                    \                                 {'branch': cs.branch,
+                    \                              'crrestrict': 'branch'})))
     "▶3 user: add `user' filter
     elseif spname is# 'user'
-        let cmd='edit '.fnameescape('aurum://log:'.epath.':'.opts.
-                    \               'user:'.s:_r.cmdutils.escape(
-                    \                           '\V'.escape(cs.user, '\')).','.
-                    \               'crrestrict:user')
+        let cmd='edit '.fnameescape(s:_r.fname('log', bvar.repo,
+                    \                          extend(copy(opts),
+                    \                        {'user': '\V'.escape(cs.user, '\'),
+                    \                   'crrestrict': 'user'})))
     "▶3 time: add `date' filter (only show commits done in the current month)
     elseif spname is# 'time'
-        let cmd='edit '.fnameescape('aurum://log:'.epath.':'.opts.
-                    \               'date:'.strftime('%Y-%m', cs.time).','.
-                    \               'crrestrict:date')
+        let cmd='edit '.fnameescape(s:_r.fname('log', bvar.repo,
+                    \                extend(copy(opts),
+                    \                       {'date': strftime('%Y-%m', cs.time),
+                    \                  'crrestrict': 'date'})))
     "▶3 changeset: show only ancestors of the current changeset
     elseif spname is# 'hex' || spname is# 'rev'
-        let cmd='edit '.fnameescape('aurum://log:'.epath.':'.opts.
-                    \               'revision:'.hex.','.
-                    \               'crrestrict:revision')
+        let cmd='edit '.fnameescape(s:_r.fname('log', bvar.repo,
+                    \                         extend(copy(opts),
+                    \                                {'revision': hex,
+                    \                               'crrestrict': 'revision'})))
     "▶3 file: view file
     elseif spname=~#'\v^file\d+$'
         " XXX If fileN special exists, then files property was definitely added, 
         " so no need to use getcsprop()
         let file=cs.files[str2nr(spname[4:])]
-        let cmd='edit '.fnameescape('aurum://file:'.epath.':'.hex.':'.
-                    \                             s:_r.cmdutils.escape(file))
+        let cmd='edit '.fnameescape(s:_r.fname('file', bvar.repo, hex, file))
     "▶3 curdiff: view diff between changeset and current state
     elseif spname is# 'curdiff'
-        let cmd='edit '.fnameescape('aurum://diff:'.epath.'::'.hex)
+        let args=['diff', bvar.repo, '', hex]
         if has_key(bvar.opts, 'files') && !has_key(bvar.opts.ignorefiles,'diff')
-            let cmd.=fnameescape(':'.join(map(copy(bvar.opts.csfiles[hex]),
-                        \                     's:_r.cmdutils.escape(v:val)'),
-                        \                 ';'))
+            let fargs+=[bvar.opts.csfiles[hex]]
         endif
+        let cmd='edit '.fnameescape(call(s:_r.fname, args, {}))
     "▶3 other: view commit diff
     else
-        let cmd='edit '.fnameescape('aurum://diff:'.epath.':'.hex.':')
+        let args=['diff', bvar.repo, hex, '']
         if has_key(bvar.opts, 'files') && !has_key(bvar.opts.ignorefiles,'diff')
-            let cmd.=fnameescape(':'.join(map(copy(bvar.opts.csfiles[hex]),
-                        \                     's:_r.cmdutils.escape(v:val)'),
-                        \                 ';'))
+            let args+=[bvar.opts.csfiles[hex]]
         endif
+        let cmd='edit '.fnameescape(call(s:_r.fname, args, {}))
     endif
     "▲3
     return s:F.cwin(bvar).":silent ".cmd."\n"
         return ''
     endif
     let bvar=s:_r.bufvars[bufnr('%')]
-    let epath=s:_r.cmdutils.escape(bvar.repo.path)
     return s:F.cwin(bvar).":silent edit ".
-                \fnameescape('aurum://file:'.epath.':'.hex.':'.
-                \                          s:_r.cmdutils.escape(file))."\n"
+                \fnameescape(s:_r.fname('file', bvar.repo, hex, file))."\n"
 endfunction
 "▶1 annotate
 function s:F.annotate()
         return ''
     endif
     let bvar=s:_r.bufvars[bufnr('%')]
-    let cs=bvar.repo.changesets[hex]
-    let epath=s:_r.cmdutils.escape(bvar.repo.path)
-    let efile=s:_r.cmdutils.escape(file)
     if a:0 && a:1
         return s:F.cwin(bvar).":silent edit ".
-                    \fnameescape('aurum://diff:'.epath.':'.hex.'::'.efile)."\n"
+                    \fnameescape(s:_r.fname('diff', bvar.repo, hex, '', file)).
+                    \"\n"
     else
         return s:F.cwin(bvar).":silent edit ".
-                    \fnameescape('aurum://diff:'.epath.'::'.hex.':'.efile)."\n"
+                    \fnameescape(s:_r.fname('diff', bvar.repo, '', hex, file)).
+                    \"\n"
     endif
 endfunction
 "▶1 vimdiff
     endif
     let bvar=s:_r.bufvars[bufnr('%')]
     let cs=bvar.repo.changesets[hex]
-    let epath=s:_r.cmdutils.escape(bvar.repo.path)
     if a:0 && a:1
         return s:F.cwin(bvar).":silent edit ".
                     \fnameescape(s:_r.os.path.join(bvar.repo.path, file))."\n".
                     \':silent diffsplit '.
-                    \fnameescape('aurum://file:'.epath.':'.hex.':'.
-                    \                          s:_r.cmdutils.escape(file))."\n"
+                    \fnameescape(s:_r.fname('file', bvar.repo, hex, file))."\n"
     elseif !empty(cs.parents)
         return s:F.cwin(bvar).":silent edit ".
-                    \fnameescape('aurum://file:'.epath.':'.hex.':'.
-                    \                          s:_r.cmdutils.escape(file))."\n".
+                    \fnameescape(s:_r.fname('file', bvar.repo, hex, file))."\n".
                     \':silent diffsplit '.
-                    \fnameescape('aurum://file:'.epath.':'.
-                    \                          cs.parents[0].':'.
-                    \                          s:_r.cmdutils.escape(file))."\n"
+                    \fnameescape(s:_r.fname('file', bvar.repo, cs.parents[0],
+                    \                       file))."\n"
     endif
     return ''
 endfunction
         return ''
     endif
     let bvar=s:_r.bufvars[bufnr('%')]
-    let opts=s:_r.cmdutils.encodeopts(bvar.opts)
-    let epath=s:_r.cmdutils.escape(bvar.repo.path)
-    return ':silent edit '.
-                \fnameescape('aurum://log:'.epath.':'.opts.
-                \            'files:'.s:_r.cmdutils.escape(
-                \                           s:_r.cmdutils.globescape(file)).','.
-                \            'crrestrict:files')."\n"
+    let crrcond=((has_key(bvar.opts, 'crrestrict'))?
+                \   (string(bvar.opts.crrestrict).' isnot# v:key &&'):
+                \   (''))
+    let opts=filter(copy(bvar.opts), crrcond.'index(s:ignkeys, v:key)==-1')
+    call extend(opts, {'files': [s:_r.cmdutils.globescape(file)],
+                \ 'crrestrict': 'files'})
+    return ':silent edit '.fnameescape(s:_r.fname('log', bvar.repo, opts))."\n"
 endfunction
 "▶1 update
 function s:F.update()

File ftplugin/aurumstatus.vim

 setlocal nomodeline
 execute frawor#Setup('0.0', {'@aurum/bufvars': '0.0',
             \                '@aurum/vimdiff': '0.0',
-            \               '@aurum/cmdutils': '0.0',
+            \                   '@aurum/edit': '0.0',
             \                 '@aurum/commit': '0.0',
             \                    '@/mappings': '0.0',
             \                          '@/os': '0.0',})
     let vline1=line("'<")
     let vline2=line("'>")
     let file=bvar.files[curline]
-    let epath=s:_r.cmdutils.escape(bvar.repo.path)
     if has_key(s:noacttypes, a:action) &&
                 \index(s:noacttypes[a:action], bvar.types[curline])!=-1
         return ''
     if a:action is# 'open'
         execute 'silent e' fnameescape(s:_r.os.path.join(bvar.repo.path,file))
     elseif a:action is# 'revopen'
-        execute 'silent e' fnameescape('aurum://file:'.epath.':'.rev1.':'.
-                    \                                s:_r.cmdutils.escape(file))
+        call s:_r.run('silent edit', 'file', bvar.repo, rev1, file)
     elseif a:action is# 'fulldiff'
-        execute 'silent e' fnameescape('aurum://diff:'.epath.':'.rev1.':'.rev2)
+        call s:_r.run('silent edit', 'diff', bvar.repo, rev1, rev2)
     elseif a:action is# 'revfulldiff'
-        execute 'silent edit' fnameescape('aurum://diff:'.epath.':'.rev1)
+        call s:_r.run('silent edit', 'diff', bvar.repo, rev1)
     elseif a:action is# 'revvimdiff' || a:action is# 'vimdiff'
-        let file1='aurum://file:'.epath.':'.rev1.':'.s:_r.cmdutils.escape(file)
+        let file1=s:_r.fname('file', bvar.repo, rev1, file)
         if empty(rev2) || a:action is# 'vimdiff'
             let file2=s:_r.os.path.join(bvar.repo.path, file)
         else
-            let file2='aurum://file:'.epath.':'.rev2.':'.
-                        \           s:_r.cmdutils.escape(file)
+            let file2=s:_r.fname('file', bvar.repo, rev2, file)
         endif
         if get(bvar.opts, 'record', 0)
             execute 'silent view' fnameescape(file2)
             call s:_r.vimdiff.split(file1, -1)
         endif
     elseif a:action is# 'annotate'
-        execute 'silent edit' fnameescape('aurum://file:'.epath.':'.rev1.':'.
-                    \                                s:_r.cmdutils.escape(file))
+        call s:_r.run('silent edit', 'file', bvar.repo, rev1, file)
         AuAnnotate
     endif
     if visual
         call map(copy(files), 'bvar.repo.functions.forget(bvar.repo, v:val)')
         silent edit!
     elseif a:action is# 'diff'
-        execute 'silent edit'
-                    \fnameescape('aurum://diff:'.epath.':'.rev1.'::'.
-                    \            join(map(copy(files),
-                    \                     's:_r.cmdutils.escape(v:val)'), ';'))
+        call s:_r.run('silent edit', 'diff', bvar.repo, rev1,  '',  files)
     elseif a:action is# 'revdiff'
-        execute 'silent edit'
-                    \fnameescape('aurum://diff:'.epath.':'.rev1.':'.rev2.':'.
-                    \            join(map(copy(files),
-                    \                     's:_r.cmdutils.escape(v:val)'), ';'))
+        call s:_r.run('silent edit', 'diff', bvar.repo, rev1, rev2, files)
     endif
 endfunction
 let s:_augroups+=['AuStatusCommit']

File plugin/aurum.vim

                 \                '@aurum/log': '0.0',
                 \             '@aurum/commit': '0.0',
                 \               '@aurum/repo': '0.0',
+                \               '@aurum/edit': '0.0',
                 \            '@aurum/bufvars': '0.0',
                 \            '@aurum/vimdiff': '0.0',}, 0)
     "▶2 Команды
 "▶1 filterfiles
 function s:F.filterfiles(repo, globs, files)
     let r=[]
-    for pattern in map(copy(a:globs), 's:_r.cmdutils.globtopat('.
+    for pattern in map(copy(a:globs), 's:_r.globtopat('.
                 \                     'a:repo.functions.reltorepo(a:repo, '.
                 \                                                'v:val))')
         let r+=filter(copy(a:files), 'v:val=~#pattern && index(r, v:val)==-1')
         let files=[repo.functions.reltorepo(repo,
                     \s:_r.cmdutils.getrrf(rrfopts, 'nocurf', -1)[3])]
     elseif a:0>1 && get(a:opts, 'rightrepl', 0)
-        let patterns=map(a:000[:-2], 's:_r.cmdutils.globtopat('.
+        let patterns=map(a:000[:-2], 's:_r.globtopat('.
                     \                'repo.functions.reltorepo(repo,v:val), 1)')
         let moves={}
         let repl=a:000[-1]
     elseif a:0==2 && a:2=~#'[*?]' &&
                 \substitute(a:1, '\v%(^|$|\\.|[^*])[^*?]*', '-', 'g') is#
                 \substitute(a:2, '\v%(^|$|\\.|[^*])[^*?]*', '-', 'g')
-        let pattern=s:_r.cmdutils.globtopat(repo.functions.reltorepo(repo, a:1),
+        let pattern=s:_r.globtopat(repo.functions.reltorepo(repo, a:1),
                     \                       1)
         let repl=split(a:2, '\V\(**\?\|?\)', 1)
         let moves={}
                     \'extend(allfiles, filter(v:val, '.
                     \                        '"index(allfiles, v:val)==-1"))')
         for pattern in map(copy(a:opts.files),
-                    \'s:_r.cmdutils.globtopat('.
-                    \                  'repo.functions.reltorepo(repo, v:val))')
+                    \'s:_r.globtopat(repo.functions.reltorepo(repo, v:val))')
             let files+=filter(copy(allfiles),
                         \     'v:val=~#pattern && index(files, v:val)==-1')
         endfor
     endif
     let wdfiles=((has_key(a:opts, 'wdfiles'))?(a:opts.wdfiles):
                 \                             (s:_f.getoption('workdirfiles')))
-    let epath=s:_r.cmdutils.escape(repo.path)
     let qf=repo.functions.grep(repo, a:pattern, files, revisions,
                 \              get(a:opts, 'ignorecase', 0), wdfiles)
     for item in filter(copy(qf), 'type(v:val.filename)=='.type([]))
-        let item.filename='aurum://file:'.epath.':'.item.filename[0].':'.
-                    \                   s:_r.cmdutils.escape(item.filename[1])
+        let item.filename=s:_r.fname('file', repo, item.filename[0],
+                    \                item.filename[1])
     endfor
     call setqflist(qf)
 endfunction

File plugin/aurum/annotate.vim

     if rev is 0
         let rev=repo.work_hex
     endif
-    let epath=s:_r.cmdutils.escape(repo.path)
     if hasannbuf
         let annbuf=bufnr('%')
     else
         " TODO Check for errors
-        let afile='aurum://file:'.epath.':'.rev.':'.
-                    \           s:_r.cmdutils.escape(file)
-        let existed=bufexists(afile)
-        execute 'silent edit' fnameescape(afile)
+        let existed=s:_r.run('silent edit', 'file', repo, rev, file)
         let annbuf=bufnr('%')
         if !existed
             setlocal bufhidden=wipe
     endif
     setlocal scrollbind
     let anwidth=min([42, winwidth(0)/2-1])
-    execute 'silent leftabove '.anwidth.'vsplit '.
-                \fnameescape('aurum://annotate:'.epath.':'.rev.':'.
-                \                              s:_r.cmdutils.escape(file))
+    call s:_r.run('silent leftabove '.anwidth.'vsplit', 'annotate', repo,
+                \ rev, file)
     setlocal scrollbind
     setlocal bufhidden=wipe
     let buf=bufnr('%')

File plugin/aurum/cmdutils.vim

     execute frawor#Setup('0.0', {'@/resources': '0.0',
                 \                       '@/os': '0.0',
                 \                '@aurum/repo': '0.0',
+                \                '@aurum/edit': '0.0',
                 \               '@aurum/cache': '0.0',
                 \             '@aurum/bufvars': '0.0',}, 0)
     finish
 function s:F.globescape(path)
     return escape(a:path, '\*?[]{}')
 endfunction
-"▶1 globtopattern :: glob[, catchstars] → pattern
-function s:F.globtopattern(glob, ...)
-    let r='\V\^'
-    let g=substitute(a:glob, '\V//\+', '/', 'g')
-    if g[-1:] is# '/'
-        let g=g[:-2]
-    endif
-    let catchstars=(a:0&&a:1)
-    let incurl=0
-    let curlit=[]
-    let outr=[]
-    while !empty(g)
-        let lit=matchstr(g, '\v^(\\.|[^*?[{,}])*')
-        let r.=substitute(lit, '\v\\([^\\])', '\1', 'g')
-        let g=g[len(lit):]
-        if empty(g)
-            break
-        endif
-        let c=g[0]
-        let g=g[1:]
-        if c is# '*'
-            if catchstars
-                let r.='\('
-            endif
-            if g[0] is# '*'
-                let g=g[1:]
-                if g[0] is# '/'
-                    let g=g[1:]
-                    let r.='\%(\.\+/\)\='
-                else
-                    let r.='\.\*'
-                endif
-            else
-                let r.='\[^/]\*'
-            endif
-            if catchstars
-                let r.='\)'
-            endif
-        elseif c is# '?'
-            let r.=((catchstars)?('\(\[^/]\)'):('\[^/]'))
-        elseif c is# '[' && stridx(g, ']')!=-1
-            let r.='\['
-            if g[0] is# '!'
-                let g=g[1:]
-                let r.='^'
-            elseif g[0] is# '^'
-                let g=g[1:]
-                let r.='\^'
-            elseif g[0] is# ']'
-                let g=g[1:]
-                let r.='\]'
-            endif
-            let colinner=matchstr(g, '\v^(\\.|[^\]])+')
-            let g=g[len(colinner):]
-            let r.=substitute(colinner, '\v\\([^\^\]\-\\])', '\1', 'g')
-        elseif c is# '{'
-            let incurl+=1
-            let curlit+=[[]]
-            let outr+=[r]
-            let r=''
-        elseif incurl && c is# ','
-            let curlit[-1]+=[r]
-            let r=''
-        elseif incurl && c is# '}'
-            let incurl-=1
-            let cl=remove(curlit, -1)
-            if empty(cl)
-                let r='{'.r.'}'
-            else
-                let r='\%('.join(cl+[r], '\|').'\)'
-            endif
-            let r=remove(outr, -1).r
-        else
-            let r.=c
-        endif
-    endwhile
-    if incurl
-        let curlit[-1]+=[r]
-        let r=''
-        for cl in curlit
-            let r.=remove(outr, 0).'{'.join(cl, ',')
-        endfor
-    endif
-    let r.='\v($|\/)'
-    return r
-endfunction
-"▶1 oescape :: String → String
-let s:ecodes={
-            \'%': '%',
-            \',': 'c', ':': '.', ';': 's',
-            \'/': '-', '\': '+',
-            \'[': 'b', ']': 'B',
-            \'{': 'f', '}': 'F',
-            \'*': 'a', '?': 'q',
-            \'`': "'", '$': 'd',
-        \}
-let s:epattern='\v['.escape(join(keys(s:ecodes), ''), '\]-^').']'
-let s:fbecodes=copy(s:ecodes)
-unlet s:fbecodes['%']
-function s:F.oescape(str)
-    if substitute('a', '.', '\="a"', '') is# 'a'
-        return substitute(a:str, s:epattern, '\="%".s:ecodes[submatch(0)]', 'g')
-    else
-        let r=substitute(a:str, '\V%', '%%', 'g')
-        for [c, l] in items(s:fbecodes)
-            let r=substitute(r, '\V'.escape(c, '\'), '%'.escape(l, '\~&'), 'g')
-        endfor
-        return r
-    endif
-endfunction
-"▶1 ounescape :: String → String
-let s:unecodes={}
-call map(copy(s:ecodes), 'extend(s:unecodes, {v:val : v:key}, "error")')
-let s:unepattern='\V%\(\['.escape(join(keys(s:unecodes), ''), '\]-^').']\)'
-function s:F.ounescape(str)
-    if substitute('a', '.', '\="a"', '') is# 'a'
-        return substitute(a:str, s:unepattern, '\=s:unecodes[submatch(1)]', 'g')
-    else
-        let lstr=len(a:str)
-        let i=0
-        let r=''
-        while i<lstr
-            let idx=stridx(a:str, '%', i)
-            if idx==-1
-                let r.=a:str[(i):]
-                break
-            else
-                if idx
-                    let r.=a:str[(i):(idx-1)]
-                endif
-                let r.=s:unecodes[a:str[idx+1]]
-                let i=idx+2
-            endif
-        endwhile
-        return r
-    endif
-endfunction
-"▶1 encodeopts :: opts → String
-let s:ignkeys=['crrestrict', 'filepats', 'revs', 'cmd', 'repo']
-function s:F.encodeopts(opts)
-    let r=''
-    let crrestrict=get(a:opts, 'crrestrict', 0)
-    for [key, value] in filter(items(a:opts), 'crrestrict isnot# v:val[0] &&'.
-                \                             'type(v:val[1])!=2 &&'.
-                \                             'type(v:val[1])!='.type({}).' &&'.
-                \                             'index(s:ignkeys, v:val[0])==-1')
-        let r.=key.':'
-        if type(value)==type([])
-            let r.=join(map(copy(value), 's:F.oescape(v:val)'), ';')
-        else
-            let r.=s:F.oescape(value)
-        endif
-        let r.=','
-        unlet value
-    endfor
-    return r
-endfunction
 "▶1 getdifffile :: bvar + cursor → file
 function s:F.getdifffile(bvar)
     if len(a:bvar.files)==1
                                     \bufwinnr(bvar.annbuf)!=-1
                             execute bufwinnr(bvar.annbuf).'wincmd w'
                         else
-                            let epath=s:F.oescape(repo.path)
                             setlocal scrollbind
-                            execute 'silent rightbelow vsplit'
-                                        \fnameescape('aurum://file:'.epath.':'.
-                                        \                            rev.  ':'.
-                                        \                     s:F.oescape(file))
+                            call s:_r.run('silent rightbelow vsplit',
+                                        \ 'file', repo, rev, file)
                             let bvar.annbuf=bufnr('%')
                             setlocal scrollbind
                         endif
     endif
     return 1
 endfunction
-"▶1 setlines :: [String], read::Bool → + buffer
-function s:F.setlines(lines, read)
-    let d={'set': function((a:read)?('append'):('setline'))}
-    if len(a:lines)>1 && empty(a:lines[-1])
-        call d.set('.', a:lines[:-2])
-    else
-        if !a:read
-            setlocal binary noendofline
-        endif
-        call d.set('.', a:lines)
-    endif
-endfunction
 "▶1 closebuf :: bvar → + buf
 function s:F.closebuf(bvar)
     let r=''
     return r
 endfunction
 "▶1 Post cmdutils resource
-call s:_f.postresource('cmdutils', {'globtopat': s:F.globtopattern,
-            \                      'globescape': s:F.globescape,
-            \                      'encodeopts': s:F.encodeopts,
-            \                          'getrrf': s:F.getrrf,
-            \                     'getdifffile': s:F.getdifffile,
-            \                       'checkrepo': s:F.checkrepo,
-            \                        'setlines': s:F.setlines,
-            \                        'closebuf': s:F.closebuf,
-            \                         'prevbuf': s:F.prevbuf,
-            \                          'escape': s:F.oescape,
-            \                        'unescape': s:F.ounescape,
-            \                    'nogetrepoarg': s:nogetrepoarg,
+call s:_f.postresource('cmdutils', {'globescape': s:F.globescape,
+            \                           'getrrf': s:F.getrrf,
+            \                      'getdifffile': s:F.getdifffile,
+            \                        'checkrepo': s:F.checkrepo,
+            \                         'closebuf': s:F.closebuf,
+            \                          'prevbuf': s:F.prevbuf,
+            \                     'nogetrepoarg': s:nogetrepoarg,
             \})
 "▶1 Some completion-related globals
 let s:cmds=['new', 'vnew', 'edit',

File plugin/aurum/commit.vim

     endif
     "▲2
     if empty(message)
-        let epath=s:_r.cmdutils.escape(a:repo.path)
-        let euser=s:_r.cmdutils.escape(user)
-        execute 'silent new '.
-                    \fnameescape('aurum://commit:'.epath.':'.euser.':'.date.':'.
-                    \                                        cb.':'.
-                    \            join(map(copy(a:files), 'escape(v:val,"\\;")'),
-                    \                 ';'))
+        call s:_r.run('silent new', 'commit', a:repo, user, date, cb, a:files)
         if exists('g:AuPreviousRepoPath') &&
                     \   g:AuPreviousRepoPath is# a:repo.path &&
                     \exists('g:AuPreviousTip') &&
             let types=s:_r.status.parseshow(a:opts.type)
         endif
         let filepats=map(filter(copy(a:000), 'v:val isnot# ":"'),
-                    \    's:_r.cmdutils.globtopat('.
+                    \    's:_r.globtopat('.
                     \    'repo.functions.reltorepo(repo, v:val))')
         let statfiles={}
         for [type, sfiles] in items(status)

File plugin/aurum/diff.vim

     "▶2 Filter out requested files
     call map(csfiles, 'join(s:_r.os.path.split(v:val)[1:], "/")')
     let filelist=[]
-    for pattern in map(copy(files), 's:_r.cmdutils.globtopat(v:val)')
+    for pattern in map(copy(files), 's:_r.globtopat(v:val)')
         let filelist+=filter(copy(csfiles), 'v:val=~#pattern && '.
                     \                       'index(filelist, v:val)==-1')
     endfor
         return
     endif
     "▲2
-    let opts=s:_r.cmdutils.encodeopts(filter(copy(a:opts),
-                \                    'index(s:_r.repo.diffoptslst, v:key)!=-1'))
-    let epath=s:_r.cmdutils.escape(repo.path)
-    let efiles=join(map(filelist, 's:_r.cmdutils.escape(v:val)'), ';')
+    let opts=filter(copy(a:opts), 'index(s:_r.repo.diffoptslst, v:key)!=-1')
     let prevbuf=s:_r.cmdutils.prevbuf()
-    execute get(a:opts, 'cmd', 'silent edit')
-                \ fnameescape('aurum://diff:'.epath.':'.rev1.':'.rev2.
-                \                         ':'.efiles.':'.opts)
+    call s:_r.run(get(a:opts, 'cmd', 'silent edit'), 'diff', repo, rev1, rev2,
+                \ filelist, opts)
     if !has_key(a:opts, 'cmd')
         let s:_r.bufvars[bufnr('%')].prevbuf=prevbuf
         setlocal bufhidden=wipe
         else
             let rev2=bvar.repo.functions.getnthparent(bvar.repo,bvar.rev2,c).hex
         endif
-        let epath=s:_r.cmdutils.escape(bvar.repo.path)
-        let filesstr=join(map(copy(bvar.files), 's:_r.cmdutils.escape(v:val)'),
-                    \     ';')
         let cmd.=':edit '.
-                    \fnameescape('aurum://diff:'.epath.':'.rev1.':'.rev2.':'.
-                    \                filesstr.':'.
-                    \                s:_r.cmdutils.encodeopts(bvar.opts))."\n"
+                    \fnameescape(s:_r.fname('diff', bvar.repo, rev1, rev2,
+                    \                       bvar.files, bvar.opts))."\n"
         let cmd.=s:mmgroup
         let cmd.=":bwipeout ".buf."\n"
     elseif a:action is# 'open'
         if file is 0
             return ''
         endif
-        let epath=s:_r.cmdutils.escape(bvar.repo.path)
         let fullpath=s:_r.os.path.join(bvar.repo.path, file)
         if empty(bvar.rev1)
             if filereadable(fullpath)
     endif
     "▲2
     if a:read
-        call s:_r.cmdutils.setlines(a:repo.functions.diff(a:repo, rev1, rev2,
-                    \                                     a:files, a:opts), 1)
+        call s:_r.setlines(a:repo.functions.diff(a:repo, rev1, rev2, a:files,
+                    \                            a:opts), 1)
         return {}
     else
         call a:repo.functions.difftobuffer(a:repo, bufnr('%'), rev1, rev2,

File plugin/aurum/edit.vim

 if !exists('s:_pluginloaded')
     execute frawor#Setup('0.0', {'@/autocommands': '0.0',
                 \                   '@/functions': '0.0',
+                \                   '@/resources': '0.0',
                 \                   '@aurum/repo': '0.0',
-                \               '@aurum/cmdutils': '0.0',
                 \                '@aurum/bufvars': '0.0',}, 0)
     call FraworLoad('@/autocommands')
     call FraworLoad('@/functions')
             \        '(only lowercase latin letters allowed)',
             \ 'dup': 'string `%s'' from key `%s'' was already listed',
         \}, '"Error while registering command %s for plugin %s: ".v:val'))
+"▶1 globtopat :: glob[, catchstars] → pattern
+function s:F.globtopat(glob, ...)
+    let r='\V\^'
+    let g=substitute(a:glob, '\V//\+', '/', 'g')
+    if g[-1:] is# '/'
+        let g=g[:-2]
+    endif
+    let catchstars=(a:0&&a:1)
+    let incurl=0
+    let curlit=[]
+    let outr=[]
+    while !empty(g)
+        let lit=matchstr(g, '\v^(\\.|[^*?[{,}])*')
+        let r.=substitute(lit, '\v\\([^\\])', '\1', 'g')
+        let g=g[len(lit):]
+        if empty(g)
+            break
+        endif
+        let c=g[0]
+        let g=g[1:]
+        if c is# '*'
+            if catchstars
+                let r.='\('
+            endif
+            if g[0] is# '*'
+                let g=g[1:]
+                if g[0] is# '/'
+                    let g=g[1:]
+                    let r.='\%(\.\+/\)\='
+                else
+                    let r.='\.\*'
+                endif
+            else
+                let r.='\[^/]\*'
+            endif
+            if catchstars
+                let r.='\)'
+            endif
+        elseif c is# '?'
+            let r.=((catchstars)?('\(\[^/]\)'):('\[^/]'))
+        elseif c is# '[' && stridx(g, ']')!=-1
+            let r.='\['
+            if g[0] is# '!'
+                let g=g[1:]
+                let r.='^'
+            elseif g[0] is# '^'
+                let g=g[1:]
+                let r.='\^'
+            elseif g[0] is# ']'
+                let g=g[1:]
+                let r.='\]'
+            endif
+            let colinner=matchstr(g, '\v^(\\.|[^\]])+')
+            let g=g[len(colinner):]
+            let r.=substitute(colinner, '\v\\([^\^\]\-\\])', '\1', 'g')
+        elseif c is# '{'
+            let incurl+=1
+            let curlit+=[[]]
+            let outr+=[r]
+            let r=''
+        elseif incurl && c is# ','
+            let curlit[-1]+=[r]
+            let r=''
+        elseif incurl && c is# '}'
+            let incurl-=1
+            let cl=remove(curlit, -1)
+            if empty(cl)
+                let r='{'.r.'}'
+            else
+                let r='\%('.join(cl+[r], '\|').'\)'
+            endif
+            let r=remove(outr, -1).r
+        else
+            let r.=c
+        endif
+    endwhile
+    if incurl
+        let curlit[-1]+=[r]
+        let r=''
+        for cl in curlit
+            let r.=remove(outr, 0).'{'.join(cl, ',')
+        endfor
+    endif
+    let r.='\v($|\/)'
+    return r
+endfunction
+"▶1 oescape :: String → String
+let s:ecodes={
+            \'%': '%',
+            \',': 'c', ':': '.', ';': 's',
+            \'/': '-', '\': '+',
+            \'[': 'b', ']': 'B',
+            \'{': 'f', '}': 'F',
+            \'*': 'a', '?': 'q',
+            \'`': "'", '$': 'd',
+        \}
+let s:epattern='\v['.escape(join(keys(s:ecodes), ''), '\]-^').']'
+let s:fbecodes=copy(s:ecodes)
+unlet s:fbecodes['%']
+function s:F.oescape(str)
+    if substitute('a', '.', '\="a"', '') is# 'a'
+        return substitute(a:str, s:epattern, '\="%".s:ecodes[submatch(0)]', 'g')
+    else
+        let r=substitute(a:str, '\V%', '%%', 'g')
+        for [c, l] in items(s:fbecodes)
+            let r=substitute(r, '\V'.escape(c, '\'), '%'.escape(l, '\~&'), 'g')
+        endfor
+        return r
+    endif
+endfunction
+"▶1 ounescape :: String → String
+let s:unecodes={}
+call map(copy(s:ecodes), 'extend(s:unecodes, {v:val : v:key}, "error")')
+let s:unepattern='\V%\(\['.escape(join(keys(s:unecodes), ''), '\]-^').']\)'
+function s:F.ounescape(str)
+    if substitute('a', '.', '\="a"', '') is# 'a'
+        return substitute(a:str, s:unepattern, '\=s:unecodes[submatch(1)]', 'g')
+    else
+        let lstr=len(a:str)
+        let i=0
+        let r=''
+        while i<lstr
+            let idx=stridx(a:str, '%', i)
+            if idx==-1
+                let r.=a:str[(i):]
+                break
+            else
+                if idx
+                    let r.=a:str[(i):(idx-1)]
+                endif
+                let r.=s:unecodes[a:str[idx+1]]
+                let i=idx+2
+            endif
+        endwhile
+        return r
+    endif
+endfunction
+"▶1 encodeopts :: opts → String
+function s:F.encodeopts(opts)
+    let r=''
+    for [key, value] in filter(items(a:opts), 'type(v:val[1])!=2 &&'.
+                \                             'type(v:val[1])!='.type({}))
+        let r.=key.':'
+        if type(value)==type([])
+            let r.=join(map(copy(value), 's:F.oescape(v:val)'), ';')
+        else
+            let r.=s:F.oescape(value)
+        endif
+        let r.=','
+        unlet value
+    endfor
+    return r
+endfunction
+"▶1 setlines :: [String], read::Bool → + buffer
+function s:F.setlines(lines, read)
+    let d={'set': function((a:read)?('append'):('setline'))}
+    if len(a:lines)>1 && empty(a:lines[-1])
+        call d.set('.', a:lines[:-2])
+    else
+        if !a:read
+            setlocal binary noendofline
+        endif
+        call d.set('.', a:lines)
+    endif
+endfunction
 "▶1 copy
 function s:F.copy(read, file)
-    call s:_r.cmdutils.setlines(readfile(a:file, 'b'), a:read)
+    call s:F.setlines(readfile(a:file, 'b'), a:read)
     if !a:read
         let s:_r.bufvars[bufnr('%')]={'file': a:file, 'command': 'copy'}
     endif
 endfunction
 "▶1 auefunc
 let s:okeys={
-            \'list': 'map(split(opts[o],";"), "s:_r.cmdutils.unescape(v:val)")',
+            \'list': 'map(split(opts[o],";"), "s:F.ounescape(v:val)")',
             \'bool': '!!(+opts[o])',
             \ 'num': '+opts[o]',
-            \ 'str': 's:_r.cmdutils.unescape(opts[o])',
+            \ 'str': 's:F.ounescape(opts[o])',
         \}
 " FIXME This code is creating repository object for the second time
 function s:auefunc.function(rw)
     let args=s:F[fname](tail, argnum)
     "▶2 Get string arguments
     for i in range(1, arguments)
-        let args[i]=s:_r.cmdutils.unescape(args[i])
+        let args[i]=s:F.ounescape(args[i])
     endfor
     "▶2 Get list arguments
     if argnum>arguments
         for i in range(arguments+1, argnum)
-            let args[i]=map(split(args[i],';'), 's:_r.cmdutils.unescape(v:val)')
+            let args[i]=map(split(args[i],';'), 's:F.ounescape(v:val)')
         endfor
     endif
     "▶2 Get options
         for o in filter(copy(get(cdescr.options, 'pats', [])),
                     \   'has_key(newopts, v:val)')
             let newopts[o[:-2].'pats']=map(newopts[o],
-                        \                  's:_r.cmdutils.globtopat(v:val)')
+                        \                  's:F.globtopat(v:val)')
         endfor
         call add(args, newopts)
     endif
     "▶2 Get repository
-    let repo=s:_r.repo.get(s:_r.cmdutils.unescape(args[0]))
+    let repo=s:_r.repo.get(s:F.ounescape(args[0]))
     if repo is 0
         call s:_f.throw('nrepo', args[0])
     endif
 "▶1 Register feature
 call s:_f.newfeature('newcommand', {'cons': s:F.newcommand,
             \                     'unload': s:F.delcommand,})
+"▶1 encodecmd
+function s:F.encodecmd(args)
+    let r=join(map(copy(a:args), '((type(v:val)=='.type('').')?'.
+                \                   '(s:F.oescape(v:val)):'.
+                \                '((type(v:val)=='.type(00).')?'.
+                \                   '("".v:val):'.
+                \                '((type(v:val)=='.type([]).')?'.
+                \                   '(join(map(copy(v:val), '.
+                \                           '"s:F.oescape(v:val)"), '.
+                \                         '";"))'.
+                \                ':'.
+                \                   '(s:F.encodeopts(v:val)))))'),
+                \':')
+    return r
+endfunction
+"▶1 fname :: command, repo[, arg1[, …]] → filename(aurum://)
+function s:F.fname(command, repo, ...)
+    let repopath=((type(a:repo)==type({}))?(a:repo.path):(a:repo))
+    return 'aurum://'.a:command.':'.s:F.encodecmd([repopath]+a:000)
+endfunction
+"▶1 runcmd
+function s:F.runcmd(vcommand, command, repo, ...)
+    let file=call(s:F.fname, [a:command, a:repo]+a:000, {})
+    let existed=bufexists(file)
+    execute a:vcommand fnameescape(file)
+    return existed
+endfunction
+"▶1 Register resources
+call s:_f.postresource('run',       s:F.runcmd)
+call s:_f.postresource('fname',     s:F.fname)
+call s:_f.postresource('setlines',  s:F.setlines)
+call s:_f.postresource('globtopat', s:F.globtopat)
 "▶1
 call frawor#Lockvar(s:, '_pluginloaded,_r,commands')
 " vim: ft=vim ts=4 sts=4 et fmr=▶,▲

File plugin/aurum/file.vim

     endif
     let rev=repo.functions.getrevhex(repo, a:rev)
     if get(a:opts, 'replace', 0)
-        call s:_r.cmdutils.setlines(repo.functions.readfile(repo, rev, file), 0)
+        call s:_r.setlines(repo.functions.readfile(repo, rev, file), 0)
         return
     endif
-    let epath=s:_r.cmdutils.escape(repo.path)
     if hasbuf
         let filetype=&filetype
     endif
     let prevbuf=s:_r.cmdutils.prevbuf()
-    execute get(a:opts, 'cmd', 'silent edit')
-                \ fnameescape('aurum://file:'.epath.':'.rev.':'.
-                \                           s:_r.cmdutils.escape(file))
+    call s:_r.run(get(a:opts, 'cmd', 'silent edit'), 'file', repo, rev, file)
     if exists('filetype') && &filetype isnot# filetype
         let &filetype=filetype
     endif
 let s:file={'arguments': 2,}
 function s:file.function(read, repo, rev, file)
     let rev=a:repo.functions.getrevhex(a:repo, a:rev)
-    call s:_r.cmdutils.setlines(a:repo.functions.readfile(a:repo, rev, a:file),
-                \               a:read)
+    call s:_r.setlines(a:repo.functions.readfile(a:repo, rev, a:file), a:read)
     if exists('#filetypedetect#BufRead')
         execute 'doautocmd filetypedetect BufRead'
                     \ fnameescape(s:_r.os.path.normpath(
     elseif a:action is# 'previous' || a:action is# 'next'
         let c=((a:action is# 'previous')?(v:count1):(-v:count1))
         let rev=bvar.repo.functions.getnthparent(bvar.repo, bvar.rev, c).hex
-        let epath=s:_r.cmdutils.escape(bvar.repo.path)
-        let cmd.=':edit '.fnameescape('aurum://file:'.epath.':'.rev.':'.
-                    \                      s:_r.cmdutils.escape(bvar.file))."\n"
+        let cmd.=':edit '.fnameescape(s:_r.fname('file', bvar.repo, rev,
+                    \                            bvar.file))."\n"
         let cmd.=s:mmgroup
         let cmd.=":bwipeout ".buf."\n"
     elseif a:action is# 'vimdiff' || a:action is# 'revvimdiff'
             let cmd.=':diffsplit '.fnameescape(file)."\n"
         else
             let rev=bvar.repo.functions.getnthparent(bvar.repo, bvar.rev, 1).hex
-            let epath=s:_r.cmdutils.escape(bvar.repo.path)
-            let file='aurum://file:'.epath.':'.rev.':'.
-                        \          s:_r.cmdutils.escape(bvar.file)
+            let file=s:_r.fname('file', bvar.repo, rev, bvar.file)
             let cmd.=':call call(<SNR>'.s:_sid.'_Eval("s:_r.vimdiff.split"), '.
                         \       '['.string(file).", 0], {})\n:wincmd p\n"
         endif

File plugin/aurum/log.vim

     if !a:read
         setlocal noreadonly modifiable
     endif
-    call s:_r.cmdutils.setlines(text.text, a:read)
+    call s:_r.setlines(text.text, a:read)
     if !a:read
         setlocal readonly nomodifiable buftype=nofile
         augroup AuLogNoInsert
     else
         let cmd='silent new'
     endif
-    let optsstr=s:_r.cmdutils.encodeopts(opts)
-    let epath=s:_r.cmdutils.escape(repo.path)
-    execute cmd fnameescape('aurum://log:'.epath.':'.optsstr)
+    call s:_r.run(cmd, 'log', repo, opts)
     if !has_key(opts, 'cmd')
         setlocal bufhidden=wipe
     endif

File plugin/aurum/record.vim

                 \                 '@aurum/commit': '0.0',
                 \               '@aurum/cmdutils': '0.0',
                 \                   '@aurum/repo': '0.0',
+                \                   '@aurum/edit': '0.0',
                 \                     '@/options': '0.0',}, 0)
     call FraworLoad('@/commands')
     call FraworLoad('@/functions')
     else
         let repo=s:_r.repo.get(a:opts.repo)
     endif
-    let epath=s:_r.cmdutils.escape(repo.path)
     call map(files, 'repo.functions.reltorepo(repo, v:val)')
     tabnew
     setlocal bufhidden=wipe
     let w:aurecid='AuRecordLeft'
     rightbelow vsplit
     let w:aurecid='AuRecordRight'
-    let opts='record:1'
+    let sopts={'record': 1}
     if !empty(files)
-        let opts.=',files:'.join(map(copy(files),
-                    \                's:_r.cmdutils.escape(v:val)'), ';')
+        let sopts.files=files
     endif
     let height=s:_f.getoption('recheight')
     if height<=0
         let height=winheight(0)/5
     endif
-    execute 'silent botright '.height.' split '.
-                \fnameescape('aurum://status:'.epath.':'.opts)
+    call s:_r.run('silent botright '.height.'split', 'status', repo, sopts)
     setlocal bufhidden=wipe
     let w:aurecid='AuRecordStatus'
     setlocal nomodifiable
 endfunction
 "▶1 edit
 function s:F.edit(bvar, fname, ro)
-    let existed=bufexists(a:fname)
-    execute 'silent edit' fnameescape(a:fname)
+    if type(a:fname)==type('')
+        let existed=bufexists(a:fname)
+        execute 'silent edit' fnameescape(a:fname)
+    else
+        let existed=call(s:_r.run, ['silent edit']+a:fname, {})
+    endif
     let buf=bufnr('%')
     if existed
         let a:bvar.oldbufs[buf]={'readonly': &readonly,
         let [lwnr, rwnr, swnr]=s:F.getwnrs()
         let file=bvar.lines[line('.')-1][2:]
         let type=bvar.types[line('.')-1]
-        let epath=s:_r.cmdutils.escape(bvar.repo.path)
         let status=bvar.statuses[line('.')-1]
         let modified=status%2
         execute lwnr.'wincmd w'
                 if ntype is# 'r'
                     diffthis
                     execute rwnr.'wincmd w'
-                    let epath=s:_r.cmdutils.escape(bvar.repo.path)
-                    call s:F.edit(bvar,
-                                \'aurum://file:'.epath.':'.bvar.repo.work_hex.
-                                \            ':'.s:_r.cmdutils.escape(file), 1)
+                    call s:F.edit(bvar, ['file', bvar.repo, bvar.repo.work_hex,
+                                \        file], 1)
                     diffthis
                     wincmd p
                 endif
                 let diff=&diff
                 if exists('fcontents')
                     silent %delete _
-                    call s:_r.cmdutils.setlines(fcontents, 0)
+                    call s:_r.setlines(fcontents, 0)
                     if diff
                         diffupdate
                     endif
         endif
     "▶2 commit
     elseif a:action is# 'commit'
-        let epath=s:_r.cmdutils.escape(bvar.repo.path)
         let files=filter(copy(bvar.files), 'bvar.statuses[v:key]>1')
         if empty(files)
             call s:_f.warn('recnof')

File plugin/aurum/status.vim

     if has_key(a:opts, 'files')
         call map(a:opts.files, 'repo.functions.reltorepo(repo, v:val)')
     endif
-    for [key, value] in items(a:opts)
-        let opt=key.':'
-        if key is# 'files'
-            let opt.=join(map(copy(value), 's:_r.cmdutils.escape(v:val)'), ';')
-        elseif key is# 'show'
-            let opt.=join(value, ';')
-        else
-            let opt.=s:_r.cmdutils.escape(value)
-        endif
-        call add(opts, opt)
-        unlet value
-    endfor
-    let epath=s:_r.cmdutils.escape(repo.path)
-    let statf='aurum://status:'.epath.':'.join(opts, ',')
+    let statf=s:_r.fname('status', repo, a:opts)
     let cmd='silent botright new'
     if has_key(a:opts, 'cmd')
         let cmd=a:opts.cmd

File plugin/aurum/vimdiff.vim

 if !exists('s:_pluginloaded')
     execute frawor#Setup('0.0', {'@/os': '0.0',
                 \     '@aurum/cmdutils': '0.0',
+                \         '@aurum/edit': '0.0',
                 \               '@/fwc': '0.0',
                 \          '@/mappings': '0.0',
                 \         '@/resources': '0.0',
         endif
     endif
     "▶2 Open first buffer
-    let epath=s:_r.cmdutils.escape(repo.path)
     let frev=remove(revs, 0)
     if hasbuf
         let fbuf=bufnr('%')
         if frev is 0
             execute 'silent edit' fnameescape(s:_r.os.path.join(repo.path,file))
         else
-            execute 'silent edit '.
-                        \fnameescape('aurum://file:'.epath.':'.frev.':'.
-                        \                         s:_r.cmdutils.escape(file))
+            call s:_r.run('silent edit', 'file', repo, frev, file)
         endif
         let t:auvimdiff_prevbuffers[bufnr('%')]=prevbuf
         let fbuf=bufnr('%')
         if rev is 0
             let f=file
         else
-            let f='aurum://file:'.epath.':'.rev.':'.s:_r.cmdutils.escape(file)
+            let f=s:_r.fname('file', repo, rev, file)
         endif
         if !i && hasbuf && len(revs)==1
             let existed=bufexists(f)

File test/annotate-buffers.ok

 #1: aurum://annotate:%ETMPDIR%%-test%-annotate-buffersrepo:504f74154456dbb0e9441326514e42ce66279e62:.hgignore
 *2: aurum://file:%ETMPDIR%%-test%-annotate-buffersrepo:504f74154456dbb0e9441326514e42ce66279e62:.hgignore
  3: 
- 4: aurum://status:%ETMPDIR%%-test%-annotate-buffersrepo:show:clean
+ 4: aurum://status:%ETMPDIR%%-test%-annotate-buffersrepo:show:clean,
 {{{1 aurum://diff
 #1: aurum://annotate:%ETMPDIR%%-test%-testrepo:5a6a1bf999fad1f4547eeb887af54f31d11833f2:crepo.zsh
 *2: aurum://file:%ETMPDIR%%-test%-testrepo:5a6a1bf999fad1f4547eeb887af54f31d11833f2:crepo.zsh

File test/globtopattern.vim

-execute frawor#Setup('0.0', {'@aurum/cmdutils': '0.0'})
+execute frawor#Setup('0.0', {'@aurum/edit': '0.0'})
 let files=[
             \'.hgignore',
             \'aurum-addon-info.txt',
             \                                       'test/update.ok',
             \                                       'test/^.vim']],
             \]
-    let p=s:_r.cmdutils.globtopat(g)
+    let p=s:_r.globtopat(g)
     let rr=filter(copy(files), 'v:val=~#p')
     if rr !=# r
         call writefile([g, p, string(r), string(rr)], failfile)

File test/logmaps.ok

 {{{1 <CR>
 aurum://diff:%ETMPDIR%%-test%-logmapsrepo:504f74154456dbb0e9441326514e42ce66279e62:
 {{{1 branch <CR>
-aurum://log:%ETMPDIR%%-test%-logmapsrepo:branch:A,crrestrict:branch
+aurum://log:%ETMPDIR%%-test%-logmapsrepo:crrestrict:branch,branch:A,
 {{{1 user <CR>
-aurum://log:%ETMPDIR%%-test%-logmapsrepo:user:%+VA <a@example.com>,crrestrict:user
+aurum://log:%ETMPDIR%%-test%-logmapsrepo:user:%+VA <a@example.com>,crrestrict:user,
 {{{1 date <CR>
-aurum://log:%ETMPDIR%%-test%-logmapsrepo:date:2002-02,crrestrict:date
+aurum://log:%ETMPDIR%%-test%-logmapsrepo:date:2002-02,crrestrict:date,
 {{{1 changeset <CR>
-aurum://log:%ETMPDIR%%-test%-logmapsrepo:revision:504f74154456dbb0e9441326514e42ce66279e62,crrestrict:revision
+aurum://log:%ETMPDIR%%-test%-logmapsrepo:crrestrict:revision,revision:504f74154456dbb0e9441326514e42ce66279e62,
 {{{1 gF
-aurum://log:%ETMPDIR%%-test%-logmapsrepo:showfiles:1,files:directory%-file,crrestrict:files
+aurum://log:%ETMPDIR%%-test%-logmapsrepo:showfiles:1,files:directory%-file,crrestrict:files,
 {{{1 gF+files
-aurum://log:%ETMPDIR%%-test%-logmapsrepo:showfiles:1,files:.hgignore,crrestrict:files
+aurum://log:%ETMPDIR%%-test%-logmapsrepo:showfiles:1,files:.hgignore,crrestrict:files,
 {{{1 gu
-aurum://log:%ETMPDIR%%-test%-logmapsrepo:user:%+VA <a@example.com>,crrestrict:user
+aurum://log:%ETMPDIR%%-test%-logmapsrepo:user:%+VA <a@example.com>,crrestrict:user,
 {{{1 gD
-aurum://log:%ETMPDIR%%-test%-logmapsrepo:date:2002-02,crrestrict:date
+aurum://log:%ETMPDIR%%-test%-logmapsrepo:date:2002-02,crrestrict:date,
 {{{1 gb
-aurum://log:%ETMPDIR%%-test%-logmapsrepo:branch:A,crrestrict:branch
+aurum://log:%ETMPDIR%%-test%-logmapsrepo:crrestrict:branch,branch:A,
 {{{1 gr
-aurum://log:%ETMPDIR%%-test%-logmapsrepo:revision:be92227e3e43f4e7402408afe110098d209d2568,crrestrict:revision
+aurum://log:%ETMPDIR%%-test%-logmapsrepo:crrestrict:revision,revision:be92227e3e43f4e7402408afe110098d209d2568,
 {{{1 gd
 aurum://diff:%ETMPDIR%%-test%-logmapsrepo::dfe39aa48c6ddde158e42217548b531a45ff66e9
 {{{1 gc