diff --git a/vimfiles/GetLatest/GetLatestVimScripts.dat b/vimfiles/GetLatest/GetLatestVimScripts.dat index 29cc84b..8c32e6f 100644 --- a/vimfiles/GetLatest/GetLatestVimScripts.dat +++ b/vimfiles/GetLatest/GetLatestVimScripts.dat @@ -38,5 +38,5 @@ ScriptID SourceID Filename 2975 22815 fugitive.vim 2830 22798 csv.vim 3849 22637 git-time-lapse -4932 22787 diffchar.vim -4955 22442 Merginal +4932 22924 diffchar.vim +4955 22916 Merginal diff --git a/vimfiles/autoload/merginal.vim b/vimfiles/autoload/merginal.vim index 1ebc5c0..1b26c23 100755 --- a/vimfiles/autoload/merginal.vim +++ b/vimfiles/autoload/merginal.vim @@ -140,15 +140,30 @@ endfunction "Like merginal#runGitCommandInTreeReturnResult but split result to lines function! merginal#runGitCommandInTreeReturnResultLines(repo,command) - let l:dir=getcwd() - execute 'cd '.fnameescape(a:repo.tree()) - try - return split(merginal#system(a:repo.git_command().' '.a:command),'\r\n\|\n\|\r') - finally - execute 'cd '.fnameescape(l:dir) - endtry + return split(merginal#runGitCommandInTreeReturnResult(a:repo, a:command), + \ '\r\n\|\n\|\r') endfunction +function! s:cleanup_term_codes(s) + let s = substitute(a:s, '\t', ' ', 'g') + " Remove terminal escape codes for colors (based on + " www.commandlinefu.com/commands/view/3584/). + let s = substitute(s, '\v\[([0-9]{1,3}(;[0-9]{1,3})?)?[m|K]', '', 'g') + return s +endfunction + +function! merginal#runGitCommandInTreeEcho(repo,command) + let l:lines = merginal#runGitCommandInTreeReturnResultLines(a:repo, a:command) + if len(l:lines) == 1 + " Output a single/empty line to make Vim wait for Enter. + echo ' ' + endif + for l:line in l:lines + echo "[output]" s:cleanup_term_codes(l:line) + endfor +endfunction + + "Returns 1 if there was a merginal bufffer to close function! merginal#closeMerginalBuffer() let l:merginalWindowNumber=bufwinnr('Merginal:') @@ -300,6 +315,53 @@ function! merginal#fileDetails(lineNumber) return l:result endfunction +"For the commit in the specified line, retrieve it's hash +function! merginal#commitHash(lineNumber) + if !exists('b:merginal_repo') + throw 'Unable to get commit details outside the merginal window' + endif + if line(a:lineNumber)<=b:headerLinesCount + throw 'Unable to get commit details for the header of the merginal window' + endif + "echo a:lineNumber + if type(0) == type(a:lineNumber) + let l:lineNumber = a:lineNumber + else + let l:lineNumber = line(a:lineNumber) + endif + while b:headerLinesCount < l:lineNumber && !empty(getline(l:lineNumber)) + let l:lineNumber -= 1 + endwhile + let l:lineNumber += 1 + return split(getline(l:lineNumber))[0] +endfunction + +"For the commit in the specified line, retrieve: +" - fullHash +" - authorName +" - timestamp +" - subject +" - body +function! merginal#commitDetails(lineNumber) + let l:commitHash = merginal#commitHash(a:lineNumber) + let l:entryFormat = join(['%H', '%aN', '%aE', '%ai', '%B'], '%x01') + let l:commitLines = split( + \ merginal#system(b:merginal_repo.git_command('--no-pager', 'log', '-1', '--format='.l:entryFormat, l:commitHash)), + \ '\%x01') + let l:result = {} + + let l:result.fullHash = l:commitLines[0] + let l:result.authorName = l:commitLines[1] + let l:result.authorEmail = l:commitLines[2] + let l:result.timestamp = l:commitLines[3] + + let l:commitMessage = split(l:commitLines[4], '\r\n\|\n\|\r') + let l:result.subject = l:commitMessage[0] + let l:result.body = join(l:commitMessage[2 :], "\n") + + return l:result +endfunction + function! merginal#getLocalBranchNamesThatTrackARemoteBranch(remoteBranchName) "Get verbose list of branches let l:branchList=split(merginal#system(b:merginal_repo.git_command('branch','-vv')),'\r\n\|\n\|\r') @@ -351,6 +413,8 @@ function! merginal#openBranchListBuffer(...) endfunction augroup merginal + autocmd! + autocmd User Merginal_BranchList nnoremap q q autocmd User Merginal_BranchList nnoremap R :call merginal#tryRefreshBranchListBuffer(0) autocmd User Merginal_BranchList nnoremap C :call checkoutBranchUnderCursor() autocmd User Merginal_BranchList nnoremap cc :call checkoutBranchUnderCursor() @@ -364,12 +428,14 @@ augroup merginal autocmd User Merginal_BranchList nnoremap mm :call mergeBranchUnderCursor() autocmd User Merginal_BranchList nnoremap mf :call mergeBranchUnderCursorUsingFugitive() autocmd User Merginal_BranchList nnoremap rb :call rebaseBranchUnderCursor() - autocmd User Merginal_BranchList nnoremap ps :call remoteActionForBranchUnderCursor('push',0) - autocmd User Merginal_BranchList nnoremap pS :call remoteActionForBranchUnderCursor('push',1) - autocmd User Merginal_BranchList nnoremap pl :call remoteActionForBranchUnderCursor('pull',0) - autocmd User Merginal_BranchList nnoremap pf :call remoteActionForBranchUnderCursor('fetch',0) + autocmd User Merginal_BranchList nnoremap ps :call remoteActionForBranchUnderCursor('push',[]) + autocmd User Merginal_BranchList nnoremap pS :call remoteActionForBranchUnderCursor('push',['--force']) + autocmd User Merginal_BranchList nnoremap pl :call remoteActionForBranchUnderCursor('pull',[]) + autocmd User Merginal_BranchList nnoremap pr :call remoteActionForBranchUnderCursor('pull',['--rebase']) + autocmd User Merginal_BranchList nnoremap pf :call remoteActionForBranchUnderCursor('fetch',[]) autocmd User Merginal_BranchList nnoremap gd :call diffWithBranchUnderCursor() autocmd User Merginal_BranchList nnoremap rn :call renameBranchUnderCursor() + autocmd User Merginal_BranchList nnoremap gl :call historyLogForBranchUnderCursor() augroup END "If the current buffer is a branch list buffer - refresh it! @@ -380,12 +446,11 @@ function! merginal#tryRefreshBranchListBuffer(jumpToCurrentBranch) setlocal modifiable "Clear the buffer: - normal ggdG + silent normal! gg"_dG "Write the branch list: call setline(1,l:branchList) setlocal nomodifiable - if a:jumpToCurrentBranch "Find the current branch's index let l:currentBranchIndex=-1 @@ -409,7 +474,7 @@ endfunction function! s:checkoutBranchUnderCursor() if 'Merginal:Branches'==bufname('') let l:branch=merginal#branchDetails('.') - echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'--no-pager checkout '.shellescape(l:branch.handle)) + call merginal#runGitCommandInTreeEcho(b:merginal_repo,'--no-pager checkout '.shellescape(l:branch.handle)) call merginal#reloadBuffers() call merginal#tryRefreshBranchListBuffer(0) endif @@ -427,11 +492,11 @@ function! s:trackBranchUnderCursor(promptForName) let l:newBranchName=input('Track `'.l:branch.handle.'` as: ',l:newBranchName) if empty(l:newBranchName) echo ' ' - echo 'Branch tracking canceled by the user' + echom 'Branch tracking canceled by user.' return endif endif - echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'--no-pager checkout -b '.shellescape(l:newBranchName).' --track '.shellescape(l:branch.handle)) + call merginal#runGitCommandInTreeEcho(b:merginal_repo,'--no-pager checkout -b '.shellescape(l:newBranchName).' --track '.shellescape(l:branch.handle)) call merginal#reloadBuffers() call merginal#tryRefreshBranchListBuffer(0) endif @@ -443,10 +508,10 @@ function! s:promptToCreateNewBranch() let l:newBranchName=input('Branch `'.b:merginal_repo.head().'` to: ') if empty(l:newBranchName) echo ' ' - echo 'Branch creation canceled by the user' + echom 'Branch creation canceled by user.' return endif - echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'--no-pager checkout -b '.shellescape(l:newBranchName)) + call merginal#runGitCommandInTreeEcho(b:merginal_repo,'--no-pager checkout -b '.shellescape(l:newBranchName)) call merginal#reloadBuffers() call merginal#tryRefreshBranchListBuffer(1) endif @@ -458,15 +523,14 @@ function! s:deleteBranchUnderCursor() let l:branch=merginal#branchDetails('.') let l:answer=0 if l:branch.isLocal - let l:answer='yes'==input('Delete branch `'.l:branch.handle.'`?(type "yes" to confirm) ') + let l:answer='yes'==input('Delete branch `'.l:branch.handle.'`? (type "yes" to confirm) ') elseif l:branch.isRemote "Deleting remote branches needs a special warning - let l:answer='yes-remote'==input('Delete remote(!) branch `'.l:branch.handle.'`?(type "yes-remote" to confirm) ') + let l:answer='yes-remote'==input('Delete remote(!) branch `'.l:branch.handle.'`? (type "yes-remote" to confirm) ') endif if l:answer if l:branch.isLocal - echo ' ' - echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'--no-pager branch -D '.shellescape(l:branch.handle)) + call merginal#runGitCommandInTreeEcho(b:merginal_repo,'--no-pager branch -D '.shellescape(l:branch.handle)) else execute '!'.b:merginal_repo.git_command('push').' '.shellescape(l:branch.remote).' --delete '.shellescape(l:branch.name) endif @@ -474,7 +538,7 @@ function! s:deleteBranchUnderCursor() call merginal#tryRefreshBranchListBuffer(0) else echo ' ' - echo 'Branch deletion canceled by the user' + echom 'Branch deletion canceled by user.' endif endif endfunction @@ -483,8 +547,7 @@ endfunction function! s:mergeBranchUnderCursor() if 'Merginal:Branches'==bufname('') let l:branch=merginal#branchDetails('.') - echo ' ' - echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'merge --no-commit '.shellescape(l:branch.handle)) + call merginal#runGitCommandInTreeEcho(b:merginal_repo,'merge --no-commit '.shellescape(l:branch.handle)) call merginal#reloadBuffers() if v:shell_error call merginal#openMergeConflictsBuffer(winnr()) @@ -512,8 +575,7 @@ endfunction function! s:rebaseBranchUnderCursor() if 'Merginal:Branches'==bufname('') let l:branch=merginal#branchDetails('.') - echo ' ' - echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'rebase '.shellescape(l:branch.handle)) + call merginal#runGitCommandInTreeEcho(b:merginal_repo,'rebase '.shellescape(l:branch.handle)) call merginal#reloadBuffers() if v:shell_error call merginal#openRebaseConflictsBuffer(winnr()) @@ -522,7 +584,7 @@ function! s:rebaseBranchUnderCursor() endfunction "Run various remote actions -function! s:remoteActionForBranchUnderCursor(remoteAction,force) +function! s:remoteActionForBranchUnderCursor(remoteAction,flags) if 'Merginal:Branches'==bufname('') let l:branch=merginal#branchDetails('.') if l:branch.isLocal @@ -597,9 +659,9 @@ function! s:remoteActionForBranchUnderCursor(remoteAction,force) endif let l:gitCommandWithArgs=[a:remoteAction] - if a:force - call add(l:gitCommandWithArgs,'--force') - endif + for l:flag in a:flags + call add(l:gitCommandWithArgs,l:flag) + endfor let l:reloadBuffers=0 @@ -645,10 +707,7 @@ function! s:diffWithBranchUnderCursor() if 'Merginal:Branches'==bufname('') \|| 'Merginal:RebaseAmend'==bufname('') let l:branch=merginal#branchDetails('.') - if l:branch.isCurrent - throw 'Can not diff against the current branch' - endif - call merginal#openDiffFilesBuffer(l:branch) + call merginal#openDiffFilesBuffer(l:branch.handle) endif endfunction @@ -663,10 +722,10 @@ function! s:renameBranchUnderCursor() let l:newName=input('Rename `'.l:branch.handle.'` to: ',l:branch.name) echo ' ' if empty(l:newName) - echo 'Branch rename canceled by the user' + echom 'Branch rename canceled by user.' return elseif l:newName==l:branch.name - echo 'Branch name was not modified' + echom 'Branch name was not modified.' return endif @@ -677,6 +736,16 @@ function! s:renameBranchUnderCursor() endif endfunction +"Opens the history log buffer +function! s:historyLogForBranchUnderCursor() + if 'Merginal:Branches'==bufname('') + \|| 'Merginal:RebaseAmend'==bufname('') + let l:branch=merginal#branchDetails('.') + call merginal#openHistoryLogBuffer(l:branch) + endif +endfunction + + "Open the merge conflicts buffer for resolving merge conflicts @@ -691,6 +760,7 @@ function! merginal#openMergeConflictsBuffer(...) endfunction augroup merginal + autocmd User Merginal_MergeConflicts nnoremap q q autocmd User Merginal_MergeConflicts nnoremap R :call merginal#tryRefreshMergeConflictsBuffer(0) autocmd User Merginal_MergeConflicts nnoremap :call openMergeConflictUnderCursor() autocmd User Merginal_MergeConflicts nnoremap A :call addConflictedFileToStagingArea() @@ -719,7 +789,7 @@ function! s:refreshConflictsBuffer(fileToJumpTo,headerLines) setlocal modifiable "Clear the buffer: - normal ggdG + silent normal! gg"_dG "Write the branch list: call setline(1,a:headerLines+l:conflicts) let b:headerLinesCount=len(a:headerLines) @@ -773,7 +843,7 @@ function! s:addConflictedFileToStagingArea() if empty(l:file.name) return endif - echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'--no-pager add '.shellescape(fnamemodify(l:file.name,':p'))) + call merginal#runGitCommandInTreeEcho(b:merginal_repo,'--no-pager add '.shellescape(fnamemodify(l:file.name,':p'))) if 'Merginal:Conflicts'==bufname('') if merginal#tryRefreshMergeConflictsBuffer(0) @@ -789,7 +859,7 @@ function! s:addConflictedFileToStagingArea() else if merginal#tryRefreshRebaseConflictsBuffer(0) echo 'Added the last file of this patch.' - echo 'Continue to the next patch(y/n)?' + echo 'Continue to the next patch (y/N)?' let l:answer=getchar() if char2nr('y')==l:answer || char2nr('Y')==l:answer call s:rebaseAction('continue') @@ -800,19 +870,20 @@ function! s:addConflictedFileToStagingArea() endfunction -"Open the diff files buffer for diffing agains another branch -function! merginal#openDiffFilesBuffer(diffBranch,...) +"Open the diff files buffer for diffing agains another branch/commit +function! merginal#openDiffFilesBuffer(diffTarget,...) if merginal#openTuiBuffer('Merginal:Diff',get(a:000,1,bufwinnr('Merginal:'))) doautocmd User Merginal_DiffFiles endif - let b:merginal_diffBranch=a:diffBranch + let b:merginal_diffTarget=a:diffTarget "At any rate, refresh the buffer: call merginal#tryRefreshDiffFilesBuffer() endfunction augroup merginal + autocmd User Merginal_DiffFiles nnoremap q q autocmd User Merginal_DiffFiles nnoremap R :call merginal#tryRefreshDiffFilesBuffer() autocmd User Merginal_DiffFiles nnoremap :call openDiffFileUnderCursor() autocmd User Merginal_DiffFiles nnoremap ds :call openDiffFileUnderCursorAndDiff('s') @@ -859,16 +930,16 @@ function! merginal#diffFileDetails(lineNumber) return l:result endfunction -"If the current buffer is a branch list buffer - refresh it! +"If the current buffer is a diff files buffer - refresh it! function! merginal#tryRefreshDiffFilesBuffer() if 'Merginal:Diff'==bufname('') - let l:diffBranch=b:merginal_diffBranch - let l:diffFiles=merginal#runGitCommandInTreeReturnResultLines(b:merginal_repo,'diff --name-status '.shellescape(l:diffBranch.handle)) + let l:diffTarget=b:merginal_diffTarget + let l:diffFiles=merginal#runGitCommandInTreeReturnResultLines(b:merginal_repo,'diff --name-status '.shellescape(l:diffTarget)) let l:currentLine=line('.') setlocal modifiable "Clear the buffer: - normal ggdG + silent normal! gg"_dG "Write the diff files list: call setline(1,l:diffFiles) setlocal nomodifiable @@ -903,7 +974,7 @@ function! s:openDiffFileUnderCursorAndDiff(diffType) endif let l:repo=b:merginal_repo - let l:diffBranch=b:merginal_diffBranch + let l:diffTarget=b:merginal_diffTarget "Close currently open git diffs let l:currentWindowBuffer=winbufnr('.') @@ -919,11 +990,11 @@ function! s:openDiffFileUnderCursorAndDiff(diffType) call merginal#openFileDecidedWindow(l:repo,l:diffFile.fileFullPath) - execute ':G'.a:diffType.'diff '.fnameescape(l:diffBranch.handle) + execute ':G'.a:diffType.'diff '.fnameescape(l:diffTarget) endif endfunction -"Checks out the file from the other branch to the current branch +"Checks out the file from the diff target to the current branch function! s:checkoutDiffFileUnderCursor() if 'Merginal:Diff'==bufname('') let l:diffFile=merginal#diffFileDetails('.') @@ -934,16 +1005,16 @@ function! s:checkoutDiffFileUnderCursor() let l:answer=1 if !empty(glob(l:diffFile.fileFullPath)) - let l:answer='yes'==input('Override `'.l:diffFile.fileInTree.'`?(type "yes" to confirm) ') + let l:answer='yes'==input('Override `'.l:diffFile.fileInTree.'`? (type "yes" to confirm) ') endif if l:answer - echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'--no-pager checkout '.shellescape(b:merginal_diffBranch.handle) + call merginal#runGitCommandInTreeEcho(b:merginal_repo,'--no-pager checkout '.shellescape(b:merginal_diffTarget) \.' -- '.shellescape(l:diffFile.fileFullPath)) call merginal#reloadBuffers() call merginal#tryRefreshDiffFilesBuffer() else - echo ' ' - echo 'File checkout canceled by the user' + echo + echom 'File checkout canceled by user.' endif endif endfunction @@ -961,6 +1032,7 @@ function! merginal#openRebaseConflictsBuffer(...) endfunction augroup merginal + autocmd User Merginal_RebaseConflicts nnoremap q q autocmd User Merginal_RebaseConflicts nnoremap R :call merginal#tryRefreshRebaseConflictsBuffer(0) autocmd User Merginal_RebaseConflicts nnoremap :call openMergeConflictUnderCursor() autocmd User Merginal_RebaseConflicts nnoremap A :call addConflictedFileToStagingArea() @@ -986,7 +1058,7 @@ endfunction function! s:rebaseAction(remoteAction) if 'Merginal:Rebase'==bufname('') \|| 'Merginal:RebaseAmend'==bufname('') - echo merginal#runGitCommandInTreeReturnResult(b:merginal_repo,'--no-pager rebase --'.a:remoteAction) + call merginal#runGitCommandInTreeEcho(b:merginal_repo,'--no-pager rebase --'.a:remoteAction) call merginal#reloadBuffers() if merginal#isRebaseMode() call merginal#tryRefreshRebaseConflictsBuffer(0) @@ -1012,15 +1084,18 @@ function! merginal#openRebaseAmendBuffer(...) call merginal#tryRefreshRebaseAmendBuffer() endfunction -autocmd User Merginal_RebaseAmend nnoremap R :call merginal#tryRefreshRebaseAmendBuffer() -autocmd User Merginal_RebaseAmend nnoremap ra :call rebaseAction('abort') -autocmd User Merginal_RebaseAmend nnoremap rs :call rebaseAction('skip') -autocmd User Merginal_RebaseAmend nnoremap rc :call rebaseAction('continue') -autocmd User Merginal_RebaseAmend nnoremap gd :call diffWithBranchUnderCursor() +augroup merginal + autocmd User Merginal_RebaseAmend nnoremap q q + autocmd User Merginal_RebaseAmend nnoremap R :call merginal#tryRefreshRebaseAmendBuffer() + autocmd User Merginal_RebaseAmend nnoremap ra :call rebaseAction('abort') + autocmd User Merginal_RebaseAmend nnoremap rs :call rebaseAction('skip') + autocmd User Merginal_RebaseAmend nnoremap rc :call rebaseAction('continue') + autocmd User Merginal_RebaseAmend nnoremap gd :call diffWithBranchUnderCursor() + autocmd User Merginal_RebaseAmend nnoremap gl :call historyLogForBranchUnderCursor() +augroup END function! merginal#tryRefreshRebaseAmendBuffer() if 'Merginal:RebaseAmend'==bufname('') - "let l:gitStatusOutput=split(merginal#system(b:merginal_repo.git_command('status','--all')),'\r\n\|\n\|\r') let l:currentLine=line('.') let l:newBufferLines=[] let l:amendedCommit=readfile(b:merginal_repo.dir('rebase-merge','amend')) @@ -1042,7 +1117,7 @@ function! merginal#tryRefreshRebaseAmendBuffer() setlocal modifiable "Clear the buffer: - normal ggdG + silent normal! gg"_dG "Write the new buffer lines: call setline(1,l:newBufferLines) "call setline(1,l:branchList) @@ -1050,3 +1125,113 @@ function! merginal#tryRefreshRebaseAmendBuffer() endif return 0 endfunction + + + + + +"Open the history log buffer +function! merginal#openHistoryLogBuffer(logBranch,...) + let l:currentFile=expand('%:~:.') + if merginal#openTuiBuffer('Merginal:HistoryLog',get(a:000,1,bufwinnr('Merginal:'))) + doautocmd User Merginal_HistoryLog + endif + + let b:merginal_branch=a:logBranch + + "At any rate, refresh the buffer: + call merginal#tryRefreshHistoryLogBuffer() +endfunction + +augroup merginal + autocmd User Merginal_HistoryLog nnoremap q q + autocmd User Merginal_HistoryLog nnoremap R :call merginal#tryRefreshHistoryLogBuffer() + autocmd User Merginal_HistoryLog nnoremap :call moveToNextOrPreviousCommit(-1) + autocmd User Merginal_HistoryLog nnoremap :call moveToNextOrPreviousCommit(1) + autocmd User Merginal_HistoryLog nnoremap S :call printCommitUnderCurosr('fuller') + autocmd User Merginal_HistoryLog nnoremap ss :call printCommitUnderCurosr('fuller') + autocmd User Merginal_HistoryLog nnoremap C :call checkoutCommitUnderCurosr() + autocmd User Merginal_HistoryLog nnoremap cc :call checkoutCommitUnderCurosr() + autocmd User Merginal_HistoryLog nnoremap gd :call diffWithCommitUnderCursor() +augroup END + +function! merginal#tryRefreshHistoryLogBuffer() + if 'Merginal:HistoryLog'==bufname('') + let l:entryFormat = '%h %aN%n%ai%n%s%n' + let l:logLines = split( + \ merginal#system(b:merginal_repo.git_command( + \ '--no-pager', 'log', '--format='.l:entryFormat, b:merginal_branch.handle)), + \ '\r\n\|\n\|\r') + if empty(l:logLines[len(l:logLines) - 1]) + call remove(l:logLines, len(l:logLines) - 1) + endif + let l:currentLine=line('.') + + setlocal modifiable + "Clear the buffer: + silent normal! gg"_dG + "Write the log lines: + call setline(1,l:logLines) + setlocal nomodifiable + + execute l:currentLine + endif + return 0 +endfunction + +"Exactly what it says on tin +function! s:printCommitUnderCurosr(format) + if 'Merginal:HistoryLog'==bufname('') + let l:commitHash = merginal#commitHash('.') + "Not using merginal#runGitCommandInTreeEcho because we are insterested + "in the result as more than just git command output. Also - using + "git-log with -1 instead of git-show because for some reason git-show + "ignores the --format flag... + echo merginal#system(b:merginal_repo.git_command('--no-pager', 'log', '-1', '--format='.a:format, l:commitHash)) + endif +endfunction + +"Exactly what it says on tin +function! s:checkoutCommitUnderCurosr() + if 'Merginal:HistoryLog'==bufname('') + let l:commitHash = merginal#commitHash('.') + call merginal#runGitCommandInTreeEcho(b:merginal_repo,'--no-pager checkout '.shellescape(l:commitHash)) + call merginal#reloadBuffers() + call merginal#tryRefreshBranchListBuffer(0) + endif +endfunction + +"Opens the diff files buffer +function! s:diffWithCommitUnderCursor() + if 'Merginal:HistoryLog'==bufname('') + let l:commitHash = merginal#commitHash('.') + call merginal#openDiffFilesBuffer(l:commitHash) + endif +endfunction + +function! s:moveToNextOrPreviousCommit(direction) + if 'Merginal:HistoryLog'==bufname('') + let l:line = line('.') + + "Find the first line of the current commit + while !empty(getline(l:line - 1)) + let l:line -= 1 + endwhile + + "Find the first line of the next/prev commit + let l:line += a:direction + while !empty(getline(l:line - 1)) + let l:line += a:direction + endwhile + + if l:line <= 0 || line('$') <= l:line + "We reached past the first/last commit - go back! + let l:line -= a:direction + while !empty(getline(l:line - 1)) + let l:line -= a:direction + endwhile + endif + execute l:line + endif +endfunction + diff --git a/vimfiles/doc/merginal.txt b/vimfiles/doc/merginal.txt index 124d252..db48c7b 100755 --- a/vimfiles/doc/merginal.txt +++ b/vimfiles/doc/merginal.txt @@ -4,7 +4,7 @@ Author: Idan Arye License: Same terms as Vim itself (see |license|) -Version: 1.4.0 +Version: 1.5.0 INTRODUCTION *merginal* @@ -19,6 +19,7 @@ offers interactive TUI for: * Rebasing branches * Solving merge conflicts * Renaming branches +* Viewing git history for branches REQUIREMENTS *merginal-requirements* @@ -51,7 +52,8 @@ THE BRANCH LIST *merginal-branch-list* The branch list shows a list of branches. While in that list, you can use the following keymaps to interact with the branches: -R Refresh the buffer list. +q Close the branch list. +R Refresh the branch list. cc Checkout the branch under the cursor. ct Track the remote branch under the cursor. cT Track the remote branch under the cursor, prompting for a name. @@ -74,10 +76,13 @@ rb Rebase the currently checked out branch against the branch under the ps Prompt to choose a remote to push the branch under the cursor. pS Prompt to choose a remote to force push the branch under the cursor. pl Prompt to choose a remote to pull the branch under the cursor. +pr Prompt to choose a remote to pull-rebase the branch under the cursor. pf Prompt to choose a remote to fetch the branch under the cursor. gd Open |merginal-diff-files| buffer to diff against the branch under the cursor. rn Prompt to rename the branch under the cursor. +gl Open |merginal-history-log| buffer to view the history of the branch + under the cursor. MERGE CONFLICTS *merginal-merge-conflicts* @@ -85,6 +90,7 @@ MERGE CONFLICTS *merginal-merge-conflicts* The merge conflicts buffer is used to solve merge conflicts. It shows all the files that have merge conflicts and offers the following keymaps: +q Close the merge conflicts list. R Refresh the merge conflicts list. Open the conflicted file under the cursor. aa Add the conflicted file under the cursor to the staging area. If that @@ -105,7 +111,7 @@ aa Add the conflicted file under the cursor to the staging area. If that was the last conflicted file, prompt the user to continue to the next patch. A Same as aa. -ra Abort the rebase +ra Abort the rebase. rc Continue to the next patch. rs Skip the current patch @@ -114,29 +120,51 @@ REBASE AMEND *merginal-rebase-amend* The rebase amend buffer is shown when you amend a patch during a rebase. It shows the amended commit's shortened hash and commit message. Additionally, it -shows all the branches so you can diff against them while the patch. If offers -the folloing keymaps: +shows all the branches so you can diff against them. If offers the following +keymaps: +q Close the rebase amend buffer. R Refresh the rebase amend buffer. gd Open |merginal-diff-files| buffer to diff against the branch under the cursor. -ra Abort the rebase +gl Open |merginal-history-log| buffer to view the history of the branch + under the cursor. +ra Abort the rebase. rc Continue to the next patch. -rs Skip the current patch +rs Skip the current patch. DIFF FILES *merginal-diff-files* The diff files buffer is used to diff against another branch. It displays all the differences between the currently checked out branch and the branch it was -opened against, and offerts the following keymaps: +opened against, and offers the following keymaps: +q Close the diff files list. R Refresh the diff files list. - Open the file under the cursor(if it exists in the currently checked + Open the file under the cursor (if it exists in the currently checked out branch). -ds Split-diff against the file under the cursor(if it exists in the other - branch) -ds VSplit-diff against the file under the cursor(if it exists in the other - branch) -co Check out the file under the cursor(if it exists in the other branch) +ds Split-diff against the file under the cursor (if it exists in the other + branch). +dv VSplit-diff against the file under the cursor (if it exists in the other + branch). +co Check out the file under the cursor (if it exists in the other branch) into the current branch. + + +HISTORY LOG *merginal-history-log* + +The history log buffer is used to show the history of a branch. It shows, for +each commit in the branch, the author, date and commit message subject, and +offers the following keymaps: + +q Close the history log buffer. +R Refresh the history log buffer. + Move the cursor to the previous commit. + Move the cursor to the next commit. +ss Echo the commit details(using git's --format=fuller). +S Same as ss. +cc Checkout the commit under the cursor. +C Same as cc. +gd Open |merginal-diff-files| buffer to diff against the commit under the + cursor. diff --git a/vimfiles/plugin/diffchar.vim b/vimfiles/plugin/diffchar.vim index 106c346..64411b1 100644 --- a/vimfiles/plugin/diffchar.vim +++ b/vimfiles/plugin/diffchar.vim @@ -65,11 +65,17 @@ " "OND" : E.W.Myers, "An O(ND) Difference Algorithm and Its Variations" " "Basic" : basic algorithm using edit graph and shortest edit distance " -" DiffCharExpr(iet, exd) function for the diffexpr option -" iet: 1 = internal algorithm, 0 = external diff command, -" else = threshold value of differences to apply either +" DiffCharExpr(mxi, exd) function for the diffexpr option +" mxi: the maximum number of total lines of both windows to apply internal +" algorithm, apply external diff command when more lines " exd: 1 = initially show exact differences, 0 = vim original ones " +" Update : 4.9 +" * Fixed DiffCharExpr() to check the number of total lines, not different +" lines only, of both windows and apply either internal algorithm or +" external diff command, in order to keep the appropriate performance +" for large files. +" " Update : 4.81 " * Enhanced to make DiffCharExpr() a bit faster by using uniq() or so. " @@ -209,15 +215,15 @@ " the initial version. " " Author: Rick Howe -" Last Change: 2015/01/13 +" Last Change: 2015/02/18 " Created: " Requires: -" Version: 4.81 +" Version: 4.9 if exists("g:loaded_diffchar") finish endif -let g:loaded_diffchar = 4.81 +let g:loaded_diffchar = 4.9 let s:save_cpo = &cpo set cpo&vim @@ -294,15 +300,12 @@ endif " Set a diff expression if !exists("g:DiffExpr") || g:DiffExpr if empty(&diffexpr) -let &diffexpr = "DiffCharExpr(200, 1)" " set threshold and show exact diffs -" let &diffexpr = "DiffCharExpr(1, 1)" " apply int algo and show exact diffs -" let &diffexpr = "DiffCharExpr(1, 0)" " apply int algo and show vim original -" let &diffexpr = "DiffCharExpr(0, 1)" " apply ext cmd and show exact diffs +let &diffexpr = "DiffCharExpr(200, 1)" " set # of lines and show exact diffs " let &diffexpr = "DiffCharExpr(0, 0)" " apply ext cmd and show vim original endif endif -function! DiffCharExpr(iet, exd) +function! DiffCharExpr(mxi, exd) " read both files to be diff traced let [f1, f2] = [readfile(v:fname_in), readfile(v:fname_new)] @@ -312,35 +315,8 @@ function! DiffCharExpr(iet, exd) return endif - " decide either internal or external - if a:iet > 1 - " too short to check - if len(f1 + f2) < a:iet - let int = 1 - else - " check how many differences and compare with a:iet - if exists("*uniq") - let int = (2 * len(uniq(sort(f1 + f2))) - - \len(uniq(sort(copy(f1)))) - - \len(uniq(sort(copy(f2))))) < a:iet - else - for k in [1, 2] - let d{k} = {} - for s in f{k} - let d{k}[empty(s) ? - \nr2char(10) : s] = 0 - endfor - endfor - let int = (- len(d1) - len(d2) + 2 * - \len(extend(d1, d2, "keep"))) < a:iet - endif - endif - else - let int = a:iet - endif - " get a list of diff commands - let dfcmd = int ? + let dfcmd = (len(f1 + f2) <= a:mxi) ? \s:ApplyIntDiffAlgorithm(f1, f2) : s:ApplyExtDiffCommand() " write to output file