summaryrefslogtreecommitdiffstatshomepage
path: root/cgit.css
blob: 9112bfe23f75a9ab9f0ac167f88dca4833d613d2 (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
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
body {
	font-family: arial;
	font-size: normal;
	background: white;
	padding: 0em;
	margin: 0.5em 1em;
}


h2 {
	font-size: 100%;
	font-weight: bold;
	margin-bottom: 0.1em;
}

a {
	color: blue;
	text-decoration: none;
}

a:hover {
	text-decoration: underline;
}

table.list {
	border: solid 1px black;
	border-collapse: collapse;
	border: solid 1px #aaa;
}
table.list tr {
	background: white;
}
table.list tr:hover {
	background: #eeb;
}
table.list th {
	font-weight: normal;
	background: #ddd;
	border-bottom: solid 1px #aaa;
	padding: 0.1em 0.5em 0.1em 0.5em;
	vertical-align: baseline;
}
table.list td {
	border: none;
	padding: 0.1em 0.5em 0.1em 0.5em;
}
img {
	border: none;
}


div#header {
	background-color: #ddd;
	padding: 0.25em 0.25em 0.25em 0.5em;
	font-size: 150%;
	font-weight: bold;
	border: solid 1px #aaa;
	vertical-align: middle;
	margin-bottom: 2em;
}
div#header img#logo {
	float: right;
}

div#header input {
	float: right;
	margin: 0.25em 1em;
}
div#header a {
	color: black;
}

div#content {
	margin: 0.5em 0.5em;
}

div#blob {
	border: solid 1px black;
}

div.error {
	color: red;
	font-weight: bold;
	margin: 1em 2em;
}
div.ls-blob, div.ls-dir {
	font-family: monospace;
}
div.ls-dir a {
	font-weight: bold;
}
th.filesize, td.filesize {
	text-align: right;
}
td.filesize {
	font-family: monospace;
}
td.filemode {
	font-family: monospace;
}

td.blob {
	white-space: pre;
	font-family: monospace;
	background-color: white;
}

table.nowrap td {
	white-space: nowrap;
}

table.commit-info {
	border-collapse: collapse;
	margin-top: 1.5em;
}
table.commit-info th {
	text-align: left;
	font-weight: normal;
	padding: 0.1em 1em 0.1em 0.1em;
}
table.commit-info td {
	font-weight: normal;
	padding: 0.1em 1em 0.1em 0.1em;
}
div.commit-subject {
	font-weight: bold;
	font-size: 125%;
	margin: 1.5em 0em 0.5em 0em;
	padding: 0em;
}
div.commit-msg {
	white-space: pre;
	font-family: monospace;
}
table.diffstat {
	border-collapse: collapse;
	margin-top: 1.5em;
}
table.diffstat th {
	font-weight: normal;
	text-align: left;
	text-decoration: underline;
	padding: 0.1em 1em 0.1em 0.1em;
	font-size: 100%;
}
table.diffstat td {
	padding: 0.1em 1em 0.1em 0.1em;
	font-size: 100%;
}
table.diffstat td span.modechange {
	padding-left: 1em;
	color: red;
}
table.diffstat td.add a {
	color: green;
}
table.diffstat td.del a {
	color: red;
}
table.diffstat td.upd a {
	color: blue;
}
table.diffstat td.summary {
	/* border-top: solid 1px black; */
	color: #888;
	padding-top: 0.5em;
}

table.diff td {
	border: solid 1px black;
	font-family: monospace;
	white-space: pre;
}

table.diff td div.hunk {
	background: #ccc;
}

table.diff td div.add {
	color: green;
}

table.diff td div.del {
	color: red;
}

.sha1 {
	font-family: courier;
	font-size: 90%;
}
.left {
	text-align: left;
}
.right {
	text-align: right;
}
pan class="p">); html_txt(info->old_path); html(")"); } html("</td><td class='right'>"); if (info->binary) { htmlf("bin</td><td class='graph'>%ld -> %ld bytes", info->old_size, info->new_size); return; } htmlf("%d", info->added + info->removed); html("</td><td class='graph'>"); htmlf("<table summary='file diffstat' width='%d%%'><tr>", (max_changes > 100 ? 100 : max_changes)); htmlf("<td class='add' style='width: %.1f%%;'/>", info->added * 100.0 / max_changes); htmlf("<td class='rem' style='width: %.1f%%;'/>", info->removed * 100.0 / max_changes); htmlf("<td class='none' style='width: %.1f%%;'/>", (max_changes - info->removed - info->added) * 100.0 / max_changes); html("</tr></table></td></tr>\n"); } static void count_diff_lines(char *line, int len) { if (line && (len > 0)) { if (line[0] == '+') lines_added++; else if (line[0] == '-') lines_removed++; } } static int show_filepair(struct diff_filepair *pair) { /* Always show if we have no limiting prefix. */ if (!current_prefix) return 1; /* Show if either path in the pair begins with the prefix. */ if (starts_with(pair->one->path, current_prefix) || starts_with(pair->two->path, current_prefix)) return 1; /* Otherwise we don't want to show this filepair. */ return 0; } static void inspect_filepair(struct diff_filepair *pair) { int binary = 0; unsigned long old_size = 0; unsigned long new_size = 0; if (!show_filepair(pair)) return; files++; lines_added = 0; lines_removed = 0; cgit_diff_files(&pair->one->oid, &pair->two->oid, &old_size, &new_size, &binary, 0, ctx.qry.ignorews, count_diff_lines); if (files >= slots) { if (slots == 0) slots = 4; else slots = slots * 2; items = xrealloc(items, slots * sizeof(struct fileinfo)); } items[files-1].status = pair->status; oidcpy(items[files-1].old_oid, &pair->one->oid); oidcpy(items[files-1].new_oid, &pair->two->oid); items[files-1].old_mode = pair->one->mode; items[files-1].new_mode = pair->two->mode; items[files-1].old_path = xstrdup(pair->one->path); items[files-1].new_path = xstrdup(pair->two->path); items[files-1].added = lines_added; items[files-1].removed = lines_removed; items[files-1].old_size = old_size; items[files-1].new_size = new_size; items[files-1].binary = binary; if (lines_added + lines_removed > max_changes) max_changes = lines_added + lines_removed; total_adds += lines_added; total_rems += lines_removed; } static void cgit_print_diffstat(const struct object_id *old_oid, const struct object_id *new_oid, const char *prefix) { int i; html("<div class='diffstat-header'>"); cgit_diff_link("Diffstat", NULL, NULL, ctx.qry.head, ctx.qry.sha1, ctx.qry.sha2, NULL); if (prefix) { html(" (limited to '"); html_txt(prefix); html("')"); } html("</div>"); html("<table summary='diffstat' class='diffstat'>"); max_changes = 0; cgit_diff_tree(old_oid, new_oid, inspect_filepair, prefix, ctx.qry.ignorews); for (i = 0; i<files; i++) print_fileinfo(&items[i]); html("</table>"); html("<div class='diffstat-summary'>"); htmlf("%d files changed, %d insertions, %d deletions", files, total_adds, total_rems); html("</div>"); } /* * print a single line returned from xdiff */ static void print_line(char *line, int len) { char *class = "ctx"; char c = line[len-1]; if (line[0] == '+') class = "add"; else if (line[0] == '-') class = "del"; else if (line[0] == '@') class = "hunk"; htmlf("<div class='%s'>", class); line[len-1] = '\0'; html_txt(line); html("</div>"); line[len-1] = c; } static void header(const struct object_id *oid1, char *path1, int mode1, const struct object_id *oid2, char *path2, int mode2) { char *abbrev1, *abbrev2; int subproject; subproject = (S_ISGITLINK(mode1) || S_ISGITLINK(mode2)); html("<div class='head'>"); html("diff --git a/"); html_txt(path1); html(" b/"); html_txt(path2); if (mode1 == 0) htmlf("<br/>new file mode %.6o", mode2); if (mode2 == 0) htmlf("<br/>deleted file mode %.6o", mode1); if (!subproject) { abbrev1 = xstrdup(find_unique_abbrev(oid1->hash, DEFAULT_ABBREV)); abbrev2 = xstrdup(find_unique_abbrev(oid2->hash, DEFAULT_ABBREV)); htmlf("<br/>index %s..%s", abbrev1, abbrev2); free(abbrev1); free(abbrev2); if (mode1 != 0 && mode2 != 0) { htmlf(" %.6o", mode1); if (mode2 != mode1) htmlf("..%.6o", mode2); } if (is_null_oid(oid1)) { path1 = "dev/null"; html("<br/>--- /"); } else html("<br/>--- a/"); if (mode1 != 0) cgit_tree_link(path1, NULL, NULL, ctx.qry.head, oid_to_hex(old_rev_oid), path1); else html_txt(path1); if (is_null_oid(oid2)) { path2 = "dev/null"; html("<br/>+++ /"); } else html("<br/>+++ b/"); if (mode2 != 0) cgit_tree_link(path2, NULL, NULL, ctx.qry.head, oid_to_hex(new_rev_oid), path2); else html_txt(path2); } html("</div>"); } static void filepair_cb(struct diff_filepair *pair) { unsigned long old_size = 0; unsigned long new_size = 0; int binary = 0; linediff_fn print_line_fn = print_line; if (!show_filepair(pair)) return; current_filepair = pair; if (use_ssdiff) { cgit_ssdiff_header_begin(); print_line_fn = cgit_ssdiff_line_cb; } header(&pair->one->oid, pair->one->path, pair->one->mode, &pair->two->oid, pair->two->path, pair->two->mode); if (use_ssdiff) cgit_ssdiff_header_end(); if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) { if (S_ISGITLINK(pair->one->mode)) print_line_fn(fmt("-Subproject %s", oid_to_hex(&pair->one->oid)), 52); if (S_ISGITLINK(pair->two->mode)) print_line_fn(fmt("+Subproject %s", oid_to_hex(&pair->two->oid)), 52); if (use_ssdiff) cgit_ssdiff_footer(); return; } if (cgit_diff_files(&pair->one->oid, &pair->two->oid, &old_size, &new_size, &binary, ctx.qry.context, ctx.qry.ignorews, print_line_fn)) cgit_print_error("Error running diff"); if (binary) { if (use_ssdiff) html("<tr><td colspan='4'>Binary files differ</td></tr>"); else html("Binary files differ"); } if (use_ssdiff) cgit_ssdiff_footer(); } void cgit_print_diff_ctrls(void) { int i, curr; html("<div class='cgit-panel'>"); html("<b>diff options</b>"); html("<form method='get'>"); cgit_add_hidden_formfields(1, 0, ctx.qry.page); html("<table>"); html("<tr><td colspan='2'/></tr>"); html("<tr>"); html("<td class='label'>context:</td>"); html("<td class='ctrl'>"); html("<select name='context' onchange='this.form.submit();'>"); curr = ctx.qry.context; if (!curr) curr = 3; for (i = 1; i <= 10; i++) html_intoption(i, fmt("%d", i), curr); for (i = 15; i <= 40; i += 5) html_intoption(i, fmt("%d", i), curr); html("</select>"); html("</td>"); html("</tr><tr>"); html("<td class='label'>space:</td>"); html("<td class='ctrl'>"); html("<select name='ignorews' onchange='this.form.submit();'>"); html_intoption(0, "include", ctx.qry.ignorews); html_intoption(1, "ignore", ctx.qry.ignorews); html("</select>"); html("</td>"); html("</tr><tr>"); html("<td class='label'>mode:</td>"); html("<td class='ctrl'>"); html("<select name='dt' onchange='this.form.submit();'>"); curr = ctx.qry.has_difftype ? ctx.qry.difftype : ctx.cfg.difftype; html_intoption(0, "unified", curr); html_intoption(1, "ssdiff", curr); html_intoption(2, "stat only", curr); html("</select></td></tr>"); html("<tr><td/><td class='ctrl'>"); html("<noscript><input type='submit' value='reload'/></noscript>"); html("</td></tr></table>"); html("</form>"); html("</div>"); } void cgit_print_diff(const char *new_rev, const char *old_rev, const char *prefix, int show_ctrls, int raw) { struct commit *commit, *commit2; const unsigned char *old_tree_sha1, *new_tree_sha1; diff_type difftype; /* * If "follow" is set then the diff machinery needs to examine the * entire commit to detect renames so we must limit the paths in our * own callbacks and not pass the prefix to the diff machinery. */ if (ctx.qry.follow && ctx.cfg.enable_follow_links) { current_prefix = prefix; prefix = ""; } else { current_prefix = NULL; } if (!new_rev) new_rev = ctx.qry.head; if (get_oid(new_rev, new_rev_oid)) { cgit_print_error_page(404, "Not found", "Bad object name: %s", new_rev); return; } commit = lookup_commit_reference(new_rev_oid->hash); if (!commit || parse_commit(commit)) { cgit_print_error_page(404, "Not found", "Bad commit: %s", oid_to_hex(new_rev_oid)); return; } new_tree_sha1 = commit->tree->object.oid.hash; if (old_rev) { if (get_oid(old_rev, old_rev_oid)) { cgit_print_error_page(404, "Not found", "Bad object name: %s", old_rev); return; } } else if (commit->parents && commit->parents->item) { oidcpy(old_rev_oid, &commit->parents->item->object.oid); } else { oidclr(old_rev_oid); } if (!is_null_oid(old_rev_oid)) { commit2 = lookup_commit_reference(old_rev_oid->hash); if (!commit2 || parse_commit(commit2)) { cgit_print_error_page(404, "Not found", "Bad commit: %s", oid_to_hex(old_rev_oid)); return; } old_tree_sha1 = commit2->tree->object.oid.hash; } else { old_tree_sha1 = NULL; } if (raw) { struct diff_options diffopt; diff_setup(&diffopt); diffopt.output_format = DIFF_FORMAT_PATCH; DIFF_OPT_SET(&diffopt, RECURSIVE); diff_setup_done(&diffopt); ctx.page.mimetype = "text/plain"; cgit_print_http_headers(); if (old_tree_sha1) { diff_tree_sha1(old_tree_sha1, new_tree_sha1, "", &diffopt); } else { diff_root_tree_sha1(new_tree_sha1, "", &diffopt); } diffcore_std(&diffopt); diff_flush(&diffopt); return; } difftype = ctx.qry.has_difftype ? ctx.qry.difftype : ctx.cfg.difftype; use_ssdiff = difftype == DIFF_SSDIFF; if (show_ctrls) { cgit_print_layout_start(); cgit_print_diff_ctrls(); } /* * Clicking on a link to a file in the diff stat should show a diff * of the file, showing the diff stat limited to a single file is * pretty useless. All links from this point on will be to * individual files, so we simply reset the difftype in the query * here to avoid propagating DIFF_STATONLY to the individual files. */ if (difftype == DIFF_STATONLY) ctx.qry.difftype = ctx.cfg.difftype; cgit_print_diffstat(old_rev_oid, new_rev_oid, prefix); if (difftype == DIFF_STATONLY) return; if (use_ssdiff) { html("<table summary='ssdiff' class='ssdiff'>"); } else { html("<table summary='diff' class='diff'>"); html("<tr><td>"); } cgit_diff_tree(old_rev_oid, new_rev_oid, filepair_cb, prefix, ctx.qry.ignorews); if (!use_ssdiff) html("</td></tr>"); html("</table>"); if (show_ctrls) cgit_print_layout_end(); }