From f2e08dbeb3ed54eca3e08cf418eb1da09fc8f2cc Mon Sep 17 00:00:00 2001 From: Andy Stewart Date: Fri, 24 Jan 2014 11:47:11 +0100 Subject: [PATCH] Move git-tracking check into diff command. This avoids shelling out twice per buffer: once to check whether git knows about the file and once to perform the diff. Now we simply do both in one external call. Profiling showed external calls to git taking ~20ms. This doesn't seem too bad but it adds up. --- autoload/diff.vim | 21 ++++++++++++++++++--- autoload/utility.vim | 8 +------- plugin/gitgutter.vim | 34 +++++++++++++++++++--------------- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/autoload/diff.vim b/autoload/diff.vim index f5fbbe1..2367390 100644 --- a/autoload/diff.vim +++ b/autoload/diff.vim @@ -4,17 +4,25 @@ let s:hunk_re = '^@@ -\(\d\+\),\?\(\d*\) +\(\d\+\),\?\(\d*\) @@' function! diff#run_diff(realtime, use_external_grep) + let cmd = 'git ls-files --error-unmatch' . utility#discard_stdout_and_stderr() . ' ' . shellescape(utility#file()) . ' && ' + if a:realtime let blob_name = ':./' . fnamemodify(utility#file(),':t') let blob_file = tempname() - let cmd = 'git show ' . blob_name . ' > ' . blob_file . ' && diff -U0 ' . g:gitgutter_diff_args . ' ' . blob_file . ' - ' + let cmd .= 'git show ' . blob_name . ' > ' . blob_file . + \ ' && diff -U0 ' . g:gitgutter_diff_args . ' ' . blob_file . ' - ' else - let cmd = 'git diff --no-ext-diff --no-color -U0 ' . g:gitgutter_diff_args . ' ' . shellescape(utility#file()) + let cmd .= 'git diff --no-ext-diff --no-color -U0 ' . g:gitgutter_diff_args . ' ' . shellescape(utility#file()) endif + if a:use_external_grep && s:grep_available - let cmd .= s:grep_command + " grep exits with 1 when no matches are found. However we want to treat + " non-matches as non-erroneous behaviour; so we append ` || :`. + let cmd .= s:grep_command . ' || :' endif + let cmd = utility#escape(cmd) + if a:realtime if &fileformat ==# "dos" let eol = "\r\n" @@ -28,6 +36,13 @@ function! diff#run_diff(realtime, use_external_grep) else let diff = system(utility#command_in_directory_of_file(cmd)) endif + + if v:shell_error + " A shell error indicates the file is not tracked by git (unless something + " bizarre is going on). + throw 'git-diff failed' + endif + return diff endfunction diff --git a/autoload/utility.vim b/autoload/utility.vim index 2db11d9..5ce00f4 100644 --- a/autoload/utility.vim +++ b/autoload/utility.vim @@ -1,7 +1,7 @@ let s:file = '' function! utility#is_active() - return g:gitgutter_enabled && utility#exists_file() && utility#is_tracked_by_git() + return g:gitgutter_enabled && utility#exists_file() endfunction function! utility#current_file() @@ -64,12 +64,6 @@ function! utility#command_in_directory_of_file(cmd) return substitute(utility#cmd_in_dir, "'", '"', 'g') endfunction -function! utility#is_tracked_by_git() - let cmd = utility#escape('git ls-files --error-unmatch' . utility#discard_stdout_and_stderr() . ' ' . shellescape(utility#file())) - call system(utility#command_in_directory_of_file(cmd)) - return !v:shell_error -endfunction - function! utility#differences(hunks) return len(a:hunks) != 0 endfunction diff --git a/plugin/gitgutter.vim b/plugin/gitgutter.vim index a3e1837..7daf185 100644 --- a/plugin/gitgutter.vim +++ b/plugin/gitgutter.vim @@ -55,26 +55,30 @@ command GitGutterAll call GitGutterAll() function! GitGutter(file, realtime) call utility#set_file(a:file) if utility#is_active() - if !a:realtime || utility#has_fresh_changes(a:file) - let diff = diff#run_diff(a:realtime || utility#has_unsaved_changes(a:file), 1) - let s:hunks = diff#parse_diff(diff) - let modified_lines = diff#process_hunks(s:hunks) + try + if !a:realtime || utility#has_fresh_changes(a:file) + let diff = diff#run_diff(a:realtime || utility#has_unsaved_changes(a:file), 1) + let s:hunks = diff#parse_diff(diff) + let modified_lines = diff#process_hunks(s:hunks) - if g:gitgutter_signs - if g:gitgutter_sign_column_always - call sign#add_dummy_sign() - else - if utility#differences(s:hunks) - call sign#add_dummy_sign() " prevent flicker + if g:gitgutter_signs + if g:gitgutter_sign_column_always + call sign#add_dummy_sign() else - call sign#remove_dummy_sign() + if utility#differences(s:hunks) + call sign#add_dummy_sign() " prevent flicker + else + call sign#remove_dummy_sign() + endif endif + call sign#update_signs(a:file, modified_lines) endif - call sign#update_signs(a:file, modified_lines) - endif - call utility#save_last_seen_change(a:file) - endif + call utility#save_last_seen_change(a:file) + endif + catch /git-diff failed/ + call hunk#reset() + endtry else call hunk#reset() endif