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
{! #include "../ui-tree.h" !}

{% block repo_navigation_breadcrumbs %}
				<div class="px-3">
					{# Breadcrumbs #}
					{# TODO: Make breadcrumbs hyperlinks #}
					<a href="{! cgit_shared_reporevlink_url(NULL, ctx.qry.head, ctx.qry.oid, NULL); !}" class="text-[#73D0FF] hover:text-[#73D0FF] hover:underline">{{ ctx.repo->name }}</a> / {{ ctx.qry.path }}
				</div>
{% endblock %}

{% block tree_content_directory_header %}
			{# Header for directory listing #}
			<nav class="flex text-sm mb-4 items-baseline">
				{# Repo navigation panel #}
				{! repo_summary_bar_current_branch(); !}
				{! repo_navigation_breadcrumbs(); !}
			</nav>
			<div class="grid grid-cols-[auto_1fr_auto_auto] border border-[#333A45] rounded-md mb-4">
{% endblock %}
{% block tree_content_directory_footer %}
			{# Footer for directory listing #}
			</div>
{% endblock %}
{% block tree_content_file(const struct object_id *oid, const char *path, const char *basename, const char *rev) %}
			<nav class="flex text-sm mb-4 items-baseline">
				{# Repo navigation panel #}
				{! repo_summary_bar_current_branch(); !}
				{! repo_navigation_breadcrumbs(); !}
				<div class="flex-1"></div>
				<div class="flex">
					{# File buttons #}
					<a href="{! cgit_shared_repolink_url("plain", ctx.qry.head, ctx.qry.path); !}" class="text-sm text-[#a3a29c] py-1.5 px-3 bg-[#262F3F] border border-[#333A45] rounded-md hover:bg-[#333A45]">Raw</a>
				</div>
			</nav>
			{!
				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 %}
			<div class="text-[#F07178]">
				blob size ({{ size / 1024|%ld }}KB) exceeds display size limit ({{ ctx.cfg.max_blob_size|%d }}KB).
			</div>
			{% else %}
			<div class="rendered-blob overflow-x-auto border border-[#333A45] rounded-md">
			{!
				if (is_binary) {
					cgit_tree_print_binary_buffer(buf, size);
				} else {
					cgit_tree_print_text_buffer(basename, buf, size);
				}
				free(buf);
			!}
			</div>
			{% 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
				strbuf_release(&buffer);
				
				if (S_ISGITLINK(mode)) {
					// Never recurse into submodules
					return 0;
				} else {
					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_listing_item(oid, base, pathname, mode, walk_tree_ctx->directory_child_idx > 0);
				walk_tree_ctx->directory_child_idx++;
			}
			strbuf_release(&buffer);
			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(ctx.repo->name, fmtalloc("view file \"%s/%s\"", ctx.repo->name, ctx.qry.path)); !}
{! repo_header(); !}
		<main class="max-w-7xl mx-auto py-4 pl-2 pr-2">{# 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 %}
			<nav class="flex text-sm mb-4 items-baseline">
				{# Repo navigation panel #}
				{! repo_summary_bar_current_branch(); !}
				{! repo_navigation_breadcrumbs(); !}
			</nav>
			<div class="text-[#F07178]">File not found</div>
			{% endif %}
		</main>
{! page_end(); !}
{% endpage %}