diff options
author | Freya Murphy <freya@freyacat.org> | 2025-09-04 23:42:18 +0000 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2025-09-04 23:42:18 +0000 |
commit | e6ad894ba53a185fc19f8563e26aff2ac93edd20 (patch) | |
tree | 6010b57dc2969285d0fcd88617dbaf7909d57fe6 /ui-wiki.c | |
parent | repo urls should be case insensitive (diff) | |
download | cgit-master.tar.gz cgit-master.tar.bz2 cgit-master.zip |
Diffstat (limited to '')
-rw-r--r-- | ui-wiki.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/ui-wiki.c b/ui-wiki.c new file mode 100644 index 0000000..9fdb4b9 --- /dev/null +++ b/ui-wiki.c @@ -0,0 +1,213 @@ +/* ui-wiki.c: functions for wiki output + * + * Copyright (C) 2006-2017 cgit Development Team <cgit@lists.zx2c4.com> + * Copyright (C) 2025 Freya Murphy <freya@freyacat.org> + * + * Licensed under GNU General Public License v2 + * (see COPYING for full license text) + */ + + #define USE_THE_REPOSITORY_VARIABLE + +#include "cgit.h" +#include "ui-wiki.h" +#include "html.h" +#include "ui-shared.h" + + #define WIKI_PATH ".wiki" + +struct walk_wiki_context { + char *curr_rev; + int state; + int index; +}; + +static void print_page(const struct object_id *oid, const char *path, const char *basename, const char *rev) +{ + enum object_type type; + unsigned long size; + char *buf; + + type = oid_object_info(the_repository, oid, &size); + if (type == OBJ_BAD) { + cgit_print_error_page(404, "Not found", + "Bad object name: %s", oid_to_hex(oid)); + return; + } + + buf = repo_read_object_file(the_repository, oid, &type, &size); + if (!buf) { + cgit_print_error_page(500, "Internal server error", + "Error reading object %s", oid_to_hex(oid)); + return; + } + + html("<div id='summary'>"); + cgit_open_filter(ctx.repo->about_filter, basename); + html_raw(buf, size); + cgit_close_filter(ctx.repo->about_filter); + html("</div>"); + + free(buf); +} + +static int ls_wiki(const struct object_id *oid, const char *pathname, struct walk_wiki_context *walk_wiki_ctx) +{ + char *name, *link, *ptr; + + if (isdigit(*pathname)) { + long index = strtol(pathname, &ptr, 10); + if (ptr && *ptr == '-') { + pathname = ptr + 1; + walk_wiki_ctx->index = index; + } + } + + name = xstrdup(pathname); + ptr = strrchr(name, '.'); + if (ptr) + *ptr = '\0'; + link = xstrdup(name); + for (ptr = name; *ptr; ptr++) { + if (*ptr == '-') + *ptr = ' '; + } + for (ptr = link; *ptr; ptr++) + *ptr = tolower(*ptr); + + html("<tr><td class='ls-index'>"); + htmlf("%d", walk_wiki_ctx->index); + html("</td><td class>"); + cgit_wiki_link(name, NULL, "ls-link", ctx.qry.head, walk_wiki_ctx->curr_rev, link); + html("</td></tr>\n"); + + walk_wiki_ctx->index++; + free(name); + free(link); + return 0; +} + +static void ls_head(void) +{ + cgit_print_layout_start(); + html("<table summary='wiki listing' class='list'>\n"); + html("<tr class='nohover'>"); + html("<th class='left'>Index</th>"); + html("<th class='left'>Title</th>"); + html("<th/>"); + html("</tr>\n"); +} + +static void ls_tail(void) +{ + html("</table>\n"); +} + +static int walk_wiki(const struct object_id *oid, struct strbuf *base, + const char *pathname, unsigned mode, void *cbdata) +{ + struct walk_wiki_context *walk_wiki_ctx = cbdata; + + if (!strcmp(pathname, WIKI_PATH)) + return READ_TREE_RECURSIVE; + + if (walk_wiki_ctx->state < 2) { + if (walk_wiki_ctx->state == 0) { + walk_wiki_ctx->state = 1; + ls_head(); + } + + ls_wiki(oid, pathname, walk_wiki_ctx); + } else if (walk_wiki_ctx->state == 2) { + const char *name; + + name = pathname; + if (isdigit(*name)) { + char *ptr; + strtol(name, &ptr, 10); + if (ptr && *ptr == '-') + name = ptr + 1; + } + + if (!strncasecmp(name, ctx.qry.path, strlen(ctx.qry.path))) { + struct strbuf buffer = STRBUF_INIT; + + strbuf_addbuf(&buffer, base); + strbuf_addstr(&buffer, pathname); + + walk_wiki_ctx->state = 3; + print_page(oid, pathname, buffer.buf, walk_wiki_ctx->curr_rev); + strbuf_release(&buffer); + } + } + + return 0; +} + +/* + * Show repo wiki + * rev: the commit pointing at the root ui object + * path: partial name of a wiki md file + */ +void cgit_print_wiki(const char *rev) +{ + struct object_id oid; + struct commit *commit; + struct pathspec_item path_items = { + .match = WIKI_PATH, + .len = sizeof(WIKI_PATH) - 1, + }; + struct pathspec paths = { + .nr = 1, + .items = &path_items + }; + struct walk_wiki_context walk_wiki_ctx = { + .state = 0, + .index = 1 + }; + + if (!rev) + rev = ctx.qry.head; + + if (repo_get_oid(the_repository, rev, &oid)) { + cgit_print_error_page(404, "Not found", + "Invalid revision name: %s", rev); + return; + } + commit = lookup_commit_reference(the_repository, &oid); + if (!commit || repo_parse_commit(the_repository, commit)) { + cgit_print_error_page(404, "Not found", + "Invalid commit reference: %s", rev); + return; + } + + walk_wiki_ctx.curr_rev = xstrdup(rev); + + // print wiki pages + read_tree(the_repository, repo_get_commit_tree(the_repository, commit), + &paths, walk_wiki, &walk_wiki_ctx); + + if (walk_wiki_ctx.state == 0) { + cgit_print_error_page(404, "Not found", "Wiki not found"); + goto cleanup; + } + + ls_tail(); + + // print active wiki page + if (ctx.qry.path) { + html("<hr>\n"); + + walk_wiki_ctx.state = 2; + read_tree(the_repository, repo_get_commit_tree(the_repository, commit), + &paths, walk_wiki, &walk_wiki_ctx); + + if (walk_wiki_ctx.state == 2) + cgit_print_error("Wiki page not found"); + } + + cgit_print_layout_end(); + +cleanup: + free(walk_wiki_ctx.curr_rev); +} |