Code

difftool: move 'git-difftool' out of contrib
[git.git] / git-difftool--helper.sh
diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh
new file mode 100755 (executable)
index 0000000..fc61416
--- /dev/null
@@ -0,0 +1,221 @@
+#!/bin/sh
+# git-difftool--helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher.
+# This script is typically launched by using the 'git difftool'
+# convenience command.
+#
+# Copyright (c) 2009 David Aguilar
+
+# Set GIT_DIFFTOOL_NO_PROMPT to bypass the per-file prompt.
+should_prompt () {
+       test -z "$GIT_DIFFTOOL_NO_PROMPT"
+}
+
+# This function prepares temporary files and launches the appropriate
+# merge tool.
+launch_merge_tool () {
+       # Merged is the filename as it appears in the work tree
+       # Local is the contents of a/filename
+       # Remote is the contents of b/filename
+       # Custom merge tool commands might use $BASE so we provide it
+       MERGED="$1"
+       LOCAL="$2"
+       REMOTE="$3"
+       BASE="$1"
+
+       # $LOCAL and $REMOTE are temporary files so prompt
+       # the user with the real $MERGED name before launching $merge_tool.
+       if should_prompt; then
+               printf "\nViewing: '$MERGED'\n"
+               printf "Hit return to launch '%s': " "$merge_tool"
+               read ans
+       fi
+
+       # Run the appropriate merge tool command
+       case "$merge_tool" in
+       kdiff3)
+               basename=$(basename "$MERGED")
+               "$merge_tool_path" --auto \
+                       --L1 "$basename (A)" \
+                       --L2 "$basename (B)" \
+                       "$LOCAL" "$REMOTE" \
+                       > /dev/null 2>&1
+               ;;
+
+       kompare)
+               "$merge_tool_path" "$LOCAL" "$REMOTE"
+               ;;
+
+       tkdiff)
+               "$merge_tool_path" "$LOCAL" "$REMOTE"
+               ;;
+
+       meld)
+               "$merge_tool_path" "$LOCAL" "$REMOTE"
+               ;;
+
+       diffuse)
+               "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
+               ;;
+
+       vimdiff)
+               "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$REMOTE"
+               ;;
+
+       gvimdiff)
+               "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$REMOTE"
+               ;;
+
+       xxdiff)
+               "$merge_tool_path" \
+                       -R 'Accel.Search: "Ctrl+F"' \
+                       -R 'Accel.SearchForward: "Ctrl-G"' \
+                       "$LOCAL" "$REMOTE"
+               ;;
+
+       opendiff)
+               "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
+               ;;
+
+       ecmerge)
+               "$merge_tool_path" "$LOCAL" "$REMOTE" \
+                       --default --mode=merge2 --to="$MERGED"
+               ;;
+
+       emerge)
+               "$merge_tool_path" -f emerge-files-command \
+                       "$LOCAL" "$REMOTE" "$(basename "$MERGED")"
+               ;;
+
+       *)
+               if test -n "$merge_tool_cmd"; then
+                       ( eval $merge_tool_cmd )
+               fi
+               ;;
+       esac
+}
+
+# Verifies that (difftool|mergetool).<tool>.cmd exists
+valid_custom_tool() {
+       merge_tool_cmd="$(git config difftool.$1.cmd)"
+       test -z "$merge_tool_cmd" &&
+       merge_tool_cmd="$(git config mergetool.$1.cmd)"
+       test -n "$merge_tool_cmd"
+}
+
+# Verifies that the chosen merge tool is properly setup.
+# Built-in merge tools are always valid.
+valid_tool() {
+       case "$1" in
+       kdiff3 | kompare | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge)
+               ;; # happy
+       *)
+               if ! valid_custom_tool "$1"
+               then
+                       return 1
+               fi
+               ;;
+       esac
+}
+
+# Sets up the merge_tool_path variable.
+# This handles the difftool.<tool>.path configuration.
+# This also falls back to mergetool defaults.
+init_merge_tool_path() {
+       merge_tool_path=$(git config difftool."$1".path)
+       test -z "$merge_tool_path" &&
+       merge_tool_path=$(git config mergetool."$1".path)
+       if test -z "$merge_tool_path"; then
+               case "$1" in
+               vimdiff)
+                       merge_tool_path=vim
+                       ;;
+               gvimdiff)
+                       merge_tool_path=gvim
+                       ;;
+               emerge)
+                       merge_tool_path=emacs
+                       ;;
+               *)
+                       merge_tool_path="$1"
+                       ;;
+               esac
+       fi
+}
+
+# Allow GIT_DIFF_TOOL and GIT_MERGE_TOOL to provide default values
+test -n "$GIT_MERGE_TOOL" && merge_tool="$GIT_MERGE_TOOL"
+test -n "$GIT_DIFF_TOOL" && merge_tool="$GIT_DIFF_TOOL"
+
+# If merge tool was not specified then use the diff.tool
+# configuration variable.  If that's invalid then reset merge_tool.
+# Fallback to merge.tool.
+if test -z "$merge_tool"; then
+       merge_tool=$(git config diff.tool)
+       test -z "$merge_tool" &&
+       merge_tool=$(git config merge.tool)
+       if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
+               echo >&2 "git config option diff.tool set to unknown tool: $merge_tool"
+               echo >&2 "Resetting to default..."
+               unset merge_tool
+       fi
+fi
+
+# Try to guess an appropriate merge tool if no tool has been set.
+if test -z "$merge_tool"; then
+       # We have a $DISPLAY so try some common UNIX merge tools
+       if test -n "$DISPLAY"; then
+               # If gnome then prefer meld, otherwise, prefer kdiff3 or kompare
+               if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
+                       merge_tool_candidates="meld kdiff3 kompare tkdiff xxdiff gvimdiff diffuse"
+               else
+                       merge_tool_candidates="kdiff3 kompare tkdiff xxdiff meld gvimdiff diffuse"
+               fi
+       fi
+       if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then
+               # $EDITOR is emacs so add emerge as a candidate
+               merge_tool_candidates="$merge_tool_candidates emerge opendiff vimdiff"
+       elif echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then
+               # $EDITOR is vim so add vimdiff as a candidate
+               merge_tool_candidates="$merge_tool_candidates vimdiff opendiff emerge"
+       else
+               merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff"
+       fi
+       echo "merge tool candidates: $merge_tool_candidates"
+
+       # Loop over each candidate and stop when a valid merge tool is found.
+       for i in $merge_tool_candidates
+       do
+               init_merge_tool_path $i
+               if type "$merge_tool_path" > /dev/null 2>&1; then
+                       merge_tool=$i
+                       break
+               fi
+       done
+
+       if test -z "$merge_tool" ; then
+               echo "No known merge resolution program available."
+               exit 1
+       fi
+
+else
+       # A merge tool has been set, so verify that it's valid.
+       if ! valid_tool "$merge_tool"; then
+               echo >&2 "Unknown merge tool $merge_tool"
+               exit 1
+       fi
+
+       init_merge_tool_path "$merge_tool"
+
+       if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then
+               echo "The merge tool $merge_tool is not available as '$merge_tool_path'"
+               exit 1
+       fi
+fi
+
+
+# Launch the merge tool on each path provided by 'git diff'
+while test $# -gt 6
+do
+       launch_merge_tool "$1" "$2" "$5"
+       shift 7
+done