Skip to content

Instantly share code, notes, and snippets.

@Osse
Last active October 18, 2022 18:06
Show Gist options
  • Save Osse/4709787 to your computer and use it in GitHub Desktop.
Save Osse/4709787 to your computer and use it in GitHub Desktop.
Vimdiff wrapper for use with git difftool --dir-diff
#!/usr/bin/env zsh
# Configuration:
# $ git config --global diff.tool vdwrap
# If you don't put vdwrap somewhere in $PATH then either:
# $ git config --global difftool.vdwrap.cmd '/full/path/vdwrap $LOCAL $REMOTE'
# or:
# $ git config --global difftool.vdwrap.cmd 'vdwrap $LOCAL $REMOTE'
# $ git config --global difftool.vdwrap.path '/full/path'
#
# Usage:
# $ git difftool --dir-diff foo bar
# $ git difftool foo bar # This should work as -t vimdiff
dirdiff() {
left=$1
right=$2
tmp=${1%%/left*}
vimcmdsfile="$tmp/vimcommands.vim"
left_files=( $left/**/*(.N) )
right_files=( $right/**/*(.N) )
# If the following test is true then either $right only contains symlinks
# which means that we are diffing against the working tree. We do not set
# readonly on those buffers in order to keep modifications, then. The alternative
# is that directory is empty because it should be (empty side of the diff).
# The autocmd will pick up the slack in that case
if (( ! $#right_files )); then
per_tab_ro_cmds='wincmd h | setlocal readonly'
right_files=( $right/**/*(-.N) ) # Grab the symlinks instead
else
per_tab_ro_cmds='windo setlocal readonly | wincmd h'
fi
right_files=( ${right_files[@]#$right/} )
left_files=( ${left_files[@]#$left/} )
all_files=( $left_files[@] $right_files[@] )
all_files=( ${(u)all_files[@]} )
{
# If a file doesn't exist, diff against /dev/null instead. This is what
# difftool without --dir-diff does
print 'autocmd! BufNewFile * view /dev/null | bdelete #'
for f in $all_files[@]; do
printf 'tabnew %s | vsplit %s\n' $left/$f $right/$f
print 'windo diffthis'
print $per_tab_ro_cmds
done
print 'tabfirst'
print 'tabclose'
print "cd $tmp"
} \
> $vimcmdsfile
vim -c "silent source $vimcmdsfile"
rm $vimcmdsfile
}
# Hacky way getting the default vimdiff behaviour. TODO: Can it be prettied
# without hardcoding what vim command it ends up executing? (Which by the way
# is `vim -R -f -d -c 'wincmd l' -c 'cd $GIT_PREFIX' "$@"`)
regulardiff() {
gitexecpath="$(git --exec-path)"
export PATH=$gitexecpath:$PATH
export LOCAL=$1
export REMOTE=$2
sh -c '. git-mergetool--lib; run_merge_tool vimdiff'
}
# If there are only two arguments and both are directories then --dir-diff has
# been given to 'git difftool'. Otherwise we use vimdiff like usual
if [[ -d $1 && -d $2 && -z $3 ]]
then
dirdiff "$@"
else
regulardiff "$@"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment