Source

aurum / autoload / aurum / record.vim

Diff from to

File autoload/aurum/record.vim

             \         '@%aurum/tabutils': '0.0',
             \        '@%aurum/lineutils': '0.0',
             \             '@%aurum/edit': '1.5',
+            \             '@%aurum/undo': '0.0',
             \          '@%aurum/bufvars': '0.0',})
-let s:hasundo=exists('*undotree')
 let s:_options={
             \'recheight': {'default': 0,
             \               'filter': '(if type "" earg _  range 0 inf)'},
-            \'fullundo':  {'default': s:hasundo,
+            \'fullundo':  {'default': 1,
             \               'filter': 'bool'},
         \}
 let s:_messages={
             \ 'bkpmis': 'Backup file %s not found',
             \'delfail': 'Failed to remove file %s',
             \'renfail': 'Failed to move file %s to %s',
-            \ 'uchngs': 'Found changes done manually. Resetting buffer, '.
-            \           'please retry.',
-            \ 'noundo': 'Your vim is too old, thus undo is not supported. '.
-            \           'Update to version of Vim that has undotree() '.
-            \           'function available',
             \ 'recnof': 'No files were selected for commiting',
             \   'norm': 'Can’t remove file %s as it was not added',
             \   'noad': 'Can’t add file %s as it is already included',
-            \'noutree': 'No such item in saved undo tree. '.
-            \           'If you can reproduce this error file a bug report',
-            \'tooundo': 'Undone too much changes and cannot redo',
-            \ 'undona': "Can’t undo changes. Possible reasons:\n".
-            \           "  1. You did some changes manually and thus buffer ".
-            \                "was reset\n".
-            \           "  2. You edited a file which discards undo ".
-            \                "information unless g:aurum_fullundo is set",
-            \ 'redona': "Can’t redo changes. Possible reasons:\n".
-            \           "  1. You did some changes manually and thus buffer ".
-            \                "was reset\n".
-            \           "  2. You edited a file which discards undo ".
-            \                "information unless g:aurum_fullundo is set",
         \}
 "▶1 commitvimdiffcb
 function s:F.commitvimdiffcb(file, bvar, hex)
         endif
     endfor
     let a:bvar.recopts.message = a:state.description
-    setlocal modifiable
-    call s:F.reset(a:bvar)
-    setlocal nomodifiable
+    call s:_r.undo.reset(a:bvar)
     call cursor(1, 1)
 endfunction
 "▶1 getswheight
 function s:F.getswheight()
     let height=s:_f.getoption('recheight')
     if height<=0
-        return winheight(0)/5
+        return (&lines-&cmdheight-(!!&laststatus))/5
     endif
     return height
 endfunction
     " 2:     included, unmodified
     " 3:     included,   modified
     let bvar.statuses=repeat([0], len(bvar.types))
-    let bvar.prevct=b:changedtick
-    let bvar.reset=0
     let bvar.backupfiles={}
     let bvar.filesbackup={}
     let bvar.newfiles={}
     let bvar.lines=map(copy(bvar.chars), 'v:val." ".bvar.files[v:key]')
-    let bvar.startundo=s:F.curundo()
     let bvar.recopts=extend(copy(a:opts), {'repo': repo})
     let bvar.bufnr=bufnr('%')
     let bvar.oldbufs={}
                 \        'autowrite': &autowrite,
                 \     'autowriteall': &autowriteall,
                 \         'autoread': &autoread,}
-    let bvar.fullundo=(s:hasundo && s:_f.getoption('fullundo'))
-    if bvar.fullundo
-        let bvar.undotree={bvar.startundo : {}}
-    endif
+    let bvar.resetlines=s:F.resetlines
+    let bvar.pulllines=s:F.pulllines
+    let bvar.procundoleaf=s:F.procundoleaf
+    call s:_r.undo.setup(bvar, s:_f.getoption('fullundo'))
     setglobal noautowrite noautowriteall noautoread
     setlocal noreadonly buftype=acwrite
     augroup AuRecordVimLeave
         call s:F.setstate(repo, bvar, state)
     endif
 endfunction
-"▶1 curundo :: () → UInt
-if s:hasundo
-    function s:F.curundo()
-        return undotree().seq_cur
-    endfunction
-else
-    function s:F.curundo()
-        return 0
-    endfunction
-endif
-"▶1 reset
-function s:F.reset(bvar)
+"▶1 resetlines
+function s:F.resetlines(bvar)
     for idx in range(len(a:bvar.lines))
         call setline(idx+1, s:statchars[a:bvar.statuses[idx]].a:bvar.lines[idx])
     endfor
-    let a:bvar.prevct=b:changedtick
-    let a:bvar.reset=1
-    if s:hasundo
-        let a:bvar.startundo=s:F.curundo()
-        let savedundolevels=&undolevels
-        setglobal undolevels=-1
-        execute "normal! A \<BS>\e"
-        let &undolevels=savedundolevels
-        if a:bvar.fullundo
-            let a:bvar.undotree={a:bvar.startundo : {}}
-        endif
-    endif
-endfunction
-"▶1 supdate
-function s:F.supdate(bvar, prevundo)
-    if b:changedtick!=a:bvar.prevct
-        let a:bvar.prevct=b:changedtick
-        if a:bvar.reset
-            let a:bvar.reset=0
-        endif
-        let curundo=s:F.curundo()
-        if              a:bvar.fullundo
-                    \&& has_key(a:bvar.undotree, a:prevundo)
-                    \&& curundo!=a:prevundo
-                    \&& !has_key(a:bvar.undotree, curundo)
-            let a:bvar.undotree[curundo]=copy(a:bvar.undotree[a:prevundo])
-        endif
-    endif
-    setlocal nomodifiable
 endfunction
 "▶1 restorebackup
 function s:F.restorebackup(file, backupfile)
         call s:F.restorebackup(fullpath, backupfile)
     endfor
 endfunction
-"▶1 undoup :: bvar → + bvar
-function s:F.undoup(bvar)
+"▶1 pulllines
+function s:F.pulllines(bvar)
     for line in range(1, line('$'))
         let a:bvar.statuses[line-1]=stridx(s:statchars, getline(line)[0])
     endfor
-    if a:bvar.fullundo
-        let curundo=s:F.curundo()
-        if !has_key(a:bvar.undotree, curundo)
-            call s:F.reset(a:bvar)
-            call s:_f.throw('noutree')
+endfunction
+"▶1 procundoleaf
+function s:F.procundoleaf(bvar, undoleaf)
+    for [file, contents] in items(a:undoleaf)
+        if contents is 0 && filereadable(file)
+            call delete(file)
+        else
+            call writefile(contents, file, 'b')
         endif
-        for [file, contents] in items(a:bvar.undotree[curundo])
-            if contents is 0 && filereadable(file)
-                call delete(file)
-            else
-                call writefile(contents, file, 'b')
-            endif
-            unlet contents
-        endfor
-    endif
+        unlet contents
+    endfor
 endfunction
 "▶1 undoleafwrite :: bvar, lines::[String], path → + bvar, FS
 function s:F.undoleafwrite(bvar, lines, file)
     endif
     return backupfile
 endfunction
+"▶1 updateline
+function s:F.updateline(bvar, ...)
+    let line=get(a:000, 0, line('.'))
+    call setline(line, s:statchars[a:bvar.statuses[line-1]].a:bvar.lines[line-1])
+    return 0
+endfunction
 "▶1 sactions
 let s:F.sactions={}
 "▶2 sactions.[v]add, sactions.[v]remove
 "▶2 sactions.undo
 function s:F.sactions.undo(action, bvar, buf)
     execute 'silent normal! '.v:count1.'u'
-    let curundo=s:F.curundo()
-    if curundo<a:bvar.startundo
-        while curundo<a:bvar.startundo
-            let pundo=curundo
-            silent redo
-            let curundo=s:F.curundo()
-            if curundo==pundo
-                call s:_f.throw('tooundo')
-                call s:F.reset(a:bvar)
-                setlocal nomodifiable
-                return 0
-            endif
-        endwhile
-    endif
-    return 1
+    return s:_r.undo.postundo(a:bvar)
 endfunction
 "▶2 sactions.redo, sactions.earlier, sactions.later
 let s:uactkey={
             let status=3
             let a:bvar.statuses[line('.')-1]=status
         endif
-        if a:bvar.fullundo
-            let prevundo=s:F.curundo()
-            let line=line('.')
-            call setline(line, s:statchars[status].a:bvar.lines[line-1])
-            call s:F.supdate(a:bvar, prevundo)
-            let curundo=s:F.curundo()
+        if a:bvar.undo_full
+            call s:_r.undo.doaction(a:bvar, 0, s:F.updateline)
+            let undoleaf=s:_r.undo.getundoleaf(a:bvar)
         else
-            call s:F.reset(a:bvar)
+            call s:_r.undo.reset(a:bvar)
         endif
-        setlocal nomodifiable
         execute lwnr.'wincmd w'
         call s:F.edit(a:bvar, 'aurum://edit:'.fullpath, 0)
-        if a:bvar.fullundo
+        if a:bvar.undo_full
             let ebvar=s:_r.bufvars[bufnr('%')]
-            let undoleaf=a:bvar.undotree[curundo]
             let ebvar.undoleaf=undoleaf
             let ebvar.fullpath=fullpath
             let ebvar.ewrite=ebvar.write
                 endif
                 let a:bvar.backupfiles[backupfile]=fullpath
                 let a:bvar.filesbackup[fullpath]=backupfile
-                if a:bvar.fullundo
+                if a:bvar.undo_full
                     let undoleaf[fullpath]=0
                     let undoleaf[backupfile]=readfile(backupfile, 'b')
                     let oundoleafpart={fullpath   : copy(undoleaf[backupfile]),
                                 \      backupfile : 0}
-                    call map(a:bvar.undotree,
-                                \'extend(v:val, oundoleafpart, "keep")')
+                    call s:_r.undo.updatetree(a:bvar, oundoleafpart)
                 endif
             else
                 let isexe=0
             \'removed':  'r',
             \'deleted':  'r',
         \}
-let s:uactions=['undo', 'redo', 'earlier', 'later']
+let s:uactions={
+            \   'undo': 'undo',
+            \   'redo': 'redo',
+            \'earlier': 'undo',
+            \  'later': 'redo',
+        \}
 function s:F.runstatmap(action, ...)
     "▶2 buf, bvar, reset
     let buf=get(a:000, 0, bufnr('%'))
     let bvar=s:_r.bufvars[buf]
-    setlocal modifiable
-    if !a:0 && b:changedtick!=bvar.prevct
-        if bvar.fullundo && has_key(bvar.undotree, s:F.curundo())
-            call s:F.undoup(bvar)
-        else
-            call s:_f.warn('uchngs')
-            call s:F.reset(bvar)
-            setlocal nomodifiable
+    if !a:0
+        if !s:_r.undo.preaction(bvar)
             return
         endif
     endif
     "▶2 undo
-    let isundo=(index(s:uactions, a:action)!=-1)
+    let isundo=has_key(s:uactions, a:action)
     if isundo
-        if !s:hasundo
-            call s:_f.warn('noundo')
-            return
-        endif
-        if bvar.reset
-            setlocal nomodifiable
-            call s:_f.warn(a:action.'na')
+        if !s:_r.undo.preundoaction(bvar, s:uactions[a:action])
             return
         endif
     endif
-    let prevundo=s:F.curundo()
     "▶2 action
-    if s:F.sactions[a:action](a:action, bvar, buf)
-        if bufnr('%')==buf
-            if isundo && s:F.curundo()!=prevundo
-                call s:F.undoup(bvar)
-            endif
-            call s:F.supdate(bvar, prevundo)
-        endif
+    call s:_r.undo.doaction(bvar, 1, s:F.runaction, a:action,buf,isundo)
+endfunction
+"▶1 runaction
+function s:F.runaction(bvar, action, buf, isundo)
+    if s:F.sactions[a:action](a:action, a:bvar, a:buf)
+        return a:isundo
     endif
+    return 0
 endfunction
 "▶1 runleftmap
 function s:F.runleftmap(action)
             endif
             let fidx=index(sbvar.files, bvar.recfile)
             let sbvar.statuses[fidx]=0
-            setlocal modifiable
-            let prevundo=s:F.curundo()
-            call setline(fidx+1, s:statchars[0].sbvar.lines[fidx])
-            call s:F.supdate(sbvar, prevundo)
+            call s:_r.undo.doaction(sbvar, 0, s:F.updateline, fidx+1)
         endif
     elseif a:action is# 'commit'
         silent update
         let fidx=index(sbvar.files, bvar.recfile)
         if sbvar.statuses[fidx]>1
             let sbvar.statuses[fidx]-=2
-            setlocal modifiable
-            let prevundo=s:F.curundo()
-            call setline(fidx+1, s:statchars[sbvar.statuses[fidx]].
-                        \        sbvar.lines[fidx])
-            call s:F.supdate(sbvar, prevundo)
+            call s:_r.undo.doaction(sbvar, 0, s:F.updateline, fidx)
         else
             call s:_f.warn('norm', bvar.recfile)
         endif