diff options
-rw-r--r-- | cgit.mk | 1 | ||||
-rw-r--r-- | cmd.c | 7 | ||||
-rw-r--r-- | ui-shared.c | 10 | ||||
-rw-r--r-- | ui-shared.h | 3 | ||||
-rw-r--r-- | ui-wiki.c | 213 | ||||
-rw-r--r-- | ui-wiki.h | 6 |
6 files changed, 240 insertions, 0 deletions
@@ -94,6 +94,7 @@ CGIT_OBJ_NAMES += ui-stats.o CGIT_OBJ_NAMES += ui-summary.o CGIT_OBJ_NAMES += ui-tag.o CGIT_OBJ_NAMES += ui-tree.o +CGIT_OBJ_NAMES += ui-wiki.o CGIT_OBJS := $(addprefix $(CGIT_PREFIX),$(CGIT_OBJ_NAMES)) @@ -26,6 +26,7 @@ #include "ui-summary.h" #include "ui-tag.h" #include "ui-tree.h" +#include "ui-wiki.h" static void HEAD_fn(void) { @@ -164,6 +165,11 @@ static void tree_fn(void) cgit_print_tree(ctx.qry.oid, ctx.qry.path); } +static void wiki_fn(void) +{ + cgit_print_wiki(ctx.qry.oid); +} + #define def_cmd(name, want_repo, want_vpath, is_clone) \ {#name, name##_fn, want_repo, want_vpath, is_clone} @@ -191,6 +197,7 @@ struct cgit_cmd *cgit_get_cmd(void) def_cmd(summary, 1, 0, 0), def_cmd(tag, 1, 0, 0), def_cmd(tree, 1, 1, 0), + def_cmd(wiki, 1, 0, 0), }; int i; diff --git a/ui-shared.c b/ui-shared.c index 93ab93c..d3cf24b 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -10,6 +10,7 @@ #include "cgit.h" #include "ui-shared.h" +#include "ui-blob.h" #include "cmd.h" #include "html.h" #include "version.h" @@ -348,6 +349,12 @@ void cgit_tree_link(const char *name, const char *title, const char *class, reporevlink("tree", name, title, class, head, rev, path); } +void cgit_wiki_link(const char *name, const char *title, const char *class, + const char *head, const char *rev, const char *path) +{ + reporevlink("wiki", name, title, class, head, rev, path); +} + void cgit_plain_link(const char *name, const char *title, const char *class, const char *head, const char *rev, const char *path) { @@ -1099,6 +1106,9 @@ void cgit_print_pageheader(void) else cgit_tree_link("tree", NULL, hc("tree"), ctx.qry.head, ctx.qry.oid, ctx.qry.vpath); + if (cgit_ref_path_exists(".wiki", ctx.qry.head, 0)) + cgit_wiki_link("wiki", NULL, hc("wiki"), ctx.qry.head, + ctx.qry.oid, NULL); cgit_commit_link("commit", NULL, hc("commit"), ctx.qry.head, ctx.qry.oid, ctx.qry.vpath); cgit_diff_link("diff", NULL, hc("diff"), ctx.qry.head, diff --git a/ui-shared.h b/ui-shared.h index f12fa99..65d8f75 100644 --- a/ui-shared.h +++ b/ui-shared.h @@ -24,6 +24,9 @@ extern void cgit_tag_link(const char *name, const char *title, extern void cgit_tree_link(const char *name, const char *title, const char *class, const char *head, const char *rev, const char *path); +extern void cgit_wiki_link(const char *name, const char *title, + const char *class, const char *head, + const char *rev, const char *path); extern void cgit_plain_link(const char *name, const char *title, const char *class, const char *head, const char *rev, const char *path); 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); +} diff --git a/ui-wiki.h b/ui-wiki.h new file mode 100644 index 0000000..7160010 --- /dev/null +++ b/ui-wiki.h @@ -0,0 +1,6 @@ +#ifndef UI_WIKI_H +#define UI_WIKI_H + +extern void cgit_print_wiki(const char *rev); + +#endif /* UI_TREE_H */ |