rc tools git: blame-jump to handle buffer modifications since blame

If I run

    git blame
    execute-keys 10o<esc>,j
    git blame-jump

that'll jump to the wrong commit.

Use a flag-lines option to tell if a line still has blame information
cached.

Closes #5084
This commit is contained in:
Johannes Altmanninger 2024-02-03 00:27:00 +01:00 committed by Maxime Coste
parent 7cea09d327
commit c97add7f5a

View File

@ -74,6 +74,7 @@ hook -group git-show-branch-highlight global WinSetOption filetype=git-show-bran
} }
declare-option -hidden line-specs git_blame_flags declare-option -hidden line-specs git_blame_flags
declare-option -hidden line-specs git_blame_index
declare-option -hidden str git_blame declare-option -hidden str git_blame
declare-option -hidden str git_blob declare-option -hidden str git_blob
declare-option -hidden line-specs git_diff_flags declare-option -hidden line-specs git_diff_flags
@ -180,6 +181,7 @@ define-command -params 1.. \
hide_blame() { hide_blame() {
printf %s " printf %s "
set-option buffer git_blame_flags $kak_timestamp set-option buffer git_blame_flags $kak_timestamp
set-option buffer git_blame_index $kak_timestamp
set-option buffer git_blame %{} set-option buffer git_blame %{}
remove-highlighter window/git-blame remove-highlighter window/git-blame
unmap window normal <ret> %{:git blame-jump<ret>} unmap window normal <ret> %{:git blame-jump<ret>}
@ -272,6 +274,7 @@ define-command -params 1.. \
cd_bufdir cd_bufdir
printf %s "evaluate-commands -client '$kak_client' %{ printf %s "evaluate-commands -client '$kak_client' %{
set-option buffer=$kak_bufname git_blame_flags '$kak_timestamp' set-option buffer=$kak_bufname git_blame_flags '$kak_timestamp'
set-option buffer=$kak_bufname git_blame_index '$kak_timestamp'
set-option buffer=$kak_bufname git_blame '' set-option buffer=$kak_bufname git_blame ''
}" | kak -p ${kak_session} }" | kak -p ${kak_session}
git blame --incremental "$@" <${contents_fifo} | perl -wne ' git blame --incremental "$@" <${contents_fifo} | perl -wne '
@ -297,9 +300,11 @@ define-command -params 1.. \
} }
open CMD, "|-", "kak -p $ENV{kak_session}"; open CMD, "|-", "kak -p $ENV{kak_session}";
print CMD "set-option -add buffer=$ENV{kak_bufname} git_blame_flags $flags;"; print CMD "set-option -add buffer=$ENV{kak_bufname} git_blame_flags $flags;";
print CMD "set-option -add buffer=$ENV{kak_bufname} git_blame_index $index;";
print CMD "set-option -add buffer=$ENV{kak_bufname} git_blame " . quote $raw_blame; print CMD "set-option -add buffer=$ENV{kak_bufname} git_blame " . quote $raw_blame;
close(CMD); close(CMD);
$flags = ""; $flags = "";
$index = "";
$raw_blame = ""; $raw_blame = "";
$last_sent = $now; $last_sent = $now;
} }
@ -310,6 +315,9 @@ define-command -params 1.. \
$sha = $1; $sha = $1;
$line = $3; $line = $3;
$count = $4; $count = $4;
for ( my $i = 0; $i < $count; $i++ ) {
$index .= " " . ($line+$i) . "|$.,$i";
}
} }
if (m/^author /) { if (m/^author /) {
$authors{$sha} = substr($_,7); $authors{$sha} = substr($_,7);
@ -483,11 +491,16 @@ define-command -params 1.. \
blame_jump() { blame_jump() {
echo >${kak_command_fifo} "echo -to-file ${kak_response_fifo} -- %opt{git_blame}" echo >${kak_command_fifo} "echo -to-file ${kak_response_fifo} -- %opt{git_blame}"
blame_info=$(cat < ${kak_response_fifo}) blame_info=$(cat < ${kak_response_fifo})
blame_index=
cursor_column=${kak_cursor_column} cursor_column=${kak_cursor_column}
cursor_line=${kak_cursor_line} cursor_line=${kak_cursor_line}
if [ -z "$blame_info" ] && { if [ -n "$blame_info" ]; then {
[ "${kak_opt_filetype}" = git-diff ] || [ "${kak_opt_filetype}" = git-log ] echo >${kak_command_fifo} "
}; then { update-option buffer git_blame_index
echo -to-file ${kak_response_fifo} -- %opt{git_blame_index}
"
blame_index=$(cat < ${kak_response_fifo})
} elif [ "${kak_opt_filetype}" = git-diff ] || [ "${kak_opt_filetype}" = git-log ]; then {
printf >${kak_command_fifo} %s ' printf >${kak_command_fifo} %s '
evaluate-commands -draft %{ evaluate-commands -draft %{
try %{ try %{
@ -528,7 +541,7 @@ define-command -params 1.. \
cursor_line=$3 cursor_line=$3
cursor_column=$4 cursor_column=$4
blame_info=$(git blame --porcelain "$starting_commit" -L"$cursor_line,$cursor_line" -- "$file") blame_info=$(git blame --porcelain "$starting_commit" -L"$cursor_line,$cursor_line" -- "$file")
} elif [ -z "$blame_info" ]; then { } else {
set -- set --
eval "$prepare_git_blame_args" eval "$prepare_git_blame_args"
blame_info=$(git blame --porcelain -L"$cursor_line,$cursor_line" "$@" <${contents_fifo}) blame_info=$(git blame --porcelain -L"$cursor_line,$cursor_line" "$@" <${contents_fifo})
@ -536,7 +549,7 @@ define-command -params 1.. \
rm -r $(dirname $contents_fifo) rm -r $(dirname $contents_fifo)
fi fi
} fi } fi
eval "$(printf %s "$blame_info" | eval "$(printf '%s\n---\n%s' "$blame_index" "$blame_info" |
client=${kak_opt_docsclient:-$kak_client} \ client=${kak_opt_docsclient:-$kak_client} \
cursor_line=$cursor_line cursor_column=$cursor_column \ cursor_line=$cursor_line cursor_column=$cursor_column \
perl -wne ' perl -wne '
@ -562,8 +575,28 @@ define-command -params 1.. \
return "$SQ$token$SQ"; return "$SQ$token$SQ";
} }
$target = $ENV{"cursor_line"}; $target = $ENV{"cursor_line"};
$state = "index";
} }
chomp; chomp;
if ($state eq "index") {
if ($_ eq "---") {
$state = "blame";
next;
}
@blame_index = split;
next unless @blame_index;
shift @blame_index;
foreach (@blame_index) {
$_ =~ m{(\d+)\|(\d+),(\d+)} or die "bad blame index flag: $_";
my $buffer_line = $1;
if ($buffer_line == $target) {
$target_in_blame = $2;
$target_offset = $3;
last;
}
}
defined $target_in_blame and next, or last;
}
if (m/^([0-9a-f]+) ([0-9]+) ([0-9]+) ([0-9]+)/) { if (m/^([0-9a-f]+) ([0-9]+) ([0-9]+) ([0-9]+)/) {
if ($done) { if ($done) {
last; last;
@ -572,16 +605,27 @@ define-command -params 1.. \
$old_line = $2; $old_line = $2;
$new_line = $3; $new_line = $3;
$count = $4; $count = $4;
if (defined $target_in_blame) {
if ($target_in_blame == $. - 2) {
$old_line += $target_offset;
$done = 1;
}
} else {
if ($new_line <= $target and $target < $new_line + $count) { if ($new_line <= $target and $target < $new_line + $count) {
$old_line += $target - $new_line; $old_line += $target - $new_line;
$done = 1; $done = 1;
} }
} }
}
if (m/^filename /) { $old_filenames{$sha} = substr($_,9) } if (m/^filename /) { $old_filenames{$sha} = substr($_,9) }
if (m/^author /) { $authors{$sha} = substr($_,7) } if (m/^author /) { $authors{$sha} = substr($_,7) }
if (m/^author-time ([0-9]*)/) { $dates{$sha} = strftime("%F", localtime $1) } if (m/^author-time ([0-9]*)/) { $dates{$sha} = strftime("%F", localtime $1) }
if (m/^summary /) { $summaries{$sha} = substr($_,8) } if (m/^summary /) { $summaries{$sha} = substr($_,8) }
END { END {
if (@blame_index and not defined $target_in_blame) {
print "echo fail git blame-jump: line has no blame information;";
exit;
}
if (not defined $sha) { if (not defined $sha) {
print "echo fail git blame-jump: missing blame info"; print "echo fail git blame-jump: missing blame info";
exit; exit;