Skip to content

Commit

Permalink
Blame uncommitted deletions starting from HEAD
Browse files Browse the repository at this point in the history
When starting a blame in the stage view on a deleted line, it seems
appropriate to find the commit that added the line.
To this end, instead of starting the blame view from the working tree
state of a file, use the version at HEAD, which still has the deleted line
(unless the line was only just staged).

Since we want to visit the line before application of the stage view's
diff, diff_get_lineno does not work because it computes the one after
diff application.  Introduce diff_get_old_lineno to get the correct
line number.

This works for both staged and unstaged deletions.  However, when a file
has both staged and unstaged hunks, then blaming an unstaged deletion
may jump to the wrong line number because only the unstaged diff is
considered.

Closes jonas#1008
  • Loading branch information
krobelus committed Apr 29, 2020
1 parent 484aa21 commit 9e46b6b
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 2 deletions.
4 changes: 4 additions & 0 deletions NEWS.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Bug fixes:

- Fix wrapping of lines with multibyte characters. (#988)

Improvements:

- Start blame on deleted lines in the stage view from HEAD so the line's origin can be traced. (#1008)

tig-2.5.1
---------
Expand Down
1 change: 1 addition & 0 deletions include/tig/diff.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ enum status_code diff_init_highlight(struct view *view, struct diff_state *state
bool diff_done_highlight(struct diff_state *state);

unsigned int diff_get_lineno(struct view *view, struct line *line);
unsigned int diff_get_old_lineno(struct view *view, struct line *line);
const char *diff_get_pathname(struct view *view, struct line *line);

extern struct view diff_view;
Expand Down
33 changes: 33 additions & 0 deletions src/diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,39 @@ diff_get_lineno(struct view *view, struct line *line)
return lineno;
}

unsigned int
diff_get_old_lineno(struct view *view, struct line *line)
{
const struct line *header, *chunk;
unsigned int lineno;
struct chunk_header chunk_header;

/* Verify that we are after a diff header and one of its chunks */
header = find_prev_line_by_type(view, line, LINE_DIFF_HEADER);
chunk = find_prev_line_by_type(view, line, LINE_DIFF_CHUNK);
if (!header || !chunk || chunk < header) {
return 0;
}

/*
* In a chunk header, the number after the '-' sign is the number of its
* following line, in the old version of the file. We increment this
* number for each non-addition line, until the given line position.
*/
if (!parse_chunk_header(&chunk_header, box_text(chunk))) {
return 0;
}

lineno = chunk_header.old.position;

for (chunk++; chunk < line; chunk++)
if (chunk->type != LINE_DIFF_ADD &&
chunk->type != LINE_DIFF_ADD2)
lineno++;

return lineno;
}

static enum request
diff_trace_origin(struct view *view, struct line *line)
{
Expand Down
9 changes: 7 additions & 2 deletions src/stage.c
Original file line number Diff line number Diff line change
Expand Up @@ -444,8 +444,13 @@ stage_request(struct view *view, enum request request, struct line *line)
string_ncopy(view->env->file, file, strlen(file));
}

view->env->ref[0] = 0;
view->env->goto_lineno = diff_get_lineno(view, line);
if (!is_initial_commit() && line->type == LINE_DIFF_DEL) {
string_copy(view->env->ref, "HEAD");
view->env->goto_lineno = diff_get_old_lineno(view, line);
} else {
view->env->ref[0] = 0;
view->env->goto_lineno = diff_get_lineno(view, line);
}
if (view->env->goto_lineno > 0)
view->env->goto_lineno--;
return request;
Expand Down

0 comments on commit 9e46b6b

Please sign in to comment.