" Author: Eric Van Dewoestine
"
" License: {{{
"
" Copyright (C) 2005 - 2014 Eric Van Dewoestine
"
" This program is free software: you can redistribute it and/or modify
" it under the terms of the GNU General Public License as published by
" the Free Software Foundation, either version 3 of the License, or
" (at your option) any later version.
"
" This program is distributed in the hope that it will be useful,
" but WITHOUT ANY WARRANTY; without even the implied warranty of
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
" GNU General Public License for more details.
"
" You should have received a copy of the GNU General Public License
" along with this program. If not, see .
"
" }}}
" Script Variables {{{
let s:command_add = '-command history_add -p "" -f ""'
let s:command_list = '-command history_list -p "" -f ""'
let s:command_revision =
\ '-command history_revision -p "" -f "" -r '
let s:command_clear = '-command history_clear -p "" -f ""'
" }}}
function! eclim#common#history#AddHistory() " {{{
" Adds the current state of the file to the eclipse local history (should be
" invoked prior to saving to disk).
if !filereadable(expand('%')) || !eclim#project#util#IsCurrentFileInProject(0)
return
endif
let project = eclim#project#util#GetCurrentProjectName()
let file = eclim#project#util#GetProjectRelativeFilePath()
let command = s:command_add
let command = substitute(command, '', project, '')
let command = substitute(command, '', file, '')
call eclim#Execute(command)
endfunction " }}}
function! eclim#common#history#History() " {{{
" Opens a temporary buffer with a list of local history revisions.
if !eclim#project#util#IsCurrentFileInProject()
return
endif
let project = eclim#project#util#GetCurrentProjectName()
let file = eclim#project#util#GetProjectRelativeFilePath()
let command = s:command_list
let command = substitute(command, '', project, '')
let command = substitute(command, '', file, '')
let history = eclim#Execute(command)
if type(history) != g:LIST_TYPE
return
endif
let lines = [file]
let revisions = [0]
let indent = eclim#util#GetIndent(1)
for rev in history
call add(lines, indent . rev.datetime . ' (' . rev.delta . ')')
call add(revisions, rev.timestamp)
endfor
call add(lines, '')
call eclim#util#TempWindow('[History]', lines)
setlocal modifiable noreadonly
if !g:EclimKeepLocalHistory
call append(line('$'),
\ '" Note: local history is currently disabled: ' .
\ 'g:EclimKeepLocalHistory = ' . g:EclimKeepLocalHistory)
endif
call append(line('$'), '" use ? to view help')
setlocal nomodifiable readonly
syntax match Comment /^".*/
let b:history_revisions = revisions
call s:Syntax()
command! -count=1 HistoryDiffNext call s:DiffNextPrev(1, )
command! -count=1 HistoryDiffPrev call s:DiffNextPrev(-1, )
augroup eclim_history_window
autocmd! BufWinLeave
autocmd BufWinLeave
\ delcommand HistoryDiffNext |
\ delcommand HistoryDiffPrev
augroup END
noremap :call View()
noremap d :call Diff()
noremap r :call Revert()
noremap c :call Clear(1)
" assign to buffer var to get around weird vim issue passing list containing
" a string w/ a '<' in it on execution of mapping.
let b:history_help = [
\ ' - view the entry',
\ 'd - diff the file with the version under the cursor',
\ 'r - revert the file to the version under the cursor',
\ 'c - clear the history',
\ ':HistoryDiffNext - diff the file with the next version in the history',
\ ':HistoryDiffPrev - diff the file with the previous version in the history',
\ ]
nnoremap ?
\ :call eclim#help#BufferHelp(b:history_help, 'vertical', 50)
endfunction " }}}
function! eclim#common#history#HistoryClear(bang) " {{{
" Clear the history for the current file.
if !eclim#project#util#IsCurrentFileInProject()
return
endif
call s:Clear(a:bang == '', expand('%:p'))
endfunction " }}}
function s:View(...) " {{{
" View the contents of the revision under the cursor.
if line('.') == 1 || line('.') > len(b:history_revisions)
return
endif
let current = b:filename
let entry = line('.') - 1
let revision = b:history_revisions[entry]
if eclim#util#GoToBufferWindow(current)
let filetype = &ft
let project = eclim#project#util#GetCurrentProjectName()
let file = eclim#project#util#GetProjectRelativeFilePath()
let command = s:command_revision
let command = substitute(command, '', project, '')
let command = substitute(command, '', file, '')
let command = substitute(command, '', revision, '')
let result = eclim#Execute(command)
if result == "0"
return
endif
let cmd = len(a:000) > 0 ? a:000[0] : 'split'
call eclim#util#GoToBufferWindowOrOpen(
\ current . '_' . revision, 'keepalt ' . cmd)
setlocal modifiable
setlocal noreadonly
let temp = tempname()
call writefile(split(result, '\n'), temp)
try
silent 1,$delete _
silent read ++edit `=temp`
silent 1,1delete _
finally
call delete(temp)
endtry
exec 'setlocal filetype=' . filetype
setlocal nomodified
setlocal readonly
setlocal nomodifiable
setlocal noswapfile
setlocal nobuflisted
setlocal buftype=nofile
setlocal bufhidden=wipe
doautocmd BufReadPost
call s:HighlightEntry(entry)
return 1
else
call eclim#util#EchoWarning('Target file is no longer open.')
endif
endfunction " }}}
function s:Diff() " {{{
" Diff the contents of the revision under the cursor against the current
" contents.
let hist_buf = bufnr('%')
let winend = winnr('$')
let winnum = 1
while winnum <= winend
let bufnr = winbufnr(winnum)
if getbufvar(bufnr, 'history_diff') != ''
exec bufnr . 'bd'
continue
endif
let winnum += 1
endwhile
call eclim#util#GoToBufferWindow(hist_buf)
let current = b:filename
let orien = g:EclimHistoryDiffOrientation == 'horizontal' ? '' : 'vertical'
if s:View(orien . ' below split')
let b:history_diff = 1
diffthis
augroup history_diff
autocmd! BufWinLeave
call eclim#util#GoToBufferWindowRegister(current)
autocmd BufWinLeave diffoff
augroup END
call eclim#util#GoToBufferWindow(current)
diffthis
endif
endfunction " }}}
function s:DiffNextPrev(dir, count) " {{{
let winnr = winnr()
if eclim#util#GoToBufferWindow('[History]')
let num = v:count > 0 ? v:count : a:count
let cur = exists('b:history_current_entry') ? b:history_current_entry : 0
let index = cur + (a:dir * num)
if index < 0 || index > len(b:history_revisions)
call eclim#util#EchoError('Operation exceeds history stack range.')
exec winnr . 'winc w'
return
endif
call cursor(index + 1, 0)
call s:Diff()
endif
endfunction " }}}
function s:Revert() " {{{
" Revert the file to the revision under the cursor.
if line('.') == 1 || line('.') > len(b:history_revisions)
return
endif
let current = b:filename
let revision = b:history_revisions[line('.') - 1]
if eclim#util#GoToBufferWindow(current)
let project = eclim#project#util#GetCurrentProjectName()
let file = eclim#project#util#GetProjectRelativeFilePath()
let command = s:command_revision
let command = substitute(command, '', project, '')
let command = substitute(command, '', file, '')
let command = substitute(command, '', revision, '')
let result = eclim#Execute(command)
if result == "0"
return
endif
let ff = &ff
let temp = tempname()
call writefile(split(result, '\n'), temp)
try
silent 1,$delete _
silent read ++edit `=temp`
silent 1,1delete _
finally
call delete(temp)
endtry
if ff != &ff
call eclim#util#EchoWarning(
\ "Warning: the file format is being reverted from '" . ff . "' to '" .
\ &ff . "'. Using vim's undo will not restore the previous format so " .
\ "if you choose to undo the reverting of this file, you will need to " .
\ "manually set the file format back to " . ff . " (set ff=" . ff . ").")
endif
endif
endfunction " }}}
function s:Clear(prompt, ...) " {{{
" Optional args:
" filename
let response = 1
if a:prompt
let response = eclim#util#PromptConfirm(
\ 'Clear local history?', g:EclimHighlightInfo)
endif
if response == 1
let filename = len(a:000) > 0 ? a:000[0] : b:filename
let current = eclim#project#util#GetProjectRelativeFilePath(filename)
let project = eclim#project#util#GetCurrentProjectName()
let command = s:command_clear
let command = substitute(command, '', project, '')
let command = substitute(command, '', current, '')
let result = eclim#Execute(command)
if result == "0"
return
endif
if filename != expand('%:p')
quit
endif
call eclim#util#Echo(result)
endif
endfunction " }}}
function! s:Syntax() " {{{
set ft=eclim_history
hi link HistoryFile Identifier
hi link HistoryCurrentEntry Constant
syntax match HistoryFile /.*\%1l.*/
syntax match Comment /^".*/
endfunction " }}}
function s:HighlightEntry(index) " {{{
let winnr = winnr()
if eclim#util#GoToBufferWindow('[History]')
let b:history_current_entry = a:index
try
" forces reset of syntax
call s:Syntax()
exec 'syntax match HistoryCurrentEntry /.*\%' . (a:index + 1) . 'l.*/'
finally
exec winnr . 'winc w'
endtry
endif
endfunction " }}}
" vim:ft=vim:fdm=marker