Commits

ZyX_I committed 975ec0e

@aurum/log: Started working on incremental updates implementation: made :AuLog use iterator functions

Comments (0)

Files changed (3)

plugin/aurum/log.vim

 endfunction
 "▶2 glog.graphlog
 function s:F.glog.graphlog(repo, opts, css)
-    if get(a:repo, 'requires_sort', 1)
-        let css=s:F.glog.sort_in_topological_order(a:repo, a:css)
-    else
-        let css=reverse(copy(a:css))
-    endif
     let d={}
     if get(a:repo, 'has_octopus_merges', 1)
         let d.func=s:F.glog.log_show_all
     else
         let d.func=s:F.glog.generate
     endif
-    return d.func(css, [a:repo.functions.getworkhex(a:repo)], a:opts)
+    return d.func(a:css, [a:repo.functions.getworkhex(a:repo)], a:opts)
 endfunction
 "▶1 temp
 "▶2 s:templates
 let s:datechars='YmdHM'
 function s:F.comparedates(datesel, time)
     let j=0
-    for selnum in split(a:datesel, '\v[^0-9*.]+')
+    for selnum in a:datesel
         if selnum isnot# '*'
             let spec='%'.s:datechars[j]
             if selnum is# '.'
     endfor
     return 0
 endfunction
+"▶1 requiredpropslist :: opts → [csprop]
+function s:F.requiredpropslist(opts)
+    let r=[]
+    let r+=filter(['renames', 'copies'], 'get(a:opts, "show".v:val, 0)')
+    if           get(a:opts, 'showrenames', 0) ||
+                \get(a:opts, 'showcopies',  0) ||
+                \get(a:opts, 'showfiles',   0) ||
+                \get(a:opts, 'stat',        0)
+        let r+=['files']
+    endif
+    if get(a:opts, 'showfiles', 0)
+        let r+=['changes']
+    endif
+    return r
+endfunction
+"▶1 iterfuncs :: {fname: { "start": startfunc, "next": nextfunc }}
+" startfunc :: repo, opts → d
+" nextfunc  :: d → cs
+let s:iterfuncs={}
+"▶2 ancestors
+let s:iterfuncs.ancestors={}
+function s:iterfuncs.ancestors.start(repo, opts)
+    let hex=a:repo.functions.getrevhex(a:repo, a:opts.revision)
+    return {'addrevs': [hex], 'revisions': {}, 'repo': a:repo}
+endfunction
+function s:iterfuncs.ancestors.next(d)
+    if empty(a:d.addrevs)
+        return 0
+    endif
+    let hex=remove(a:d.addrevs, 0)
+    if has_key(a:d.revisions, hex)
+        return s:iterfuncs.ancestors.next(a:d)
+    endif
+    let cs=a:d.repo.functions.getcs(a:d.repo, hex)
+    let a:d.revisions[hex]=cs
+    let a:d.addrevs+=cs.parents
+    return cs
+endfunction
+"▶2 revrange
+let s:iterfuncs.revrange={}
+function s:iterfuncs.revrange.start(repo, opts)
+    if has_key(a:opts, 'revrange')
+        let cslist=copy(call(a:repo.functions.revrange,
+                    \   [a:repo]+a:opts.revrange, {}))
+    else
+        let cslist=copy(a:repo.functions.revrange(a:repo, 0, -1))
+    endif
+    if get(a:repo, 'requires_sort', 1)
+        let cslist=s:F.glog.sort_in_topological_order(a:repo, cslist)
+    else
+        call reverse(cslist)
+    endif
+    return {'cslist': cslist}
+endfunction
+function s:iterfuncs.revrange.next(d)
+    if empty(a:d.cslist)
+        return 0
+    endif
+    return remove(a:d.cslist, 0)
+endfunction
+"▶2 changesets
+let s:iterfuncs.changesets=s:iterfuncs.revrange
+"▶1 iterfuncs.check
+let s:fcheckpropslist=['renames', 'copies', 'changes', 'files']
+let s:iterfuncs.check={}
+"▶2 iterfuncs.check.start
+let s:keytoexpr={
+            \'branch': '"a:cs.branch isnot# ".string(v:val)',
+            \'merges': '(v:val)?("len(a:cs.parents)<=1"):'.
+            \                  '("len(a:cs.parents)>1")',
+            \'search': '"a:cs.description!~#".string(v:val)',
+            \  'user':        '"a:cs.user!~#".string(v:val)',
+        \}
+function s:iterfuncs.check.start(repo, opts)
+    let r={'repo': a:repo, 'hasfiles': 0, 'hasdaterange': 0, 'hasdate': 0}
+    "▶3 Define variables for files filtering
+    if has_key(a:opts, 'files')
+        let r.hasfiles=1
+        let r.csfiles={}
+        let r.filepats=a:opts.filepats
+        let r.tocheck={}
+        let a:opts.csfiles=r.csfiles
+    endif
+    "▶3 Define variables for date filtering
+    if has_key(a:opts, 'date')
+        let idx=match(a:opts.date, '\V<=\?>')
+        if idx==-1
+            let r.hasdate=1
+            let r.selector=(stridx('<>', a:opts.date[0])==-1)?(''):
+                        \                                     (a:opts.date[0])
+            let r.acceptexact=(a:opts.date[len(r.selector)] is# '=')
+            let r.date=split(a:opts.date[(len(r.selector)+r.acceptexact):],
+                        \    '\v[^0-9*.]+')
+        else
+            let r.hasdaterange=1
+            let r.date1=split(a:opts.date[:(idx-1)], '\v[^0-9*.]+')
+            let r.acceptexact=(a:opts.date[idx+1] is# '=')
+            let r.date2=split(a:opts.date[(idx+2+r.acceptexact):],'\v[^0-9*.]+')
+        endif
+    endif
+    "▶3 Determine other filters
+    let r.expr=join(values(map(filter(copy(a:opts),
+                \                     'has_key(s:keytoexpr, v:key)'),
+                \              'eval(s:keytoexpr[v:key])')), '||')
+    "▲3
+    return r
+endfunction
+"▶2 iterfuncs.check.check
+function s:iterfuncs.check.check(d, cs)
+    "▶3 Check simple cases
+    if !empty(a:d.expr) && eval(a:d.expr)
+        return 0
+    endif
+    "▶3 Check files
+    if a:d.hasfiles
+        let copies =a:d.repo.functions.getcsprop(a:d.repo, a:cs, 'copies' )
+        let renames=a:d.repo.functions.getcsprop(a:d.repo, a:cs, 'renames')
+        let changes=a:d.repo.functions.getcsprop(a:d.repo, a:cs, 'changes')[:]
+        let csfiles=[]
+        let tcfiles=[]
+        let a:d.csfiles[a:cs.hex]=csfiles
+        if has_key(a:d.tocheck,a:cs.hex)
+            let tc=a:d.tocheck[a:cs.hex]
+            call filter(changes, '(index(tc, v:val)==-1)?(1):'.
+                        \           '([0, add(csfiles, v:val)][0])')
+            call filter(tc, 'index(csfiles, v:val)==-1')
+            if !empty(tc)
+                let allfiles=a:d.repo.functions.getcsprop(a:d.repo, a:cs,
+                            \                             'allfiles')
+                let tcfiles+=filter(copy(allfiles), 'index(tc, v:val)!=-1')
+            endif
+        endif
+        for pattern in a:d.filepats
+            let newchanges=[]
+            call map(copy(changes), 'add(((v:val=~#'.string(pattern).')?'.
+                        \                   '(csfiles):'.
+                        \                   '(newchanges)), v:val)')
+            if empty(newchanges)
+                break
+            endif
+            let changes=newchanges
+        endfor
+        if empty(csfiles)
+            return 0
+        endif
+        for file in csfiles
+            let tcfiles+=map(filter(['renames', 'copies'],
+                        \           'has_key({v:val}, file) && '.
+                        \           '{v:val}[file] isnot 0'),
+                        \    '{v:val}[file]')
+        endfor
+        call map(copy(a:cs.parents), 'extend(a:d.tocheck, {v:val : tcfiles})')
+    endif
+    "▶3 Check date
+    if a:d.hasdate
+        let cmpresult=s:F.comparedates(a:d.date, a:cs.time)
+        if !((a:d.acceptexact && cmpresult==0) ||
+                    \(a:d.selector is# '<' && cmpresult==-1) ||
+                    \(a:d.selector is# '>' && cmpresult==1))
+            return 0
+        endif
+    elseif a:d.hasdaterange
+        let cmp1result=s:F.comparedates(a:d.date1, a:cs.time)
+        let cmp2result=s:F.comparedates(a:d.date2, a:cs.time)
+        if !((cmp1result==1 && cmp2result==-1) ||
+                    \(a:d.acceptexact && (cmp1result==0 ||
+                    \                     cmp2result==0)))
+            return 0
+        endif
+    endif
+    "▲3
+    return 1
+endfunction
+"▶1 genlist :: iterfuncs, repo, opts → [cs]
+function s:F.genlist(iterfuncs, repo, opts)
+    let d=a:iterfuncs.start(a:repo, a:opts)
+    let checkd=s:iterfuncs.check.start(a:repo, a:opts)
+    let reqprops=s:F.requiredpropslist(a:opts)
+    let r=[]
+    let a:opts.skipchangesets={}
+    let haslimit=has_key(a:opts, 'limit')
+    if haslimit
+        let limit=a:opts.limit
+    endif
+    let firstidx=-1
+    let lastidx=-1
+    while 1 && (!haslimit || limit)
+        let cs=a:iterfuncs.next(d)
+        if cs is 0
+            break
+        endif
+        if s:iterfuncs.check.check(checkd, cs)
+            call map(copy(reqprops),
+                        \'a:repo.functions.getcsprop(a:repo, cs, v:val)')
+            if haslimit
+                let limit-=1
+            endif
+            if firstidx==-1
+                let firstidx=len(r)
+            endif
+            let lastidx=len(r)
+        else
+            let a:opts.skipchangesets[cs.hex]=cs
+        endif
+        let r+=[cs]
+        unlet cs
+    endwhile
+    if !get(a:repo, 'requires_sort')
+        if lastidx!=-1 && lastidx<len(r)-1
+            call remove(r, lastidx+1, -1)
+        endif
+        if firstidx>0
+            call remove(r, 0, firstidx-1)
+        endif
+    endif
+    return r
+endfunction
 "▶1 setup
-"▶2 trackfile :: repo, cs, file, csfiles → + csfiles
-function s:F.trackfile(repo, cs, file, csfiles)
-    let tocheck=[[a:file, a:cs]]
-    while !empty(tocheck)
-        let [file, cs]=remove(tocheck, 0)
-        if !has_key(a:csfiles, cs.hex)
-            continue
-        endif
-        let rename=get(cs.renames, file, 0)
-        if type(rename)!=type('')
-            let rename=file
-        endif
-        let copy=get(cs.copies, file, 0)
-        if type(copy)==type('')
-            if index(cs.changes, file)!=-1 && index(a:csfiles[cs.hex], file)==-1
-                let a:csfiles[cs.hex]+=[copy]
-            endif
-            let tocheck+=map(copy(cs.parents),'[copy,a:repo.changesets[v:val]]')
-        endif
-        if index(a:repo.functions.getcsprop(a:repo, cs, 'allfiles'), file)==-1
-            continue
-        endif
-        if index(cs.changes, file)!=-1 && index(a:csfiles[cs.hex], file)==-1
-            let a:csfiles[cs.hex]+=[file]
-        endif
-        let tocheck+=map(copy(cs.parents), '[rename, a:repo.changesets[v:val]]')
-    endwhile
-endfunction
 "▶2 getkwreg
 function s:F.getkwreg(kw, nextlit)
     if has_key(s:kwreg, a:kw)
 function s:F.setup(read, repo, opts)
     let opts=a:opts
     let bvar={}
-    call a:repo.functions.getchangesets(a:repo)
     "▶2 Add `ignorefiles'
     let ignorefiles=(has_key(opts, 'ignfiles')?
                 \               (opts.ignfiles):
     let opts.ignorefiles={}
     call map(copy(ignorefiles), 'extend(opts.ignorefiles, {v:val : 1})')
     unlet ignorefiles
-    "▶2 Get revision range
-    if has_key(opts, 'revrange')
-        let opts.revs=map(copy(opts.revrange),
-                    \'a:repo.changesets['.
-                    \   'a:repo.functions.getrevhex(a:repo, v:val)].hex')
-    elseif get(opts, 'limit', 0)>0
-        let opts.revs=[-opts.limit, -1]
-    else
-        let opts.revs=[0, -1]
-    endif
-    "▶2 Process `revision' option
-    if has_key(opts, 'revision')
-        let hex=a:repo.functions.getrevhex(a:repo, opts.revision)
-        let cs=a:repo.changesets[hex]
-        if type(cs.rev)==type(0) && cs.rev<opts.revs[1]
-            let opts.revs[1]=cs.hex
-        endif
-        let opts.revisions={}
-        let addrevs=[cs]
-        while !empty(addrevs)
-            let cs=remove(addrevs, 0)
-            if has_key(opts.revisions, cs.hex)
-                continue
-            endif
-            let opts.revisions[cs.hex]=1
-            let addrevs+=map(copy(cs.parents), 'a:repo.changesets[v:val]')
-        endwhile
-    endif
-    "▲2
-    let css=a:repo.functions.revrange(a:repo, opts.revs[0], opts.revs[1])
-    "▶2 Generate cs.{kw} for various options (`show{kw}'+`files')
-    for key in ['renames', 'copies']
-        if get(opts, 'show'.key, 0) || has_key(opts, 'files')
-            for cs in css
-                call a:repo.functions.getcsprop(a:repo, cs, key)
-            endfor
-        endif
-    endfor
-    "▶2 Generate cs.files for several options
-    if has_key(opts, 'files') || get(opts, 'showrenames', 0) ||
-                \                get(opts, 'showcopies',  0) ||
-                \                get(opts, 'showfiles',   0) ||
-                \                get(opts, 'stat',        0)
-        for cs in css
-            call a:repo.functions.getcsprop(a:repo, cs, 'files')
-        endfor
-    endif
-    "▶2 Generate cs.changes for showfiles option
-    if has_key(opts, 'files') || get(opts, 'showfiles', 0)
-        for cs in css
-            call a:repo.functions.getcsprop(a:repo, cs, 'changes')
-        endfor
-    endif
-    "▶2 Generate file lists for `files' option
-    if has_key(opts, 'files')
-        let opts.csfiles={}
-        for cs in css
-            let changes=copy(cs.changes)
-            let csfiles=[]
-            let opts.csfiles[cs.hex]=csfiles
-            for pattern in opts.filepats
-                let newfiles=filter(copy(changes), 'v:val=~#pattern')
-                call filter(changes, 'index(newfiles, v:val)==-1')
-                let csfiles+=newfiles
-                if empty(changes)
-                    break
-                endif
-            endfor
-            call map(copy(csfiles), 's:F.trackfile(a:repo, cs, v:val, '.
-                        \                         'opts.csfiles)')
-        endfor
-        let opts.totrack={}
-    endif
-    "▶2 Narrow changeset range
-    let opts.skipchangesets={}
-    let firstnoskip=-1
-    let foundfirst=0
-    let lastnoskip=-1
-    let i=opts.revs[0]
-    let requires_sort=get(a:repo, 'requires_sort', 1)
-    for cs in css
-        let skip=0
-        "▶3 `branch', `merges', `search', `user', `revision'
-        if (has_key(opts, 'branch') && cs.branch isnot# opts.branch)||
-                    \(has_key(opts, 'merges') &&
-                    \   ((opts.merges)?(len(cs.parents)<=1):
-                    \                  (len(cs.parents)>1))) ||
-                    \(has_key(opts, 'search') &&
-                    \   cs.description!~#opts.search) ||
-                    \(has_key(opts, 'user') && cs.user!~#opts.user) ||
-                    \(has_key(opts, 'revision') &&
-                    \   !has_key(opts.revisions, cs.hex))
-            let skip=1
-        "▶3 `date'
-        elseif has_key(opts, 'date')
-            if match(opts.date, '\V<=\?>')!=-1
-                let [date1, date2]=split(opts.date, '\V<=\?>')
-                let acceptexact=(stridx(opts.date, '<=>', len(date1))!=-1)
-                let cmp1result=s:F.comparedates(date1, cs.time)
-                let cmp2result=s:F.comparedates(date2, cs.time)
-                if !((cmp1result==1 && cmp2result==-1) ||
-                            \(acceptexact && (cmp1result==0 ||
-                            \                 cmp2result==0)))
-                    let skip=1
-                endif
-            else
-                let selector=opts.date[0]
-                let acceptexact=(stridx('<>', selector)==-1 || opts.date[1] is# '=')
-                let cmpresult=s:F.comparedates(opts.date, cs.time)
-                if !((acceptexact && cmpresult==0) ||
-                            \(selector is# '<' && cmpresult==-1) ||
-                            \(selector is# '>' && cmpresult==1))
-                    let skip=1
-                endif
-            endif
-        endif
-        "▶3 `files'
-        if !skip && has_key(opts, 'files')
-            let files=opts.csfiles[cs.hex]
-            if empty(files)
-                let skip=1
-            endif
-        endif
-        "▲3
-        if requires_sort
-            if skip
-                let opts.skipchangesets[cs.hex]=cs
-            endif
-        elseif skip
-            if foundfirst
-                let opts.skipchangesets[cs.hex]=cs
-            endif
-        else
-            if foundfirst
-                let lastnoskip=cs.hex
-            else
-                let foundfirst=1
-                let firstnoskip=cs.hex
-            endif
-        endif
-        let i+=1
-    endfor
-    if firstnoskip!=-1
-        let opts.revs[0]=firstnoskip
-    endif
-    if lastnoskip!=-1
-        let opts.revs[1]=lastnoskip
-    endif
+    "▶2 Get cslist
+    let opts.iterfuncs=s:iterfuncs[((has_key(opts, 'revision'))?
+                \                     ('ancestors'):
+                \                  ((has_key(opts, 'revrange'))?
+                \                     ('revrange')
+                \                  :
+                \                     ('changesets')))]
     "▶2 Get template
     if has_key(opts, 'template')
         let template=eval(opts.template)
     let bvar.templatelist=s:F.temp.parse(template)
     let opts.templatefunc=s:F.temp.compile(bvar.templatelist, opts)
     "▲2
-    let css=a:repo.functions.revrange(a:repo, opts.revs[0], opts.revs[1])
+    let css=s:F.genlist(opts.iterfuncs, a:repo, opts)
     let text=s:F.glog.graphlog(a:repo, opts, css)
     let bvar.specials=text.specials
     let bvar.rectangles=text.rectangles
 :let g:curtest='gittest'
+:let g:tipname='HEAD'
 :W{{{1 Annotate
 :Run! AuAnnotate file ./gittestrepo/* | wincmd w
 :bwipeout!
 endfunction
 command -nargs=1 -bar W call WriteFile(<q-args>)
 function s:WriteTip(writecom, cmd)
-    R AuLog limit 1
+    let tipname=get(g:, 'tipname', 'tip')
+    execute 'R AuLog limit 1 revision '.tipname
     setlocal modifiable noreadonly
     if !a:writecom
         g/Commited/delete _