diff options
Diffstat (limited to 'source/ui-blame.c')
| -rw-r--r-- | source/ui-blame.c | 62 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 file changed, 52 insertions, 10 deletions
diff --git a/source/ui-blame.c b/source/ui-blame.c index 418e3ae..d6779c0 100644 --- a/source/ui-blame.c +++ b/source/ui-blame.c @@ -16,6 +16,38 @@ #include "blame.h" +/* Blame coalesces neighbouring lines from one commit, but a commit that + * touched several separate parts of the file still comes back once per part. + * Each of those repeats a full commit parse, so the rendered detail is kept + * 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); +} + +/* Write out a run of one repeated character. A single blame entry can cover + * the whole file, so the run is handed on in batches rather than built whole. */ +static void emit_chars(char ch, unsigned long count) +{ + struct strbuf run = STRBUF_INIT; + + while (count) { + unsigned long n = count < HTML_BATCH ? count : HTML_BATCH; + + strbuf_addchars(&run, ch, n); + html_raw(run.buf, run.len); + strbuf_reset(&run); + count -= n; + } + strbuf_release(&run); +} + static char *emit_suspect_detail(struct blame_origin *suspect) { struct commitinfo *info; @@ -47,7 +79,6 @@ static void emit_blame_entry_hash(struct blame_entry *ent) { struct blame_origin *suspect = ent->suspect; struct object_id *oid = &suspect->commit->object.oid; - unsigned long line = 0; char *detail = emit_suspect_detail(suspect); html("<span class='oid'>"); @@ -65,28 +96,36 @@ static void emit_blame_entry_hash(struct blame_entry *ent) suspect->path); } - while (line++ < ent->num_lines) - html("\n"); + // Batched rather than one write per line of the entry. + emit_chars('\n', ent->num_lines); } static void emit_blame_entry_linenumber(struct blame_entry *ent) { const char *numberfmt = "<a id='n%1$d' href='#n%1$d'>%1$d</a>\n"; + struct strbuf numbers = STRBUF_INIT; + int lineno = ent->lno; - unsigned long lineno = ent->lno; - while (lineno < ent->lno + ent->num_lines) - htmlf(numberfmt, ++lineno); + // Batched rather than a formatted write per line of the entry. + while (lineno < ent->lno + ent->num_lines) { + strbuf_addf(&numbers, numberfmt, ++lineno); + if (numbers.len >= HTML_BATCH) { + html_raw(numbers.buf, numbers.len); + strbuf_reset(&numbers); + } + } + html_raw(numbers.buf, numbers.len); + strbuf_release(&numbers); } static void emit_blame_entry_line_background(struct blame_scoreboard *sb, struct blame_entry *ent) { - unsigned long line; + int line; size_t len, maxlen = 2; const char* pos, *endpos; for (line = ent->lno; line < ent->lno + ent->num_lines; line++) { - html("\n"); pos = blame_nth_line(sb, line); endpos = blame_nth_line(sb, line + 1); len = 0; @@ -99,8 +138,11 @@ static void emit_blame_entry_line_background(struct blame_scoreboard *sb, maxlen = len; } - for (len = 0; len < maxlen - 1; len++) - html(" "); + // The widest line decides the padding, so the entry has to be measured + // before any of it is written. The newlines do not depend on that + // measurement, so both runs go out batched once it is known. + emit_chars('\n', ent->num_lines); + emit_chars(' ', maxlen - 1); } struct walk_tree_context { |
