diff options
author | gennyble <gen@nyble.dev> | 2023-12-16 07:43:48 -0600 |
---|---|---|
committer | gennyble <gen@nyble.dev> | 2023-12-16 07:43:48 -0600 |
commit | 733a517036bc5ad3327b41f494b0d09cd2470262 (patch) | |
tree | 4581a25c2fd60c7e5ef075c6aad788fd1575bfbe | |
parent | fad097a08e55c9eec0fa86efec72de4426674ca2 (diff) | |
download | cgit-pink-master.tar.gz cgit-pink-master.zip |
-rw-r--r-- | cgit.c | 6 | ||||
-rw-r--r-- | cgit.h | 3 | ||||
-rw-r--r-- | cgitrc.5.txt | 14 | ||||
-rw-r--r-- | ui-repolist.c | 105 |
4 files changed, 114 insertions, 14 deletions
diff --git a/cgit.c b/cgit.c index dd28a79..a501298 100644 --- a/cgit.c +++ b/cgit.c @@ -258,7 +258,9 @@ static void config_cb(const char *name, const char *value) else if (!strcmp(name, "repository-sort")) ctx.cfg.repository_sort = xstrdup(value); else if (!strcmp(name, "section-sort")) - ctx.cfg.section_sort = atoi(value); + ctx.cfg.section_sort = xstrdup(value); + else if (!strcmp(name, "section-order")) + string_list_append(&ctx.cfg.section_order, xstrdup(value)); else if (!strcmp(name, "source-filter")) ctx.cfg.source_filter = cgit_new_filter(value, SOURCE); else if (!strcmp(name, "summary-log")) @@ -401,7 +403,7 @@ static void prepare_context(void) ctx.cfg.script_name = CGIT_SCRIPT_NAME; ctx.cfg.section = ""; ctx.cfg.repository_sort = "name"; - ctx.cfg.section_sort = 1; + ctx.cfg.section_sort = "name"; ctx.cfg.summary_branches = 10; ctx.cfg.summary_log = 10; ctx.cfg.summary_tags = 10; diff --git a/cgit.h b/cgit.h index 72fcd84..518cefe 100644 --- a/cgit.h +++ b/cgit.h @@ -212,6 +212,7 @@ struct cgit_config { char *root_readme; char *script_name; char *section; + struct string_list section_order; char *repository_sort; char *virtual_root; /* Always ends with '/'. */ char *strict_export; @@ -256,7 +257,7 @@ struct cgit_config { int scan_hidden_path; int section_from_path; int snapshots; - int section_sort; + char *section_sort; int summary_branches; int summary_log; int summary_tags; diff --git a/cgitrc.5.txt b/cgitrc.5.txt index cafb535..4fa3f9a 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -389,10 +389,16 @@ section:: none. section-sort:: - Flag which, when set to "1", will sort the sections on the repository - listing by name. Set this flag to "0" if the order in the cgitrc file should - be preserved. Default value: "1". See also: section, - case-sensitive-sort, repository-sort. + The way in which sections are sorted. Valid values are "name" for sorting + by section name or "order" to sort with section-order. Any other value will + preserve the order in the cgitrc file. Default value: "name". See also: + section, section-order, case-sensitive-sort, repository-sort. + +section-order:: + The name of a directory to put at the top of the repolist. Multiple config + keys may be specified and will appear in order. Repositories without a + section appear before ordered sections and sections not defined will appear + after, sorted by name. See also: section-sort section-from-path:: A number which, if defined prior to scan-path, specifies how many diff --git a/ui-repolist.c b/ui-repolist.c index 97b11c5..a46df0e 100644 --- a/ui-repolist.c +++ b/ui-repolist.c @@ -236,6 +236,64 @@ static int sort_section(const void *a, const void *b) return result; } +static int string_list_index(const struct string_list *list, const char *str) +{ + for (int i = 0; i < list->nr; ++i) { + if (strcmp(list->items[i].string, str) == 0) + return i; + } + + return -1; +} + +static int strempty(const char *str) { + if (str == NULL) + return 1; + + return str[0] == 0; +} + +static int sort_section_order(const void *a, const void *b) +{ + const struct cgit_repo *r1 = a; + const struct cgit_repo *r2 = b; + int result; + + int sec1_idx = string_list_index(&ctx.cfg.section_order, r1->section); + int sec2_idx = string_list_index(&ctx.cfg.section_order, r2->section); + int both_unordered = sec1_idx == -1 && sec2_idx == -1; + int both_empty = strempty(r1->section) && strempty(r2->section); + + if (both_empty) { + // both sections empty, sort within the emptiness + result = 0; + } else if (strempty(r1->section)) { + return -1; + } else if (strempty(r2->section)) { + return 1; + } else if (both_unordered) { + // Both are unordered, compare lexigraphically + result = cmp(r1->section, r2->section); + } else if (sec1_idx == -1) { + return 1; + } else if (sec2_idx == -1) { + return -1; + } else { + result = sec1_idx - sec2_idx; + } + + if (result == 0) { + // sections are equal, sort within them + if (strcmp(ctx.cfg.repository_sort, "age") == 0) + result = sort_idle(r1, r2); + + if (result == 0) + result = cmp(r1->name, r2->name); + } + + return result; +} + struct sortcolumn { const char *name; int (*fn)(const void *a, const void *b); @@ -243,6 +301,7 @@ struct sortcolumn { static const struct sortcolumn sortcolumn[] = { {"section", sort_section}, + {"section_order", sort_section_order}, {"name", sort_name}, {"desc", sort_desc}, {"owner", sort_owner}, @@ -253,12 +312,13 @@ static const struct sortcolumn sortcolumn[] = { static int sort_repolist(char *field) { const struct sortcolumn *column; - for (column = &sortcolumn[0]; column->name; column++) { if (strcmp(field, column->name)) continue; + qsort(cgit_repolist.repos, cgit_repolist.count, sizeof(struct cgit_repo), column->fn); + return 1; } return 0; @@ -290,46 +350,71 @@ void cgit_print_repolist(void) if (ctx.qry.sort) sorted = sort_repolist(ctx.qry.sort); - else if (ctx.cfg.section_sort) + else if (strcmp(ctx.cfg.section_sort, "name") == 0) sort_repolist("section"); + else if (strcmp(ctx.cfg.section_sort, "order") == 0) + sort_repolist("section_order"); html("<table summary='repository list' class='list nowrap'>"); for (i = 0; i < cgit_repolist.count; i++) { ctx.repo = &cgit_repolist.repos[i]; + if (!is_visible(ctx.repo)) continue; + hits++; if (hits <= ctx.qry.ofs) continue; + if (hits > ctx.qry.ofs + ctx.cfg.max_repo_count) continue; + if (!header++) print_header(); + section = ctx.repo->section; if (section && !strcmp(section, "")) section = NULL; - if (!sorted && - ((last_section == NULL && section != NULL) || - (last_section != NULL && section == NULL) || - (last_section != NULL && section != NULL && - strcmp(section, last_section)))) { + + // condition: + // - not sorted AND + // - one of them exist, but not both OR + // - both exist and are not equal + // + // ( one of them exists, but not both ) + // (!last && section) || (last && !section) || (both exist and are not equal) + if (!sorted && ( + (last_section == NULL && section != NULL) || + (last_section != NULL && section == NULL) || + (last_section != NULL && section != NULL && strcmp(section, last_section)) + )) { htmlf("<tr class='nohover-highlight'><td colspan='%d' class='reposection'>", columns); html_txt(section); html("</td></tr>"); last_section = section; } + htmlf("<tr><td class='%s'>", !sorted && section ? "sublevel-repo" : "toplevel-repo"); + cgit_summary_link(ctx.repo->name, NULL, NULL, NULL); + html("</td><td>"); + repourl = cgit_repourl(ctx.repo->url); + html_link_open(repourl, NULL, NULL); + free(repourl); + if (html_ntxt(ctx.repo->desc, ctx.cfg.max_repodesc_len) < 0) html("..."); + html_link_close(); + html("</td><td>"); + if (ctx.cfg.enable_index_owner) { if (ctx.repo->owner_filter) { cgit_open_filter(ctx.repo->owner_filter); @@ -348,8 +433,10 @@ void cgit_print_repolist(void) } html("</td><td>"); } + print_modtime(ctx.repo); html("</td>"); + if (ctx.cfg.enable_index_links) { html("<td>"); cgit_summary_link("summary", NULL, "button", NULL); @@ -360,11 +447,15 @@ void cgit_print_repolist(void) cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); html("</td>"); } + html("</tr>\n"); } + html("</table>"); + if (hits > ctx.cfg.max_repo_count) print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search, ctx.qry.sort); + cgit_print_docend(); } |