kakoune/rc/filetype/diff-parse.pl

144 lines
3.2 KiB
Perl
Raw Permalink Normal View History

#!/usr/bin/env perl
use warnings;
sub quote {
my $token = shift;
$token =~ s/'/''/g;
return "'$token'";
}
sub fail {
my $reason = shift;
print "set-register e fail " . quote("diff-parse.pl: $reason");
exit;
}
my $begin;
my $end;
while (defined $ARGV[0]) {
if ($ARGV[0] eq "--") {
shift;
last;
}
if ($ARGV[0] =~ m{^(BEGIN|END)$}) {
if (not defined $ARGV[1]) {
fail "missing argument to $ARGV[0]";
}
if ($ARGV[0] eq "BEGIN") {
$begin = $ARGV[1];
} else {
$end = $ARGV[1];
}
shift, shift;
next;
}
fail "unknown argument: $ARGV[0]";
}
# Inputs
our $directory = $ENV{PWD};
our $strip;
rc tools git: command for easy recursive blaming Our ":git blame" annotates each line with the most recent commit. However often a line has been modified by several commits. Introduce ":git blame-jump" which shows the commit that added the line at cursor. Crucially, it works also in Git diff buffers, so it can be used recursively to find the full history of a line. To do the recursive blame from a diff, I need to navigate to the old (deleted) version of a line. Since old and new line are usually neighbors. Speed up the common scenario of finding the old version by making ":git blame-jump" jump to the new version. This means the initial diff view might not include the commit message etc. Compensate this by showing the commit's date+author+subject in the status line. Here are some test cases. - run blame-jump after "git blame" - create an uncommitted or unsaved line, run "git blame" and "blame-jump" on the uncommitted line - run blame-jump without running "git blame" - run blame-jump in "git show" - run blame-jump in "git diff HEAD" - run blame-jump in "git diff --cached" - run blame-jump in "git diff" (YMMV if there are cached changes, could fix that) Naming: there are some similar commands in the wild [1]; they are usually called "show-blamed" or similar, but they don't jump to the corresponding line. Also our list of git commands is getting a bit messy (especially the undocumented show-diff/hide-diff/next-hunk/prev-hunk; subject first naming seems better). [1]: https://github.com/robertmeta/kak/blob/f6e78ec4c0eeccd091e6275828234d98e6aa3a7f/kakrc#L423 Future work: to go back to the previously-blamed commit we need to have had the foresight to use "rename-buffer". Perhaps we want to add some kind of buffer stack (like Magit does for example).
2024-02-03 00:26:56 +01:00
our $in_file;
our $in_file_line;
our $version = "+";
eval $begin if defined $begin;
rc tools git: command for easy recursive blaming Our ":git blame" annotates each line with the most recent commit. However often a line has been modified by several commits. Introduce ":git blame-jump" which shows the commit that added the line at cursor. Crucially, it works also in Git diff buffers, so it can be used recursively to find the full history of a line. To do the recursive blame from a diff, I need to navigate to the old (deleted) version of a line. Since old and new line are usually neighbors. Speed up the common scenario of finding the old version by making ":git blame-jump" jump to the new version. This means the initial diff view might not include the commit message etc. Compensate this by showing the commit's date+author+subject in the status line. Here are some test cases. - run blame-jump after "git blame" - create an uncommitted or unsaved line, run "git blame" and "blame-jump" on the uncommitted line - run blame-jump without running "git blame" - run blame-jump in "git show" - run blame-jump in "git diff HEAD" - run blame-jump in "git diff --cached" - run blame-jump in "git diff" (YMMV if there are cached changes, could fix that) Naming: there are some similar commands in the wild [1]; they are usually called "show-blamed" or similar, but they don't jump to the corresponding line. Also our list of git commands is getting a bit messy (especially the undocumented show-diff/hide-diff/next-hunk/prev-hunk; subject first naming seems better). [1]: https://github.com/robertmeta/kak/blob/f6e78ec4c0eeccd091e6275828234d98e6aa3a7f/kakrc#L423 Future work: to go back to the previously-blamed commit we need to have had the foresight to use "rename-buffer". Perhaps we want to add some kind of buffer stack (like Magit does for example).
2024-02-03 00:26:56 +01:00
$in_file = "$directory/$in_file" if defined $in_file;
# Outputs
rc tools git: command for easy recursive blaming Our ":git blame" annotates each line with the most recent commit. However often a line has been modified by several commits. Introduce ":git blame-jump" which shows the commit that added the line at cursor. Crucially, it works also in Git diff buffers, so it can be used recursively to find the full history of a line. To do the recursive blame from a diff, I need to navigate to the old (deleted) version of a line. Since old and new line are usually neighbors. Speed up the common scenario of finding the old version by making ":git blame-jump" jump to the new version. This means the initial diff view might not include the commit message etc. Compensate this by showing the commit's date+author+subject in the status line. Here are some test cases. - run blame-jump after "git blame" - create an uncommitted or unsaved line, run "git blame" and "blame-jump" on the uncommitted line - run blame-jump without running "git blame" - run blame-jump in "git show" - run blame-jump in "git diff HEAD" - run blame-jump in "git diff --cached" - run blame-jump in "git diff" (YMMV if there are cached changes, could fix that) Naming: there are some similar commands in the wild [1]; they are usually called "show-blamed" or similar, but they don't jump to the corresponding line. Also our list of git commands is getting a bit messy (especially the undocumented show-diff/hide-diff/next-hunk/prev-hunk; subject first naming seems better). [1]: https://github.com/robertmeta/kak/blob/f6e78ec4c0eeccd091e6275828234d98e6aa3a7f/kakrc#L423 Future work: to go back to the previously-blamed commit we need to have had the foresight to use "rename-buffer". Perhaps we want to add some kind of buffer stack (like Magit does for example).
2024-02-03 00:26:56 +01:00
our $diff_line = 0;
our $commit;
our $file;
our $file_line;
our $diff_line_text;
my $other_version;
if ($version eq "+") {
$other_version = "-";
} else {
$other_version = "+";
}
my $is_recursive_diff = 0;
my $state = "header";
my $fallback_file;
my $other_file;
my $other_file_line;
sub strip {
my $is_recursive_diff = shift;
my $f = shift;
my $effective_strip;
if (defined $strip) {
$effective_strip = $strip;
} else {
# A "diff -r" or "git diff" adds "diff" lines to
# the output. If no such line is present, we have
# a plain diff between files (not directories), so
# there should be no need to strip the directory.
$effective_strip = $is_recursive_diff ? 1 : 0;
}
if ($f !~ m{^/}) {
$f =~ s,^([^/]+/+){$effective_strip},, or fail "directory prefix underflow";
$f = "$directory/$f";
}
return $f;
}
while (<STDIN>) {
rc tools git: command for easy recursive blaming Our ":git blame" annotates each line with the most recent commit. However often a line has been modified by several commits. Introduce ":git blame-jump" which shows the commit that added the line at cursor. Crucially, it works also in Git diff buffers, so it can be used recursively to find the full history of a line. To do the recursive blame from a diff, I need to navigate to the old (deleted) version of a line. Since old and new line are usually neighbors. Speed up the common scenario of finding the old version by making ":git blame-jump" jump to the new version. This means the initial diff view might not include the commit message etc. Compensate this by showing the commit's date+author+subject in the status line. Here are some test cases. - run blame-jump after "git blame" - create an uncommitted or unsaved line, run "git blame" and "blame-jump" on the uncommitted line - run blame-jump without running "git blame" - run blame-jump in "git show" - run blame-jump in "git diff HEAD" - run blame-jump in "git diff --cached" - run blame-jump in "git diff" (YMMV if there are cached changes, could fix that) Naming: there are some similar commands in the wild [1]; they are usually called "show-blamed" or similar, but they don't jump to the corresponding line. Also our list of git commands is getting a bit messy (especially the undocumented show-diff/hide-diff/next-hunk/prev-hunk; subject first naming seems better). [1]: https://github.com/robertmeta/kak/blob/f6e78ec4c0eeccd091e6275828234d98e6aa3a7f/kakrc#L423 Future work: to go back to the previously-blamed commit we need to have had the foresight to use "rename-buffer". Perhaps we want to add some kind of buffer stack (like Magit does for example).
2024-02-03 00:26:56 +01:00
$diff_line++;
s/^(> )*//g;
$diff_line_text = $_;
rc tools git: command for easy recursive blaming Our ":git blame" annotates each line with the most recent commit. However often a line has been modified by several commits. Introduce ":git blame-jump" which shows the commit that added the line at cursor. Crucially, it works also in Git diff buffers, so it can be used recursively to find the full history of a line. To do the recursive blame from a diff, I need to navigate to the old (deleted) version of a line. Since old and new line are usually neighbors. Speed up the common scenario of finding the old version by making ":git blame-jump" jump to the new version. This means the initial diff view might not include the commit message etc. Compensate this by showing the commit's date+author+subject in the status line. Here are some test cases. - run blame-jump after "git blame" - create an uncommitted or unsaved line, run "git blame" and "blame-jump" on the uncommitted line - run blame-jump without running "git blame" - run blame-jump in "git show" - run blame-jump in "git diff HEAD" - run blame-jump in "git diff --cached" - run blame-jump in "git diff" (YMMV if there are cached changes, could fix that) Naming: there are some similar commands in the wild [1]; they are usually called "show-blamed" or similar, but they don't jump to the corresponding line. Also our list of git commands is getting a bit messy (especially the undocumented show-diff/hide-diff/next-hunk/prev-hunk; subject first naming seems better). [1]: https://github.com/robertmeta/kak/blob/f6e78ec4c0eeccd091e6275828234d98e6aa3a7f/kakrc#L423 Future work: to go back to the previously-blamed commit we need to have had the foresight to use "rename-buffer". Perhaps we want to add some kind of buffer stack (like Magit does for example).
2024-02-03 00:26:56 +01:00
if (m{^commit (\w+)}) {
$commit = $1;
next;
}
if (m{^diff\b}) {
$state = "header";
$is_recursive_diff = 1;
if (m{^diff -\S* (\S+) (\S+)$}) {
$fallback_file = strip $is_recursive_diff, ($version eq "+" ? $2 : $1);
}
next;
}
if ($state eq "header") {
if (m{^[$version]{3} ([^\t\n]+)}) {
$file = strip $is_recursive_diff, $1;
next;
}
if (m{^[$other_version]{3} ([^\t\n]+)}) {
$other_file = strip $is_recursive_diff, $1;
next;
}
}
if (m{^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@}) {
$state = "contents";
$file_line = ($version eq "+" ? $2 : $1) - 1;
$other_file_line = ($version eq "+" ? $1 : $2) - 1;
} else {
my $iscontext = m{^[ ]};
if (m{^[ $version]}) {
$file_line++ if defined $file_line;
}
if (m{^[ $other_version]}) {
$other_file_line++ if defined $other_file_line;
}
}
rc tools git: command for easy recursive blaming Our ":git blame" annotates each line with the most recent commit. However often a line has been modified by several commits. Introduce ":git blame-jump" which shows the commit that added the line at cursor. Crucially, it works also in Git diff buffers, so it can be used recursively to find the full history of a line. To do the recursive blame from a diff, I need to navigate to the old (deleted) version of a line. Since old and new line are usually neighbors. Speed up the common scenario of finding the old version by making ":git blame-jump" jump to the new version. This means the initial diff view might not include the commit message etc. Compensate this by showing the commit's date+author+subject in the status line. Here are some test cases. - run blame-jump after "git blame" - create an uncommitted or unsaved line, run "git blame" and "blame-jump" on the uncommitted line - run blame-jump without running "git blame" - run blame-jump in "git show" - run blame-jump in "git diff HEAD" - run blame-jump in "git diff --cached" - run blame-jump in "git diff" (YMMV if there are cached changes, could fix that) Naming: there are some similar commands in the wild [1]; they are usually called "show-blamed" or similar, but they don't jump to the corresponding line. Also our list of git commands is getting a bit messy (especially the undocumented show-diff/hide-diff/next-hunk/prev-hunk; subject first naming seems better). [1]: https://github.com/robertmeta/kak/blob/f6e78ec4c0eeccd091e6275828234d98e6aa3a7f/kakrc#L423 Future work: to go back to the previously-blamed commit we need to have had the foresight to use "rename-buffer". Perhaps we want to add some kind of buffer stack (like Magit does for example).
2024-02-03 00:26:56 +01:00
if (defined $in_file and defined $file and $file eq $in_file) {
if (defined $in_file_line and defined $file_line and $file_line >= $in_file_line) {
last;
}
}
}
if (not defined $file) {
$file = ($fallback_file or $other_file);
}
if (not defined $file) {
fail "missing diff header";
}
eval $end if defined $end;