Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Vim/Git: replace git-jump with vcs-jump
Port git-jump to Ruby and teach it to handle both Mercurial and Git. The code is a bit of a hack job (blend of Ruby-style and the original Shell-plus-Perl-style) but it seems to handle the basic cases ok. For now, "diff" is supported for Mercurial and Git, but "merge" and "grep" are only supported for Git. I would have just adapted the existing script, but Mercurial's `hg diff` has no equivalent of `git diff --relative` that I am aware of, and manipulating ("relativizing") the paths in Bash would have been a little more painful. Switching to Ruby, where we have the Pathname class, makes path manipulation easier. As a nicety, if the editor is Vim, we open the quickfix window instead of only jumping to the first error. On errors, such as when we don't seem to be inside a repo, we raise an exception; this means that you see some diagnostic info on the console when running `vcs-jump` on the command line. When running it inside Vim using the mapping, we redirect error output to /dev/null, which means you just get an empty error listing (ie. nothing happens). Signed-off-by: Wincent Colaiuta <win@wincent.com>
- Loading branch information
Showing
4 changed files
with
168 additions
and
80 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
#!/usr/bin/env ruby | ||
|
||
# based on `git-jump`, that comes with Git, but works with Mercurial as well | ||
# (ported to Ruby to make some of the relative path manipulation easier) | ||
|
||
require 'pathname' | ||
require 'shellwords' | ||
require 'tempfile' | ||
|
||
def usage() | ||
puts <<-EOF.gsub(/^ {4}/, '') | ||
usage: vcs-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. | ||
[supports: git, hg] | ||
merge: elements are merge conflicts. Arguments are ignored. | ||
[supports: git] | ||
grep: elements are grep hits. Arguments are given to grep. | ||
[supports: git] | ||
EOF | ||
end | ||
|
||
def open_editor(tmp) | ||
editor = `git var GIT_EDITOR 2> /dev/null`.chomp | ||
editor = ENV['EDITOR'] if !$?.success? | ||
editor = `which vim`.chomp unless editor | ||
raise 'error: cannot locate editor' if editor == '' | ||
|
||
if Pathname.new(editor).basename.to_s == 'vim' | ||
additional_args = %w[-c :cw] # open the quickfix window | ||
end | ||
|
||
exec(editor, '-q', tmp, *additional_args) | ||
end | ||
|
||
def pwd | ||
@pwd ||= Pathname.pwd.realpath | ||
end | ||
|
||
def absolutize(file) | ||
Pathname.new(file).realpath | ||
end | ||
|
||
def relativize(file) | ||
return file if git? | ||
relative = pwd.relative_path_from(root).to_s | ||
file.to_s.sub("#{relative}/", '') | ||
end | ||
|
||
def git_root | ||
root = `git rev-parse --show-toplevel 2> /dev/null`.chomp | ||
[absolutize(root), 'git'] if $?.success? | ||
end | ||
|
||
def hg_root | ||
root = `hg root`.chomp | ||
[absolutize(root), 'hg'] if $?.success? | ||
end | ||
|
||
def vcs_info | ||
@info ||= begin | ||
info = git_root | ||
info = hg_root unless info | ||
|
||
raise 'Unable to detect VCS info' unless info | ||
|
||
info | ||
end | ||
end | ||
|
||
def root | ||
vcs_info[0] | ||
end | ||
|
||
def vcs | ||
vcs_info[1] | ||
end | ||
|
||
def git? | ||
vcs == 'git' | ||
end | ||
|
||
def hg? | ||
vcs == 'hg' | ||
end | ||
|
||
def require_git | ||
raise 'error: not a Git repo!' unless git? | ||
end | ||
|
||
def shellescape(args) | ||
ARGV.map { |arg| Shellwords.shellescape(arg) }.join(' ') | ||
end | ||
|
||
def redir(new_fd, &block) | ||
old_stdout, old_stderr = $stdout, $stderr | ||
$stdout, $stderr = new_fd, new_fd | ||
yield | ||
ensure | ||
$stdout, $stderr = old_stdout, old_stderr | ||
end | ||
|
||
def mode_diff(args) | ||
args = shellescape(args) | ||
diff = git? ? `git diff --relative #{args}` : `hg diff --git #{args}` | ||
idx = nil | ||
file = nil | ||
|
||
diff.lines.each do |line| | ||
# setting the inner Perl hacker free since 2007 | ||
(line =~ %r{^\+\+\+ b/(.*)}) ? (file = relativize($~[1])) : (next unless file) | ||
(line =~ %r{^@@ .*\+(\d+)}) ? (idx = $~[1].to_i) : (next unless idx) | ||
(line =~ %r{^ }) && (idx += 1; next) | ||
(line =~ %r{^[-+]\s*(.*)}) && ( puts "#{file}:#{idx}: #{$~[1]}"; idx = nil) | ||
end | ||
end | ||
|
||
def mode_merge(__args__ignored) | ||
require_git() | ||
puts %x{ | ||
git ls-files -u | | ||
perl -pe 's/^.*?\t//' | | ||
sort -u | | ||
while IFS= read fn; do | ||
grep -Hn '^<<<<<<<' "$fn" | ||
done | ||
} | ||
end | ||
|
||
# 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. | ||
def mode_grep(args) | ||
require_git | ||
puts %x{git grep -n #{shellescape args} | perl -pe 's/[ \t]+/ /g; s/^ *//;'} | ||
end | ||
|
||
if ARGV.count < 1 | ||
usage() | ||
exit 1 | ||
end | ||
|
||
mode = ARGV.shift | ||
|
||
if STDOUT.tty? | ||
begin | ||
tmp = Tempfile.new('vcs-jump') | ||
redir(tmp) { send("mode_#{mode}", ARGV) } | ||
tmp.flush | ||
open_editor(tmp.path) | ||
ensure | ||
tmp.close | ||
end | ||
else | ||
send("mode_#{mode}", ARGV) | ||
end |
This file was deleted.
Oops, something went wrong.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
function! VcsJump(command) | ||
cexpr system("vcs-jump " . a:command . " 2> /dev/null") | ||
cw | ||
endfunction | ||
|
||
command! -nargs=+ -complete=file VcsJump call VcsJump(<q-args>) | ||
nnoremap <leader>d :VcsJump diff<space> |