From a6b8305ef4f10bb1f9929536e656dca7b5805119 Mon Sep 17 00:00:00 2001 From: tslil Date: Sun, 30 Aug 2026 14:34:19 +0000 Subject: [PATCH] Add default-tab option and explicit summary page URLs A bare repository URL (/repo/) is currently always served as the summary page. With a readme configured, however, the about page is often a better landing page. Add a new global cgitrc option, default-tab, which configures the page that /repo/ should land on: default-tab=about When default-tab is set to anything other than the summary page, a request for the bare repository URL is redirected to /repo//. Repository name links (header breadcrumb, repository list on the index page) keep pointing at the bare repository URL, so they follow the redirect. The summary tab in the page header, and the summary button on the index page, previously pointed at the bare repository URL as well, which made them land on whatever the bare URL redirected to. They now explicitly point at /repo/summary/. A new cgit_repo_link() emits the bare repository URL for the links that should follow the default-tab redirect, while cgit_summary_link() now always points at the summary page. Finally, the fallback in about_fn() for repositories without a readme and without a homepage used to redirect to the repository URL with ../ appended (e.g. /repo/about../), relying on the web server to mangle that back to the summary page. It now redirects straight to /repo/summary/. Signed-off-by: tslil --- cgit.c | 31 +++++++++++++++++++++++++++++++ cgit.h | 1 + cgitrc.5.txt | 14 ++++++++++++++ cmd.c | 11 ++++++----- ui-repolist.c | 2 +- ui-shared.c | 8 +++++++- ui-shared.h | 2 ++ 7 files changed, 62 insertions(+), 7 deletions(-) diff --git a/cgit.c b/cgit.c index ca318e8..bf62d40 100644 --- a/cgit.c +++ b/cgit.c @@ -163,6 +163,25 @@ static void config_cb(const char *name, const char *value) ctx.cfg.logo_link = strdup_first_line(value); else if (!strcmp(name, "module-link")) ctx.cfg.module_link = strdup_first_line(value); + else if (!strcmp(name, "default-tab")) { + const char *tabs[] = { + "summary", "about", "log", "tree", "refs", + "commit", "stats" + }; + const char *valid = NULL; + size_t i; + for (i = 0; i < sizeof(tabs)/sizeof(*tabs); i++) + if (!strcmp(value, tabs[i])) { + valid = tabs[i]; + break; + } + if (valid) + ctx.cfg.default_tab = strdup_first_line(valid); + else + fprintf(stderr, + "[cgit] ignoring invalid default-tab value '%s'\n", + value); + } else if (!strcmp(name, "strict-export")) ctx.cfg.strict_export = strdup_first_line(value); else if (!strcmp(name, "virtual-root")) @@ -734,6 +753,18 @@ static void process_request(void) if (ctx.repo) prepare_repo_env(&nongit); + /* Redirect a bare repository URL to the configured default tab, if + * one is set. The summary page is the native handler for the bare + * URL, so no redirect is needed for it. */ + if (ctx.repo && !ctx.qry.page && + ctx.cfg.default_tab && strcmp(ctx.cfg.default_tab, "summary")) { + char *url = cgit_pageurl(ctx.repo->url, ctx.cfg.default_tab, + NULL); + cgit_redirect(url, false); + free(url); + return; + } + cmd = cgit_get_cmd(); if (!cmd) { ctx.page.title = "cgit error"; diff --git a/cgit.h b/cgit.h index 7d7ece7..48dfc17 100644 --- a/cgit.h +++ b/cgit.h @@ -198,6 +198,7 @@ struct cgit_config { char *cache_root; char *clone_prefix; char *clone_url; + char *default_tab; char *favicon; char *footer; char *head_include; diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 7c39bf9..c488478 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -129,6 +129,20 @@ css:: Default value: "/cgit.css". May be given multiple times, each css URL path is added in the head section of the document in turn. +default-tab:: + The page to use as the default landing page for a repository. When + set to a value other than "summary", a request for the bare repository + URL (e.g. /repo/) is redirected to /repo//, so the named tab + becomes the repository's landing page. Repository name links (the + header breadcrumb and the repository list on the index page) point at + the bare repository URL and therefore follow this redirect. The value + must be one of: "summary", "about", "log", "tree", "refs", "commit", + or "stats". Default value: "summary" (the bare repository URL serves + the summary page directly, as in stock cgit). Note that an about page + only exists for repositories which have a configured readme file (see + "repo.readme"); for repositories without one, /repo/about/ redirects + to /repo/summary/. See also: "REPOSITORY SETTINGS". + email-filter:: Specifies a command which will be invoked to format names and email address of committers, authors, and taggers, as represented in various diff --git a/cmd.c b/cmd.c index 0eb75b1..6c1777e 100644 --- a/cmd.c +++ b/cmd.c @@ -54,11 +54,12 @@ static void about_fn(void) else if (ctx.repo->homepage) cgit_redirect(ctx.repo->homepage, false); else { - char *currenturl = cgit_currenturl(); - char *redirect = fmtalloc("%s../", currenturl); - cgit_redirect(redirect, false); - free(currenturl); - free(redirect); + /* No readme and no homepage: fall back to the + * summary page. */ + char *url = cgit_pageurl(ctx.repo->url, "summary", + NULL); + cgit_redirect(url, false); + free(url); } } else cgit_print_site_readme(); diff --git a/ui-repolist.c b/ui-repolist.c index 1b224cf..e5ec5a9 100644 --- a/ui-repolist.c +++ b/ui-repolist.c @@ -321,7 +321,7 @@ void cgit_print_repolist(void) } htmlf("", !sorted && section ? "sublevel-repo" : "toplevel-repo"); - cgit_summary_link(ctx.repo->name, NULL, NULL, NULL); + cgit_repo_link(ctx.repo->name, NULL, NULL, NULL); html(""); repourl = cgit_repourl(ctx.repo->url); html_link_open(repourl, NULL, NULL); diff --git a/ui-shared.c b/ui-shared.c index df52a9b..da78b67 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -332,6 +332,12 @@ static void reporevlink(const char *page, const char *name, const char *title, void cgit_summary_link(const char *name, const char *title, const char *class, const char *head) +{ + reporevlink("summary", name, title, class, head, NULL, NULL); +} + +void cgit_repo_link(const char *name, const char *title, const char *class, + const char *head) { reporevlink(NULL, name, title, class, head, NULL, NULL); } @@ -1041,7 +1047,7 @@ static void print_header(void) if (ctx.repo) { cgit_index_link("index", NULL, NULL, NULL, NULL, 0, 1); html(" : "); - cgit_summary_link(ctx.repo->name, NULL, NULL, NULL); + cgit_repo_link(ctx.repo->name, NULL, NULL, NULL); if (ctx.env.authenticated) { html(""); html("
\n"); diff --git a/ui-shared.h b/ui-shared.h index 2a3a7f5..99ae667 100644 --- a/ui-shared.h +++ b/ui-shared.h @@ -19,6 +19,8 @@ extern void cgit_index_link(const char *name, const char *title, const char *class, const char *pattern, const char *sort, int ofs, int always_root); extern void cgit_summary_link(const char *name, const char *title, const char *class, const char *head); +extern void cgit_repo_link(const char *name, const char *title, + const char *class, const char *head); extern void cgit_tag_link(const char *name, const char *title, const char *class, const char *tag); extern void cgit_tree_link(const char *name, const char *title, -- 2.55.0