{! static int get_num_commits(void); static int get_num_branches(void); static int get_num_tags(void); static void short_commit_id(char *hex); !} {% block page_start %} <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>{{ ctx.page.title }}</title>{# ctx.page.title is usually set by prepare_repo_cmd #} <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap"> <link rel="stylesheet" href="/themed.css"> </head> <body class="text-gray-900"> {% endblock %} {% block repo_header %} <header class="bg-gray-50 border-b border-gray-300">{# Repo header #} <div class="max-w-[1280px] mx-auto py-4 flex gap-x-1"> {# Heroicons outline cube #} <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="m21 7.5-9-5.25L3 7.5m18 0-9 5.25m9-5.25v9l-9 5.25M3 7.5l9 5.25M3 7.5v9l9 5.25m0-9v9" /></svg> <div class="text-lg"><a href="{{ cgit_rooturl()|attr }}" class="hover:text-blue-600 hover:underline">index</a> / <a href="{! cgit_shared_repolink_url(NULL, NULL, NULL); !}" class="font-semibold hover:text-blue-600 hover:underline">{{ ctx.repo->name }}</a></div> </div> </header> {% endblock %} {% block repo_description_panel %} <div class="mb-4"> {# Description panel #} {{ ctx.repo->desc }} </div> {% endblock %} {% block repo_summary_bar_current_branch %} <a href="{! cgit_shared_repolink_url("refs", ctx.qry.head, NULL); !}" class="flex gap-x-1.5 py-1.5 px-3 bg-gray-50 border border-gray-300 rounded-md hover:bg-gray-100"> {# Heroicons micro list-bullet #} <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center text-gray-500"><path d="M3 4.75a1 1 0 1 0 0-2 1 1 0 0 0 0 2ZM6.25 3a.75.75 0 0 0 0 1.5h7a.75.75 0 0 0 0-1.5h-7ZM6.25 7.25a.75.75 0 0 0 0 1.5h7a.75.75 0 0 0 0-1.5h-7ZM6.25 11.5a.75.75 0 0 0 0 1.5h7a.75.75 0 0 0 0-1.5h-7ZM4 12.25a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM3 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" /></svg> <span class="font-semibold self-baseline"> {% if (strcmp(ctx.qry.page, "tree") == 0 || strcmp(ctx.qry.page, "summary") == 0) && ctx.qry.oid %} {! short_commit_id(ctx.qry.oid); !} {% else %} {{ ctx.qry.head }} {% endif %} </span> {# Heroicons micro chevron-down #} <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center text-gray-500"><path fill-rule="evenodd" d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" /></svg> </a> {% endblock %} {% block repo_summary_bar %} <nav class="flex text-sm mb-4"> {# Repo navigation panel #} {! repo_summary_bar_current_branch(); !} <a href="{! cgit_shared_repolink_url("log", ctx.qry.head, NULL); !}" class="flex gap-x-1 py-1.5 px-3 ml-3 rounded-md hover:bg-gray-100"> {# Heroicons micro clock #} <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center text-gray-500"><path fill-rule="evenodd" d="M1 8a7 7 0 1 1 14 0A7 7 0 0 1 1 8Zm7.75-4.25a.75.75 0 0 0-1.5 0V8c0 .414.336.75.75.75h3.25a.75.75 0 0 0 0-1.5h-2.5v-3.5Z" clip-rule="evenodd" /></svg> {! int num_commits = get_num_commits(); !} <span class="font-semibold">{{ num_commits|%d }}</span><span class="font-semibold text-gray-500">Commit{% if num_commits != 1 %}s{% endif %}</span> </a> <a href="{! cgit_shared_repolink_url("refs", ctx.qry.head, "heads"); !}" class="flex gap-x-1 py-1.5 px-3 rounded-md hover:bg-gray-100"> {# Heroicons micro list-bullet #} <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center text-gray-500"><path d="M3 4.75a1 1 0 1 0 0-2 1 1 0 0 0 0 2ZM6.25 3a.75.75 0 0 0 0 1.5h7a.75.75 0 0 0 0-1.5h-7ZM6.25 7.25a.75.75 0 0 0 0 1.5h7a.75.75 0 0 0 0-1.5h-7ZM6.25 11.5a.75.75 0 0 0 0 1.5h7a.75.75 0 0 0 0-1.5h-7ZM4 12.25a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM3 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" /></svg> {! int num_branches = get_num_branches(); !} <span class="font-semibold">{{ num_branches|%d }}</span><span class="font-semibold text-gray-500">Branch{% if num_branches != 1 %}es{% endif %}</span> </a> <a href="{! cgit_shared_repolink_url("refs", ctx.qry.head, "tags"); !}" class="flex gap-x-1 py-1.5 px-3 rounded-md hover:bg-gray-100"> {# Heroicons micro tag #} <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center text-gray-500"><path fill-rule="evenodd" d="M4.5 2A2.5 2.5 0 0 0 2 4.5v2.879a2.5 2.5 0 0 0 .732 1.767l4.5 4.5a2.5 2.5 0 0 0 3.536 0l2.878-2.878a2.5 2.5 0 0 0 0-3.536l-4.5-4.5A2.5 2.5 0 0 0 7.38 2H4.5ZM5 6a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" clip-rule="evenodd" /></svg> {! int num_tags = get_num_tags(); !} <span class="font-semibold">{{ num_tags|%d }}</span><span class="font-semibold text-gray-500">Tag{% if num_tags != 1 %}s{% endif %}</span> </a> <div class="flex-1"></div> <!-- <div class="flex outline-1 outline-gray-300 rounded-lg has-[input:focus-within]:outline-2 has-[input:focus-within]:outline-blue-600"> {# Search box #} <select class="py-1.5 px-2 text-sm text-gray-500 focus:outline-none"> <option>Log msg</option> <option>Author</option> <option>Committer</option> <option>Range</option> </select> <input type="text" placeholder="Search commits…" class="py-1.5 pl-2 text-sm focus:outline-none"> <button class="py-1.5 px-2 cursor-pointer"> {# Heroicons micro magnifying-glass #} <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="text-gray-700 size-4"><path fill-rule="evenodd" d="M9.965 11.026a5 5 0 1 1 1.06-1.06l2.755 2.754a.75.75 0 1 1-1.06 1.06l-2.755-2.754ZM10.5 7a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Z" clip-rule="evenodd" /></svg> </button> </div> --> <div class="flex relative"> {# Code box and panel #} <button class="flex gap-x-1.5 py-1.5 px-3 ml-3 bg-blue-500 text-white rounded-md cursor-pointer hover:bg-blue-600 peer"> {# Code box #} {# Heroicons micro code-bracket #} <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center"><path fill-rule="evenodd" d="M4.78 4.97a.75.75 0 0 1 0 1.06L2.81 8l1.97 1.97a.75.75 0 1 1-1.06 1.06l-2.5-2.5a.75.75 0 0 1 0-1.06l2.5-2.5a.75.75 0 0 1 1.06 0ZM11.22 4.97a.75.75 0 0 0 0 1.06L13.19 8l-1.97 1.97a.75.75 0 1 0 1.06 1.06l2.5-2.5a.75.75 0 0 0 0-1.06l-2.5-2.5a.75.75 0 0 0-1.06 0ZM8.856 2.008a.75.75 0 0 1 .636.848l-1.5 10.5a.75.75 0 0 1-1.484-.212l1.5-10.5a.75.75 0 0 1 .848-.636Z" clip-rule="evenodd" /></svg> <span class="font-semibold">Code</span> {# Heroicons micro chevron-down #} <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center"><path fill-rule="evenodd" d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" /></svg> </button> <div class="absolute top-10 right-0 w-[300px] border border-gray-300 rounded-md bg-white p-2 hidden peer-focus:block hover:block"> {# Code panel #} <div class="flex gap-x-1 items-center mb-2"> {# Heroicons micro command-line #} <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4"><path fill-rule="evenodd" d="M2 4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V4Zm2.22 1.97a.75.75 0 0 0 0 1.06l.97.97-.97.97a.75.75 0 1 0 1.06 1.06l1.5-1.5a.75.75 0 0 0 0-1.06l-1.5-1.5a.75.75 0 0 0-1.06 0ZM8.75 8.5a.75.75 0 0 0 0 1.5h2.5a.75.75 0 0 0 0-1.5h-2.5Z" clip-rule="evenodd" /></svg> <span class="font-semibold text-sm">Clone</span> </div> <div class="flex outline-1 outline-gray-300 rounded-lg mb-2 has-[input:focus-within]:outline-2 has-[input:focus-within]:outline-blue-600"> {# Clone URL box #} <span class="py-1.5 px-2 text-sm text-gray-500 bg-gray-50 border-r border-gray-300"> HTTPS </span> <input type="text" value="{! cgit_add_clone_urls(html_attr); !}" class="repo-clone-url flex-1 py-1.5 pl-2 text-sm focus:outline-none" onfocus="this.select();" readonly> <button class="py-1.5 px-2 cursor-pointer" onclick="document.querySelector('.repo-clone-url').select();document.execCommand('copy');"> {# Heroicons micro clipboard #} <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 text-gray-500"><path fill-rule="evenodd" d="M10.986 3H12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h1.014A2.25 2.25 0 0 1 7.25 1h1.5a2.25 2.25 0 0 1 2.236 2ZM9.5 4v-.75a.75.75 0 0 0-.75-.75h-1.5a.75.75 0 0 0-.75.75V4h3Z" clip-rule="evenodd" /></svg> </button> </div> <a href="vscode://vscode.git/clone?url={! cgit_add_clone_urls(html_url_arg); !}" class="flex items-center gap-x-1 hover:text-blue-600 hover:underline mb-2"> {# Heroicons micro arrow-top-right-on-square #} <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4"><path d="M6.22 8.72a.75.75 0 0 0 1.06 1.06l5.22-5.22v1.69a.75.75 0 0 0 1.5 0v-3.5a.75.75 0 0 0-.75-.75h-3.5a.75.75 0 0 0 0 1.5h1.69L6.22 8.72Z" /><path d="M3.5 6.75c0-.69.56-1.25 1.25-1.25H7A.75.75 0 0 0 7 4H4.75A2.75 2.75 0 0 0 2 6.75v4.5A2.75 2.75 0 0 0 4.75 14h4.5A2.75 2.75 0 0 0 12 11.25V9a.75.75 0 0 0-1.5 0v2.25c0 .69-.56 1.25-1.25 1.25h-4.5c-.69 0-1.25-.56-1.25-1.25v-4.5Z" /></svg> Open with VS Code </a> <a href="vscodium://vscode.git/clone?url={! cgit_add_clone_urls(html_url_arg); !}" class="flex items-center gap-x-1 hover:text-blue-600 hover:underline mb-2"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4"><path d="M6.22 8.72a.75.75 0 0 0 1.06 1.06l5.22-5.22v1.69a.75.75 0 0 0 1.5 0v-3.5a.75.75 0 0 0-.75-.75h-3.5a.75.75 0 0 0 0 1.5h1.69L6.22 8.72Z" /><path d="M3.5 6.75c0-.69.56-1.25 1.25-1.25H7A.75.75 0 0 0 7 4H4.75A2.75 2.75 0 0 0 2 6.75v4.5A2.75 2.75 0 0 0 4.75 14h4.5A2.75 2.75 0 0 0 12 11.25V9a.75.75 0 0 0-1.5 0v2.25c0 .69-.56 1.25-1.25 1.25h-4.5c-.69 0-1.25-.56-1.25-1.25v-4.5Z" /></svg> Open with VSCodium </a> <a href="jetbrains://idea/checkout/git?idea.required.plugins.id=Git4Idea&checkout.repo={! cgit_add_clone_urls(html_url_arg); !}" class="flex items-center gap-x-1 hover:text-blue-600 hover:underline"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4"><path d="M6.22 8.72a.75.75 0 0 0 1.06 1.06l5.22-5.22v1.69a.75.75 0 0 0 1.5 0v-3.5a.75.75 0 0 0-.75-.75h-3.5a.75.75 0 0 0 0 1.5h1.69L6.22 8.72Z" /><path d="M3.5 6.75c0-.69.56-1.25 1.25-1.25H7A.75.75 0 0 0 7 4H4.75A2.75 2.75 0 0 0 2 6.75v4.5A2.75 2.75 0 0 0 4.75 14h4.5A2.75 2.75 0 0 0 12 11.25V9a.75.75 0 0 0-1.5 0v2.25c0 .69-.56 1.25-1.25 1.25h-4.5c-.69 0-1.25-.56-1.25-1.25v-4.5Z" /></svg> Open with IntelliJ IDEA </a> </div> </div> </nav> {% endblock %} {% block page_end %} <footer class="border-t border-gray-300"> {# Footer panel #} <div class="max-w-[1280px] mx-auto py-4"> <div class="text-sm text-gray-500"> {# cgit footer #} generated by <a href="https://git.zx2c4.com/cgit/about/" class="hover:text-blue-600 hover:underline">cgit</a> (<a href="https://yingtongli.me/git/cgit-yli-theme" class="hover:text-blue-600 hover:underline">cgit-yli-theme {{ cgit_version }}</a>, <a href="https://git-scm.com/" class="hover:text-blue-600 hover:underline">git {{ git_version_string }}</a>) at {{ show_date(time(NULL), 0, cgit_date_mode(DATE_ISO8601)) }} </div> </div> </footer> </body> </html> {% endblock %} {! static int get_num_commits(void) { int num_commits = 0; // Based on ui-stats collect_stats struct rev_info rev; struct commit *commit; const char *argv[] = {NULL, ctx.qry.head}; int argc = 2; repo_init_revisions(the_repository, &rev, NULL); rev.abbrev = DEFAULT_ABBREV; rev.commit_format = CMIT_FMT_DEFAULT; rev.max_parents = 1; rev.verbose_header = 1; rev.show_root_diff = 0; setup_revisions(argc, argv, &rev, NULL); prepare_revision_walk(&rev); while ((commit = get_revision(&rev)) != NULL) { // Process the commit num_commits++; // This causes subsequent walks to return commits with index 0 - unsure why // Checked with Valgrind - commenting this out seems not to leak memory //release_commit_memory(the_repository->parsed_objects, commit); //commit->parents = NULL; } reset_revision_walk(); release_revisions(&rev); return num_commits; } static int get_num_branches(void) { struct reflist list; list.refs = NULL; list.alloc = list.count = 0; refs_for_each_branch_ref(get_main_ref_store(the_repository), cgit_refs_cb, &list); int num_branches = list.count; cgit_free_reflist_inner(&list); return num_branches; } static int get_num_tags(void) { struct reflist list; list.refs = NULL; list.alloc = list.count = 0; refs_for_each_tag_ref(get_main_ref_store(the_repository), cgit_refs_cb, &list); int num_tags = list.count; cgit_free_reflist_inner(&list); return num_tags; } static void short_commit_id(char *hex) { char short_commit_id[8]; memcpy(short_commit_id, hex, 7); short_commit_id[7] = '\0'; html_txt(short_commit_id); } !} {! #include "mincrypt_sha256.h" static void gravatar_url(char *email) { // Trim email of whitespace, < and > while (isspace(*email) || *email == '<') email++; char* strend = email + strlen(email) - 1; while (isspace(*strend) || *strend == '>') strend--; // Now strend points to the last character // Email to lowercase size_t email_len = strend - email + 1; char *email_lower = malloc(email_len + 1); // +1 for null terminator for (int i = 0; i < email_len; i++) { email_lower[i] = tolower(email[i]); } email_lower[email_len] = '\0'; // For good measure // Compute hash and print Gravatar link uint8_t digest[32]; SHA256_hash(email, strend - email + 1, digest); htmlf( "https://gravatar.com/avatar/%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15], digest[16], digest[17], digest[18], digest[19], digest[20], digest[21], digest[22], digest[23], digest[24], digest[25], digest[26], digest[27], digest[28], digest[29], digest[30], digest[31] ); free(email_lower); } !}