Reputation: 33
I'm trying to add the result of the following command to my diy vim status line
git diff --numstat <filename>
I've tried a bunch of methods, all of which have failed, almost the same way. Example:
function! GetGitDiffSummary()
let l:adds = "+".system("git diff --numstat -- % | awk '{print($1)}'")
let l:subs = "-".system("git diff --numstat -- % | awk '{print($2)}'")
return l:adds."/".l:subs
endfunction
And then try to use it like this:
set statusline+=\ \ %{GetGitDiffSummary()}\ \
Problem 1: the values themselves don't really show up, I just see +/- without any values. Problem 2: when I press and hold keys that move the cursor (arrow keys & hjkl) I get the respective characters printed out. They don't change the contents of the file, but I still see them.
Quitting and reopening the file doesn't display the weird chars anymore, but if I press and hold up/down/j/k again, I see them again in my file.
Upvotes: 0
Views: 178
Reputation:
One problem is that the %
character only turns into the current buffer in Vim's command-line, but not when evaluated through system
. Instead, you should put expand('%')
and ideally wrap it in shellescape()
to ensure that any special characters are escaped for use in the shell.
Provided you have a recent enough Vim, you should also have the trim(
function to clean up some whitespace, so the function might look something like this:
function! GetGitDiffSummary()
let l:git_command = "git diff --numstat -- " . shellescape(expand('%'))
let l:adds = "+".trim(system(l:git_command . " | awk '{print($1)}'"))
let l:subs = "-".trim(system(l:git_command . " | awk '{print($2)}'"))
return l:adds."/".l:subs
endfunction
Problem 2: when I press and hold keys that move the cursor (arrow keys & hjkl) I get the respective characters printed out. They don't change the contents of the file, but I still see them.
This is a problem with performance. The system
call could potentially take a while, and it blocks Vim. It gets invoked every time you move the cursor, which is unnecessary for this particular check -- git will only see a change in lines when you write the buffer. So maybe something like this would work better:
augroup UpdateDiffSummary
autocmd!
autocmd BufReadPost * let b:git_diff_summary = GetGitDiffSummary()
autocmd BufWritePost * let b:git_diff_summary = GetGitDiffSummary()
augroup END
set statusline+=%{get(b:,'git_diff_summary')}
These autocommands should trigger when opening a file and when writing the buffer, which are the two moments when this data would change. The reason to use get(b:, 'git_diff_summary')
instead of b:git_diff_summary
is to avoid an error if that variable isn't set.
There's other optimizations that could be done -- you could make a single system call instead of two, and it might make sense to check if l:adds
and l:subs
are the empty string to replace them with 0. But this should work as a start, I think.
Upvotes: 1