blob: f37650d162f6e2d5c924c17cc5bc5e3109995211 (plain)
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
/*
 * The repository summary page and the about page. The summary stacks the
 * branch list, the tag list and the head of the log into one table and ends
 * with the clone urls, reusing the listings ui-refs.c and ui-log.c draw
 * elsewhere. The about page renders the readme that config parsing picked for
 * the repository, either through the configured about filter or escaped as
 * plain text.
 */

#include "cgit.h"
#include "filter.h"
#include "html.h"
#include "shared.h"
#include "ui-blob.h"
#include "ui-log.h"
#include "ui-refs.h"
#include "ui-shared.h"
#include "ui-summary.h"

// Age, commit message and author, the three columns a log row always has.
// ui-log.c adds one more for each of the two optional counts.
#define LOG_BASE_COLUMNS 3

static int clone_urls_printed;

static int log_columns(void)
{
	int columns = LOG_BASE_COLUMNS;

	if (ctx.repo->enable_log_filecount)
		columns++;
	if (ctx.repo->enable_log_linecount)
		columns++;
	return columns;
}

/*
 * The sections share one table, which is as wide as the widest of them, and
 * every row fills it, since a short row would end its stripe short of the
 * table's edge.
 */
static int table_columns(void)
{
	if (ctx.cfg.summary_log > 0 && log_columns() > REF_COLUMNS)
		return log_columns();
	return REF_COLUMNS;
}

static void print_clone_url(const char *url)
{
	int columns = table_columns();

	// cgit_add_clone_urls may call back no times at all, so the heading
	// waits for a first url rather than being printed ahead of the walk.
	if (clone_urls_printed++ == 0) {
		html("<tbody class='clone'>\n");
		htmlf("<tr class='nohover'><th colspan='%d' class='left' scope='col'>Clone</th></tr>\n",
			columns);
	}

	cgit_print_clone_row(url, columns);
}

void cgit_print_summary(void)
{
	int columns = table_columns();

	cgit_print_layout_start();
	// One table, so the columns line up across the sections, each of
	// which is a body of its own.
	html("<table class='list summary' aria-label='Summary'>\n");
	cgit_print_branches(ctx.cfg.summary_branches, columns);
	cgit_print_tags(ctx.cfg.summary_tags, columns);
	if (ctx.cfg.summary_log > 0)
		cgit_print_log(ctx.qry.head, 0, ctx.cfg.summary_log, NULL, NULL, NULL, 0, 0, 0, columns);
	clone_urls_printed = 0;
	cgit_add_clone_urls(print_clone_url);
	if (clone_urls_printed)
		html("</tbody>\n");
	html("</table>\n");
	cgit_print_layout_end();
}

void cgit_print_repo_readme(void)
{
	char *filename, *ref;
	int err = 0;

	cgit_print_layout_start();
	filename = ctx.repo->readme.items[0].string;
	ref = ctx.repo->readme.items[0].util;

	html("<div id='about'>");
	if (!ctx.repo->about_filter) {
		// With no about-filter there is nothing to turn the readme
		// into safe HTML, so it is escaped rather than served raw.
		html("<pre class='plaintext'>");
		if (ref) {
			err = cgit_print_file(filename, ref, 1, 1);
		} else {
			struct strbuf sb = STRBUF_INIT;
			if (strbuf_read_file(&sb, filename, 0) >= 0)
				html_txt(sb.buf);
			strbuf_release(&sb);
		}
		html("</pre>");
	} else {
		struct strbuf tree_base = STRBUF_INIT, tree_query = STRBUF_INIT;

		// A tracked readme's links lead into the tree at the ref it was
		// read from, while one on disk has no tree to lead into.
		if (ref)
			cgit_tree_url(ref, &tree_base, &tree_query);
		// The filter is what makes the source safe here, so it is fed
		// through unescaped.
		cgit_open_filter(ctx.repo->about_filter, filename, tree_base.buf, tree_query.buf);
		if (ref)
			err = cgit_print_file(filename, ref, 1, 0);
		else
			html_include(filename);
		cgit_close_filter(ctx.repo->about_filter);
		strbuf_release(&tree_base);
		strbuf_release(&tree_query);
	}
	html("</div>");
	// A readme past max-blob-size is never read, which would otherwise
	// leave the about page with nothing on it.
	if (err == -2)
		cgit_print_error_page(413, "Content Too Large", "The readme is larger than max-blob-size (%d KB)",
			ctx.cfg.max_blob_size);
	cgit_print_layout_end();
}