Diff options
Diffstat (limited to '')
-rw-r--r--source/ui-blame.c123
1 file changed, 33 insertions, 90 deletions
diff --git a/source/ui-blame.c b/source/ui-blame.c
index 48cbf8e..eef8602 100644
--- a/source/ui-blame.c
+++ b/source/ui-blame.c
@@ -24,7 +24,7 @@ enum blame_target {
};
struct walk_tree_context {
- char *rev;
+ const char *rev;
int match_baselen;
enum blame_target found;
};
@@ -34,15 +34,6 @@ struct walk_tree_context {
// detail is cached here and looked up by object id.
static struct string_list suspect_details = STRING_LIST_INIT_DUP;
-static void free_suspect_details(void)
-{
- struct string_list_item *item;
-
- for_each_string_list_item(item, &suspect_details)
- free(item->util);
- string_list_clear(&suspect_details, 0);
-}
-
/*
* The scoreboard keeps a pointer to revs, so the caller owns both and has to
* keep them alive together.
@@ -57,7 +48,8 @@ static void run_blame(struct blame_scoreboard *sb, struct rev_info *revs,
strvec_push(&argv, rev);
repo_init_revisions(the_repository, revs, NULL);
revs->diffopt.flags.allow_textconv = 1;
- setup_revisions(argv.nr, argv.v, revs, NULL);
+ setup_revisions_from_strvec(&argv, revs, NULL);
+ strvec_clear(&argv);
init_scoreboard(sb);
sb->revs = revs;
sb->repo = the_repository;
@@ -67,7 +59,6 @@ static void run_blame(struct blame_scoreboard *sb, struct rev_info *revs,
prio_queue_put(&sb->commits, origin->commit);
blame_origin_decref(origin);
sb->ent = NULL;
- sb->path = path;
assign_blame(sb, 0);
blame_sort_final(sb);
blame_coalesce(sb);
@@ -161,44 +152,20 @@ static void emit_entry_hash(struct blame_entry *ent)
emit_chars('\n', ent->num_lines);
}
-static void emit_hashes(struct blame_scoreboard *sb)
-{
- struct blame_entry *ent;
-
- html("<td class='hashes'>");
- for (ent = sb->ent; ent; ent = ent->next) {
- html("<div class='alt'><pre>");
- emit_entry_hash(ent);
- html("</pre></div>");
- }
- html("</td>\n");
-}
-
static void emit_entry_linenumbers(struct blame_entry *ent)
{
- struct strbuf numbers = STRBUF_INIT;
- int lineno = ent->lno;
-
- while (lineno < ent->lno + ent->num_lines) {
- lineno++;
- strbuf_addf(&numbers, "<a id='n%d' href='#n%d'>%d</a>\n", lineno, lineno, lineno);
- if (numbers.len >= HTML_BATCH) {
- html_raw(numbers.buf, numbers.len);
- strbuf_reset(&numbers);
- }
- }
- html_raw(numbers.buf, numbers.len);
- strbuf_release(&numbers);
+ cgit_print_line_anchors((size_t)ent->lno + 1, (size_t)ent->lno + ent->num_lines);
}
-static void emit_linenumbers(struct blame_scoreboard *sb)
+static void emit_column(struct blame_scoreboard *sb, const char *class,
+ void (*emit_entry)(struct blame_entry *ent))
{
struct blame_entry *ent;
- html("<td class='linenumbers'>");
+ htmlf("<td class='%s'>", class);
for (ent = sb->ent; ent; ent = ent->next) {
html("<div class='alt'><pre>");
- emit_entry_linenumbers(ent);
+ emit_entry(ent);
html("</pre></div>");
}
html("</td>\n");
@@ -220,9 +187,10 @@ static size_t line_width(struct blame_scoreboard *sb, int line)
pos += len;
continue;
}
- width++;
if (*pos++ == '\t')
- width = (width + TAB_WIDTH - 1) & ~(TAB_WIDTH - 1);
+ width += TAB_WIDTH - width % TAB_WIDTH;
+ else
+ width++;
}
return width;
}
@@ -275,8 +243,9 @@ static void print_blame_page(const struct object_id *oid, const char *path,
enum object_type type;
char *buf;
size_t size;
- struct rev_info revs;
+ struct rev_info revs = REV_INFO_INIT;
struct blame_scoreboard sb;
+ int binary;
type = odb_read_object_info(the_repository->objects, oid, &size);
if (type == OBJ_BAD) {
@@ -295,7 +264,13 @@ static void print_blame_page(const struct object_id *oid, const char *path,
return;
}
- run_blame(&sb, &revs, path, rev);
+ // A NUL past the window buffer_is_binary sniffs would end a Lua
+ // filter's output early while the hash and line number columns still
+ // cover the whole file, so a blob holding one anywhere is treated as
+ // binary too.
+ binary = buffer_is_binary(buf, size) || memchr(buf, 0, size);
+ if (!binary)
+ run_blame(&sb, &revs, path, rev);
cgit_set_title_from_path(path);
cgit_prefix_title("blame");
@@ -307,29 +282,16 @@ static void print_blame_page(const struct object_id *oid, const char *path,
cgit_tree_link("tree", NULL, NULL, ctx.qry.head, rev, path);
html(")</div>\n");
- // A NUL past the window buffer_is_binary sniffs would end a Lua
- // filter's output early while the hash and line number columns still
- // cover the whole file, so a blob holding one anywhere is treated as
- // binary too.
- if (buffer_is_binary(buf, size) || memchr(buf, 0, size)) {
- struct blame_entry *ent = sb.ent, *next;
-
- // The scoreboard is normally consumed by the column passes,
- // so this early exit has to release it itself.
- for (; ent; ent = next) {
- next = ent->next;
- free(ent);
- }
- free((void *)sb.final_buf);
+ if (binary) {
html("<div class='error'>Blob is binary</div>");
goto cleanup;
}
html("<table class='blame blob'>\n<tr>\n");
- emit_hashes(&sb);
+ emit_column(&sb, "hashes", emit_entry_hash);
if (ctx.cfg.enable_tree_linenumbers)
- emit_linenumbers(&sb);
+ emit_column(&sb, "linenumbers", emit_entry_linenumbers);
html("<td class='lines'><div>");
emit_line_backgrounds(&sb);
@@ -338,12 +300,9 @@ static void print_blame_page(const struct object_id *oid, const char *path,
html("<pre><code>");
if (ctx.repo->source_filter) {
- char *filter_arg = xstrdup(filename);
-
- cgit_open_filter(ctx.repo->source_filter, filter_arg);
+ cgit_open_filter(ctx.repo->source_filter, filename);
html_raw(buf, size);
cgit_close_filter(ctx.repo->source_filter);
- free(filter_arg);
} else {
html_blob_txt(buf, size);
}
@@ -355,8 +314,9 @@ static void print_blame_page(const struct object_id *oid, const char *path,
cleanup:
cgit_print_layout_end();
- free_suspect_details();
+ string_list_clear(&suspect_details, 1);
free(buf);
+ release_revisions(&revs);
}
static int walk_tree(const struct object_id *oid, struct strbuf *base,
@@ -399,18 +359,8 @@ void cgit_print_blame(void)
const char *rev = ctx.qry.oid;
struct object_id oid;
struct commit *commit;
- int path_len = ctx.qry.path ? strlen(ctx.qry.path) : 0;
- // nowildcard_len matches len so git treats the path as literal rather
- // than as a glob, which is what a request naming one file means.
- struct pathspec_item path_items = {
- .match = ctx.qry.path,
- .len = path_len,
- .nowildcard_len = path_len
- };
- struct pathspec paths = {
- .nr = 1,
- .items = &path_items
- };
+ struct pathspec_item path_item;
+ struct pathspec paths = { 0 };
struct walk_tree_context walk = {
.found = TARGET_MISSING
};
@@ -418,24 +368,17 @@ void cgit_print_blame(void)
if (!rev)
rev = ctx.qry.head;
- if (repo_get_oid(the_repository, rev, &oid)) {
- cgit_print_error_page(404, "Not Found", "Bad object id: %s", rev);
+ commit = cgit_get_commit(rev, &oid);
+ if (!commit)
return;
- }
- commit = lookup_commit_reference(the_repository, &oid);
- if (!commit || repo_parse_commit(the_repository, commit)) {
- cgit_print_error_page(404, "Not Found", "Not a commit: %s", rev);
- return;
- }
- walk.rev = xstrdup(rev);
- walk.match_baselen = path_items.match ? basedir_len(path_items.match) : -1;
+ walk.rev = rev;
+ walk.match_baselen = ctx.qry.path ? basedir_len(ctx.qry.path) : -1;
+ cgit_literal_pathspec(&paths, &path_item, ctx.qry.path);
read_tree(the_repository, repo_get_commit_tree(the_repository, commit), &paths, walk_tree, &walk);
if (walk.found == TARGET_MISSING)
cgit_print_error_page(404, "Not Found", "Not found");
else if (walk.found == TARGET_FOLDER)
cgit_print_error_page(404, "Not Found", "Blame is not available for a directory");
-
- free(walk.rev);
}