ZyX_I avatar ZyX_I committed 34c56aa

Added :AuStatus command, some refactoring (including lazy creation of changeset list)

Comments (0)

Files changed (7)

ftplugin/aurumannotate.vim

 setlocal nonumber norelativenumber
 setlocal noswapfile
 setlocal nomodeline
+if exists('s:_pluginloaded')
+    call s:F.setup()
+endif
 execute frawor#Setup('0.0', {'@aurum': '0.0',
             \            '@/mappings': '0.0',
             \        '@/autocommands': '0.0',
 "▶1 formatann :: repo, hex, lnum → String
 function s:F.formatann(repo, hex, lnum)
     if !has_key(self, a:hex)
-        let cs=a:repo.changesets[a:hex]
+        let cs=a:repo.functions.getcs(a:repo, a:hex)
         let numlen=len(len(a:repo.cslist))
         let description=matchstr(cs.description, '\v[^\r\n]+')
         while s:_r.strdisplaywidth(description, numlen+1)>30
 function s:F.setup()
     let bvar=s:_r.aurum.bufvars[bufnr('%')]
     let ann=bvar.repo.functions.annotate(bvar.repo, bvar.rev, bvar.file)
-    setlocal readonly
+    setlocal readonly nomodifiable
     let d={}
     call map(ann, 'call(s:F.formatann, [bvar.repo, v:val, v:key], d)')
     call setline('.', ann)
     augroup AuAnnotateNoInsert
-        autocmd InsertEnter <buffer> :call feedkeys("\e", "n")
+        autocmd InsertEnter <buffer> :call feedkeys("\e", 'n')
     augroup END
 endfunction
 let s:_augroups+=['AuAnnotateNoInsert']
-let s:filetype=expand('<sfile>:t:r')
-call s:_f.augroup.add('AuAnnotate', [['FileType', s:filetype, 0, s:F.setup]])
 call s:F.setup()
 "▶1 getfile :: cs → path
 function s:F.getfile(cs)
     let bvar=s:_r.aurum.bufvars[buf]
     let rev=+matchstr(getline('.'), '\m\S\+')
     let hex=bvar.repo.functions.getrevhex(bvar.repo, rev)
-    let cs=bvar.repo.changesets[hex]
+    let cs=bvar.repo.functions.getcs(bvar.repo, hex)
     let epath=escape(bvar.repo.path, ':\')
     if a:action[-4:] is# 'diff'
         let rev1=''
             \   'RVdiff': {'lhs':  'C',   'rhs': s:F.getrhs('revvimdiff'   )},
             \     'Open': {'lhs':  'o',   'rhs': s:F.getrhs('open'         )},
             \}, {'silent': 1})
+"▶1
+call frawor#Lockvar(s:, '')
+" vim: ft=vim ts=4 sts=4 et fmr=▶,▲

ftplugin/aurumgraphlog.vim

 setlocal nonumber norelativenumber
 setlocal noswapfile
 setlocal nomodeline
+if exists('s:_pluginloaded')
+    call s:F.setup()
+endif
 execute frawor#Setup('0.0', {'@aurum': '0.0',
             \            '@/mappings': '0.0',
             \        '@/autocommands': '0.0',
 function s:F.setup()
     let buf=bufnr('%')
     let bvar=s:_r.aurum.bufvars[buf]
+    if has_key(bvar, 'createdlog')
+        return
+    endif
+    let bvar.createdlog=1
+    call bvar.repo.functions.getchangesets(bvar.repo)
     "▶2 Create buffer name
     if empty(bufname('%'))
         let epath=escape(bvar.repo.path, ':\')
         execute 'edit' fnameescape('aurum://noop:glog:'.epath.':'.
                     \              s:F.encodeopts(bvar.opts))
-        setlocal buftype=nofile
+        let &l:syntax=&l:syntax
     endif
     "▶2 Get revision range
     if has_key(bvar.opts, 'rev')
     let bvar.rectangles=text.rectangles
     let bvar.csstarts=text.csstarts
     call setline(1, text.text)
-    setlocal readonly
+    setlocal readonly nomodifiable buftype=nofile
     augroup AuGlogNoInsert
         autocmd InsertEnter <buffer> :call feedkeys("\e", "n")
     augroup END
 endfunction
 let s:_augroups+=['AuGlogNoInsert']
-let s:filetype=expand('<sfile>:t:r')
-call s:_f.augroup.add('AuGlog', [['FileType', s:filetype, 0, s:F.setup]])
 call s:F.setup()
 "▶1 checkinblock :: block → -1|0|1
 function s:F.checkinblock(block)
 "▶1 open
 function s:F.open()
     let [hex, file]=s:F.gethexfile()
+    if file is 0
+        return ''
+    endif
     let bvar=s:_r.aurum.bufvars[bufnr('%')]
     let epath=escape(bvar.repo.path, ':\')
-    if file isnot 0
-        return ':edit '.fnameescape('aurum://file:'.epath.':'.hex.':'.file)."\n"
-    endif
-    return ''
+    return ':edit '.fnameescape('aurum://file:'.epath.':'.hex.':'.file)."\n"
 endfunction
 "▶1 vimdiff
 function s:F.vimdiff(...)
     let [hex, file]=s:F.gethexfile()
+    if file is 0
+        return ''
+    endif
     let bvar=s:_r.aurum.bufvars[bufnr('%')]
     let cs=bvar.repo.changesets[hex]
+    let epath=escape(bvar.repo.path, ':\')
     if a:0 && a:1
         return ':e '.fnameescape(s:_r.os.path.join(bvar.repo.path, file))."\n".
                     \':diffsplit '.fnameescape('aurum://file:'.epath.':'.
                     \                          hex.':'.file)."\n"
     elseif !empty(cs.parents)
-        let epath=escape(bvar.repo.path, ':\')
         return ':e '.fnameescape('aurum://file:'.epath.':'.hex.':'.file)."\n".
                     \':diffsplit '.fnameescape('aurum://file:'.epath.':'.
                     \                          cs.parents[0].':'.file)."\n"
 "▶1 filehistory
 function s:F.filehistory()
     let [hex, file]=s:F.gethexfile()
+    if file is 0
+        return ''
+    endif
     let bvar=s:_r.aurum.bufvars[bufnr('%')]
     let opts=s:F.encodeopts(bvar.opts)
     let epath=escape(bvar.repo.path, ':\')
             \    'Next': {'lhs':  'K', 'rhs': s:F.next                        },
             \    'Prev': {'lhs':  'J', 'rhs': s:F.prev                        },
             \    'Open': {'lhs':  'o', 'rhs': s:F.open                        },
-            \}, {'func': s:F.cr})
+            \}, {'func': s:F.cr, 'silent': 1})
 "▶1
 execute frawor#Lockvar(s:, '_r')
+" vim: ft=vim ts=4 sts=4 et fmr=▶,▲

ftplugin/aurumstatus.vim

+"▶1 
+scriptencoding utf-8
+setlocal textwidth=0
+setlocal nolist nowrap
+setlocal noswapfile
+setlocal nomodeline
+if exists('s:_pluginloaded')
+    call s:F.setup()
+endif
+execute frawor#Setup('0.0', {'@aurum': '0.0',
+            \            '@/mappings': '0.0',
+            \        '@/autocommands': '0.0',
+            \               '@/table': '0.0',})
+"▶1 setup
+let s:statchars={
+            \ 'deleted': '!',
+            \ 'unknown': '?',
+        \}
+function s:F.setup()
+    let bvar=s:_r.aurum.bufvars[bufnr('%')]
+    let status=bvar.repo.functions.status(bvar.repo, bvar.rev1, bvar.rev2)
+    for [type, files] in items(status)
+        let char=has_key(s:statchars, type)? s:statchars[type]: toupper(type[0])
+        call append('$', map(copy(files), 'char." ".v:val'))
+    endfor
+    1 delete _
+    setlocal readonly nomodifiable
+    augroup AuStatusNoInsert
+        autocmd InsertEnter <buffer> :call feedkeys("\e", 'n')
+    augroup END
+endfunction
+let s:_augroups+=['AuStatusNoInsert']
+call s:F.setup()
+"▶1
+call frawor#Lockvar(s:, '')
+" vim: ft=vim ts=4 sts=4 et fmr=▶,▲
     call s:_f.command.add('AuAnnotate', s:annfunc, {'nargs': '*'})
     let s:difffunc={}
     call s:_f.command.add('AuVimDiff', s:difffunc, {'nargs': '*'})
+    let s:statfunc={}
+    call s:_f.command.add('AuStatus', s:statfunc, {'nargs': '*'})
     "▶2 Autocommands
     call FraworLoad('@/autocommands')
     let s:auefunc={}
 "▶3 hg.update
 function s:F.hg.update(repo)
     let d={}
-    execute s:_r.py.cmd 'aurum.get_updates(vim.eval("a:repo.path"), '.
-                \                         'vim.eval("a:repo.tip_hex"))'
+    let start=len(a:repo.cslist)-2
+    if start<0
+        let start=0
+    endif
+    execute s:_r.py.cmd 'aurum.get_updates(vim.eval("a:repo.path"), '.start.')'
     if empty(d)
         return a:repo
     endif
-    call a:repo.functions.removechangesets(a:repo, d.startrev)
+    if !empty(a:repo.cslist)
+        call a:repo.functions.removechangesets(a:repo, d.startrev)
+    endif
     let a:repo.cslist+=d.css
     call a:repo.functions.addchangesets(a:repo, d.css)
-    let a:repo.work_hex=d.work_hex
-    let a:repo.tip_hex=d.tip_hex
     return a:repo
 endfunction
 "▶3 hg.repo
 function s:F.hg.repo(path)
     if has_key(s:repos, a:path)
         let repo=s:repos[a:path]
-        return repo.functions.update(repo)
+        if empty(repo.changesets)
+            let repo.tip_hex=repo.functions.getrevhex(repo, 'tip')
+            let repo.work_hex=repo.functions.getrevhex(repo, '.')
+        else
+            call repo.functions.update(repo)
+        endif
+        return repo
     endif
     let repo={}
     try
     catch
         return 0
     endtry
-    call s:F.hg.addchangesets(repo, repo.cslist)
     let s:repos[a:path]=repo
     return repo
 endfunction
+"▶3 hg.getchangesets :: repo → changesets + repo.changesets
+function s:F.hg.getchangesets(repo)
+    call a:repo.functions.update(a:repo)
+    return a:repo.changesets
+endfunction
 "▶3 hg.getrevhex :: repo, rev → rev(hex)
 function s:F.hg.getrevhex(repo, rev)
     execute s:_r.py.cmd
 endfunction
 "▶3 hg.getcs :: repo, rev → cs
 function s:F.hg.getcs(repo, rev)
-    let hex=a:repo.functions.getrevhex(a:rev)
-    return a:repo.changesets[hex]
+    let hex=a:repo.functions.getrevhex(a:repo, a:rev)
+    if has_key(a:repo.changesets, hex)
+        return a:repo.changesets[hex]
+    else
+        let cs={}
+        execute s:_r.py.cmd 'aurum.get_cs(vim.eval("a:repo.path"), "'.hex.'")'
+        let a:repo.changesets[hex]=cs
+        return cs
+    endif
 endfunction
 "▶3 hg.renamed :: repo, cs[, [file]] → [Maybe String]
 function s:F.hg.renamed(repo, cs, ...)
         endif
     endtry
 endfunction
+"▶3 hg.status :: repo[, rev1[, rev2]] → {type : [file]}
+" type :: "modified" | "added" | "removed" | "deleted" | "unknown" | "ignored"
+"       | "clean"
+function s:F.hg.status(repo, ...)
+    let revargs=join(map(copy(a:000), 'v:val is 0? "None": string(v:val)'), ',')
+    let r={}
+    execute s:_r.py.cmd 'aurum.get_status(vim.eval("a:repo.path"), '.revargs.')'
+    return r
+endfunction
 "▶2 comm
 "▶3 comm.difftobuffer
 function s:F.comm.difftobuffer(repo, buf, ...)
     let tail=substitute(expand('<amatch>'), '\V\^aurum://', '', '')
     let command=tolower(matchstr(tail, '\v^\w+'))
     let tail=tail[len(command)+1:]
+    "▲4
+    setlocal buftype=nofile
     "▶4 glog command (repo:opts)
     if command is# 'glog'
         let [repo, opts]=s:F.comm.repotupleoptssplit(tail, 0)
             let opts[key]=+opts[key]
         endfor
         let s:bufvars[bufnr('%')]={'repo': repo, 'opts': opts}
-        setlocal buftype=nofile filetype=aurumgraphlog bufhidden=wipe
+        setlocal filetype=aurumgraphlog bufhidden=wipe
         runtime ftplugin/aurumgraphlog.vim
     "▶4 file command (repo:rev:file)
     elseif command is# 'file'
         let [repo, rev, file]=s:F.comm.repotuplesplit(tail, 2)
-        setlocal buftype=nofile
         let fcontents=repo.functions.readfile(repo, rev, file)
         if empty(fcontents[-1])
             call remove(fcontents, -1)
     elseif command is# 'annotate'
         let [repo, rev, file]=s:F.comm.repotuplesplit(tail, 2)
         let s:bufvars[bufnr('%')]={'repo': repo, 'rev': rev, 'file': file}
-        setlocal buftype=nofile filetype=aurumannotate bufhidden=wipe
+        setlocal filetype=aurumannotate bufhidden=wipe
         runtime ftplugin/aurumannotate.vim
     "▶4 diff command (repo:rev1:rev2:files:opts)
     elseif command is# 'diff'
         endif
         if !empty(rev1)
             let rev1=repo.functions.getrevhex(repo, rev1)
-            let csfiles=repo.functions.getcsprop(repo, repo.changesets[rev1],
-                        \                        'files')
+            let cs1=repo.functions.getcs(repo, rev1)
+            let csfiles=repo.functions.getcsprop(repo, cs1, 'files')
         endif
         if !empty(rev2)
             let rev2=repo.functions.getrevhex(repo, rev2)
-            let csfiles=repo.functions.getcsprop(repo, repo.changesets[rev2],
-                        \                        'files')
+            let cs2=repo.functions.getcs(repo, rev2)
+            let csfiles=repo.functions.getcsprop(repo, cs2, 'files')
         endif
         if !empty(rev1) && !empty(rev2)
-            let cs1files=repo.changesets[rev1].files
-            let cs2files=repo.changesets[rev2].files
+            let cs1files=cs1.files
+            let cs2files=cs2.files
             let csfiles=filter(cs1files, 'index(cs2files, v:val)!=-1')+cs2files
         endif
         "▶5 Add directories to the list of files
         let buf=bufnr('%')
         let s:bufvars[buf]={'repo': repo, 'rev1': rev1, 'rev2': rev2,
                     \       'files': filelist,}
-        setlocal buftype=nofile filetype=diff
+        setlocal filetype=diff
         call repo.functions.difftobuffer(repo, buf, rev1, rev2, filelist, opts)
+    "▶4 status command (repo:rev1:rev2:files)
+    elseif command is# 'status'
+        let [repo, rev1, rev2, files]=s:F.comm.repotuplesplit(tail, 3)
+        if empty(rev1)
+            let rev1=0
+        endif
+        if empty(rev2)
+            let rev2=0
+        endif
+        let buf=bufnr('%')
+        let s:bufvars[buf]={'repo': repo, 'rev1': rev1, 'rev2': rev2,
+                    \      'files': map(split(files,'\v%(\\@<!\\%(\\\\)*)@<!;'),
+                    \                   's:F.comm.globtopattern(v:val)'),}
+        setlocal filetype=aurumstatus bufhidden=wipe
+        runtime ftplugin/aurumstatus.vim
     "▶4 noop command (do nothing)
     elseif command is# 'noop'
     endif
                     \               '"/")')
     endif
     let s:bufvars[bufnr('%')]={'repo': a:repo, 'opts': a:opts}
-    setlocal buftype=nofile filetype=aurumgraphlog bufhidden=wipe
+    setlocal filetype=aurumgraphlog bufhidden=wipe
     runtime ftplugin/aurumgraphlog.vim
 endfunction
 let s:glogfunc['@FWC']=['[:*F.comm.getrepo(".") '.
     setlocal scrollbind
     let s:bufvars[bufnr('%')].annbuf=annbuf
 endfunction
+"▶3 statfunc
+function s:statfunc.function(...)
+    let repo=s:F.comm.getrepo(get(a:000, 0, ''))
+    let rev1=escape(get(a:000, 1, ''), '\:')
+    let rev2=escape(get(a:000, 2, ''), '\:')
+    let files=join(map(copy(a:000[3:]), 'escape(v:val, "\\;")'), ';')
+    execute 'new' fnameescape('aurum://status:'.escape(repo.path, '\:').':'.
+                \             rev1.':'.rev2.':'.files)
+endfunction
 "▶3 difffunc
 function s:difffunc.function(...)
     let repo=s:F.comm.getrepo('')
 
 from mercurial import hg, ui, commands
+from mercurial.repo import error
 import vim
 import os
 import json
             r+=obj
         else:
             tobj=type(obj)
-            if tobj is dict:
+            if tobj is int:
+                r+=str(obj)
+            elif tobj is float:
+                r += "%1.1e" % obj
+            elif tobj is list or tobj is tuple:
+                r+='['
+                todump.insert(0, ('inject', ']'))
+                for value in reversed(obj):
+                    todump[:0]=[('dump', value), ('inject', ',')]
+            elif tobj is dict:
                 r+='{'
                 todump.insert(0, ('inject', '}'))
                 for key, value in obj.items():
                                 ('inject', ':'),
                                 ('dump', value),
                                 ('inject', ',')]
-            elif tobj is list:
-                r+='['
-                todump.insert(0, ('inject', ']'))
-                for value in reversed(obj):
-                    todump[:0]=[('dump', value), ('inject', ',')]
-            elif tobj is int:
-                r+=str(obj)
-            elif tobj is float:
-                r += "%1.1e" % obj
             else:
                 r+='"'+str(obj).replace('\\', '\\\\').replace('"', '\\"')+'"'
     return r
     cs_vim['description']=cs.description()
     cs_vim['user']=cs.user()
     cs_vim['parents']=[parent.hex() for parent in cs.parents()]
+    cs_vim['children']=[]
     try:
         branch=cs.branch()
         cs_vim['branch']=branch
         pass
     return cs_vim
 
-def get_updates(path, oldtip):
+def get_revlist(repo, startrev=0):
+    cscount=len(repo)
+    r=[set_rev_dict(repo[i], {'rev': i,}) for i in range(startrev, cscount+1)]
+    return r
+
+def get_updates(path, oldtip=None):
     repo=get_repo(path)
-    cs=repo[oldtip]
     tipcs=repo['tip']
-    if tipcs.hex()==cs.hex():
-        return
-    startrev=cs.rev()
+    if oldtip is not None:
+        try:
+            cs=repo[oldtip]
+            if tipcs.hex()==cs.hex():
+                return
+            startrev=cs.rev()
+        except error.RepoLookupError:
+            startrev=0
+    else:
+        startrev=0
     r=get_revlist(repo, startrev)
+    vim.eval('extend(a:repo, {"tip_hex": "'+tipcs.hex()+'", '+
+                             '"work_hex": "'+repo['.'].hex()+'", '+
+                             '"csnum": "'+str(len(repo))+'"})')
     vim.eval('extend(d, {"css": '+utf_dumps(r)+', '+
-                        '"tip_hex": "'+tipcs.hex()+'", '+
-                        '"work_hex": "'+repo['.'].hex()+'", '+
                         '"startrev": '+str(startrev)+'})')
 
-def get_revlist(repo, startrev=0):
-    cscount=repo['tip'].rev()+1
-    r=[set_rev_dict(repo[i], {'rev': i,
-                          'parents': [],
-                         'children': [],}) for i in range(0, cscount+1)]
-    return r
+def get_cs(path, rev):
+    cs=get_repo(path)[rev]
+    cs_vim=set_rev_dict(cs, {'rev': cs.rev()})
+    vim.eval('extend(cs, '+utf_dumps(cs_vim)+')')
 
 def new_repo(path):
     repo=get_repo(path)
                               'changesets': {},
                                 'work_hex': repo['.'].hex(),
                                  'tip_hex': repo['tip'].hex(),
-                                  'cslist': get_revlist(repo),
+                                  'cslist': [],
+                                   'csnum': len(repo),
                                    'local': 1 if repo.local() else 0,
                                     })+')')
 
     cs=get_repo(path)[rev]
     vim.eval('extend(a:cs.renames, '+nonutf_dumps(
             {f: get_renames_value(cs.filectx(f).renamed()) for f in files})+')')
+
+def get_status(path, rev1=None, rev2=None):
+    if rev1 is None and rev2 is None:
+        rev1='.'
+    status=get_repo(path).status(rev1, rev2, ignored=True, clean=True,
+                                 unknown=True)
+    vim.eval('extend(r, '+nonutf_dumps({'modified': status[0],
+                                           'added': status[1],
+                                         'removed': status[2],
+                                         'deleted': status[3],
+                                         'unknown': status[4],
+                                         'ignored': status[5],
+                                           'clean': status[6],
+                                       })+')')

syntax/aurumgraphlog.vim

 syn match auGlogChangesetSep      /:/          contained nextgroup=auGlogChangesetHexStart
 syn match auGlogChangesetHexStart /\v\x{12}/   contained nextgroup=auGlogChangesetHexEnd
 syn match auGlogChangesetHexEnd   /\v\x+/      contained nextgroup=auGlogBranch conceal
-syn region auGlogBranch  start=/\V (branch / end=/\V)/ contains=auGlogBranchName matchgroup=auGlogBranchDec oneline contained keepend
+syn region auGlogBranch matchgroup=auGlogBranchDec start=/\V (branch / end=/\V)/ contains=auGlogBranchName oneline contained keepend
 syn match auGlogBranchName /\v \S+ \zs.{-}\ze\)/ contained
 
 syn match auGlogCommit       /Commited /          contained nextgroup=auGlogCommitDate

syntax/aurumstatus.vim

+if exists('b:current_syntax')
+    finish
+endif
+
+syn region auStatusModified matchgroup=auStatusModifiedStart start=/\m^M / end=/\v$/ contains=auStatusFile
+syn region auStatusAdded    matchgroup=auStatusAddedStart    start=/\m^A / end=/\v$/ contains=auStatusFile
+syn region auStatusRemoved  matchgroup=auStatusRemovedStart  start=/\m^R / end=/\v$/ contains=auStatusFile
+syn region auStatusDeleted  matchgroup=auStatusDeletedStart  start=/\m^! / end=/\v$/ contains=auStatusFile
+syn region auStatusUnknown  matchgroup=auStatusUnknownStart  start=/\m^? / end=/\v$/ contains=auStatusFile
+syn region auStatusIgnored  matchgroup=auStatusIgnoredStart  start=/\m^I / end=/\v$/ contains=auStatusFile
+syn region auStatusClean    matchgroup=auStatusCleanStart    start=/\m^C / end=/\v$/ contains=auStatusFile
+
+hi def link auStatusModifiedStart  auStatusModified
+hi def link auStatusAddedStart     auStatusAdded
+hi def link auStatusRemovedStart   auStatusRemoved
+hi def link auStatusDeletedStart   auStatusDeleted
+hi def link auStatusUnknownStart   auStatusUnknown
+hi def link auStatusIgnoredStart   auStatusIgnored
+hi def link auStatusCleanStart     auStatusClean
+
+hi def link auStatusModified PreProc
+hi def link auStatusAdded    Type
+hi def link auStatusRemoved  String
+hi def link auStatusDeleted  Underlined
+hi def link auStatusUnknown  Identifier
+hi def link auStatusIgnored  Comment
+
+let b:current_syntax=expand('<sfile>:t:r')
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.