Commits

ZyX_I committed 76d265f

Add `:AuRecord amend` and `:AuCommit amend` support

Largely untested

Ref #89

Comments (0)

Files changed (5)

autoload/aurum/commit.vim

 "▶1 
 scriptencoding utf-8
-execute frawor#Setup('1.4', {'@/resources': '0.0',
+execute frawor#Setup('1.5', {'@/resources': '0.0',
             \                '@/functions': '0.1',
             \                  '@/options': '0.0',
             \                       '@/os': '0.0',
         endif
     endif
 endfunction
-"▶1 commit :: repo, opts, files, status, types[, cmd[, bvarpart[, edit]]]
+"▶1 commit :: repo, opts, files, status, types[, cmd[, bvarpart]]
 let s:defdate=['strftime("%Y")',
             \  'strftime("%m")',
             \  'strftime("%d")',
         let date=join(dparts[:2], '-').' '.join(dparts[3:], ':')
     endif
     "▲2
-    if empty(message) || (a:0>2 && a:3 isnot 0)
+    let edit=get(a:opts, 'amend', 0)
+    if empty(message) || edit
         call s:_r.run(((a:0 && a:1 isnot 0)? a:1 : 'silent new'),
                     \ 'commit', a:repo, user, date, cb, a:files)
         " Workaround problem with templates created on BufNewFile. Namely if you 
         let bvar.revstatus=revstatus
         "▶2 Add previous message
         let addedprevmessage=0
-        if exists('g:AuPreviousRepoPath') &&
+        if edit
+            let addedprevmessage=1
+            call setline('.', split(message, "\n", 1))
+            call cursor(line('$'), col([line('$'), '$']))
+        elseif exists('g:AuPreviousRepoPath') &&
                     \   g:AuPreviousRepoPath is# a:repo.path &&
                     \exists('g:AuPreviousTip') &&
                     \   g:AuPreviousTip is# a:repo.functions.gettiphex(a:repo)&&
             call setline('.', split(g:AuPreviousCommitMessage, "\n", 1))
             call cursor(line('$'), col([line('$'), '$']))
             unlet g:AuPreviousRepoPath g:AuPreviousTip g:AuPreviousCommitMessage
-        elseif a:0>2 && a:3 isnot 0
-            call setline('.', split(message, "\n", 1))
-            call cursor(line('$'), col([line('$'), '$']))
         endif
         "▶2 Add comment
         let fmessage=[]
             \                                 '\:[0-5]\d'.
             \                                 '%(\:[0-5]\d)?)?$/'.
             \' !?closebranch'.
+            \' !?amend'.
             \'}'.
             \'+ '.s:_r.cmdutils.comp.file, 'filter']}
 let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
             \                                     [], s:_f.fwc.compile)
 function s:_aufunctions.cmd.function(opts, ...)
-    let rrfopts=copy(a:opts)
+    let opts=copy(a:opts)
     let hasall=index(a:000, 'all')!=-1
     if a:0 && !hasall
-        let rrfopts.files=a:000
+        let opts.files=a:000
     endif
-    let [repo, rev, files]=s:_r.cmdutils.getrrf(rrfopts,
+    let edit=0
+    let [repo, rev, files]=s:_r.cmdutils.getrrf(opts,
                 \                               ((a:0)?(0):('nocfile')),
                 \                               'getfiles')[1:]
+    if get(opts, 'amend', 0)
+        let edit=1
+        if !has_key(opts, 'message')
+            let cs=repo.functions.getcs(repo, rev)
+            let opts.message=cs.description
+        endif
+        call repo.functions.strip(repo)
+    endif
     call s:_r.cmdutils.checkrepo(repo)
     let status=repo.functions.status(repo)
     "▶2 Get file list
         unlet files
         let files=[]
     elseif a:0
-        if has_key(a:opts, 'type')
-            let types=s:_r.status.parseshow(a:opts.type)
+        if has_key(opts, 'type')
+            let types=s:_r.status.parseshow(opts.type)
             call filter(types, 'v:val isnot# "clean" && v:val isnot# "ignored"')
         endif
         let filepats=map(filter(copy(a:000), 'v:val isnot# ":"'),
         call s:_f.throw('nocfile')
     endif
     "▲2
-    return s:F.commit(repo, a:opts, files, status, types)
+    return s:F.commit(repo, opts, files, status, types, edit)
 endfunction
 "▶1 aurum://commit
 let s:commit={'arguments': 3,

autoload/aurum/drivers/mercurial.vim

     return s:_r.utils.usefile(a:repo, a:message, 'logfile', 'message',
                 \             s:F.runcmd, args, kwargs)
 endfunction
+"▶1 hg.strip :: [rev[, force]]
+function s:hg.strip(repo, ...)
+    let kwargs={'force': (a:0>1 && !empty(a:2))}
+    if a:0 && !empty(a:1)
+        let kwargs.rev=a:1
+        let cmd='strip'
+    else
+        let cmd='rollback'
+    endif
+    return s:F.runcmd(a:repo, cmd, [], kwargs)
+endfunction
 "▶1 hg.branch :: repo, branchname, force → + FS
 function s:hg.branch(repo, branch, force)
     return s:F.runcmd(a:repo, 'branch', [a:branch], {'force': !!a:force})

autoload/aurum/record.vim

 "▶1 
 scriptencoding utf-8
-execute frawor#Setup('0.0', {'@/options': '0.0',
+execute frawor#Setup('0.1', {'@/options': '0.0',
             \                     '@/os': '0.0',
             \               '@/mappings': '0.0',
             \              '@/functions': '0.1',
             \           "['commit', ".expand('<abuf>')."], {})\n","n")
     call map(copy(s:_r.cache.allkeys), 's:_r.cache.wipe(v:val)')
 endfunction
+"▶1 genstate
+function s:F.genstate(repo)
+    let cs       = a:repo.functions.getwork(a:repo)
+    let allfiles = a:repo.functions.getcsprop(a:repo, cs, 'allfiles')
+    let status   = a:repo.functions.status(a:repo, 0, 0, allfiles)
+    let state={'files': allfiles, 'contents': {}, 'removes': {}, 'revstatus': {},
+                \'description': cs.description}
+    for [s, files] in items(status)
+        for file in files
+            if index(allfiles, file)!=-1
+                let state.contents[file]=
+                            \a:repo.functions.readfile(a:repo, cs.hex, file)
+            else
+                let state.removes[file]=1
+            endif
+        endfor
+    endfor
+    return state
+endfunction
+"▶1 setstate
+function s:F.setstate(repo, bvar, state)
+    for idx in range(len(a:bvar.lines))
+        let file=a:bvar.files[idx]
+        if has_key(a:state.removes, file)
+            let type=a:bvar.types[idx]
+            if index(['added', 'unknown'], type)!=-1
+                " Do nothing: just do not include the file in the commit
+            elseif a:bvar.types[idx] is# 'modified'
+                call a:repo.functions.forget(file)
+                let a:bvar.types[idx]='removed'
+                let a:bvar.chars[idx]='R'
+                let a:bvar.lines[idx]='R '.file
+                let a:bvar.statuses[idx]=2
+            elseif index(['deleted', 'removed'], type)
+                let a:bvar.statuses[idx]=2
+            endif
+        elseif index(a:state.files, file)!=-1
+            if has_key(a:state.contents, file)
+                let fullpath=s:_r.os.path.join(a:repo.path, file)
+                let backupfile=s:F.getbackupfile(a:bvar, fullpath)
+                if rename(fullpath, backupfile)
+                    call s:_f.throw('renfail', fullpath, backupfile)
+                endif
+                call writefile(a:state.contents[file], fullpath, 'b')
+                if filereadable(fullpath)
+                    " FIXME may loose executable bit
+                    let a:bvar.backupfiles[backupfile]=fullpath
+                    let a:bvar.filesbackup[fullpath]=backupfile
+                else
+                    let a:bvar.newfiles[fullpath]=1
+                endif
+                let a:bvar.statuses[idx]=3
+            else
+                let a:bvar.statuses[idx]=2
+            endif
+        endif
+    endfor
+    let a:bvar.recopts.message = a:state.description
+    setlocal modifiable
+    call s:F.reset(a:bvar)
+    setlocal nomodifiable
+    call cursor(1, 1)
+endfunction
 "▶1 recfunc
 " TODO investigate why closing record tab is causing next character consumption
 "      under wine
             \'  ?date        type ""'.
             \'  ?user        type ""'.
             \' !?closebranch'.
+            \' !?amend'.
             \'} '.
             \'+ '.s:_r.cmdutils.comp.file, 'filter']}
 let s:_aufunctions.comp=s:_r.cmdutils.gencompfunc(s:_aufunctions.cmd['@FWC'][0],
     else
         let repo=s:_r.cmdutils.checkedgetrepo(a:opts.repo)
     endif
+    if get(a:opts, 'amend', 0)
+        let state=s:F.genstate(repo)
+        call repo.functions.strip(repo)
+    endif
     call map(files, 'repo.functions.reltorepo(repo, v:val)')
     tabnew
     setlocal bufhidden=wipe
     if empty(bvar.chars)
         bwipeout!
     endif
+    if get(a:opts, 'amend', 0)
+        call s:F.setstate(repo, bvar, state)
+    endif
 endfunction
 "▶1 curundo :: () → UInt
 if s:hasundo
 endif
 "▶1 reset
 function s:F.reset(bvar)
-    for idx in range(0, len(a:bvar.lines)-1)
+    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
     endif
     return a:bvar.ewrite(a:bvar, a:lines, a:file)
 endfunction
+"▶1 getbackupfile
+function s:F.getbackupfile(bvar, fullpath)
+    if has_key(a:bvar.filesbackup, a:fullpath)
+        let backupfile=a:bvar.filesbackup[a:fullpath]
+    else
+        let backupfile=a:fullpath.'.orig'
+        let i=0
+        while s:_r.os.path.exists(backupfile)
+            let backupfile=a:fullpath.'.'.i.'.orig'
+            let i+=1
+        endwhile
+    endif
+    return backupfile
+endfunction
 "▶1 sactions
 let s:F.sactions={}
 "▶2 sactions.[v]add, sactions.[v]remove
     let ntype=get(s:ntypes, type, 0)
     if !modified
         if ntype is# 'm' || ntype is# 'a'
-            if has_key(a:bvar.filesbackup, fullpath)
-                let backupfile=a:bvar.filesbackup[fullpath]
-            else
-                let backupfile=fullpath.'.orig'
-                let i=0
-                while s:_r.os.path.exists(backupfile)
-                    let backupfile=fullpath.'.'.i.'.orig'
-                    let i+=1
-                endwhile
-            endif
+            let backupfile=s:F.getbackupfile(a:bvar, fullpath)
         elseif ntype is# 'r'
             let a:bvar.newfiles[fullpath]=1
         endif

autoload/aurum/repo.vim

 "▶1
-execute frawor#Setup('5.5', { '@/resources': '0.0',
+execute frawor#Setup('5.6', { '@/resources': '0.0',
             \                        '@/os': '0.0',
             \                   '@/options': '0.0',
             \                    '@/python': '1.0',
 let s:requiredfuncs=['repo', 'getcs', 'checkdir']
 let s:optfuncs=['readfile', 'annotate', 'diff', 'status', 'commit', 'update',
             \   'diffre', 'getrepoprop', 'forget', 'branch', 'label',
-            \   'push', 'pull']
+            \   'push', 'pull', 'strip']
 "▶2 regdriver :: {f}, name, funcs → + s:drivers
 function s:F.regdriver(plugdict, fdict, name, funcs)
     "▶3 Check arguments
     date    Commit date in form yy-mm-dd_HH:MM:SS. Both date and time parts 
             are optional (though you must specify one of them), you can omit 
             year or use full four-digit form. Seconds are also optional.
+    [no]amend
+            Flag. If set, strips working directory revision and proceeds as 
+            usual for |:AuCommit|. Note: unlike “hg commit --amend” this won’t 
+            preserve changes that were committed. Use “|:AuRecord| amend” to 
+            preserve.
     [no]closebranch
             Flag. See description of --close-branch in “hg help commit”.
     repo    Path. Repository that should be committed to.
 AuRecord {opts} [glob1 [...]]                                      *:AuRecord*
     Start record mode (|aurum-record|). Possible options are just the same as 
     |:AuCommit| has (except for “type” option that is absent).
+    Note: `AuRecord amend` preserves changes from previous commit.
 
 AuStatus [{repo}] {opts}                                           *:AuStatus*
     Display status of the repository. Possible options:
     removes))”. “closebranch” and “force” arguments have Bool type, “user” and 
     “date” are strings. Neither “user” nor “date” argument should have any 
     normalized form, they just should be accepted by VCS.
+  strip :: [hex[, force]] -> _                                *aurum-rf-strip*
+    Delete a changeset and its descendants. Default changeset is a working 
+    directory one.
   branch :: branch, force -> _                               *aurum-rf-branch*
     Create new branch.
   label :: type, label, hex, force, local -> _                *aurum-rf-label*
 |aurum-rf-getcsprop|(…, "children") requires at least mercurial-1.7 or manual 
     preceding |aurum-rf-getchangesets| call. Thus many Next mappings do not 
     work.
+|aurum-rf-strip| without arguments uses “hg rollback”, with: “hg strip”. It is 
+    not guaranteed that using “hg rollback” to strip changesets will.
 |aurum-rf-astatus| in “non-python” version supports only 
     status(repo,0,0,[file],1,1) calls.
 |aurum-rf-agetcs| is absent in non-python version of driver.
     5.4: Added |aurum-rf-astatus|, |aurum-rf-agetcs|, |aurum-rf-agetrepoprop|, 
          |aurum-rf-aget| and |aurum-rf-aremove|.
     5.5: Added |aurum-rf-apause| and |aurum-rf-aresume|.
+    5.6: Added |aurum-rf-strip|.
 @aurum:
     0.1: Added |:AuBranch| and |:AuName|.
     0.2: Added |:AuOther|.
     1.3: Added seventh optional argument to _r.commit.commit() and 
          |g:aurum_commitautoopendiff| option.
     1.4: Added eighth optional argument to _r.commit.commit().
+    1.5: Added |:AuCommit| amend, replaced eighth optional argument with 
+         a:opts.amend.
 @%aurum/annotate:
     1.0: Removed one argument to _r.annotate.setannbuf().
 @%aurum/cmdutils:
     0.1: Added support for password in URL.
 @%aurum/maputils:
     0.1: Added _r.maputils.getnthparentfile().
+@%aurum/record:
+    0.1: Added |:AuRecord| amend.
 
 vim: ft=help:tw=78