From ff262e488c280c809f3ddc40ae3efd65fd350801 Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Sun, 19 Jul 2026 16:22:09 -1000 Subject: Stat oversized diffs instead of inlining them --- source/ui-diff.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'source/ui-diff.c') diff --git a/source/ui-diff.c b/source/ui-diff.c index baaa1f8..b34f7b3 100644 --- a/source/ui-diff.c +++ b/source/ui-diff.c @@ -40,6 +40,11 @@ static int use_ssdiff = 0; static struct diff_filepair *current_filepair; static const char *current_prefix; +/* Caps apply only to whole-commit views. A single-file diff page must + * always render fully, since it is where the capped views link to. */ +static int cap_diffs; +static int item_idx; + struct diff_filespec *cgit_get_current_old_file(void) { return current_filepair->one; @@ -299,11 +304,13 @@ static void filepair_cb(struct diff_filepair *pair) unsigned long old_size = 0; unsigned long new_size = 0; int binary = 0; + int idx; linediff_fn print_line_fn = print_line; if (!show_filepair(pair)) return; + idx = item_idx++; current_filepair = pair; if (use_ssdiff) { cgit_ssdiff_header_begin(); @@ -313,6 +320,29 @@ static void filepair_cb(struct diff_filepair *pair) &pair->two->oid, pair->two->path, pair->two->mode); if (use_ssdiff) cgit_ssdiff_header_end(); + + /* The diffstat pass counted this file's lines. Over the budget, + * print the header and hand off to the single-file diff page + * instead of rendering the whole thing inline. */ + if (cap_diffs && ctx.cfg.max_diff_lines > 0 && idx < files && + !items[idx].binary && items[idx].added + items[idx].removed > + (unsigned int)ctx.cfg.max_diff_lines) { + if (use_ssdiff) + html(""); + else + html("
"); + html("This diff is too large to be rendered inline. "); + cgit_diff_link("View it on its own page", NULL, NULL, + ctx.qry.head, ctx.qry.oid, ctx.qry.oid2, + items[idx].new_path); + html("."); + if (use_ssdiff) { + html(""); + cgit_ssdiff_footer(); + } else + html("
"); + return; + } if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) { if (S_ISGITLINK(pair->one->mode)) { char *l = fmt("-Subproject %s", oid_to_hex(&pair->one->oid)); @@ -406,6 +436,8 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, current_prefix = NULL; } + cap_diffs = !prefix && !current_prefix; + if (!new_rev) new_rev = ctx.qry.head; if (repo_get_oid(the_repository, new_rev, new_rev_oid)) { @@ -493,12 +525,28 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, return; } + /* A commit touching more files than max-diff-files stops at the + * stat above, where every file links to its own diff page. */ + if (cap_diffs && ctx.cfg.max_diff_files > 0 && + files > ctx.cfg.max_diff_files) { + html("
"); + html("This diff is too large to be rendered inline. " + "Follow a file above, or the "); + cgit_patch_link("patch", NULL, NULL, NULL, ctx.qry.oid, NULL); + html(" link for the whole commit."); + html("
"); + if (show_ctrls) + cgit_print_layout_end(); + return; + } + if (use_ssdiff) { html(""); } else { html("
"); html("
"); } + item_idx = 0; cgit_diff_tree(old_rev_oid, new_rev_oid, filepair_cb, prefix, ctx.qry.ignorews); if (!use_ssdiff) -- cgit v2.8.0