blob: 40c4b0d111071676c278651f49669036e90f079a [file] [log] [blame]
#!/bin/sh
usage() {
cat <<\EOF
usage: git jump [--stdout] <mode> [<args>]
Jump to interesting elements in an editor.
The <mode> parameter is one of:
diff: elements are diff hunks. Arguments are given to diff.
merge: elements are merge conflicts. Arguments are ignored.
grep: elements are grep hits. Arguments are given to git grep or, if
configured, to the command in `jump.grepCmd`.
ws: elements are whitespace errors. Arguments are given to diff --check.
If the optional argument `--stdout` is given, print the quickfix
lines to standard output instead of feeding it to the editor.
EOF
}
open_editor() {
editor=`git var GIT_EDITOR`
case "$editor" in
*emacs*)
# Supported editor values are:
# - emacs
# - emacsclient
# - emacsclient -t
#
# Wait for completion of the asynchronously executed process
# to avoid race conditions in case of "emacsclient".
eval "$editor --eval \"(let ((buf (grep \\\"cat \$1\\\"))) (pop-to-buffer buf) (select-frame-set-input-focus (selected-frame)) (while (get-buffer-process buf) (sleep-for 0.1)))\""
;;
*)
# assume anything else is vi-compatible
eval "$editor -q \$1"
;;
esac
}
mode_diff() {
git diff --no-prefix --relative "$@" |
perl -ne '
if (m{^\+\+\+ (.*)}) { $file = $1; next }
defined($file) or next;
if (m/^@@ .*?\+(\d+)/) { $line = $1; next }
defined($line) or next;
if (/^ /) { $line++; next }
if (/^[-+]\s*(.*)/) {
print "$file:$line: $1\n";
$line = undef;
}
'
}
mode_merge() {
git ls-files -u "$@" |
perl -pe 's/^.*?\t//' |
sort -u |
while IFS= read fn; do
grep -Hn '^<<<<<<<' "$fn"
done
}
# Grep -n generates nice quickfix-looking lines by itself,
# but let's clean up extra whitespace, so they look better if the
# editor shows them to us in the status bar.
mode_grep() {
cmd=$(git config jump.grepCmd)
test -n "$cmd" || cmd="git grep -n --column"
$cmd "$@" |
perl -pe '
s/[ \t]+/ /g;
s/^ *//;
'
}
mode_ws() {
git diff --check "$@"
}
use_stdout=
while test $# -gt 0; do
case "$1" in
--stdout)
use_stdout=t
;;
--*)
usage >&2
exit 1
;;
*)
break
;;
esac
shift
done
if test $# -lt 1; then
usage >&2
exit 1
fi
mode=$1; shift
type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }
if test "$use_stdout" = "t"; then
"mode_$mode" "$@"
exit 0
fi
trap 'rm -f "$tmp"' 0 1 2 3 15
tmp=`mktemp -t git-jump.XXXXXX` || exit 1
"mode_$mode" "$@" >"$tmp"
test -s "$tmp" || exit 0
open_editor "$tmp"