{! #include "../ui-tree.h" !} {% block repo_navigation_breadcrumbs %}
{# Breadcrumbs #} {# TODO: Make breadcrumbs hyperlinks #} {{ ctx.repo->name }} / {{ ctx.qry.path }}
{% endblock %} {% block tree_content_directory_header %} {# Header for directory listing #}
{% endblock %} {% block tree_content_directory_item(const struct object_id *oid, struct strbuf *base, const char *pathname, unsigned mode, int child_idx) %} {# Directory listing entry #} {! unsigned long size = 0; if (!S_ISGITLINK(mode)) { oid_object_info(the_repository, oid, &size); } struct strbuf fullpath = STRBUF_INIT; strbuf_addf(&fullpath, "%s%s", base->buf, pathname); !}
{% if S_ISDIR(mode) %} {# Heroicons solid folder #} {% else %} {# Heroicons outline document #} {% endif %}
{{ pathname }}
{! cgit_print_filemode(mode); !}
{% if !S_ISDIR(mode) %}{{ size|%ld }}{% endif %}
{! strbuf_release(&fullpath); !} {% endblock %} {% block tree_content_directory_footer %} {# Footer for directory listing #}
{% endblock %} {% block tree_content_file(const struct object_id *oid, const char *path, const char *basename, const char *rev) %} {! unsigned long size; enum object_type type = oid_object_info(the_repository, oid, &size); if (type == OBJ_BAD) { die("Bad object name"); } char *buf = repo_read_object_file(the_repository, oid, &type, &size); if (!buf) { die("Error reading object"); } bool is_binary = buffer_is_binary(buf, size); !} {% if ctx.cfg.max_blob_size && size / 1024 > ctx.cfg.max_blob_size %}
blob size ({{ size / 1024|%ld }}KB) exceeds display size limit ({{ ctx.cfg.max_blob_size|%d }}KB).
{% else %}
{! if (is_binary) { cgit_tree_print_binary_buffer(buf, size); } else { cgit_tree_print_text_buffer(basename, buf, size); } !}
{% endif %} {% endblock %} {! struct walk_tree_context { char *curr_rev; char *match_path; int state; int directory_child_idx; }; static int walk_tree(const struct object_id *oid, struct strbuf *base, const char *pathname, unsigned mode, void *cbdata) { struct walk_tree_context *walk_tree_ctx = cbdata; if (walk_tree_ctx->state == 0) { // State 0 = Walking recursively to find the target path struct strbuf buffer = STRBUF_INIT; strbuf_addbuf(&buffer, base); strbuf_addstr(&buffer, pathname); if (strcmp(walk_tree_ctx->match_path, buffer.buf)) { // Not the target path, so continue to walk the tree return READ_TREE_RECURSIVE; } // This is the target path if (S_ISDIR(mode)) { // Target path is a directory - set state to 1 and do one final walk to get contents walk_tree_ctx->state = 1; strbuf_release(&buffer); tree_content_directory_header(); return READ_TREE_RECURSIVE; } else { // Target path is a file - set state to 2, display file and exit walk_tree_ctx->state = 2; tree_content_file(oid, buffer.buf, pathname, walk_tree_ctx->curr_rev); strbuf_release(&buffer); return 0; } } if (walk_tree_ctx->state == 1) { // State 1 = Target path is a directory, one final walk to get contents // Either a child of the directory of interest, or a child of a parent directory - so must check the path struct strbuf buffer = STRBUF_INIT; strbuf_addstr(&buffer, walk_tree_ctx->match_path); strbuf_addstr(&buffer, "/"); if (!strcmp(buffer.buf, base->buf)) { tree_content_directory_item(oid, base, pathname, mode, walk_tree_ctx->directory_child_idx); walk_tree_ctx->directory_child_idx++; } return 0; } return 0; // Should be unreachable } !} {% page cgit_print_tree %} {! // Redirect to summary page if no subdirectory if (!ctx.qry.path) { return cgit_print_summary_impl(); } !} {! page_start(); !} {! repo_header(); !}
{# Main content #} {! repo_description_panel(); !} {! char *hex = ctx.qry.oid; if (!hex) { hex = ctx.qry.head; } struct object_id oid; if (repo_get_oid(the_repository, hex, &oid)) { die("Bad object id"); } struct commit *commit = lookup_commit_reference(the_repository, &oid); if (!commit) { die("Bad commit reference"); } // Prepare to walk the tree recursively to find the path struct pathspec paths = { .nr = 0 }; struct walk_tree_context walk_tree_ctx = { .curr_rev = xstrdup(hex), .match_path = ctx.qry.path, .state = 0, .directory_child_idx = 0 }; // State 0 = Walking recursively to find the target path // State 1 = Target path is a directory, one final walk to get contents // State 2 = Target path is a file read_tree(the_repository, repo_get_commit_tree(the_repository, commit), &paths, walk_tree, &walk_tree_ctx); free(walk_tree_ctx.curr_rev); !} {% if walk_tree_ctx.state == 0 %}
File not found
{% endif %}
{! page_end(); !} {% endpage %}