summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.css27
-rwxr-xr-xtests/t0104-tree.sh4
-rw-r--r--ui-tree.c31
3 files changed, 34 insertions, 28 deletions
diff --git a/cgit.css b/cgit.css
index 7928c2f..068c37b 100644
--- a/cgit.css
+++ b/cgit.css
@@ -47,404 +47,409 @@ table#header td.form {
47 text-align: right; 47 text-align: right;
48 vertical-align: bottom; 48 vertical-align: bottom;
49 padding-right: 1em; 49 padding-right: 1em;
50 padding-bottom: 2px; 50 padding-bottom: 2px;
51 white-space: nowrap; 51 white-space: nowrap;
52} 52}
53 53
54table#header td.form form, 54table#header td.form form,
55table#header td.form input, 55table#header td.form input,
56table#header td.form select { 56table#header td.form select {
57 font-size: 90%; 57 font-size: 90%;
58} 58}
59 59
60table#header td.sub { 60table#header td.sub {
61 color: #777; 61 color: #777;
62 border-top: solid 1px #ccc; 62 border-top: solid 1px #ccc;
63 padding-left: 10px; 63 padding-left: 10px;
64} 64}
65 65
66table.tabs { 66table.tabs {
67 /* border-bottom: solid 2px #ccc; */ 67 /* border-bottom: solid 2px #ccc; */
68 border-collapse: collapse; 68 border-collapse: collapse;
69 margin-top: 2em; 69 margin-top: 2em;
70 margin-bottom: 0px; 70 margin-bottom: 0px;
71 width: 100%; 71 width: 100%;
72} 72}
73 73
74table.tabs td { 74table.tabs td {
75 padding: 0px 1em; 75 padding: 0px 1em;
76 vertical-align: bottom; 76 vertical-align: bottom;
77} 77}
78 78
79table.tabs td a { 79table.tabs td a {
80 padding: 2px 0.75em; 80 padding: 2px 0.75em;
81 color: #777; 81 color: #777;
82 font-size: 110%; 82 font-size: 110%;
83} 83}
84 84
85table.tabs td a.active { 85table.tabs td a.active {
86 color: #000; 86 color: #000;
87 background-color: #ccc; 87 background-color: #ccc;
88} 88}
89 89
90table.tabs td.form { 90table.tabs td.form {
91 text-align: right; 91 text-align: right;
92} 92}
93 93
94table.tabs td.form form { 94table.tabs td.form form {
95 padding-bottom: 2px; 95 padding-bottom: 2px;
96 font-size: 90%; 96 font-size: 90%;
97 white-space: nowrap; 97 white-space: nowrap;
98} 98}
99 99
100table.tabs td.form input, 100table.tabs td.form input,
101table.tabs td.form select { 101table.tabs td.form select {
102 font-size: 90%; 102 font-size: 90%;
103} 103}
104 104
105div.content { 105div.content {
106 margin: 0px; 106 margin: 0px;
107 padding: 2em; 107 padding: 2em;
108 border-top: solid 3px #ccc; 108 border-top: solid 3px #ccc;
109 border-bottom: solid 3px #ccc; 109 border-bottom: solid 3px #ccc;
110} 110}
111 111
112 112
113table.list { 113table.list {
114 width: 100%; 114 width: 100%;
115 border: none; 115 border: none;
116 border-collapse: collapse; 116 border-collapse: collapse;
117} 117}
118 118
119table.list tr { 119table.list tr {
120 background: white; 120 background: white;
121} 121}
122 122
123table.list tr.logheader { 123table.list tr.logheader {
124 background: #eee; 124 background: #eee;
125} 125}
126 126
127table.list tr:hover { 127table.list tr:hover {
128 background: #eee; 128 background: #eee;
129} 129}
130 130
131table.list tr.nohover:hover { 131table.list tr.nohover:hover {
132 background: white; 132 background: white;
133} 133}
134 134
135table.list th { 135table.list th {
136 font-weight: bold; 136 font-weight: bold;
137 /* color: #888; 137 /* color: #888;
138 border-top: dashed 1px #888; 138 border-top: dashed 1px #888;
139 border-bottom: dashed 1px #888; 139 border-bottom: dashed 1px #888;
140 */ 140 */
141 padding: 0.1em 0.5em 0.05em 0.5em; 141 padding: 0.1em 0.5em 0.05em 0.5em;
142 vertical-align: baseline; 142 vertical-align: baseline;
143} 143}
144 144
145table.list td { 145table.list td {
146 border: none; 146 border: none;
147 padding: 0.1em 0.5em 0.1em 0.5em; 147 padding: 0.1em 0.5em 0.1em 0.5em;
148} 148}
149 149
150table.list td.logsubject { 150table.list td.logsubject {
151 font-family: monospace; 151 font-family: monospace;
152 font-weight: bold; 152 font-weight: bold;
153} 153}
154 154
155table.list td.logmsg { 155table.list td.logmsg {
156 font-family: monospace; 156 font-family: monospace;
157 white-space: pre; 157 white-space: pre;
158 padding: 1em 0em 2em 0em; 158 padding: 1em 0em 2em 0em;
159} 159}
160 160
161table.list td a { 161table.list td a {
162 color: black; 162 color: black;
163} 163}
164 164
165table.list td a:hover { 165table.list td a:hover {
166 color: #00f; 166 color: #00f;
167} 167}
168 168
169img { 169img {
170 border: none; 170 border: none;
171} 171}
172 172
173input#switch-btn { 173input#switch-btn {
174 margin: 2px 0px 0px 0px; 174 margin: 2px 0px 0px 0px;
175} 175}
176 176
177td#sidebar input.txt { 177td#sidebar input.txt {
178 width: 100%; 178 width: 100%;
179 margin: 2px 0px 0px 0px; 179 margin: 2px 0px 0px 0px;
180} 180}
181 181
182table#grid { 182table#grid {
183 margin: 0px; 183 margin: 0px;
184} 184}
185 185
186td#content { 186td#content {
187 vertical-align: top; 187 vertical-align: top;
188 padding: 1em 2em 1em 1em; 188 padding: 1em 2em 1em 1em;
189 border: none; 189 border: none;
190} 190}
191 191
192div#summary { 192div#summary {
193 vertical-align: top; 193 vertical-align: top;
194 margin-bottom: 1em; 194 margin-bottom: 1em;
195} 195}
196 196
197table#downloads { 197table#downloads {
198 float: right; 198 float: right;
199 border-collapse: collapse; 199 border-collapse: collapse;
200 border: solid 1px #777; 200 border: solid 1px #777;
201 margin-left: 0.5em; 201 margin-left: 0.5em;
202 margin-bottom: 0.5em; 202 margin-bottom: 0.5em;
203} 203}
204 204
205table#downloads th { 205table#downloads th {
206 background-color: #ccc; 206 background-color: #ccc;
207} 207}
208 208
209div#blob { 209div#blob {
210 border: solid 1px black; 210 border: solid 1px black;
211} 211}
212 212
213div.error { 213div.error {
214 color: red; 214 color: red;
215 font-weight: bold; 215 font-weight: bold;
216 margin: 1em 2em; 216 margin: 1em 2em;
217} 217}
218 218
219a.ls-blob, a.ls-dir, a.ls-mod { 219a.ls-blob, a.ls-dir, a.ls-mod {
220 font-family: monospace; 220 font-family: monospace;
221} 221}
222 222
223td.ls-size { 223td.ls-size {
224 text-align: right; 224 text-align: right;
225 font-family: monospace; 225 font-family: monospace;
226 width: 10em; 226 width: 10em;
227} 227}
228 228
229td.ls-mode { 229td.ls-mode {
230 font-family: monospace; 230 font-family: monospace;
231 width: 10em; 231 width: 10em;
232} 232}
233 233
234table.blob { 234table.blob {
235 margin-top: 0.5em; 235 margin-top: 0.5em;
236 border-top: solid 1px black; 236 border-top: solid 1px black;
237} 237}
238 238
239table.blob td.no { 239table.blob td.lines {
240 border-right: solid 1px black; 240 margin: 0; padding: 0;
241 vertical-align: top;
241 color: black; 242 color: black;
243}
244
245table.blob td.linenumbers {
246 margin: 0; padding: 0;
247 vertical-align: top;
248 border-right: 1px solid gray;
242 background-color: #eee; 249 background-color: #eee;
243 text-align: right;
244} 250}
245 251
246table.blob td.no a { 252table.blob pre {
247 color: black; 253 padding: 0; margin: 0;
248} 254}
249 255
250table.blob td.no a:hover { 256table.blob a.no {
251 color: black; 257 color: gray;
258 text-align: right;
252 text-decoration: none; 259 text-decoration: none;
253} 260}
254 261
255table.blob td.txt { 262table.blob a.no a:hover {
256 white-space: pre; 263 color: black;
257 font-family: monospace;
258 padding-left: 0.5em;
259} 264}
260 265
261table.nowrap td { 266table.nowrap td {
262 white-space: nowrap; 267 white-space: nowrap;
263} 268}
264 269
265table.commit-info { 270table.commit-info {
266 border-collapse: collapse; 271 border-collapse: collapse;
267 margin-top: 1.5em; 272 margin-top: 1.5em;
268} 273}
269 274
270table.commit-info th { 275table.commit-info th {
271 text-align: left; 276 text-align: left;
272 font-weight: normal; 277 font-weight: normal;
273 padding: 0.1em 1em 0.1em 0.1em; 278 padding: 0.1em 1em 0.1em 0.1em;
274 vertical-align: top; 279 vertical-align: top;
275} 280}
276 281
277table.commit-info td { 282table.commit-info td {
278 font-weight: normal; 283 font-weight: normal;
279 padding: 0.1em 1em 0.1em 0.1em; 284 padding: 0.1em 1em 0.1em 0.1em;
280} 285}
281 286
282div.commit-subject { 287div.commit-subject {
283 font-weight: bold; 288 font-weight: bold;
284 font-size: 125%; 289 font-size: 125%;
285 margin: 1.5em 0em 0.5em 0em; 290 margin: 1.5em 0em 0.5em 0em;
286 padding: 0em; 291 padding: 0em;
287} 292}
288 293
289div.commit-msg { 294div.commit-msg {
290 white-space: pre; 295 white-space: pre;
291 font-family: monospace; 296 font-family: monospace;
292} 297}
293 298
294div.diffstat-header { 299div.diffstat-header {
295 font-weight: bold; 300 font-weight: bold;
296 padding-top: 1.5em; 301 padding-top: 1.5em;
297} 302}
298 303
299table.diffstat { 304table.diffstat {
300 border-collapse: collapse; 305 border-collapse: collapse;
301 border: solid 1px #aaa; 306 border: solid 1px #aaa;
302 background-color: #eee; 307 background-color: #eee;
303} 308}
304 309
305table.diffstat th { 310table.diffstat th {
306 font-weight: normal; 311 font-weight: normal;
307 text-align: left; 312 text-align: left;
308 text-decoration: underline; 313 text-decoration: underline;
309 padding: 0.1em 1em 0.1em 0.1em; 314 padding: 0.1em 1em 0.1em 0.1em;
310 font-size: 100%; 315 font-size: 100%;
311} 316}
312 317
313table.diffstat td { 318table.diffstat td {
314 padding: 0.2em 0.2em 0.1em 0.1em; 319 padding: 0.2em 0.2em 0.1em 0.1em;
315 font-size: 100%; 320 font-size: 100%;
316 border: none; 321 border: none;
317} 322}
318 323
319table.diffstat td.mode { 324table.diffstat td.mode {
320 white-space: nowrap; 325 white-space: nowrap;
321} 326}
322 327
323table.diffstat td span.modechange { 328table.diffstat td span.modechange {
324 padding-left: 1em; 329 padding-left: 1em;
325 color: red; 330 color: red;
326} 331}
327 332
328table.diffstat td.add a { 333table.diffstat td.add a {
329 color: green; 334 color: green;
330} 335}
331 336
332table.diffstat td.del a { 337table.diffstat td.del a {
333 color: red; 338 color: red;
334} 339}
335 340
336table.diffstat td.upd a { 341table.diffstat td.upd a {
337 color: blue; 342 color: blue;
338} 343}
339 344
340table.diffstat td.graph { 345table.diffstat td.graph {
341 width: 500px; 346 width: 500px;
342 vertical-align: middle; 347 vertical-align: middle;
343} 348}
344 349
345table.diffstat td.graph table { 350table.diffstat td.graph table {
346 border: none; 351 border: none;
347} 352}
348 353
349table.diffstat td.graph td { 354table.diffstat td.graph td {
350 padding: 0px; 355 padding: 0px;
351 border: 0px; 356 border: 0px;
352 height: 7pt; 357 height: 7pt;
353} 358}
354 359
355table.diffstat td.graph td.add { 360table.diffstat td.graph td.add {
356 background-color: #5c5; 361 background-color: #5c5;
357} 362}
358 363
359table.diffstat td.graph td.rem { 364table.diffstat td.graph td.rem {
360 background-color: #c55; 365 background-color: #c55;
361} 366}
362 367
363div.diffstat-summary { 368div.diffstat-summary {
364 color: #888; 369 color: #888;
365 padding-top: 0.5em; 370 padding-top: 0.5em;
366} 371}
367 372
368table.diff { 373table.diff {
369 width: 100%; 374 width: 100%;
370} 375}
371 376
372table.diff td { 377table.diff td {
373 font-family: monospace; 378 font-family: monospace;
374 white-space: pre; 379 white-space: pre;
375} 380}
376 381
377table.diff td div.head { 382table.diff td div.head {
378 font-weight: bold; 383 font-weight: bold;
379 margin-top: 1em; 384 margin-top: 1em;
380 color: black; 385 color: black;
381} 386}
382 387
383table.diff td div.hunk { 388table.diff td div.hunk {
384 color: #009; 389 color: #009;
385} 390}
386 391
387table.diff td div.add { 392table.diff td div.add {
388 color: green; 393 color: green;
389} 394}
390 395
391table.diff td div.del { 396table.diff td div.del {
392 color: red; 397 color: red;
393} 398}
394 399
395.sha1 { 400.sha1 {
396 font-family: monospace; 401 font-family: monospace;
397 font-size: 90%; 402 font-size: 90%;
398} 403}
399 404
400.left { 405.left {
401 text-align: left; 406 text-align: left;
402} 407}
403 408
404.right { 409.right {
405 text-align: right; 410 text-align: right;
406} 411}
407 412
408table.list td.repogroup { 413table.list td.repogroup {
409 font-style: italic; 414 font-style: italic;
410 color: #888; 415 color: #888;
411} 416}
412 417
413a.button { 418a.button {
414 font-size: 80%; 419 font-size: 80%;
415 padding: 0em 0.5em; 420 padding: 0em 0.5em;
416} 421}
417 422
418a.primary { 423a.primary {
419 font-size: 100%; 424 font-size: 100%;
420} 425}
421 426
422a.secondary { 427a.secondary {
423 font-size: 90%; 428 font-size: 90%;
424} 429}
425 430
426td.toplevel-repo { 431td.toplevel-repo {
427 432
428} 433}
429 434
430table.list td.sublevel-repo { 435table.list td.sublevel-repo {
431 padding-left: 1.5em; 436 padding-left: 1.5em;
432} 437}
433 438
434div.pager { 439div.pager {
435 text-align: center; 440 text-align: center;
436 margin: 1em 0em 0em 0em; 441 margin: 1em 0em 0em 0em;
437} 442}
438 443
439div.pager a { 444div.pager a {
440 color: #777; 445 color: #777;
441 margin: 0em 0.5em; 446 margin: 0em 0.5em;
442} 447}
443 448
444span.age-mins { 449span.age-mins {
445 font-weight: bold; 450 font-weight: bold;
446 color: #080; 451 color: #080;
447} 452}
448 453
449span.age-hours { 454span.age-hours {
450 color: #080; 455 color: #080;
diff --git a/tests/t0104-tree.sh b/tests/t0104-tree.sh
index 33f4eb0..2ce1251 100755
--- a/tests/t0104-tree.sh
+++ b/tests/t0104-tree.sh
@@ -1,33 +1,33 @@
1#!/bin/sh 1#!/bin/sh
2 2
3. ./setup.sh 3. ./setup.sh
4 4
5prepare_tests "Check content on tree page" 5prepare_tests "Check content on tree page"
6 6
7run_test 'generate bar/tree' 'cgit_url "bar/tree" >trash/tmp' 7run_test 'generate bar/tree' 'cgit_url "bar/tree" >trash/tmp'
8run_test 'find file-1' 'grep -e "file-1" trash/tmp' 8run_test 'find file-1' 'grep -e "file-1" trash/tmp'
9run_test 'find file-50' 'grep -e "file-50" trash/tmp' 9run_test 'find file-50' 'grep -e "file-50" trash/tmp'
10 10
11run_test 'generate bar/tree/file-50' 'cgit_url "bar/tree/file-50" >trash/tmp' 11run_test 'generate bar/tree/file-50' 'cgit_url "bar/tree/file-50" >trash/tmp'
12 12
13run_test 'find line 1' ' 13run_test 'find line 1' '
14 grep -e "<a id=.n1. name=.n1. href=.#n1.>1</a>" trash/tmp 14 grep -e "<a class=.no. id=.n1. name=.n1. href=.#n1.>1</a>" trash/tmp
15' 15'
16 16
17run_test 'no line 2' ' 17run_test 'no line 2' '
18 ! grep -e "<a id=.n2. name=.n2. href=.#n2.>2</a>" trash/tmp 18 ! grep -e "<a class=.no. id=.n2. name=.n2. href=.#n2.>2</a>" trash/tmp
19' 19'
20 20
21run_test 'generate foo+bar/tree' 'cgit_url "foo%2bbar/tree" >trash/tmp' 21run_test 'generate foo+bar/tree' 'cgit_url "foo%2bbar/tree" >trash/tmp'
22 22
23run_test 'verify a+b link' ' 23run_test 'verify a+b link' '
24 grep -e "/foo+bar/tree/a+b" trash/tmp 24 grep -e "/foo+bar/tree/a+b" trash/tmp
25' 25'
26 26
27run_test 'generate foo+bar/tree?h=1+2' 'cgit_url "foo%2bbar/tree&h=1%2b2" >trash/tmp' 27run_test 'generate foo+bar/tree?h=1+2' 'cgit_url "foo%2bbar/tree&h=1%2b2" >trash/tmp'
28 28
29run_test 'verify a+b?h=1+2 link' ' 29run_test 'verify a+b?h=1+2 link' '
30 grep -e "/foo+bar/tree/a+b?h=1%2b2" trash/tmp 30 grep -e "/foo+bar/tree/a+b?h=1%2b2" trash/tmp
31' 31'
32 32
33tests_done 33tests_done
diff --git a/ui-tree.c b/ui-tree.c
index 9876c99..2a8625c 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -1,225 +1,226 @@
1/* ui-tree.c: functions for tree output 1/* ui-tree.c: functions for tree output
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10#include "html.h" 10#include "html.h"
11#include "ui-shared.h" 11#include "ui-shared.h"
12 12
13char *curr_rev; 13char *curr_rev;
14char *match_path; 14char *match_path;
15int header = 0; 15int header = 0;
16 16
17static void print_object(const unsigned char *sha1, char *path) 17static void print_object(const unsigned char *sha1, char *path)
18{ 18{
19 enum object_type type; 19 enum object_type type;
20 char *buf; 20 char *buf;
21 unsigned long size, lineno, start, idx; 21 unsigned long size, lineno, idx;
22 const char *linefmt = "<tr><td class='no'><a id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a></td><td class='txt'>"; 22 const char *numberfmt = "<a class='no' id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a>\n";
23 23
24 type = sha1_object_info(sha1, &size); 24 type = sha1_object_info(sha1, &size);
25 if (type == OBJ_BAD) { 25 if (type == OBJ_BAD) {
26 cgit_print_error(fmt("Bad object name: %s", 26 cgit_print_error(fmt("Bad object name: %s",
27 sha1_to_hex(sha1))); 27 sha1_to_hex(sha1)));
28 return; 28 return;
29 } 29 }
30 30
31 buf = read_sha1_file(sha1, &type, &size); 31 buf = read_sha1_file(sha1, &type, &size);
32 if (!buf) { 32 if (!buf) {
33 cgit_print_error(fmt("Error reading object %s", 33 cgit_print_error(fmt("Error reading object %s",
34 sha1_to_hex(sha1))); 34 sha1_to_hex(sha1)));
35 return; 35 return;
36 } 36 }
37 37
38 html(" ("); 38 html(" (");
39 cgit_plain_link("plain", NULL, NULL, ctx.qry.head, 39 cgit_plain_link("plain", NULL, NULL, ctx.qry.head,
40 curr_rev, path); 40 curr_rev, path);
41 htmlf(")<br/>blob: %s", sha1_to_hex(sha1)); 41 htmlf(")<br/>blob: %s\n", sha1_to_hex(sha1));
42 42
43 html("<table summary='blob content' class='blob'>\n"); 43 html("<table summary='blob content' class='blob'>\n");
44 html("<tr>\n");
45
46 html("<td class='linenumbers'><pre>");
44 idx = 0; 47 idx = 0;
45 start = 0;
46 lineno = 0; 48 lineno = 0;
47 while(idx < size) { 49 htmlf(numberfmt, ++lineno);
50 while(idx < size - 1) { // skip absolute last newline
48 if (buf[idx] == '\n') { 51 if (buf[idx] == '\n') {
49 buf[idx] = '\0'; 52 htmlf(numberfmt, ++lineno);
50 htmlf(linefmt, ++lineno);
51 html_txt(buf + start);
52 html("</td></tr>\n");
53 start = idx + 1;
54 } 53 }
55 idx++; 54 idx++;
56 } 55 }
57 if (start < idx) { 56 html("</pre></td>\n");
58 htmlf(linefmt, ++lineno); 57
59 html_txt(buf + start); 58 html("<td class='lines'><pre><code>");
60 } 59 html_txt(buf);
61 html("</td></tr>\n"); 60 html("</code></pre></td>\n");
61
62 html("</tr>\n");
62 html("</table>\n"); 63 html("</table>\n");
63} 64}
64 65
65 66
66static int ls_item(const unsigned char *sha1, const char *base, int baselen, 67static int ls_item(const unsigned char *sha1, const char *base, int baselen,
67 const char *pathname, unsigned int mode, int stage, 68 const char *pathname, unsigned int mode, int stage,
68 void *cbdata) 69 void *cbdata)
69{ 70{
70 char *name; 71 char *name;
71 char *fullpath; 72 char *fullpath;
72 enum object_type type; 73 enum object_type type;
73 unsigned long size = 0; 74 unsigned long size = 0;
74 75
75 name = xstrdup(pathname); 76 name = xstrdup(pathname);
76 fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "", 77 fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "",
77 ctx.qry.path ? "/" : "", name); 78 ctx.qry.path ? "/" : "", name);
78 79
79 if (!S_ISGITLINK(mode)) { 80 if (!S_ISGITLINK(mode)) {
80 type = sha1_object_info(sha1, &size); 81 type = sha1_object_info(sha1, &size);
81 if (type == OBJ_BAD) { 82 if (type == OBJ_BAD) {
82 htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", 83 htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>",
83 name, 84 name,
84 sha1_to_hex(sha1)); 85 sha1_to_hex(sha1));
85 return 0; 86 return 0;
86 } 87 }
87 } 88 }
88 89
89 html("<tr><td class='ls-mode'>"); 90 html("<tr><td class='ls-mode'>");
90 cgit_print_filemode(mode); 91 cgit_print_filemode(mode);
91 html("</td><td>"); 92 html("</td><td>");
92 if (S_ISGITLINK(mode)) { 93 if (S_ISGITLINK(mode)) {
93 htmlf("<a class='ls-mod' href='"); 94 htmlf("<a class='ls-mod' href='");
94 html_attr(fmt(ctx.repo->module_link, 95 html_attr(fmt(ctx.repo->module_link,
95 name, 96 name,
96 sha1_to_hex(sha1))); 97 sha1_to_hex(sha1)));
97 html("'>"); 98 html("'>");
98 html_txt(name); 99 html_txt(name);
99 html("</a>"); 100 html("</a>");
100 } else if (S_ISDIR(mode)) { 101 } else if (S_ISDIR(mode)) {
101 cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, 102 cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head,
102 curr_rev, fullpath); 103 curr_rev, fullpath);
103 } else { 104 } else {
104 cgit_tree_link(name, NULL, "ls-blob", ctx.qry.head, 105 cgit_tree_link(name, NULL, "ls-blob", ctx.qry.head,
105 curr_rev, fullpath); 106 curr_rev, fullpath);
106 } 107 }
107 htmlf("</td><td class='ls-size'>%li</td>", size); 108 htmlf("</td><td class='ls-size'>%li</td>", size);
108 109
109 html("<td>"); 110 html("<td>");
110 cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev, 111 cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev,
111 fullpath, 0, NULL, NULL, ctx.qry.showmsg); 112 fullpath, 0, NULL, NULL, ctx.qry.showmsg);
112 html("</td></tr>\n"); 113 html("</td></tr>\n");
113 free(name); 114 free(name);
114 return 0; 115 return 0;
115} 116}
116 117
117static void ls_head() 118static void ls_head()
118{ 119{
119 html("<table summary='tree listing' class='list'>\n"); 120 html("<table summary='tree listing' class='list'>\n");
120 html("<tr class='nohover'>"); 121 html("<tr class='nohover'>");
121 html("<th class='left'>Mode</th>"); 122 html("<th class='left'>Mode</th>");
122 html("<th class='left'>Name</th>"); 123 html("<th class='left'>Name</th>");
123 html("<th class='right'>Size</th>"); 124 html("<th class='right'>Size</th>");
124 html("<th/>"); 125 html("<th/>");
125 html("</tr>\n"); 126 html("</tr>\n");
126 header = 1; 127 header = 1;
127} 128}
128 129
129static void ls_tail() 130static void ls_tail()
130{ 131{
131 if (!header) 132 if (!header)
132 return; 133 return;
133 html("</table>\n"); 134 html("</table>\n");
134 header = 0; 135 header = 0;
135} 136}
136 137
137static void ls_tree(const unsigned char *sha1, char *path) 138static void ls_tree(const unsigned char *sha1, char *path)
138{ 139{
139 struct tree *tree; 140 struct tree *tree;
140 141
141 tree = parse_tree_indirect(sha1); 142 tree = parse_tree_indirect(sha1);
142 if (!tree) { 143 if (!tree) {
143 cgit_print_error(fmt("Not a tree object: %s", 144 cgit_print_error(fmt("Not a tree object: %s",
144 sha1_to_hex(sha1))); 145 sha1_to_hex(sha1)));
145 return; 146 return;
146 } 147 }
147 148
148 ls_head(); 149 ls_head();
149 read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL); 150 read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL);
150 ls_tail(); 151 ls_tail();
151} 152}
152 153
153 154
154static int walk_tree(const unsigned char *sha1, const char *base, int baselen, 155static int walk_tree(const unsigned char *sha1, const char *base, int baselen,
155 const char *pathname, unsigned mode, int stage, 156 const char *pathname, unsigned mode, int stage,
156 void *cbdata) 157 void *cbdata)
157{ 158{
158 static int state; 159 static int state;
159 static char buffer[PATH_MAX]; 160 static char buffer[PATH_MAX];
160 char *url; 161 char *url;
161 162
162 if (state == 0) { 163 if (state == 0) {
163 memcpy(buffer, base, baselen); 164 memcpy(buffer, base, baselen);
164 strcpy(buffer+baselen, pathname); 165 strcpy(buffer+baselen, pathname);
165 url = cgit_pageurl(ctx.qry.repo, "tree", 166 url = cgit_pageurl(ctx.qry.repo, "tree",
166 fmt("h=%s&amp;path=%s", curr_rev, buffer)); 167 fmt("h=%s&amp;path=%s", curr_rev, buffer));
167 html("/"); 168 html("/");
168 cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head, 169 cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head,
169 curr_rev, buffer); 170 curr_rev, buffer);
170 171
171 if (strcmp(match_path, buffer)) 172 if (strcmp(match_path, buffer))
172 return READ_TREE_RECURSIVE; 173 return READ_TREE_RECURSIVE;
173 174
174 if (S_ISDIR(mode)) { 175 if (S_ISDIR(mode)) {
175 state = 1; 176 state = 1;
176 ls_head(); 177 ls_head();
177 return READ_TREE_RECURSIVE; 178 return READ_TREE_RECURSIVE;
178 } else { 179 } else {
179 print_object(sha1, buffer); 180 print_object(sha1, buffer);
180 return 0; 181 return 0;
181 } 182 }
182 } 183 }
183 ls_item(sha1, base, baselen, pathname, mode, stage, NULL); 184 ls_item(sha1, base, baselen, pathname, mode, stage, NULL);
184 return 0; 185 return 0;
185} 186}
186 187
187 188
188/* 189/*
189 * Show a tree or a blob 190 * Show a tree or a blob
190 * rev: the commit pointing at the root tree object 191 * rev: the commit pointing at the root tree object
191 * path: path to tree or blob 192 * path: path to tree or blob
192 */ 193 */
193void cgit_print_tree(const char *rev, char *path) 194void cgit_print_tree(const char *rev, char *path)
194{ 195{
195 unsigned char sha1[20]; 196 unsigned char sha1[20];
196 struct commit *commit; 197 struct commit *commit;
197 const char *paths[] = {path, NULL}; 198 const char *paths[] = {path, NULL};
198 199
199 if (!rev) 200 if (!rev)
200 rev = ctx.qry.head; 201 rev = ctx.qry.head;
201 202
202 curr_rev = xstrdup(rev); 203 curr_rev = xstrdup(rev);
203 if (get_sha1(rev, sha1)) { 204 if (get_sha1(rev, sha1)) {
204 cgit_print_error(fmt("Invalid revision name: %s", rev)); 205 cgit_print_error(fmt("Invalid revision name: %s", rev));
205 return; 206 return;
206 } 207 }
207 commit = lookup_commit_reference(sha1); 208 commit = lookup_commit_reference(sha1);
208 if (!commit || parse_commit(commit)) { 209 if (!commit || parse_commit(commit)) {
209 cgit_print_error(fmt("Invalid commit reference: %s", rev)); 210 cgit_print_error(fmt("Invalid commit reference: %s", rev));
210 return; 211 return;
211 } 212 }
212 213
213 html("path: <a href='"); 214 html("path: <a href='");
214 html_attr(cgit_pageurl(ctx.qry.repo, "tree", fmt("h=%s", rev))); 215 html_attr(cgit_pageurl(ctx.qry.repo, "tree", fmt("h=%s", rev)));
215 html("'>root</a>"); 216 html("'>root</a>");
216 217
217 if (path == NULL) { 218 if (path == NULL) {
218 ls_tree(commit->tree->object.sha1, NULL); 219 ls_tree(commit->tree->object.sha1, NULL);
219 return; 220 return;
220 } 221 }
221 222
222 match_path = path; 223 match_path = path;
223 read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree, NULL); 224 read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree, NULL);
224 ls_tail(); 225 ls_tail();
225} 226}