Neovim: run diffs asynchronously.

This commit is contained in:
Andy Stewart
2016-02-08 14:19:09 +00:00
parent 0416f209d8
commit 18b7836168
4 changed files with 83 additions and 26 deletions

View File

@@ -5,6 +5,7 @@ A Vim plugin which shows a git diff in the 'gutter' (sign column). It shows whe
Features: Features:
* Shows signs for added, modified, and removed lines. * Shows signs for added, modified, and removed lines.
* Neovim: runs the diffs asynchronously.
* Ensures signs are always as up to date as possible (but without running more than necessary). * Ensures signs are always as up to date as possible (but without running more than necessary).
* Quick jumping between blocks of changed lines ("hunks"). * Quick jumping between blocks of changed lines ("hunks").
* Stage/revert/preview individual hunks. * Stage/revert/preview individual hunks.

View File

@@ -20,20 +20,9 @@ function! gitgutter#process_buffer(bufnr, realtime)
try try
if !a:realtime || gitgutter#utility#has_fresh_changes() if !a:realtime || gitgutter#utility#has_fresh_changes()
let diff = gitgutter#diff#run_diff(a:realtime || gitgutter#utility#has_unsaved_changes(), 1) let diff = gitgutter#diff#run_diff(a:realtime || gitgutter#utility#has_unsaved_changes(), 1)
call gitgutter#hunk#set_hunks(gitgutter#diff#parse_diff(diff)) if diff != 'async'
let modified_lines = gitgutter#diff#process_hunks(gitgutter#hunk#hunks()) call gitgutter#handle_diff(diff)
if len(modified_lines) > g:gitgutter_max_signs
call gitgutter#utility#warn_once('exceeded maximum number of signs (configured by g:gitgutter_max_signs).', 'max_signs')
call gitgutter#sign#clear_signs()
return
endif endif
if g:gitgutter_signs || g:gitgutter_highlight_lines
call gitgutter#sign#update_signs(modified_lines)
endif
call gitgutter#utility#save_last_seen_change()
endif endif
catch /diff failed/ catch /diff failed/
call gitgutter#hunk#reset() call gitgutter#hunk#reset()
@@ -43,6 +32,46 @@ function! gitgutter#process_buffer(bufnr, realtime)
endif endif
endfunction endfunction
function! gitgutter#handle_diff_job(job_id, data, event)
if a:event == 'stdout'
" a:data is a list
call gitgutter#utility#job_output_received(a:job_id, 'stdout')
call gitgutter#handle_diff(join(a:data,"\n")."\n")
elseif a:event == 'exit'
" If the exit event is triggered without a preceding stdout event,
" the diff was empty.
if gitgutter#utility#is_pending_job(a:job_id)
call gitgutter#handle_diff("")
call gitgutter#utility#job_output_received(a:job_id, 'exit')
endif
else
call gitgutter#hunk#reset()
call gitgutter#utility#job_output_received(a:job_id, 'stderr')
endif
endfunction
function! gitgutter#handle_diff(diff)
call gitgutter#hunk#set_hunks(gitgutter#diff#parse_diff(a:diff))
let modified_lines = gitgutter#diff#process_hunks(gitgutter#hunk#hunks())
if len(modified_lines) > g:gitgutter_max_signs
call gitgutter#utility#warn_once('exceeded maximum number of signs (configured by g:gitgutter_max_signs).', 'max_signs')
call gitgutter#sign#clear_signs()
return
endif
if g:gitgutter_signs || g:gitgutter_highlight_lines
call gitgutter#sign#update_signs(modified_lines)
endif
call gitgutter#utility#save_last_seen_change()
endfunction
function! gitgutter#disable() function! gitgutter#disable()
" get list of all buffers (across all tabs) " get list of all buffers (across all tabs)
let buflist = [] let buflist = []

View File

@@ -116,23 +116,35 @@ function! gitgutter#diff#run_diff(realtime, use_external_grep)
endif endif
end end
let diff = gitgutter#utility#system(gitgutter#utility#command_in_directory_of_file(cmd))
if a:realtime
call delete(blob_file)
call delete(buff_file)
endif
if gitgutter#utility#shell_error()
" A shell error indicates the file is not tracked by git (unless something bizarre is going on).
throw 'diff failed'
endif
if !tracked if !tracked
call setbufvar(bufnr, 'gitgutter_tracked', 1) call setbufvar(bufnr, 'gitgutter_tracked', 1)
endif endif
return diff if has('nvim') && a:use_external_grep
let cmd = gitgutter#utility#command_in_directory_of_file(cmd)
" Note that when `cmd` doesn't produce any output, i.e. the diff is empty,
" the `stdout` event is not fired on the job handler. Therefore we keep
" track of the jobs ourselves so we can spot empty diffs.
let job_id = jobstart([&shell, '-c', cmd], {
\ 'on_stdout': function('gitgutter#handle_diff_job'),
\ 'on_stderr': function('gitgutter#handle_diff_job'),
\ 'on_exit': function('gitgutter#handle_diff_job')
\ })
call gitgutter#utility#pending_job(job_id)
return 'async'
else
let diff = gitgutter#utility#system(gitgutter#utility#command_in_directory_of_file(cmd))
if gitgutter#utility#shell_error()
" A shell error indicates the file is not tracked by git (unless something bizarre is going on).
throw 'diff failed'
endif
return diff
endif
if a:realtime
" call delete(blob_file)
" call delete(buff_file)
endif
endfunction endfunction
function! gitgutter#diff#parse_diff(diff) function! gitgutter#diff#parse_diff(diff)

View File

@@ -2,6 +2,7 @@ let s:file = ''
let s:using_xolox_shell = -1 let s:using_xolox_shell = -1
let s:exit_code = 0 let s:exit_code = 0
let s:fish = &shell =~# 'fish' let s:fish = &shell =~# 'fish'
let s:jobs = {}
function! gitgutter#utility#warn(message) function! gitgutter#utility#warn(message)
echohl WarningMsg echohl WarningMsg
@@ -162,3 +163,17 @@ endfunction
function! gitgutter#utility#strip_trailing_new_line(line) function! gitgutter#utility#strip_trailing_new_line(line)
return substitute(a:line, '\n$', '', '') return substitute(a:line, '\n$', '', '')
endfunction endfunction
function! gitgutter#utility#pending_job(job_id)
let s:jobs[a:job_id] = 1
endfunction
function! gitgutter#utility#is_pending_job(job_id)
return has_key(s:jobs, a:job_id)
endfunction
function! gitgutter#utility#job_output_received(job_id, event)
if has_key(s:jobs, a:job_id)
unlet s:jobs[a:job_id]
endif
endfunction