Skip to content

Instantly share code, notes, and snippets.

@romainl
Last active January 10, 2024 16:47
Show Gist options
  • Save romainl/a3ddb1d08764b93183260f8cdf0f524f to your computer and use it in GitHub Desktop.
Save romainl/a3ddb1d08764b93183260f8cdf0f524f to your computer and use it in GitHub Desktop.
git-jump hack that can be used FROM Vim
#!/bin/sh
usage() {
cat <<\EOF
usage: git jump <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.
EOF
}
open_editor() {
if test -t 1; then
editor=`git var GIT_EDITOR`
eval "$editor -q \$1"
else
eval "cat \$1"
fi
}
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 "$@"
}
if test $# -lt 1; then
usage >&2
exit 1
fi
mode=$1; shift
trap 'rm -f "$tmp"' 0 1 2 3 15
tmp=`mktemp -t git-jump.XXXXXX` || exit 1
type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }
"mode_$mode" "$@" >"$tmp"
test -s "$tmp" || exit 0
open_editor "$tmp"

NOTE: The original git-jump now supports the flag --stdout, which makes this hack redundant, but I will keep it for posterity.

To use it from Vim, just add the new flag to your custom command:

:command! -bar -nargs=* Jump cexpr system('git jump --stdout ' . expand(<q-args>))

Thanks to @rafikdraoui for the heads-up, @yoichi for the commit, and to everyone else for their interest in this little hack.

Introduction

git-jump is an amazing little script that can be used to start Vim with the quickfix list populated with interesting things:

  1. The beginning of any diff hunks.
  2. The beginning of any merge conflict markers.
  3. Any grep matches, including the column of the first match on a line.
  4. Any whitespace errors detected by git diff --check.

Example usage:

$ git jump diff
$ git jump grep GetUser

But the original script is written from a shell perspective so it always opens Vim and thus can't be used to populate the quickfix list from within Vim. Bummer…

This hack makes it possible to get two behaviors out of git-jump for the price of one.

  • When executed in an interactive context, it starts Vim with the list:

    $ git jump diff
    
  • when executed in a non-interactive context, it outputs the list:

    $ git jump grep foo | grep -v bar
    

Integration

Having the same feature inside and outside of Vim is quite handy but:

:cexpr system('git jump diff')

is a lot to type! Let's turn that into a proper command:

:command! -bar -nargs=* Jump cexpr system('git jump ' . expand(<q-args>))

that we can use easily:

:Jump diff
:Jump merge
:Jump grep foo
@romainl
Copy link
Author

romainl commented May 9, 2023

Thank you @rafikdraoui, I will mention that in the description.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment