From bc9003fd69291bf96fe5c1df2f546c8da0140618 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sun, 28 Jun 2026 16:35:55 +0300 Subject: [PATCH] optimize pr files html (50% reduction) --- diff.v | 46 +++++++++++++--- pr_routes.v | 38 +++++++++---- static/assets/version | 2 +- static/css/gitly.scss | 110 ++++++++++++++++++++------------------ templates/commit.html | 16 +----- templates/pull_files.html | 24 +-------- 6 files changed, 129 insertions(+), 107 deletions(-) diff --git a/diff.v b/diff.v index e33f16b..2cd2030 100644 --- a/diff.v +++ b/diff.v @@ -4,11 +4,37 @@ module main import veb import highlight +import strings + +fn render_diff_table(fd FileDiff) veb.RawHtml { + mut out := strings.new_builder(1024) + out.write_string('
') + for hunk in fd.hunks { + out.write_string(diff_hunk_header_html(hunk.header)) + for dline in hunk.lines { + out.write_string(diff_line_row_html(fd.path, dline)) + } + } + out.write_string('
') + return veb.RawHtml(out.str()) +} + +fn diff_hunk_header_html(header string) string { + return '

${html_escape_text(header)}

' +} + +fn diff_line_row_html(file_path string, dline DiffLine) string { + return '

${dline.old_line_str()}${dline.new_line_str()}${dline.compact_sign()}${highlight.highlight_line(dline.content, + file_path)}

' +} -// render_diff_line is a template helper that returns the diff line's -// content with single-line syntax highlighting applied. -fn render_diff_line(content string, file_path string) veb.RawHtml { - return veb.RawHtml(highlight.highlight_line(content, file_path)) +fn diff_comment_box_html(file_path string, dline DiffLine, lang Lang) string { + if dline.kind == 'context' { + return '' + } + name := html_escape_text(dline.comment_field_name(file_path)) + placeholder := html_escape_text(veb.tr(lang.str(), 'pr_line_comment_placeholder').trim_space()) + return '

' } struct FileDiff { @@ -134,11 +160,19 @@ fn parse_unified_diff(raw string) []FileDiff { return files } -fn (d &DiffLine) sign() string { +fn (d &DiffLine) compact_sign() string { return match d.kind { 'add' { '+' } 'del' { '-' } - else { ' ' } + else { '' } + } +} + +fn (d &DiffLine) compact_class() string { + return match d.kind { + 'add' { 'a' } + 'del' { 'd' } + else { 'c' } } } diff --git a/pr_routes.v b/pr_routes.v index d284e60..5a89ffc 100644 --- a/pr_routes.v +++ b/pr_routes.v @@ -6,6 +6,7 @@ import veb import validation import git import time +import strings struct PrWithUser { pr PullRequest @@ -300,6 +301,7 @@ pub fn (mut app App) pull_request_files(mut ctx Context, username string, repo_n user: u } } + can_comment := ctx.logged_in && pr.is_open() return $veb.html('templates/pull_files.html') } @@ -603,9 +605,26 @@ fn merge_branches_in_bare(repo Repo, base string, head string, author string, me return commit_sha } -// render_inline_comments returns the HTML rows for any line comments -// attached to a given diff line (matched on file_path, side, line_number). -fn render_inline_comments(file_path string, dline DiffLine, comments_by_key map[string][]PrReviewCommentWithUser) veb.RawHtml { +fn render_pr_diff_table(fd FileDiff, comments_by_key map[string][]PrReviewCommentWithUser, can_comment bool, lang Lang) veb.RawHtml { + mut out := strings.new_builder(1024) + out.write_string('
') + for hunk in fd.hunks { + out.write_string(diff_hunk_header_html(hunk.header)) + for dline in hunk.lines { + out.write_string(diff_line_row_html(fd.path, dline)) + if can_comment && dline.kind != 'context' { + out.write_string(diff_comment_box_html(fd.path, dline, lang)) + } + out.write_string(inline_comments_html(fd.path, dline, comments_by_key)) + } + } + out.write_string('
') + return veb.RawHtml(out.str()) +} + +// inline_comments_html returns any line comments attached to a given diff line, +// matched on file_path, side, and line_number. +fn inline_comments_html(file_path string, dline DiffLine, comments_by_key map[string][]PrReviewCommentWithUser) string { mut side := '' mut line_no := 0 if dline.kind == 'add' { @@ -615,24 +634,21 @@ fn render_inline_comments(file_path string, dline DiffLine, comments_by_key map[ side = 'old' line_no = dline.old_line } else { - return veb.RawHtml('') + return '' } key := '${file_path}|${side}|${line_no}' - list := comments_by_key[key] or { return veb.RawHtml('') } + list := comments_by_key[key] or { return '' } if list.len == 0 { - return veb.RawHtml('') + return '' } mut out := '' for c in list { body := html_escape_text(c.item.text) username := html_escape_text(c.user.username) rel := html_escape_text(c.item.relative()) - out += '' + - '
' + - '${username} commented ${rel}' + - '

${body}

' + '
' + out += '

${username} commented ${rel}
${body}

' } - return veb.RawHtml(out) + return out } // is_safe_ref does a strict whitelist check for branch names used in shell. diff --git a/static/assets/version b/static/assets/version index 94df513..827d24b 100644 --- a/static/assets/version +++ b/static/assets/version @@ -1 +1 @@ -06e10ac \ No newline at end of file +17255ce \ No newline at end of file diff --git a/static/css/gitly.scss b/static/css/gitly.scss index f359de8..e32809d 100644 --- a/static/css/gitly.scss +++ b/static/css/gitly.scss @@ -2540,71 +2540,76 @@ form { .pr-diff__table { width: 100%; - border-collapse: collapse; + overflow-x: auto; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 12px; background-color: $white; - table-layout: auto; } -.pr-diff__hunk-header td, -.pr-diff__hunk-header td code { - background-color: #ddf4ff; - color: #57606a; - padding: 4px 12px; - font-size: 12px; +.pr-diff__table > p { + display: grid; + grid-template-columns: 56px 56px 18px max-content; + min-width: 100%; + margin: 0; + line-height: 20px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; + font-size: 12px; } -.pr-diff__row td { +.pr-diff__table > p > u, +.pr-diff__table > p > i, +.pr-diff__table > p > s { padding: 0 8px; white-space: pre; - vertical-align: top; - line-height: 20px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 12px; } -.pr-diff__row--context td { background-color: $white; } -.pr-diff__row--add td { background-color: #e6ffec; } -.pr-diff__row--del td { background-color: #ffebe9; } +.pr-diff__table > p.h { + display: block; + background-color: #ddf4ff; +} + +.pr-diff__table > p.h > code { + display: block; + color: #57606a; + padding: 4px 12px; + font-size: 12px; + font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; +} + +.pr-diff__table > p.c > * { background-color: $white; } +.pr-diff__table > p.a > * { background-color: #e6ffec; } +.pr-diff__table > p.d > * { background-color: #ffebe9; } -.pr-diff__row--add .pr-diff__lineno, -.pr-diff__row--add .pr-diff__sign { +.pr-diff__table > p.a > u, +.pr-diff__table > p.a > i { background-color: #ccffd8; } -.pr-diff__row--del .pr-diff__lineno, -.pr-diff__row--del .pr-diff__sign { +.pr-diff__table > p.d > u, +.pr-diff__table > p.d > i { background-color: #ffd7d5; } -.pr-diff__lineno { +.pr-diff__table > p > u { color: rgba(36, 41, 46, 0.4); text-align: right; - width: 1%; + text-decoration: none; user-select: none; - min-width: 40px; border-right: 1px solid rgba(0, 0, 0, 0.04); } -.pr-diff__sign { - width: 1%; - min-width: 18px; +.pr-diff__table > p > i { + color: inherit; + font-style: normal; text-align: center; user-select: none; } -.pr-diff__content { - width: 100%; - - pre { - margin: 0; - font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; - font-size: 12px; - line-height: 20px; - white-space: pre; - } +.pr-diff__table > p > s { + display: block; + text-decoration: none; b { font-weight: 600; @@ -2622,22 +2627,23 @@ form { } } -.pr-diff__commentrow td { +.pr-diff__table > p.m { background-color: $white; padding: 4px 8px; } -.pr-files-content .pr-diff__commentrow { +.pr-files-content .pr-diff__table > p.m { display: none; } -.pr-files-content .pr-diff__row:hover + .pr-diff__commentrow, -.pr-files-content .pr-diff__commentrow:hover, -.pr-files-content .pr-diff__commentrow:focus-within { - display: table-row; +.pr-files-content .pr-diff__table > p.a:hover + p.m, +.pr-files-content .pr-diff__table > p.d:hover + p.m, +.pr-files-content .pr-diff__table > p.m:hover, +.pr-files-content .pr-diff__table > p.m:focus-within { + display: block; } -.pr-diff__commentbox { +.pr-diff__table > p.m > textarea { width: 100%; box-sizing: border-box; font-family: system-ui, sans-serif; @@ -2646,22 +2652,24 @@ form { resize: vertical; } -.pr-diff__inline-comment td { +.pr-diff__table > p.n { background-color: #fffbea; padding: 8px 12px; -} - -.pr-inline-comment { font-family: system-ui, sans-serif; + font-size: 13px; - p { - margin: 4px 0 0; + i { + color: $gray-dark; + font-size: 12px; + font-style: normal; } -} -.pr-inline-comment__meta { - color: $gray-dark; - font-size: 12px; + s { + display: block; + margin-top: 4px; + text-decoration: none; + white-space: pre-wrap; + } } .pr-review-form { diff --git a/templates/commit.html b/templates/commit.html index 075ece5..f07f53f 100644 --- a/templates/commit.html +++ b/templates/commit.html @@ -56,21 +56,7 @@ @if fd.is_binary
%commit_binary_file
@else - - @for hunk in fd.hunks - - - - @for dline in hunk.lines - - - - - - - @end - @end -
@hunk.header
@{dline.old_line_str()}@{dline.new_line_str()}@{dline.sign()}
@{render_diff_line(dline.content, fd.path)}
+ @{render_diff_table(fd)} @end @end diff --git a/templates/pull_files.html b/templates/pull_files.html index cf97541..1b36ea4 100644 --- a/templates/pull_files.html +++ b/templates/pull_files.html @@ -131,29 +131,7 @@ @if fd.is_binary
%pr_binary_file
@else - - @for hunk in fd.hunks - - - - @for dline in hunk.lines - - - - - - - @{render_inline_comments(fd.path, dline, comments_by_key)} - @if ctx.logged_in && pr.is_open() && dline.kind != 'context' - - - - @end - @end - @end -
@hunk.header
@{dline.old_line_str()}@{dline.new_line_str()}@{dline.sign()}
@{render_diff_line(dline.content, fd.path)}
- -
+ @{render_pr_diff_table(fd, comments_by_key, can_comment, ctx.lang)} @end @end -- 2.39.5