Skip to content

Commit

Permalink
Change the blame view to use porcelain
Browse files Browse the repository at this point in the history
Fixes jonas#978
Fixes jonas#1189
  • Loading branch information
koutcher committed May 26, 2022
1 parent a56671d commit db4a6b4
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 97 deletions.
1 change: 1 addition & 0 deletions NEWS.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Bug fixes:
- Fix cursor behaviour during staging. (#842, #1028)
- Fix navigation in split tree view.
- Enable textconv in the stage view.
- Change the blame view to use porcelain. (#978, #1189)

tig-2.5.5
---------
Expand Down
3 changes: 2 additions & 1 deletion include/tig/git.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
"git", "diff-files", (output_arg), "%(cmdlineargs)", NULL

#define GIT_DIFF_BLAME(encoding_arg, context_arg, space_arg, new_name) \
GIT_DIFF_UNSTAGED(encoding_arg, context_arg, space_arg, "", new_name)
"git", "diff-files", (encoding_arg), "--root", "--textconv", "--patch-with-stat", "-C", "-M", \
(context_arg), (space_arg), "--", (new_name), NULL

#define GIT_DIFF_BLAME_NO_PARENT(encoding_arg, context_arg, space_arg, new_name) \
GIT_DIFF_INITIAL(encoding_arg, "", context_arg, space_arg, "/dev/null", new_name)
Expand Down
2 changes: 1 addition & 1 deletion include/tig/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ OPTION_INFO(DEFINE_OPTION_EXTERNS)
_(width, int, VIEW_NO_FLAGS) \

#define FILE_NAME_COLUMN_OPTIONS(_) \
_(display, enum filename, VIEW_GREP_LIKE) \
_(display, enum filename, VIEW_BLAME_LIKE | VIEW_GREP_LIKE) \
_(width, int, VIEW_NO_FLAGS) \
_(maxwidth, int, VIEW_NO_FLAGS) \

Expand Down
2 changes: 1 addition & 1 deletion include/tig/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct blame_header {
size_t group;
};

bool parse_blame_header(struct blame_header *header, const char *text, size_t max_lineno);
bool parse_blame_header(struct blame_header *header, const char *text);
bool parse_blame_info(struct blame_commit *commit, char author[SIZEOF_STR], char *line);

/* Parse author lines where the name may be empty:
Expand Down
117 changes: 31 additions & 86 deletions src/blame.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,8 @@ struct blame {

struct blame_state {
struct blame_commit *commit;
struct blame_header header;
char author[SIZEOF_STR];
int blamed;
bool done_reading;
bool auto_filename_display;
const char *filename;
/* The history state for the current view is cached in the view
Expand All @@ -78,7 +77,11 @@ static enum status_code
blame_open(struct view *view, enum open_flags flags)
{
struct blame_state *state = view->private;
const char *file_argv[] = { repo.exec_dir, view->env->file , NULL };
const char *blame_argv[] = {
"git", "blame", encoding_arg, "%(blameargs)", "-p",
*view->env->ref ? view->env->ref : "", "--", view->env->file, NULL
};
enum status_code code;
size_t i;

if (!(repo.is_inside_work_tree || *repo.worktree))
Expand Down Expand Up @@ -145,15 +148,9 @@ blame_open(struct view *view, enum open_flags flags)
return error("No file chosen, press %s to open tree view",
get_view_key(view, REQ_VIEW_TREE));

if (*view->env->ref || begin_update(view, repo.exec_dir, file_argv, flags) != SUCCESS) {
const char *blame_cat_file_argv[] = {
"git", "cat-file", "blob", "%(ref):%(file)", NULL
};
enum status_code code = begin_update(view, repo.exec_dir, blame_cat_file_argv, flags);

if (code != SUCCESS)
return code;
}
code = begin_update(view, repo.exec_dir, blame_argv, flags);
if (code != SUCCESS)
return code;

/* First pass: remove multiple references to the same commit. */
for (i = 0; i < view->lines; i++) {
Expand Down Expand Up @@ -210,77 +207,27 @@ get_blame_commit(struct view *view, const char *id)
static struct blame_commit *
read_blame_commit(struct view *view, const char *text, struct blame_state *state)
{
struct blame_header header;
struct blame_commit *commit;
struct blame *blame;

if (!parse_blame_header(&header, text, view->lines))
if (!parse_blame_header(&state->header, text))
return NULL;

commit = get_blame_commit(view, text);
if (!commit)
return NULL;

state->blamed += header.group;
while (header.group--) {
struct line *line = &view->line[header.lineno + header.group - 1];

blame = line->data;
blame->commit = commit;
blame->lineno = header.orig_lineno + header.group - 1;
line->dirty = 1;
}

return commit;
}

static bool
blame_read_file(struct view *view, struct buffer *buf, struct blame_state *state)
{
if (!buf) {
const char *blame_argv[] = {
"git", "blame", encoding_arg, "%(blameargs)", "--incremental",
*view->env->ref ? view->env->ref : "--incremental", "--", view->env->file, NULL
};

if (failed_to_load_initial_view(view))
die("No blame exist for %s", view->vid);

if (view->lines == 0 || begin_update(view, repo.exec_dir, blame_argv, OPEN_EXTRA) != SUCCESS) {
report("Failed to load blame data");
return true;
}

if (view->env->goto_lineno > 0) {
select_view_line(view, view->env->goto_lineno);
view->env->goto_lineno = 0;
}

state->done_reading = true;
return false;

} else {
struct blame *blame;

if (!add_line_alloc(view, &blame, LINE_DEFAULT, buf->size, false))
return false;

blame->commit = NULL;
strncpy(blame->text, buf->data, buf->size);
blame->text[buf->size] = 0;
return true;
}
}

static bool
blame_read(struct view *view, struct buffer *buf, bool force_stop)
{
struct blame_state *state = view->private;

if (!state->done_reading)
return blame_read_file(view, buf, state);

if (!buf) {
if (failed_to_load_initial_view(view))
die("No blame exist for %s", view->vid);

string_format(view->ref, "%s", view->vid);
if (view_is_displayed(view)) {
update_view_title(view);
Expand All @@ -291,13 +238,24 @@ blame_read(struct view *view, struct buffer *buf, bool force_stop)

if (!state->commit) {
state->commit = read_blame_commit(view, buf->data, state);
string_format(view->ref, "%s %2zu%%", view->vid,
view->lines ? 5 * (size_t) (state->blamed * 20 / view->lines) : 0);

} else if (parse_blame_info(state->commit, state->author, buf->data)) {
bool update_view_columns = true;
int i;
} else if (*buf->data == '\t') {
struct blame *blame;
struct line *line = add_line_alloc(view, &blame, LINE_DEFAULT, buf->size - 1, false);

if (!line)
return false;

blame->commit = state->commit;
blame->lineno = state->header.orig_lineno;
strncpy(blame->text, buf->data + 1, buf->size - 1);
blame->text[buf->size - 1] = 0;

view_column_info_update(view, line);

state->commit = NULL;

} else if (parse_blame_info(state->commit, state->author, buf->data)) {
if (!state->commit->filename)
return false;

Expand All @@ -309,19 +267,6 @@ blame_read(struct view *view, struct buffer *buf, bool force_stop)
blame_update_file_name_visibility(view);
}

for (i = 0; i < view->lines; i++) {
struct line *line = &view->line[i];
struct blame *blame = line->data;

if (blame && blame->commit == state->commit) {
line->dirty = 1;
if (update_view_columns)
view_column_info_update(view, line);
update_view_columns = false;
}
}

state->commit = NULL;
}

return true;
Expand Down Expand Up @@ -363,7 +308,7 @@ setup_blame_parent_line(struct view *view, struct blame *blame)
char from[SIZEOF_REF + SIZEOF_STR];
char to[SIZEOF_REF + SIZEOF_STR];
const char *diff_tree_argv[] = {
"git", "diff", encoding_arg, "--no-textconv", "--no-ext-diff",
"git", "diff", encoding_arg, "--no-ext-diff",
"--no-color", "-U0", from, to, "--", NULL
};
struct io io;
Expand Down Expand Up @@ -539,7 +484,7 @@ blame_select(struct view *view, struct line *line)
static struct view_ops blame_ops = {
"line",
argv_env.commit,
VIEW_SEND_CHILD_ENTER | VIEW_BLAME_LIKE,
VIEW_SEND_CHILD_ENTER | VIEW_BLAME_LIKE | VIEW_REFRESH,
sizeof(struct blame_state),
blame_open,
blame_read,
Expand Down
2 changes: 1 addition & 1 deletion src/diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ diff_blame_line(const char *ref, const char *file, unsigned long lineno,

while (io_get(&io, &buf, '\n', true)) {
if (header) {
if (!parse_blame_header(header, buf.data, 9999999))
if (!parse_blame_header(header, buf.data))
break;
header = NULL;

Expand Down
12 changes: 5 additions & 7 deletions src/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ parse_author_line(char *ident, const struct ident **author, struct time *time)
*/

static bool
parse_number(const char **posref, size_t *number, size_t min, size_t max)
parse_number(const char **posref, size_t *number)
{
const char *pos = *posref;

Expand All @@ -101,15 +101,13 @@ parse_number(const char **posref, size_t *number, size_t min, size_t max)
if (!pos || !isdigit(pos[1]))
return false;
*number = atoi(pos + 1);
if (*number < min || *number > max)
return false;

*posref = pos;
return true;
}

bool
parse_blame_header(struct blame_header *header, const char *text, size_t max_lineno)
parse_blame_header(struct blame_header *header, const char *text)
{
const char *pos = text + SIZEOF_REV - 2;

Expand All @@ -118,10 +116,10 @@ parse_blame_header(struct blame_header *header, const char *text, size_t max_lin

string_ncopy(header->id, text, SIZEOF_REV);

if (!parse_number(&pos, &header->orig_lineno, 1, 9999999) ||
!parse_number(&pos, &header->lineno, 1, max_lineno) ||
!parse_number(&pos, &header->group, 1, max_lineno - header->lineno + 1))
if (!parse_number(&pos, &header->orig_lineno) ||
!parse_number(&pos, &header->lineno))
return false;
parse_number(&pos, &header->group);

return true;
}
Expand Down

0 comments on commit db4a6b4

Please sign in to comment.