summaryrefslogtreecommitdiff
path: root/ui-wiki.c
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-09-04 23:42:18 +0000
committerFreya Murphy <freya@freyacat.org>2025-09-04 23:42:18 +0000
commite6ad894ba53a185fc19f8563e26aff2ac93edd20 (patch)
tree6010b57dc2969285d0fcd88617dbaf7909d57fe6 /ui-wiki.c
parentrepo urls should be case insensitive (diff)
downloadcgit-e6ad894ba53a185fc19f8563e26aff2ac93edd20.tar.gz
cgit-e6ad894ba53a185fc19f8563e26aff2ac93edd20.tar.bz2
cgit-e6ad894ba53a185fc19f8563e26aff2ac93edd20.zip
add wiki support to cgitHEADmaster
Diffstat (limited to 'ui-wiki.c')
-rw-r--r--ui-wiki.c213
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);
+}