Last active
October 18, 2022 18:06
-
-
Save Osse/4709787 to your computer and use it in GitHub Desktop.
Vimdiff wrapper for use with git difftool --dir-diff
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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