the repository which powers this website
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
{! 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 #}
		{% if ctx.cfg.css_themed.items %}
		{! for_each_string_list(&ctx.cfg.css_themed, cgit_shared_emit_css_link, NULL); !}
		{% else %}
		{! cgit_shared_emit_css_link(NULL, "/themed.css"); !}
		{% endif %}

		<link rel='shortcut icon' href='/favicon.ico'>
	</head>
	<body class="bg-[#1F2430] text-[#CCCAC2]">
{% endblock %}
{% block repo_header %}
		<header class="bg-[#262F3F] border-b border-[#333A45]">{# Repo header #}
			<div class="max-w-7xl mx-auto py-4 flex gap-x-1 items-center pl-2">
				<a href="{{ cgit_rooturl()|attr }}"><img width="40px" height="40px" src="/favicon.ico"></img></a>
				<div class="text-4xl"><a href="{{ cgit_rooturl()|attr }}" class="hover:text-[#73D0FF] hover:underline">{{ ctx.cfg.root_title }}</a> / <a href="{! cgit_shared_repolink_url(NULL, NULL, NULL); !}" class="font-semibold hover:text-[#73D0FF] 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-[#262F3F] border border-[#333A45] rounded-md hover:bg-[#333A45]">
					{# 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-[#a3a29c]"><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-[#a3a29c]"><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-[#333A45]">
					{# Heroicons micro clock #}
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center text-[#a3a29c]"><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-[#a3a29c]">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-[#333A45]">
					{# 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-[#a3a29c]"><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-[#a3a29c]">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-[#333A45]">
					{# Heroicons micro tag #}
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 self-center text-[#a3a29c]"><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-[#a3a29c]">Tag{% if num_tags != 1 %}s{% endif %}</span>
				</a>
				<div class="flex-1"></div>
				<!--
				<div class="flex outline-1 outline-[#333A45] rounded-lg has-[input:focus-within]:outline-2 has-[input:focus-within]:outline-[#73D0FF]">
					{# Search box #}
					<select class="py-1.5 px-2 text-sm text-[#a3a29c] focus:outline-none">
						<option>Log msg</option>
						<option>Author</option>
						<option>Committer</option>
						<option>Range</option>
					</select>
					<input type="text" placeholder="Search commits&hellip;" 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-[#CCCAC2] 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-[#73D0FF] text-[#1F2430] rounded-md cursor-pointer hover:bg-[#4CB3FF] 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-75 border border-[#333A45] rounded-md bg-[#262F3F] 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-[#333A45] rounded-lg mb-2 has-[input:focus-within]:outline-2 has-[input:focus-within]:outline-[#73D0FF]">
							{# Clone URL box #}
							<span class="py-1.5 px-2 text-sm text-[#a3a29c] bg-[#262F3F] border-r border-[#333A45]">
								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 bg-[#1F2430] text-[#CCCAC2]" 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-[#a3a29c]"><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>
						<div class="flex outline-1 outline-[#333A45] rounded-lg mb-2 has-[input:focus-within]:outline-2 has-[input:focus-within]:outline-[#73D0FF]">
							{# Clone URL box #}
							<span class="whitespace-pre py-1.5 px-2 text-sm text-[#a3a29c] bg-[#262F3F] border-r border-[#333A45]">SSH  </span>
							<input type="text" value="[email protected]/{! html_attr(ctx.repo->url); !}" class="ssh-repo-clone-url flex-1 py-1.5 pl-2 text-sm focus:outline-none bg-[#1F2430] text-[#CCCAC2]" onfocus="this.select();" readonly>
							<button class="py-1.5 px-2 cursor-pointer" onclick="document.querySelector('.ssh-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-[#a3a29c]"><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-[#73D0FF] 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-[#73D0FF] 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> -->
					</div>
				</div>
			</nav>
{% endblock %}
{% block page_end %}
		<footer class="border-t border-[#333A45]">
			{# Footer panel #}
			<div class="max-w-7xl mx-auto py-4">
				<div class="text-sm text-[#a3a29c]">
					{# cgit footer #}
					generated by
					<a href="https://git.zx2c4.com/cgit/about/" class="hover:text-[#73D0FF] hover:underline">cgit</a>
					(<a href="https://git-scm.com/" class="hover:text-[#73D0FF] 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);
	}
!}