From e1b24b557d00407fb96755c34a8956afff56a51a Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Sat, 26 Sep 2026 08:38:40 -1000 Subject: Add stable markup hooks for site themes --- source/ui-blame.c | 4 +-- source/ui-commit.c | 12 ++++----- source/ui-diff.c | 71 +++++++++++++++++++++++++++++----------------------- source/ui-log.c | 41 ++++++++++++++++-------------- source/ui-refs.c | 29 ++++++++++++--------- source/ui-repolist.c | 17 +++++++------ source/ui-shared.c | 51 ++++++++++++++++++++++++++----------- source/ui-ssdiff.c | 11 +++++--- source/ui-ssdiff.h | 7 ++++-- source/ui-stats.c | 25 +++++++++--------- source/ui-summary.c | 20 +++++++-------- source/ui-tag.c | 10 ++++---- source/ui-tree.c | 32 +++++++++++++++-------- 13 files changed, 194 insertions(+), 136 deletions(-) (limited to 'source') diff --git a/source/ui-blame.c b/source/ui-blame.c index c020dbc..5d88f94 100644 --- a/source/ui-blame.c +++ b/source/ui-blame.c @@ -294,11 +294,11 @@ static void print_blame_page(const struct object_id *oid, const char *path, cgit_set_title_from_path(path); cgit_print_layout_start(); - htmlf("blob: %s (", oid_to_hex(oid)); + htmlf("
blob: %s (", oid_to_hex(oid)); cgit_plain_link("plain", NULL, NULL, ctx.qry.head, rev, path); html(") ("); cgit_tree_link("tree", NULL, NULL, ctx.qry.head, rev, path); - html(")\n"); + 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 diff --git a/source/ui-commit.c b/source/ui-commit.c index 1fdc5fa..1ac96aa 100644 --- a/source/ui-commit.c +++ b/source/ui-commit.c @@ -31,7 +31,7 @@ static void print_ident_row(const char *role, const char *name, const char *email, timestamp_t date, int tz) { - htmlf("%s", role); + htmlf("%s", role); cgit_open_filter(ctx.repo->email_filter, email ? email : "", "commit"); html_txt(name); if (ctx.cfg.enable_plain_email) { @@ -69,7 +69,7 @@ static int print_parent_rows(struct commit *commit, const char *rev, const char } if (!parents) oidcpy(first, &p->item->object.oid); - html("parent
"); + html("parent
"); parent_hex = label = oid_to_hex(&p->item->object.oid); info = ctx.repo->enable_subject_links ? cgit_parse_commit(parent) : NULL; if (info) @@ -178,7 +178,7 @@ static void print_trailers(const char *msg) html("\n"); strbuf_reset(&key); strbuf_addbuf(&key, &iter.key); - html(""); + html(""); html_txt(key.buf); html(""); open = 1; @@ -279,7 +279,7 @@ void cgit_print_commit(char *hex, const char *prefix) // The spanning cells are kept out of the column widths, so a hash row // never pushes the dates away from the names above it. - html("commit
"); + html("commit
"); commit_hex = oid_to_hex(&commit->object.oid); cgit_commit_link(commit_hex, NULL, NULL, ctx.qry.head, commit_hex, prefix); html(" ("); @@ -290,7 +290,7 @@ void cgit_print_commit(char *hex, const char *prefix) // together, leaving the tree beside the download links. parents = print_parent_rows(commit, hex, prefix, &first_oid); - html("tree
"); + html("tree
"); tree_rev = xstrdup(hex); cgit_tree_link(oid_to_hex(get_commit_tree_oid(commit)), NULL, NULL, ctx.qry.head, tree_rev, NULL); if (prefix) { @@ -301,7 +301,7 @@ void cgit_print_commit(char *hex, const char *prefix) html("
\n"); if (ctx.repo->snapshots) { - html("download
"); + html("download
"); cgit_print_snapshot_links(ctx.repo, hex, "
"); html("
\n"); } diff --git a/source/ui-diff.c b/source/ui-diff.c index f258e9f..5c9cd1c 100644 --- a/source/ui-diff.c +++ b/source/ui-diff.c @@ -234,6 +234,13 @@ static void print_file_header(const struct object_id *old_oid, char *old_path, u int subproject; subproject = (S_ISGITLINK(old_mode) || S_ISGITLINK(new_mode)); + // The side by side view opens its file group before the header row, + // so only the unified view opens one here. + if (!use_ssdiff) { + html("
"); + } html("
"); html("diff --git a/"); html_txt(old_path); @@ -281,6 +288,20 @@ static void print_file_header(const struct object_id *old_oid, char *old_path, u html("
"); } +/* + * Closes the group print_file_header or cgit_ssdiff_header_begin opened. The + * side by side footer closes its own, so the unified view is the only one with + * work to do here. + */ +static void end_file(void) +{ + // The unified table keeps its whitespace, so no newline follows. + if (use_ssdiff) + cgit_ssdiff_footer(); + else + html("
"); +} + /* * The length passed counts the terminator, because a renderer strips the last * byte of every line it is given. @@ -315,12 +336,11 @@ static void print_truncated(const char *path) cgit_diff_link("View it on its own page", NULL, NULL, ctx.qry.head, ctx.qry.oid, ctx.qry.oid2, path); html("."); - if (use_ssdiff) { + if (use_ssdiff) html(""); - cgit_ssdiff_footer(); - } else { + else html("
"); - } + end_file(); } static struct fileinfo *reserve_item(void) @@ -353,7 +373,7 @@ static void collect_body(struct diff_filepair *pair, struct fileinfo *item, int html_capture_begin(body); if (use_ssdiff) - cgit_ssdiff_header_begin(); + cgit_ssdiff_header_begin(pair->two->path); print_file_header(&pair->one->oid, pair->one->path, pair->one->mode, &pair->two->oid, pair->two->path, pair->two->mode); if (use_ssdiff) @@ -383,8 +403,7 @@ static void collect_body(struct diff_filepair *pair, struct fileinfo *item, int if (*binary) print_binary_differs(); } - if (use_ssdiff) - cgit_ssdiff_footer(); + end_file(); if (render_suppressed) { // Setting the length back would keep the grown allocation, @@ -491,7 +510,7 @@ static void filepair_cb(struct diff_filepair *pair) idx = item_idx++; current_filepair = pair; if (use_ssdiff) { - cgit_ssdiff_header_begin(); + cgit_ssdiff_header_begin(pair->two->path); line_fn = cgit_ssdiff_line_cb; } print_file_header(&pair->one->oid, pair->one->path, pair->one->mode, @@ -505,8 +524,7 @@ static void filepair_cb(struct diff_filepair *pair) } if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) { print_subproject_lines(pair, line_fn); - if (use_ssdiff) - cgit_ssdiff_footer(); + end_file(); return; } if (cgit_diff_files(&pair->one->oid, &pair->two->oid, &old_size, &new_size, @@ -514,8 +532,7 @@ static void filepair_cb(struct diff_filepair *pair) cgit_print_error("Error running diff"); if (binary) print_binary_differs(); - if (use_ssdiff) - cgit_ssdiff_footer(); + end_file(); } static void print_raw_patch(const struct object_id *old_tree_oid, const struct object_id *new_tree_oid) @@ -553,14 +570,11 @@ void cgit_print_diff_ctrls(void) html("
\n"); html("diff options"); - html("
"); + html(""); cgit_add_hidden_formfields(1, 0, ctx.qry.page); - html(""); - html(""); - html(""); - html(""); - html(""); - html(""); - html(""); - html(""); - html(""); - html(""); - html(""); - html("
context:"); - html(""); selected = ctx.qry.context; if (!selected) selected = DEFAULT_DIFF_CONTEXT; @@ -569,27 +583,20 @@ void cgit_print_diff_ctrls(void) for (i = 15; i <= MAX_DIFF_CONTEXT_LINES; i += 5) html_intoption(i, cgit_fmt("%d", i), selected); html(""); - html("
space:"); - html(""); html_intoption(0, "include", ctx.qry.ignorews); html_intoption(1, "ignore", ctx.qry.ignorews); html(""); - html("
mode:"); - html(""); selected = ctx.qry.has_difftype ? ctx.qry.difftype : ctx.cfg.difftype; html_intoption(0, "unified", selected); html_intoption(1, "ssdiff", selected); html_intoption(2, "stat only", selected); - html("
"); + html(""); html(""); - html("
"); + html("
"); html("\n"); html("
\n"); } diff --git a/source/ui-log.c b/source/ui-log.c index 86cb756..9f21114 100644 --- a/source/ui-log.c +++ b/source/ui-log.c @@ -227,7 +227,7 @@ static void print_commit(struct commit *commit, struct rev_info *revs) print_graph_above(revs, &graphbuf, columns); info = cgit_parse_commit(commit); - htmlf("", ctx.qry.showmsg ? " class='logheader'" : ""); + htmlf("", ctx.qry.showmsg ? " logheader" : ""); if (revs->graph) { html(""); @@ -372,11 +372,11 @@ static void print_pager(struct rev_info *revs, int ofs, int cnt) { struct commit *more = get_revision(revs); - html("\n"); + html("\n\n"); // A single page needs no pager, and an empty list has nothing to page. if (ofs <= 0 && !more) return; - html("
    "); + html("
"); } /* @@ -562,15 +562,15 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern if (pager) { cgit_print_layout_start(); - html("\n"); + html("
\n"); } - html(""); + html("\n"); if (commit_graph) html(""); else - html(""); - html(""); + html(""); + html(""); if (rev.graph) - html(""); + html(""); if (ctx.repo->enable_log_filecount) { - html(""); + html(""); columns++; } if (ctx.repo->enable_log_linecount) { - html(""); + html(""); columns++; } html("\n"); @@ -617,13 +617,16 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern if (pager) { print_pager(&rev, ofs, cnt); cgit_print_layout_end(); - } else if ((commit = get_revision(&rev))) { - htmlf("\n"); + } else { + if ((commit = get_revision(&rev))) { + htmlf("\n"); + } + html("\n"); } if (must_free_tip) diff --git a/source/ui-refs.c b/source/ui-refs.c index d89e3ea..e4a0dd0 100644 --- a/source/ui-refs.c +++ b/source/ui-refs.c @@ -79,10 +79,11 @@ static void collect_branches(struct reflist *list) static void print_branch_header(void) { html( - "" - "" - "" - "\n" + "\n" + "" + "" + "" + "\n" ); } @@ -93,7 +94,7 @@ static int print_branch(struct refinfo *ref) if (!info) return 1; - html("" - "" - "" - "\n" + "\n" + "" + "" + "" + "\n" ); } @@ -152,7 +154,7 @@ static int print_tag(struct refinfo *ref) return 1; } - html("\n"); cgit_free_reflist_inner(&list); } @@ -278,6 +281,7 @@ static void print_tags_page(int pagesize) if (page.size < list.count) print_ref_pager(page.start, page.size, list.count, "tags"); + html("\n"); cgit_free_reflist_inner(&list); } @@ -305,6 +309,7 @@ void cgit_print_branches(int maxcount) if (maxcount < list.count) print_refs_link("heads"); + html("\n"); cgit_free_reflist_inner(&list); } @@ -328,6 +333,7 @@ void cgit_print_tags(int maxcount) if (maxcount < list.count) print_refs_link("tags"); + html("\n"); cgit_free_reflist_inner(&list); } @@ -335,7 +341,7 @@ void cgit_print_tags(int maxcount) void cgit_print_refs(void) { cgit_print_layout_start(); - html("
AgeCommit message"); + html("AgeCommit message"); if (pager) { html(" ("); cgit_log_link( @@ -580,15 +580,15 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern ); html(")"); } - html("AuthorAuthorAgeAgeFilesFilesLinesLines
", columns); - cgit_log_link( - "[...]", NULL, NULL, ctx.qry.head, NULL, ctx.qry.vpath, 0, - NULL, NULL, ctx.qry.showmsg, ctx.qry.follow - ); - html("
", columns); + cgit_log_link( + "[...]", NULL, NULL, ctx.qry.head, NULL, ctx.qry.vpath, 0, + NULL, NULL, ctx.qry.showmsg, ctx.qry.follow + ); + html("
BranchCommit messageAuthorAge
BranchCommit messageAuthorAge
"); + html("
"); cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL, ctx.qry.showmsg, 0); html(""); @@ -128,10 +129,11 @@ static void collect_tags(struct reflist *list) static void print_tag_header(void) { html( - "
TagDownloadAuthorAge
TagDownloadAuthorAge
"); + html("
"); cgit_tag_link(name, NULL, NULL, name); html(""); if (ctx.repo->snapshots && (obj->type == OBJ_COMMIT)) @@ -255,6 +257,7 @@ static void print_branches_page(int pagesize) if (page.size < list.count) print_ref_pager(page.start, page.size, list.count, "heads"); + html("
\n"); + html("
\n"); if (ctx.qry.path && starts_with(ctx.qry.path, "heads")) { print_branches_page(ctx.cfg.max_ref_count); @@ -343,7 +349,6 @@ void cgit_print_refs(void) print_tags_page(ctx.cfg.max_ref_count); } else { cgit_print_branches(ctx.cfg.max_ref_count); - html("\n"); cgit_print_tags(ctx.cfg.max_ref_count); } html("
\n"); diff --git a/source/ui-repolist.c b/source/ui-repolist.c index 031cb0d..6dcc976 100644 --- a/source/ui-repolist.c +++ b/source/ui-repolist.c @@ -181,7 +181,7 @@ static int any_repos_visible(void) */ static void print_column_header(const char *title, const char *column, const char *currenturl) { - htmlf(""); + html("\n"); print_column_header("Name", "name", currenturl); print_column_header("Description", "desc", currenturl); if (ctx.cfg.enable_index_owner) print_column_header("Owner", "owner", currenturl); print_column_header("Idle", "idle", currenturl); if (ctx.cfg.enable_index_links) - html("Links"); + html("Links"); html("\n"); } @@ -224,7 +224,8 @@ static void print_repo_row(const char *currenturl, int sublevel) { char *repourl; - htmlf("", sublevel ? "sublevel-repo" : "toplevel-repo"); + htmlf("", + sublevel ? "sublevel-repo" : "toplevel-repo"); cgit_summary_link(ctx.repo->name, NULL, NULL, NULL); html(""); repourl = cgit_repourl(ctx.repo->url); @@ -267,7 +268,7 @@ static void print_pager(int total, int pagelen, char *search, char *sort) int i, ofs; char *class; - html("
    \n"); + html("
\n"); } static int cmp_str(const char *s1, const char *s2) @@ -420,7 +421,7 @@ void cgit_print_repolist(void) sort_repolist("section"); currenturl = cgit_currenturl(); - html("\n"); + html("
\n"); for (i = 0; i < cgit_repolist.count; i++) { char *section; @@ -448,6 +449,8 @@ void cgit_print_repolist(void) } print_repo_row(currenturl, !column_sorted && section); } + if (shown) + html("\n"); html("
\n"); if (hits > ctx.cfg.max_repo_count) print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search, ctx.qry.sort); diff --git a/source/ui-shared.c b/source/ui-shared.c index 4417975..0f2f1e3 100644 --- a/source/ui-shared.c +++ b/source/ui-shared.c @@ -104,6 +104,22 @@ static void site_url(const char *page, const char *search, const char *sort, int } } +/* + * Write the class of a link, and mark the link as the current one for + * assistive technology when the class says it is the active tab or the + * current page of a pager. + */ +static void link_class(const char *class) +{ + if (!class) + return; + html(" class='"); + html_attr(class); + html("'"); + if (!strcmp(class, "active") || !strcmp(class, "current")) + html(" aria-current='page'"); +} + static void site_link(const char *page, const char *name, const char *title, const char *class, const char *search, const char *sort, int ofs, int always_root) { @@ -113,11 +129,7 @@ static void site_link(const char *page, const char *name, const char *title, html_attr(title); html("'"); } - if (class) { - html(" class='"); - html_attr(class); - html("'"); - } + link_class(class); html(" href='"); site_url(page, search, sort, ofs, always_root); html("'>"); @@ -142,11 +154,7 @@ static const char *repolink(const char *title, const char *class, const char *pa html_attr(title); html("'"); } - if (class) { - html(" class='"); - html_attr(class); - html("'"); - } + link_class(class); html(" href='"); if (ctx.cfg.virtual_root) { html_url_path(ctx.cfg.virtual_root); @@ -631,7 +639,7 @@ static void print_repo_tabs(void) static void print_repo_search(void) { - html("\n"); html("
\n"); } diff --git a/source/ui-summary.c b/source/ui-summary.c index 0b33a96..eb04ecd 100644 --- a/source/ui-summary.c +++ b/source/ui-summary.c @@ -44,8 +44,9 @@ static void print_clone_url(const char *url) // cgit_add_clone_urls may call back no times at all, so the heading // waits for a first url rather than being printed ahead of the walk. if (clone_urls_printed++ == 0) { - htmlf("\n", columns); - htmlf("Clone\n", columns); + html("\n"); + htmlf("Clone\n", + columns); } cgit_print_clone_row(url, columns); @@ -113,19 +114,18 @@ static char *resolve_about_path(const char *filename, const char *ref, const cha void cgit_print_summary(void) { - int columns = log_columns(); - cgit_print_layout_start(); - html("\n"); + // One table, so the columns line up across the sections, each of + // which is a body of its own. + html("
\n"); cgit_print_branches(ctx.cfg.summary_branches); - htmlf("\n", columns); cgit_print_tags(ctx.cfg.summary_tags); - if (ctx.cfg.summary_log > 0) { - htmlf("\n", columns); + if (ctx.cfg.summary_log > 0) cgit_print_log(ctx.qry.head, 0, ctx.cfg.summary_log, NULL, NULL, NULL, 0, 0, 0); - } clone_urls_printed = 0; cgit_add_clone_urls(print_clone_url); + if (clone_urls_printed) + html("\n"); html("
\n"); cgit_print_layout_end(); } @@ -159,7 +159,7 @@ void cgit_print_repo_readme(const char *path) goto done; } - html("
"); + html("
"); if (!ctx.repo->about_filter) { // With no about-filter there is nothing to turn the readme // into safe HTML, so it is escaped rather than served raw. diff --git a/source/ui-tag.c b/source/ui-tag.c index 6811e0c..559cb54 100644 --- a/source/ui-tag.c +++ b/source/ui-tag.c @@ -19,7 +19,7 @@ static void print_name_row(const char *revname, const struct object_id *oid) { - html("tag name"); + html("tag name"); html_txt(revname); if (oid) htmlf(" (%s)", oid_to_hex(oid)); @@ -28,7 +28,7 @@ static void print_name_row(const char *revname, const struct object_id *oid) static void print_date_row(struct taginfo *info) { - html("tag date