From b927386173b179d124815e366989da07a711ab3e Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Sat, 24 Oct 2026 09:17:41 -1000 Subject: Show characters a browser breaks at as escapes The HTML parser turns a carriage return with no line feed after it into a line feed, and WebKit starts a new line at U+2028 and U+2029, while git and the line numbers count line feeds alone, so each one set every later line of the tree and blame pages a line below its number. CSS Text makes vertical tab, form feed and next line forced breaks as well, though no engine honours that yet. The escapes follow gitweb, which shows control characters the same way. --- source/ui-blame.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'source/ui-blame.c') diff --git a/source/ui-blame.c b/source/ui-blame.c index 8fd6c83..f60020c 100644 --- a/source/ui-blame.c +++ b/source/ui-blame.c @@ -211,6 +211,15 @@ static size_t line_width(struct blame_scoreboard *sb, int line) size_t width = 0; while (pos < end) { + size_t len; + const char *esc = html_line_break_escape(pos, end, &len); + + // An escaped character takes the room of its escape sequence. + if (esc) { + width += strlen(esc); + pos += len; + continue; + } width++; if (*pos++ == '\t') width = (width + TAB_WIDTH - 1) & ~(TAB_WIDTH - 1); @@ -297,9 +306,10 @@ 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(")\n"); - // A NUL past the window buffer_is_binary sniffs would end html_txt - // early while the hash and line number columns still cover the whole - // file, so a blob holding one anywhere is treated as binary too. + // 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; @@ -334,7 +344,7 @@ static void print_blame_page(const struct object_id *oid, const char *path, cgit_close_filter(ctx.repo->source_filter); free(filter_arg); } else { - html_txt(buf); + html_blob_txt(buf, size); } html(""); -- cgit 2.9.1