This commit is contained in:
Stefan Liebl 2015-02-19 12:55:54 +01:00
parent 121cd1ddca
commit f8ab290619
4 changed files with 306 additions and 117 deletions

View File

@ -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

View File

@ -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 <buffer> q <C-w>q
autocmd User Merginal_BranchList nnoremap <buffer> R :call merginal#tryRefreshBranchListBuffer(0)<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> C :call <SID>checkoutBranchUnderCursor()<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> cc :call <SID>checkoutBranchUnderCursor()<Cr>
@ -364,12 +428,14 @@ augroup merginal
autocmd User Merginal_BranchList nnoremap <buffer> mm :call <SID>mergeBranchUnderCursor()<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> mf :call <SID>mergeBranchUnderCursorUsingFugitive()<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> rb :call <SID>rebaseBranchUnderCursor()<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> ps :call <SID>remoteActionForBranchUnderCursor('push',0)<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> pS :call <SID>remoteActionForBranchUnderCursor('push',1)<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> pl :call <SID>remoteActionForBranchUnderCursor('pull',0)<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> pf :call <SID>remoteActionForBranchUnderCursor('fetch',0)<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> ps :call <SID>remoteActionForBranchUnderCursor('push',[])<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> pS :call <SID>remoteActionForBranchUnderCursor('push',['--force'])<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> pl :call <SID>remoteActionForBranchUnderCursor('pull',[])<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> pr :call <SID>remoteActionForBranchUnderCursor('pull',['--rebase'])<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> pf :call <SID>remoteActionForBranchUnderCursor('fetch',[])<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> gd :call <SID>diffWithBranchUnderCursor()<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> rn :call <SID>renameBranchUnderCursor()<Cr>
autocmd User Merginal_BranchList nnoremap <buffer> gl :call <SID>historyLogForBranchUnderCursor()<Cr>
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
@ -465,8 +530,7 @@ function! s:deleteBranchUnderCursor()
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 <buffer> q <C-w>q
autocmd User Merginal_MergeConflicts nnoremap <buffer> R :call merginal#tryRefreshMergeConflictsBuffer(0)<Cr>
autocmd User Merginal_MergeConflicts nnoremap <buffer> <Cr> :call <SID>openMergeConflictUnderCursor()<Cr>
autocmd User Merginal_MergeConflicts nnoremap <buffer> A :call <SID>addConflictedFileToStagingArea()<Cr>
@ -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 <buffer> q <C-w>q
autocmd User Merginal_DiffFiles nnoremap <buffer> R :call merginal#tryRefreshDiffFilesBuffer()<Cr>
autocmd User Merginal_DiffFiles nnoremap <buffer> <Cr> :call <SID>openDiffFileUnderCursor()<Cr>
autocmd User Merginal_DiffFiles nnoremap <buffer> ds :call <SID>openDiffFileUnderCursorAndDiff('s')<Cr>
@ -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('.')
@ -937,13 +1008,13 @@ function! s:checkoutDiffFileUnderCursor()
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 <buffer> q <C-w>q
autocmd User Merginal_RebaseConflicts nnoremap <buffer> R :call merginal#tryRefreshRebaseConflictsBuffer(0)<Cr>
autocmd User Merginal_RebaseConflicts nnoremap <buffer> <Cr> :call <SID>openMergeConflictUnderCursor()<Cr>
autocmd User Merginal_RebaseConflicts nnoremap <buffer> A :call <SID>addConflictedFileToStagingArea()<Cr>
@ -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
augroup merginal
autocmd User Merginal_RebaseAmend nnoremap <buffer> q <C-w>q
autocmd User Merginal_RebaseAmend nnoremap <buffer> R :call merginal#tryRefreshRebaseAmendBuffer()<Cr>
autocmd User Merginal_RebaseAmend nnoremap <buffer> ra :call <SID>rebaseAction('abort')<Cr>
autocmd User Merginal_RebaseAmend nnoremap <buffer> rs :call <SID>rebaseAction('skip')<Cr>
autocmd User Merginal_RebaseAmend nnoremap <buffer> rc :call <SID>rebaseAction('continue')<Cr>
autocmd User Merginal_RebaseAmend nnoremap <buffer> gd :call <SID>diffWithBranchUnderCursor()<Cr>
autocmd User Merginal_RebaseAmend nnoremap <buffer> gl :call <SID>historyLogForBranchUnderCursor()<Cr>
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 <buffer> q <C-w>q
autocmd User Merginal_HistoryLog nnoremap <buffer> R :call merginal#tryRefreshHistoryLogBuffer()<Cr>
autocmd User Merginal_HistoryLog nnoremap <buffer> <C-p> :call <SID>moveToNextOrPreviousCommit(-1)<Cr>
autocmd User Merginal_HistoryLog nnoremap <buffer> <C-n> :call <SID>moveToNextOrPreviousCommit(1)<Cr>
autocmd User Merginal_HistoryLog nnoremap <buffer> S :call <SID>printCommitUnderCurosr('fuller')<Cr>
autocmd User Merginal_HistoryLog nnoremap <buffer> ss :call <SID>printCommitUnderCurosr('fuller')<Cr>
autocmd User Merginal_HistoryLog nnoremap <buffer> C :call <SID>checkoutCommitUnderCurosr()<Cr>
autocmd User Merginal_HistoryLog nnoremap <buffer> cc :call <SID>checkoutCommitUnderCurosr()<Cr>
autocmd User Merginal_HistoryLog nnoremap <buffer> gd :call <SID>diffWithCommitUnderCursor()<Cr>
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

View File

@ -4,7 +4,7 @@
Author: Idan Arye <https://github.com/idanarye/>
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.
<Cr> 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.
<Cr> 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)
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.
<C-p> Move the cursor to the previous commit.
<C-n> 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.

View File

@ -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