fe8b5eb4c5
Commit cc2b17d462c9460c2f5f4a0d71a3edf6e6a71987 removed the '&&' used to check whether the p4 info command succeeded. This caused incorrect invocation of the p4 diff command. Add back the check for p4 info command success. Prior to this commit the command invoked was: p4 info >/dev/null 2>&1 env P4DIFF= P4COLORS= p4 diff -du0 This commit makes the invocation as: p4 info >/dev/null 2>&1 && env P4DIFF= P4COLORS= p4 diff -du0
482 lines
15 KiB
VimL
482 lines
15 KiB
VimL
" vim: et sw=2 sts=2
|
|
|
|
scriptencoding utf-8
|
|
|
|
" Function: #detect {{{1
|
|
function! sy#repo#detect() abort
|
|
for vcs in s:vcs_list
|
|
let b:sy.detecting += 1
|
|
call sy#repo#get_diff_start(vcs)
|
|
endfor
|
|
endfunction
|
|
|
|
" Function: s:callback_nvim_stdout{{{1
|
|
function! s:callback_nvim_stdout(_job_id, data, _event) dict abort
|
|
if empty(self.stdoutbuf) || empty(self.stdoutbuf[-1])
|
|
let self.stdoutbuf += a:data
|
|
else
|
|
let self.stdoutbuf = self.stdoutbuf[:-2]
|
|
\ + [self.stdoutbuf[-1] . get(a:data, 0, '')]
|
|
\ + a:data[1:]
|
|
endif
|
|
endfunction
|
|
|
|
" Function: s:callback_nvim_exit {{{1
|
|
function! s:callback_nvim_exit(_job_id, exitval, _event) dict abort
|
|
call s:job_exit(self.bufnr, self.vcs, a:exitval, self.stdoutbuf)
|
|
endfunction
|
|
|
|
" Function: s:callback_vim_stdout {{{1
|
|
function! s:callback_vim_stdout(_job_id, data) dict abort
|
|
let self.stdoutbuf += [a:data]
|
|
endfunction
|
|
|
|
" Function: s:callback_vim_close {{{1
|
|
function! s:callback_vim_close(channel) dict abort
|
|
let job = ch_getjob(a:channel)
|
|
while 1
|
|
if job_status(job) == 'dead'
|
|
let exitval = job_info(job).exitval
|
|
break
|
|
endif
|
|
sleep 10m
|
|
endwhile
|
|
call s:job_exit(self.bufnr, self.vcs, exitval, self.stdoutbuf)
|
|
endfunction
|
|
|
|
" Function: s:job_exit {{{1
|
|
function! s:job_exit(bufnr, vcs, exitval, diff) abort
|
|
call sy#verbose('job_exit()', a:vcs)
|
|
let sy = getbufvar(a:bufnr, 'sy')
|
|
if empty(sy)
|
|
call sy#verbose(printf('No b:sy found for %s', bufname(a:bufnr)), a:vcs)
|
|
return
|
|
elseif !empty(sy.updated_by) && sy.updated_by != a:vcs
|
|
call sy#verbose(printf('Signs already got updated by %s.', sy.updated_by), a:vcs)
|
|
return
|
|
elseif empty(sy.vcs) && sy.active
|
|
let sy.detecting -= 1
|
|
endif
|
|
call sy#repo#get_diff_{a:vcs}(sy, a:exitval, a:diff)
|
|
call setbufvar(a:bufnr, 'sy_job_id_'.a:vcs, 0)
|
|
endfunction
|
|
|
|
" Function: sy#get_diff_start {{{1
|
|
function! sy#repo#get_diff_start(vcs) abort
|
|
call sy#verbose('get_diff_start()', a:vcs)
|
|
|
|
let job_id = get(b:, 'sy_job_id_'.a:vcs)
|
|
" Neovim
|
|
if has('nvim')
|
|
if job_id
|
|
silent! call jobstop(job_id)
|
|
endif
|
|
|
|
let [cmd, options] = s:initialize_job(a:vcs)
|
|
|
|
call sy#verbose(printf('CMD: %s | CWD: %s', string(cmd), b:sy.info.dir), a:vcs)
|
|
let b:sy_job_id_{a:vcs} = jobstart(cmd, extend(options, {
|
|
\ 'cwd': b:sy.info.dir,
|
|
\ 'on_stdout': function('s:callback_nvim_stdout'),
|
|
\ 'on_exit': function('s:callback_nvim_exit'),
|
|
\ }))
|
|
|
|
" Newer Vim
|
|
elseif has('patch-7.4.1967')
|
|
if type(job_id) != type(0)
|
|
silent! call job_stop(job_id)
|
|
endif
|
|
|
|
let [cmd, options] = s:initialize_job(a:vcs)
|
|
let [cwd, chdir] = sy#util#chdir()
|
|
|
|
try
|
|
execute chdir fnameescape(b:sy.info.dir)
|
|
call sy#verbose(printf('CMD: %s | CWD: %s', string(cmd), getcwd()), a:vcs)
|
|
let opts = {
|
|
\ 'in_io': 'null',
|
|
\ 'out_cb': function('s:callback_vim_stdout', options),
|
|
\ 'close_cb': function('s:callback_vim_close', options),
|
|
\ }
|
|
let b:sy_job_id_{a:vcs} = job_start(cmd, opts)
|
|
finally
|
|
execute chdir fnameescape(cwd)
|
|
endtry
|
|
|
|
" Older Vim
|
|
else
|
|
let diff = split(s:run(a:vcs), '\n')
|
|
call sy#repo#get_diff_{a:vcs}(b:sy, v:shell_error, diff)
|
|
endif
|
|
endfunction
|
|
|
|
" Function: s:get_diff_end {{{1
|
|
function! s:get_diff_end(sy, found_diff, vcs, diff) abort
|
|
call sy#verbose('get_diff_end()', a:vcs)
|
|
if a:found_diff
|
|
if index(a:sy.vcs, a:vcs) == -1
|
|
let a:sy.vcs += [a:vcs]
|
|
endif
|
|
call sy#set_signs(a:sy, a:vcs, a:diff)
|
|
else
|
|
call sy#verbose('No valid diff found. Disabling this VCS.', a:vcs)
|
|
endif
|
|
endfunction
|
|
|
|
" Function: #get_diff_git {{{1
|
|
function! sy#repo#get_diff_git(sy, exitval, diff) abort
|
|
call sy#verbose('get_diff_git()', 'git')
|
|
let [found_diff, diff] = a:exitval ? [0, []] : [1, a:diff]
|
|
call s:get_diff_end(a:sy, found_diff, 'git', diff)
|
|
endfunction
|
|
|
|
" Function: #get_diff_hg {{{1
|
|
function! sy#repo#get_diff_hg(sy, exitval, diff) abort
|
|
call sy#verbose('get_diff_hg()', 'hg')
|
|
let [found_diff, diff] = a:exitval ? [0, []] : [1, a:diff]
|
|
call s:get_diff_end(a:sy, found_diff, 'hg', diff)
|
|
endfunction
|
|
|
|
" Function: #get_diff_svn {{{1
|
|
function! sy#repo#get_diff_svn(sy, exitval, diff) abort
|
|
call sy#verbose('get_diff_svn()', 'svn')
|
|
let [found_diff, diff] = a:exitval ? [0, []] : [1, a:diff]
|
|
call s:get_diff_end(a:sy, found_diff, 'svn', diff)
|
|
endfunction
|
|
|
|
" Function: #get_diff_bzr {{{1
|
|
function! sy#repo#get_diff_bzr(sy, exitval, diff) abort
|
|
call sy#verbose('get_diff_bzr()', 'bzr')
|
|
let [found_diff, diff] = (a:exitval =~ '[012]') ? [1, a:diff] : [0, []]
|
|
call s:get_diff_end(a:sy, found_diff, 'bzr', diff)
|
|
endfunction
|
|
|
|
" Function: #get_diff_darcs {{{1
|
|
function! sy#repo#get_diff_darcs(sy, exitval, diff) abort
|
|
call sy#verbose('get_diff_darcs()', 'darcs')
|
|
let [found_diff, diff] = a:exitval ? [0, []] : [1, a:diff]
|
|
call s:get_diff_end(a:sy, found_diff, 'darcs', diff)
|
|
endfunction
|
|
|
|
" Function: #get_diff_fossil {{{1
|
|
function! sy#repo#get_diff_fossil(sy, exitval, diff) abort
|
|
call sy#verbose('get_diff_fossil()', 'fossil')
|
|
let [found_diff, diff] = a:exitval ? [0, []] : [1, a:diff]
|
|
call s:get_diff_end(a:sy, found_diff, 'fossil', diff)
|
|
endfunction
|
|
|
|
" Function: #get_diff_cvs {{{1
|
|
function! sy#repo#get_diff_cvs(sy, exitval, diff) abort
|
|
call sy#verbose('get_diff_cvs()', 'cvs')
|
|
let [found_diff, diff] = [0, []]
|
|
if a:exitval == 1
|
|
for diffline in a:diff
|
|
if diffline =~ '^+++'
|
|
let [found_diff, diff] = [1, a:diff]
|
|
break
|
|
endif
|
|
endfor
|
|
endif
|
|
call s:get_diff_end(a:sy, found_diff, 'cvs', diff)
|
|
endfunction
|
|
|
|
" Function: #get_diff_rcs {{{1
|
|
function! sy#repo#get_diff_rcs(sy, exitval, diff) abort
|
|
call sy#verbose('get_diff_rcs()', 'rcs')
|
|
let [found_diff, diff] = a:exitval == 2 ? [0, []] : [1, a:diff]
|
|
call s:get_diff_end(a:sy, found_diff, 'rcs', diff)
|
|
endfunction
|
|
|
|
" Function: #get_diff_accurev {{{1
|
|
function! sy#repo#get_diff_accurev(sy, exitval, diff) abort
|
|
call sy#verbose('get_diff_accurev()', 'accurev')
|
|
let [found_diff, diff] = (a:exitval >= 2) ? [0, []] : [1, a:diff]
|
|
call s:get_diff_end(a:sy, found_diff, 'accurev', diff)
|
|
endfunction
|
|
|
|
" Function: #get_diff_perforce {{{1
|
|
function! sy#repo#get_diff_perforce(sy, exitval, diff) abort
|
|
call sy#verbose('get_diff_perforce()', 'perforce')
|
|
let [found_diff, diff] = a:exitval ? [0, []] : [1, a:diff]
|
|
call s:get_diff_end(a:sy, found_diff, 'perforce', diff)
|
|
endfunction
|
|
|
|
" Function: #get_diff_tfs {{{1
|
|
function! sy#repo#get_diff_tfs(sy, exitval, diff) abort
|
|
call sy#verbose('get_diff_tfs()', 'tfs')
|
|
let [found_diff, diff] = a:exitval ? [0, []] : [1, s:strip_context(a:diff)]
|
|
call s:get_diff_end(a:sy, found_diff, 'tfs', diff)
|
|
endfunction
|
|
|
|
" Function: #get_stats {{{1
|
|
function! sy#repo#get_stats() abort
|
|
return exists('b:sy') ? b:sy.stats : [-1, -1, -1]
|
|
endfunction
|
|
|
|
" Function: #debug_detection {{{1
|
|
function! sy#repo#debug_detection()
|
|
if !exists('b:sy')
|
|
echomsg 'signify: I cannot detect any changes!'
|
|
return
|
|
endif
|
|
|
|
for vcs in s:vcs_list
|
|
let cmd = s:expand_cmd(vcs, g:signify_vcs_cmds)
|
|
echohl Statement
|
|
echo cmd
|
|
echo repeat('=', len(cmd))
|
|
echohl NONE
|
|
|
|
let diff = s:run(vcs)
|
|
if v:shell_error
|
|
echohl ErrorMsg
|
|
echo diff
|
|
echohl NONE
|
|
else
|
|
echo empty(diff) ? "<none>" : diff
|
|
endif
|
|
echo "\n"
|
|
endfor
|
|
endfunction
|
|
|
|
" Function: #diffmode {{{1
|
|
function! sy#repo#diffmode() abort
|
|
execute sy#util#return_if_no_changes()
|
|
|
|
let vcs = b:sy.updated_by
|
|
if !has_key(g:signify_vcs_cmds_diffmode, vcs)
|
|
echomsg 'SignifyDiff has no support for: '. vcs
|
|
echomsg 'Open an issue for it at: https://github.com/mhinz/vim-signify/issues'
|
|
return
|
|
endif
|
|
let cmd = s:expand_cmd(vcs, g:signify_vcs_cmds_diffmode)
|
|
call sy#verbose('SignifyDiff: '. cmd, vcs)
|
|
let ft = &filetype
|
|
tabedit %
|
|
diffthis
|
|
let [cwd, chdir] = sy#util#chdir()
|
|
try
|
|
execute chdir fnameescape(b:sy.info.dir)
|
|
leftabove vnew
|
|
silent put =system(cmd)
|
|
finally
|
|
execute chdir fnameescape(cwd)
|
|
endtry
|
|
silent 1delete
|
|
diffthis
|
|
set buftype=nofile bufhidden=wipe nomodified
|
|
let &filetype = ft
|
|
wincmd p
|
|
silent! %foldopen!
|
|
normal! ]czt
|
|
endfunction
|
|
|
|
" Function: s:initialize_job {{{1
|
|
function! s:initialize_job(vcs) abort
|
|
let vcs_cmd = s:expand_cmd(a:vcs, g:signify_vcs_cmds)
|
|
if has('win32')
|
|
if has('nvim')
|
|
let cmd = &shell =~ 'cmd' ? vcs_cmd : ['sh', '-c', vcs_cmd]
|
|
else
|
|
let cmd = join([&shell, &shellcmdflag, vcs_cmd])
|
|
endif
|
|
else
|
|
let cmd = ['sh', '-c', vcs_cmd]
|
|
endif
|
|
let options = {
|
|
\ 'stdoutbuf': [],
|
|
\ 'vcs': a:vcs,
|
|
\ 'bufnr': bufnr('%'),
|
|
\ }
|
|
return [cmd, options]
|
|
endfunction
|
|
|
|
" Function: s:get_vcs_path {{{1
|
|
function! s:get_vcs_path(vcs) abort
|
|
return (a:vcs =~# '\v(git|cvs|accurev|tfs)') ? b:sy.info.file : b:sy.info.path
|
|
endfunction
|
|
|
|
" Function: s:expand_cmd {{{1
|
|
function! s:expand_cmd(vcs, vcs_cmds) abort
|
|
let cmd = a:vcs_cmds[a:vcs]
|
|
let cmd = s:replace(cmd, '%f', s:get_vcs_path(a:vcs))
|
|
let cmd = s:replace(cmd, '%d', s:difftool)
|
|
let cmd = s:replace(cmd, '%n', s:devnull)
|
|
return cmd
|
|
endfunction
|
|
|
|
" Function: s:run {{{1
|
|
function! s:run(vcs)
|
|
let [cwd, chdir] = sy#util#chdir()
|
|
try
|
|
execute chdir fnameescape(b:sy.info.dir)
|
|
let ret = system(s:expand_cmd(a:vcs, g:signify_vcs_cmds))
|
|
catch
|
|
" This exception message can be seen via :SignifyDebugUnknown.
|
|
" E.g. unquoted VCS programs in vcd_cmds can lead to E484.
|
|
let ret = v:exception .' at '. v:throwpoint
|
|
finally
|
|
execute chdir fnameescape(cwd)
|
|
return ret
|
|
endtry
|
|
endfunction
|
|
|
|
" Function: s:replace {{{1
|
|
function! s:replace(cmd, pat, sub)
|
|
let parts = split(a:cmd, a:pat, 1)
|
|
return join(parts, a:sub)
|
|
endfunction
|
|
|
|
" Function: s:strip_context {{{1
|
|
function! s:strip_context(context)
|
|
let diff = []
|
|
let hunk = []
|
|
let state = 0
|
|
let lines = a:context
|
|
let linenr = 0
|
|
|
|
while linenr < len(lines)
|
|
let line = lines[linenr]
|
|
|
|
if state == 0
|
|
if line =~ "^@@ "
|
|
let tokens = matchlist(line, '^@@ -\v(\d+),?(\d*) \+(\d+),?(\d*)')
|
|
let old_line = str2nr(tokens[1])
|
|
let new_line = str2nr(tokens[3])
|
|
let old_count = empty(tokens[2]) ? 1 : str2nr(tokens[2])
|
|
let new_count = empty(tokens[4]) ? 1 : str2nr(tokens[4])
|
|
let hunk = []
|
|
let state = 1
|
|
else
|
|
call add(diff,line)
|
|
endif
|
|
let linenr += 1
|
|
elseif index([1,2,3],state) >= 0 && index(['\','/'],line[0]) >= 0
|
|
let linenr += 1
|
|
call add(hunk,line)
|
|
elseif state == 1
|
|
if line[0] == ' '
|
|
let old_line += 1
|
|
let new_line += 1
|
|
let old_count -= 1
|
|
let new_count -= 1
|
|
let linenr += 1
|
|
else
|
|
let old_count_part = 0
|
|
let new_count_part = 0
|
|
let state = 2
|
|
endif
|
|
elseif state == 2
|
|
if line[0] == '-'
|
|
call add(hunk,line)
|
|
let old_count_part += 1
|
|
let linenr += 1
|
|
else
|
|
let state = 3
|
|
endif
|
|
elseif state == 3
|
|
if line[0] == '+'
|
|
call add(hunk,line)
|
|
let new_count_part += 1
|
|
let linenr += 1
|
|
else
|
|
call add(diff, printf("@@ -%d%s +%d%s @@",(old_count_part == 0 && old_line > 0) ? old_line -1 : old_line, old_count_part == 1 ? "" : printf(",%d", old_count_part), (new_count_part == 0 && new_line > 0) ? new_line - 1 : new_line, new_count_part == 1 ? "" : printf(",%d", new_count_part)))
|
|
let diff += hunk
|
|
let hunk = []
|
|
let old_count -= old_count_part
|
|
let new_count -= new_count_part
|
|
let old_line += old_count_part
|
|
let new_line += new_count_part
|
|
let state = 1
|
|
endif
|
|
endif
|
|
|
|
if state > 0 && new_count <= 0 && old_count <= 0
|
|
if len(hunk) > 0
|
|
call add(diff, printf("@@ -%d%s +%d%s @@",(old_count_part == 0 && old_line > 0) ? old_line -1 : old_line, old_count_part == 1 ? "" : printf(",%d", old_count_part), (new_count_part == 0 && new_line > 0) ? new_line - 1 : new_line, new_count_part == 1 ? "" : printf(",%d", new_count_part)))
|
|
let diff = diff + hunk
|
|
let hunk = []
|
|
endif
|
|
let state = 0
|
|
endif
|
|
endwhile
|
|
if len(hunk) > 0
|
|
call add(diff, printf("@@ -%d%s +%d%s @@",(old_count_part == 0 && old_line > 0) ? old_line -1 : old_line, old_count_part == 1 ? "" : printf(",%d", old_count_part), (new_count_part == 0 && new_line > 0) ? new_line - 1 : new_line, new_count_part == 1 ? "" : printf(",%d", new_count_part)))
|
|
let diff = diff + hunk
|
|
let hunk = []
|
|
endif
|
|
return diff
|
|
endfunction
|
|
|
|
" Variables {{{1
|
|
let s:difftool = get(g:, 'signify_difftool', 'diff')
|
|
if executable(s:difftool)
|
|
let s:vcs_dict = {
|
|
\ 'git': 'git',
|
|
\ 'hg': 'hg',
|
|
\ 'svn': 'svn',
|
|
\ 'darcs': 'darcs',
|
|
\ 'bzr': 'bzr',
|
|
\ 'fossil': 'fossil',
|
|
\ 'cvs': 'cvs',
|
|
\ 'rcs': 'rcsdiff',
|
|
\ 'accurev': 'accurev',
|
|
\ 'perforce': 'p4',
|
|
\ 'tfs': 'tf'
|
|
\ }
|
|
else
|
|
call sy#verbose('No "diff" executable found. Disable support for svn, darcs, bzr, fossil.')
|
|
let s:vcs_dict = {
|
|
\ 'git': 'git',
|
|
\ 'hg': 'hg',
|
|
\ 'cvs': 'cvs',
|
|
\ 'rcs': 'rcsdiff',
|
|
\ 'accurev': 'accurev',
|
|
\ 'perforce': 'p4',
|
|
\ 'tfs': 'tf'
|
|
\ }
|
|
endif
|
|
|
|
let s:vcs_list = get(g:, 'signify_vcs_list', [])
|
|
if empty(s:vcs_list)
|
|
let s:vcs_list = keys(filter(s:vcs_dict, 'executable(v:val)'))
|
|
endif
|
|
|
|
let s:default_vcs_cmds = {
|
|
\ 'git': 'git diff --no-color --no-ext-diff -U0 -- %f',
|
|
\ 'hg': 'hg diff --config extensions.color=! --config defaults.diff= --nodates -U0 -- %f',
|
|
\ 'svn': 'svn diff --diff-cmd %d -x -U0 -- %f',
|
|
\ 'bzr': 'bzr diff --using %d --diff-options=-U0 -- %f',
|
|
\ 'darcs': 'darcs diff --no-pause-for-gui --no-unified --diff-opts=-U0 -- %f',
|
|
\ 'fossil': 'fossil set diff-command "%d -U 0" && fossil diff --unified -c 0 -- %f',
|
|
\ 'cvs': 'cvs diff -U0 -- %f',
|
|
\ 'rcs': 'rcsdiff -U0 %f 2>%n',
|
|
\ 'accurev': 'accurev diff %f -- -U0',
|
|
\ 'perforce': 'p4 info '. sy#util#shell_redirect('%n') . (has('win32') ? ' &&' : ' && env P4DIFF= P4COLORS=') .' p4 diff -du0 %f',
|
|
\ 'tfs': 'tf diff -version:W -noprompt -format:Unified %f'
|
|
\ }
|
|
|
|
let s:default_vcs_cmds_diffmode = {
|
|
\ 'git': 'git show HEAD:./%f',
|
|
\ 'hg': 'hg cat %f',
|
|
\ 'svn': 'svn cat %f',
|
|
\ 'bzr': 'bzr cat %f',
|
|
\ 'darcs': 'darcs show contents -- %f',
|
|
\ 'cvs': 'cvs up -p -- %f 2>%n',
|
|
\ 'perforce': 'p4 print %f',
|
|
\ }
|
|
|
|
if exists('g:signify_vcs_cmds')
|
|
call extend(g:signify_vcs_cmds, s:default_vcs_cmds, 'keep')
|
|
else
|
|
let g:signify_vcs_cmds = s:default_vcs_cmds
|
|
endif
|
|
if exists('g:signify_vcs_cmds_diffmode')
|
|
call extend(g:signify_vcs_cmds_diffmode, s:default_vcs_cmds_diffmode, 'keep')
|
|
else
|
|
let g:signify_vcs_cmds_diffmode = s:default_vcs_cmds_diffmode
|
|
endif
|
|
|
|
let s:difftool = sy#util#escape(s:difftool)
|
|
let s:devnull = has('win32') || has ('win64') ? 'NUL' : '/dev/null'
|