aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--cgit.c25
-rw-r--r--cgit.css347
-rw-r--r--cgit.h2
-rw-r--r--cgitrc.5.txt13
-rwxr-xr-xfilters/syntax-highlighting.sh28
-rw-r--r--html.c4
-rw-r--r--parsing.c2
-rw-r--r--shared.c5
-rwxr-xr-xtests/setup.sh5
-rwxr-xr-xtests/t0108-patch.sh2
-rw-r--r--ui-diff.c17
-rw-r--r--ui-log.c3
-rw-r--r--ui-plain.c9
-rw-r--r--ui-repolist.c9
-rw-r--r--ui-shared.c86
-rw-r--r--ui-shared.h5
-rw-r--r--ui-ssdiff.c29
-rw-r--r--ui-ssdiff.h12
-rw-r--r--ui-tree.c13
20 files changed, 393 insertions, 227 deletions
diff --git a/Makefile b/Makefile
index 538a9f8..eac24ad 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
1CGIT_VERSION = v0.9.0.1 1CGIT_VERSION = v0.9.0.3
2CGIT_SCRIPT_NAME = cgit.cgi 2CGIT_SCRIPT_NAME = cgit.cgi
3CGIT_SCRIPT_PATH = /var/www/htdocs/cgit 3CGIT_SCRIPT_PATH = /var/www/htdocs/cgit
4CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH) 4CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH)
@@ -13,7 +13,7 @@ pdfdir = $(docdir)
13mandir = $(prefix)/share/man 13mandir = $(prefix)/share/man
14SHA1_HEADER = <openssl/sha.h> 14SHA1_HEADER = <openssl/sha.h>
15GIT_VER = 1.7.4 15GIT_VER = 1.7.4
16GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 16GIT_URL = http://hjemli.net/git/git/snapshot/git-$(GIT_VER).tar.bz2
17INSTALL = install 17INSTALL = install
18MAN5_TXT = $(wildcard *.5.txt) 18MAN5_TXT = $(wildcard *.5.txt)
19MAN_TXT = $(MAN5_TXT) 19MAN_TXT = $(MAN5_TXT)
diff --git a/cgit.c b/cgit.c
index abb698b..b9b3a66 100644
--- a/cgit.c
+++ b/cgit.c
@@ -60,6 +60,8 @@ static void process_cached_repolist(const char *path);
60 60
61void repo_config(struct cgit_repo *repo, const char *name, const char *value) 61void repo_config(struct cgit_repo *repo, const char *name, const char *value)
62{ 62{
63 struct string_list_item *item;
64
63 if (!strcmp(name, "name")) 65 if (!strcmp(name, "name"))
64 repo->name = xstrdup(value); 66 repo->name = xstrdup(value);
65 else if (!strcmp(name, "clone-url")) 67 else if (!strcmp(name, "clone-url"))
@@ -86,7 +88,10 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value)
86 repo->max_stats = cgit_find_stats_period(value, NULL); 88 repo->max_stats = cgit_find_stats_period(value, NULL);
87 else if (!strcmp(name, "module-link")) 89 else if (!strcmp(name, "module-link"))
88 repo->module_link= xstrdup(value); 90 repo->module_link= xstrdup(value);
89 else if (!strcmp(name, "section")) 91 else if (!prefixcmp(name, "module-link.")) {
92 item = string_list_append(&repo->submodules, name + 12);
93 item->util = xstrdup(value);
94 } else if (!strcmp(name, "section"))
90 repo->section = xstrdup(value); 95 repo->section = xstrdup(value);
91 else if (!strcmp(name, "readme") && value != NULL) 96 else if (!strcmp(name, "readme") && value != NULL)
92 repo->readme = xstrdup(value); 97 repo->readme = xstrdup(value);
@@ -300,6 +305,7 @@ static void querystring_cb(const char *name, const char *value)
300 ctx.qry.period = xstrdup(value); 305 ctx.qry.period = xstrdup(value);
301 } else if (!strcmp(name, "ss")) { 306 } else if (!strcmp(name, "ss")) {
302 ctx.qry.ssdiff = atoi(value); 307 ctx.qry.ssdiff = atoi(value);
308 ctx.qry.has_ssdiff = 1;
303 } else if (!strcmp(name, "all")) { 309 } else if (!strcmp(name, "all")) {
304 ctx.qry.show_all = atoi(value); 310 ctx.qry.show_all = atoi(value);
305 } else if (!strcmp(name, "context")) { 311 } else if (!strcmp(name, "context")) {
@@ -340,7 +346,6 @@ static void prepare_context(struct cgit_context *ctx)
340 ctx->cfg.max_repodesc_len = 80; 346 ctx->cfg.max_repodesc_len = 80;
341 ctx->cfg.max_blob_size = 0; 347 ctx->cfg.max_blob_size = 0;
342 ctx->cfg.max_stats = 0; 348 ctx->cfg.max_stats = 0;
343 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
344 ctx->cfg.project_list = NULL; 349 ctx->cfg.project_list = NULL;
345 ctx->cfg.renamelimit = -1; 350 ctx->cfg.renamelimit = -1;
346 ctx->cfg.remove_suffix = 0; 351 ctx->cfg.remove_suffix = 0;
@@ -418,6 +423,17 @@ char *find_default_branch(struct cgit_repo *repo)
418 return ref; 423 return ref;
419} 424}
420 425
426static char *guess_defbranch(const char *repo_path)
427{
428 const char *ref;
429 unsigned char sha1[20];
430
431 ref = resolve_ref("HEAD", sha1, 0, NULL);
432 if (!ref || prefixcmp(ref, "refs/heads/"))
433 return "master";
434 return xstrdup(ref + 11);
435}
436
421static int prepare_repo_cmd(struct cgit_context *ctx) 437static int prepare_repo_cmd(struct cgit_context *ctx)
422{ 438{
423 char *tmp; 439 char *tmp;
@@ -444,10 +460,12 @@ static int prepare_repo_cmd(struct cgit_context *ctx)
444 } 460 }
445 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); 461 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc);
446 462
463 if (!ctx->repo->defbranch)
464 ctx->repo->defbranch = guess_defbranch(ctx->repo->path);
465
447 if (!ctx->qry.head) { 466 if (!ctx->qry.head) {
448 ctx->qry.nohead = 1; 467 ctx->qry.nohead = 1;
449 ctx->qry.head = find_default_branch(ctx->repo); 468 ctx->qry.head = find_default_branch(ctx->repo);
450 ctx->repo->defbranch = ctx->qry.head;
451 } 469 }
452 470
453 if (!ctx->qry.head) { 471 if (!ctx->qry.head) {
@@ -471,6 +489,7 @@ static int prepare_repo_cmd(struct cgit_context *ctx)
471 cgit_print_docend(); 489 cgit_print_docend();
472 return 1; 490 return 1;
473 } 491 }
492 sort_string_list(&ctx->repo->submodules);
474 cgit_prepare_repo_env(ctx->repo); 493 cgit_prepare_repo_env(ctx->repo);
475 return 0; 494 return 0;
476} 495}
diff --git a/cgit.css b/cgit.css
index 55afa94..e06c261 100644
--- a/cgit.css
+++ b/cgit.css
@@ -1,4 +1,4 @@
1body, table, form { 1body, div#cgit table, div#cgit form {
2 padding: 0em; 2 padding: 0em;
3 margin: 0em; 3 margin: 0em;
4} 4}
@@ -11,39 +11,40 @@ body {
11 padding: 4px; 11 padding: 4px;
12} 12}
13 13
14a { 14div#cgit a {
15 color: blue; 15 color: blue;
16 text-decoration: none; 16 text-decoration: none;
17} 17}
18 18
19a:hover { 19div#cgit a:hover {
20 text-decoration: underline; 20 text-decoration: underline;
21} 21}
22 22
23table { 23div#cgit table {
24 border-collapse: collapse; 24 border-collapse: collapse;
25} 25}
26 26
27table#header { 27div#cgit table#header {
28 width: 100%; 28 width: 100%;
29 margin-bottom: 1em; 29 margin-bottom: 1em;
30} 30}
31 31
32table#header td.logo { 32div#cgit table#header td.logo {
33 width: 96px; 33 width: 96px;
34 vertical-align: top;
34} 35}
35 36
36table#header td.main { 37div#cgit table#header td.main {
37 font-size: 250%; 38 font-size: 250%;
38 padding-left: 10px; 39 padding-left: 10px;
39 white-space: nowrap; 40 white-space: nowrap;
40} 41}
41 42
42table#header td.main a { 43div#cgit table#header td.main a {
43 color: #000; 44 color: #000;
44} 45}
45 46
46table#header td.form { 47div#cgit table#header td.form {
47 text-align: right; 48 text-align: right;
48 vertical-align: bottom; 49 vertical-align: bottom;
49 padding-right: 1em; 50 padding-right: 1em;
@@ -51,19 +52,19 @@ table#header td.form {
51 white-space: nowrap; 52 white-space: nowrap;
52} 53}
53 54
54table#header td.form form, 55div#cgit table#header td.form form,
55table#header td.form input, 56div#cgit table#header td.form input,
56table#header td.form select { 57div#cgit table#header td.form select {
57 font-size: 90%; 58 font-size: 90%;
58} 59}
59 60
60table#header td.sub { 61div#cgit table#header td.sub {
61 color: #777; 62 color: #777;
62 border-top: solid 1px #ccc; 63 border-top: solid 1px #ccc;
63 padding-left: 10px; 64 padding-left: 10px;
64} 65}
65 66
66table.tabs { 67div#cgit table.tabs {
67 border-bottom: solid 3px #ccc; 68 border-bottom: solid 3px #ccc;
68 border-collapse: collapse; 69 border-collapse: collapse;
69 margin-top: 2em; 70 margin-top: 2em;
@@ -71,74 +72,74 @@ table.tabs {
71 width: 100%; 72 width: 100%;
72} 73}
73 74
74table.tabs td { 75div#cgit table.tabs td {
75 padding: 0px 1em; 76 padding: 0px 1em;
76 vertical-align: bottom; 77 vertical-align: bottom;
77} 78}
78 79
79table.tabs td a { 80div#cgit table.tabs td a {
80 padding: 2px 0.75em; 81 padding: 2px 0.75em;
81 color: #777; 82 color: #777;
82 font-size: 110%; 83 font-size: 110%;
83} 84}
84 85
85table.tabs td a.active { 86div#cgit table.tabs td a.active {
86 color: #000; 87 color: #000;
87 background-color: #ccc; 88 background-color: #ccc;
88} 89}
89 90
90table.tabs td.form { 91div#cgit table.tabs td.form {
91 text-align: right; 92 text-align: right;
92} 93}
93 94
94table.tabs td.form form { 95div#cgit table.tabs td.form form {
95 padding-bottom: 2px; 96 padding-bottom: 2px;
96 font-size: 90%; 97 font-size: 90%;
97 white-space: nowrap; 98 white-space: nowrap;
98} 99}
99 100
100table.tabs td.form input, 101div#cgit table.tabs td.form input,
101table.tabs td.form select { 102div#cgit table.tabs td.form select {
102 font-size: 90%; 103 font-size: 90%;
103} 104}
104 105
105div.path { 106div#cgit div.path {
106 margin: 0px; 107 margin: 0px;
107 padding: 5px 2em 2px 2em; 108 padding: 5px 2em 2px 2em;
108 color: #000; 109 color: #000;
109 background-color: #eee; 110 background-color: #eee;
110} 111}
111 112
112div.content { 113div#cgit div.content {
113 margin: 0px; 114 margin: 0px;
114 padding: 2em; 115 padding: 2em;
115 border-bottom: solid 3px #ccc; 116 border-bottom: solid 3px #ccc;
116} 117}
117 118
118 119
119table.list { 120div#cgit table.list {
120 width: 100%; 121 width: 100%;
121 border: none; 122 border: none;
122 border-collapse: collapse; 123 border-collapse: collapse;
123} 124}
124 125
125table.list tr { 126div#cgit table.list tr {
126 background: white; 127 background: white;
127} 128}
128 129
129table.list tr.logheader { 130div#cgit table.list tr.logheader {
130 background: #eee; 131 background: #eee;
131} 132}
132 133
133table.list tr:hover { 134div#cgit table.list tr:hover {
134 background: #eee; 135 background: #eee;
135} 136}
136 137
137table.list tr.nohover:hover { 138div#cgit table.list tr.nohover:hover {
138 background: white; 139 background: white;
139} 140}
140 141
141table.list th { 142div#cgit table.list th {
142 font-weight: bold; 143 font-weight: bold;
143 /* color: #888; 144 /* color: #888;
144 border-top: dashed 1px #888; 145 border-top: dashed 1px #888;
@@ -148,93 +149,93 @@ table.list th {
148 vertical-align: baseline; 149 vertical-align: baseline;
149} 150}
150 151
151table.list td { 152div#cgit table.list td {
152 border: none; 153 border: none;
153 padding: 0.1em 0.5em 0.1em 0.5em; 154 padding: 0.1em 0.5em 0.1em 0.5em;
154} 155}
155 156
156table.list td.commitgraph { 157div#cgit table.list td.commitgraph {
157 font-family: monospace; 158 font-family: monospace;
158 white-space: pre; 159 white-space: pre;
159} 160}
160 161
161table.list td.commitgraph .column1 { 162div#cgit table.list td.commitgraph .column1 {
162 color: #a00; 163 color: #a00;
163} 164}
164 165
165table.list td.commitgraph .column2 { 166div#cgit table.list td.commitgraph .column2 {
166 color: #0a0; 167 color: #0a0;
167} 168}
168 169
169table.list td.commitgraph .column3 { 170div#cgit table.list td.commitgraph .column3 {
170 color: #aa0; 171 color: #aa0;
171} 172}
172 173
173table.list td.commitgraph .column4 { 174div#cgit table.list td.commitgraph .column4 {
174 color: #00a; 175 color: #00a;
175} 176}
176 177
177table.list td.commitgraph .column5 { 178div#cgit table.list td.commitgraph .column5 {
178 color: #a0a; 179 color: #a0a;
179} 180}
180 181
181table.list td.commitgraph .column6 { 182div#cgit table.list td.commitgraph .column6 {
182 color: #0aa; 183 color: #0aa;
183} 184}
184 185
185table.list td.logsubject { 186div#cgit table.list td.logsubject {
186 font-family: monospace; 187 font-family: monospace;
187 font-weight: bold; 188 font-weight: bold;
188} 189}
189 190
190table.list td.logmsg { 191div#cgit table.list td.logmsg {
191 font-family: monospace; 192 font-family: monospace;
192 white-space: pre; 193 white-space: pre;
193 padding: 0 0.5em; 194 padding: 0 0.5em;
194} 195}
195 196
196table.list td a { 197div#cgit table.list td a {
197 color: black; 198 color: black;
198} 199}
199 200
200table.list td a.ls-dir { 201div#cgit table.list td a.ls-dir {
201 font-weight: bold; 202 font-weight: bold;
202 color: #00f; 203 color: #00f;
203} 204}
204 205
205table.list td a:hover { 206div#cgit table.list td a:hover {
206 color: #00f; 207 color: #00f;
207} 208}
208 209
209img { 210div#cgit img {
210 border: none; 211 border: none;
211} 212}
212 213
213input#switch-btn { 214div#cgit input#switch-btn {
214 margin: 2px 0px 0px 0px; 215 margin: 2px 0px 0px 0px;
215} 216}
216 217
217td#sidebar input.txt { 218div#cgit td#sidebar input.txt {
218 width: 100%; 219 width: 100%;
219 margin: 2px 0px 0px 0px; 220 margin: 2px 0px 0px 0px;
220} 221}
221 222
222table#grid { 223div#cgit table#grid {
223 margin: 0px; 224 margin: 0px;
224} 225}
225 226
226td#content { 227div#cgit td#content {
227 vertical-align: top; 228 vertical-align: top;
228 padding: 1em 2em 1em 1em; 229 padding: 1em 2em 1em 1em;
229 border: none; 230 border: none;
230} 231}
231 232
232div#summary { 233div#cgit div#summary {
233 vertical-align: top; 234 vertical-align: top;
234 margin-bottom: 1em; 235 margin-bottom: 1em;
235} 236}
236 237
237table#downloads { 238div#cgit table#downloads {
238 float: right; 239 float: right;
239 border-collapse: collapse; 240 border-collapse: collapse;
240 border: solid 1px #777; 241 border: solid 1px #777;
@@ -242,152 +243,152 @@ table#downloads {
242 margin-bottom: 0.5em; 243 margin-bottom: 0.5em;
243} 244}
244 245
245table#downloads th { 246div#cgit table#downloads th {
246 background-color: #ccc; 247 background-color: #ccc;
247} 248}
248 249
249div#blob { 250div#cgit div#blob {
250 border: solid 1px black; 251 border: solid 1px black;
251} 252}
252 253
253div.error { 254div#cgit div.error {
254 color: red; 255 color: red;
255 font-weight: bold; 256 font-weight: bold;
256 margin: 1em 2em; 257 margin: 1em 2em;
257} 258}
258 259
259a.ls-blob, a.ls-dir, a.ls-mod { 260div#cgit a.ls-blob, div#cgit a.ls-dir, div#cgit a.ls-mod {
260 font-family: monospace; 261 font-family: monospace;
261} 262}
262 263
263td.ls-size { 264div#cgit td.ls-size {
264 text-align: right; 265 text-align: right;
265 font-family: monospace; 266 font-family: monospace;
266 width: 10em; 267 width: 10em;
267} 268}
268 269
269td.ls-mode { 270div#cgit td.ls-mode {
270 font-family: monospace; 271 font-family: monospace;
271 width: 10em; 272 width: 10em;
272} 273}
273 274
274table.blob { 275div#cgit table.blob {
275 margin-top: 0.5em; 276 margin-top: 0.5em;
276 border-top: solid 1px black; 277 border-top: solid 1px black;
277} 278}
278 279
279table.blob td.lines { 280div#cgit table.blob td.lines {
280 margin: 0; padding: 0 0 0 0.5em; 281 margin: 0; padding: 0 0 0 0.5em;
281 vertical-align: top; 282 vertical-align: top;
282 color: black; 283 color: black;
283} 284}
284 285
285table.blob td.linenumbers { 286div#cgit table.blob td.linenumbers {
286 margin: 0; padding: 0 0.5em 0 0.5em; 287 margin: 0; padding: 0 0.5em 0 0.5em;
287 vertical-align: top; 288 vertical-align: top;
288 text-align: right; 289 text-align: right;
289 border-right: 1px solid gray; 290 border-right: 1px solid gray;
290} 291}
291 292
292table.blob pre { 293div#cgit table.blob pre {
293 padding: 0; margin: 0; 294 padding: 0; margin: 0;
294} 295}
295 296
296table.blob a.no, table.ssdiff a.no { 297div#cgit table.blob a.no, div#cgit table.ssdiff a.no {
297 color: gray; 298 color: gray;
298 text-align: right; 299 text-align: right;
299 text-decoration: none; 300 text-decoration: none;
300} 301}
301 302
302table.blob a.no a:hover { 303div#cgit table.blob a.no a:hover {
303 color: black; 304 color: black;
304} 305}
305 306
306table.bin-blob { 307div#cgit table.bin-blob {
307 margin-top: 0.5em; 308 margin-top: 0.5em;
308 border: solid 1px black; 309 border: solid 1px black;
309} 310}
310 311
311table.bin-blob th { 312div#cgit table.bin-blob th {
312 font-family: monospace; 313 font-family: monospace;
313 white-space: pre; 314 white-space: pre;
314 border: solid 1px #777; 315 border: solid 1px #777;
315 padding: 0.5em 1em; 316 padding: 0.5em 1em;
316} 317}
317 318
318table.bin-blob td { 319div#cgit table.bin-blob td {
319 font-family: monospace; 320 font-family: monospace;
320 white-space: pre; 321 white-space: pre;
321 border-left: solid 1px #777; 322 border-left: solid 1px #777;
322 padding: 0em 1em; 323 padding: 0em 1em;
323} 324}
324 325
325table.nowrap td { 326div#cgit table.nowrap td {
326 white-space: nowrap; 327 white-space: nowrap;
327} 328}
328 329
329table.commit-info { 330div#cgit table.commit-info {
330 border-collapse: collapse; 331 border-collapse: collapse;
331 margin-top: 1.5em; 332 margin-top: 1.5em;
332} 333}
333 334
334div.cgit-panel { 335div#cgit div.cgit-panel {
335 float: right; 336 float: right;
336 margin-top: 1.5em; 337 margin-top: 1.5em;
337} 338}
338 339
339div.cgit-panel table { 340div#cgit div.cgit-panel table {
340 border-collapse: collapse; 341 border-collapse: collapse;
341 border: solid 1px #aaa; 342 border: solid 1px #aaa;
342 background-color: #eee; 343 background-color: #eee;
343} 344}
344 345
345div.cgit-panel th { 346div#cgit div.cgit-panel th {
346 text-align: center; 347 text-align: center;
347} 348}
348 349
349div.cgit-panel td { 350div#cgit div.cgit-panel td {
350 padding: 0.25em 0.5em; 351 padding: 0.25em 0.5em;
351} 352}
352 353
353div.cgit-panel td.label { 354div#cgit div.cgit-panel td.label {
354 padding-right: 0.5em; 355 padding-right: 0.5em;
355} 356}
356 357
357div.cgit-panel td.ctrl { 358div#cgit div.cgit-panel td.ctrl {
358 padding-left: 0.5em; 359 padding-left: 0.5em;
359} 360}
360 361
361table.commit-info th { 362div#cgit table.commit-info th {
362 text-align: left; 363 text-align: left;
363 font-weight: normal; 364 font-weight: normal;
364 padding: 0.1em 1em 0.1em 0.1em; 365 padding: 0.1em 1em 0.1em 0.1em;
365 vertical-align: top; 366 vertical-align: top;
366} 367}
367 368
368table.commit-info td { 369div#cgit table.commit-info td {
369 font-weight: normal; 370 font-weight: normal;
370 padding: 0.1em 1em 0.1em 0.1em; 371 padding: 0.1em 1em 0.1em 0.1em;
371} 372}
372 373
373div.commit-subject { 374div#cgit div.commit-subject {
374 font-weight: bold; 375 font-weight: bold;
375 font-size: 125%; 376 font-size: 125%;
376 margin: 1.5em 0em 0.5em 0em; 377 margin: 1.5em 0em 0.5em 0em;
377 padding: 0em; 378 padding: 0em;
378} 379}
379 380
380div.commit-msg { 381div#cgit div.commit-msg {
381 white-space: pre; 382 white-space: pre;
382 font-family: monospace; 383 font-family: monospace;
383} 384}
384 385
385div.notes-header { 386div#cgit div.notes-header {
386 font-weight: bold; 387 font-weight: bold;
387 padding-top: 1.5em; 388 padding-top: 1.5em;
388} 389}
389 390
390div.notes { 391div#cgit div.notes {
391 white-space: pre; 392 white-space: pre;
392 font-family: monospace; 393 font-family: monospace;
393 border: solid 1px #ee9; 394 border: solid 1px #ee9;
@@ -396,22 +397,22 @@ div.notes {
396 float: left; 397 float: left;
397} 398}
398 399
399div.notes-footer { 400div#cgit div.notes-footer {
400 clear: left; 401 clear: left;
401} 402}
402 403
403div.diffstat-header { 404div#cgit div.diffstat-header {
404 font-weight: bold; 405 font-weight: bold;
405 padding-top: 1.5em; 406 padding-top: 1.5em;
406} 407}
407 408
408table.diffstat { 409div#cgit table.diffstat {
409 border-collapse: collapse; 410 border-collapse: collapse;
410 border: solid 1px #aaa; 411 border: solid 1px #aaa;
411 background-color: #eee; 412 background-color: #eee;
412} 413}
413 414
414table.diffstat th { 415div#cgit table.diffstat th {
415 font-weight: normal; 416 font-weight: normal;
416 text-align: left; 417 text-align: left;
417 text-decoration: underline; 418 text-decoration: underline;
@@ -419,282 +420,286 @@ table.diffstat th {
419 font-size: 100%; 420 font-size: 100%;
420} 421}
421 422
422table.diffstat td { 423div#cgit table.diffstat td {
423 padding: 0.2em 0.2em 0.1em 0.1em; 424 padding: 0.2em 0.2em 0.1em 0.1em;
424 font-size: 100%; 425 font-size: 100%;
425 border: none; 426 border: none;
426} 427}
427 428
428table.diffstat td.mode { 429div#cgit table.diffstat td.mode {
429 white-space: nowrap; 430 white-space: nowrap;
430} 431}
431 432
432table.diffstat td span.modechange { 433div#cgit table.diffstat td span.modechange {
433 padding-left: 1em; 434 padding-left: 1em;
434 color: red; 435 color: red;
435} 436}
436 437
437table.diffstat td.add a { 438div#cgit table.diffstat td.add a {
438 color: green; 439 color: green;
439} 440}
440 441
441table.diffstat td.del a { 442div#cgit table.diffstat td.del a {
442 color: red; 443 color: red;
443} 444}
444 445
445table.diffstat td.upd a { 446div#cgit table.diffstat td.upd a {
446 color: blue; 447 color: blue;
447} 448}
448 449
449table.diffstat td.graph { 450div#cgit table.diffstat td.graph {
450 width: 500px; 451 width: 500px;
451 vertical-align: middle; 452 vertical-align: middle;
452} 453}
453 454
454table.diffstat td.graph table { 455div#cgit table.diffstat td.graph table {
455 border: none; 456 border: none;
456} 457}
457 458
458table.diffstat td.graph td { 459div#cgit table.diffstat td.graph td {
459 padding: 0px; 460 padding: 0px;
460 border: 0px; 461 border: 0px;
461 height: 7pt; 462 height: 7pt;
462} 463}
463 464
464table.diffstat td.graph td.add { 465div#cgit table.diffstat td.graph td.add {
465 background-color: #5c5; 466 background-color: #5c5;
466} 467}
467 468
468table.diffstat td.graph td.rem { 469div#cgit table.diffstat td.graph td.rem {
469 background-color: #c55; 470 background-color: #c55;
470} 471}
471 472
472div.diffstat-summary { 473div#cgit div.diffstat-summary {
473 color: #888; 474 color: #888;
474 padding-top: 0.5em; 475 padding-top: 0.5em;
475} 476}
476 477
477table.diff { 478div#cgit table.diff {
478 width: 100%; 479 width: 100%;
479} 480}
480 481
481table.diff td { 482div#cgit table.diff td {
482 font-family: monospace; 483 font-family: monospace;
483 white-space: pre; 484 white-space: pre;
484} 485}
485 486
486table.diff td div.head { 487div#cgit table.diff td div.head {
487 font-weight: bold; 488 font-weight: bold;
488 margin-top: 1em; 489 margin-top: 1em;
489 color: black; 490 color: black;
490} 491}
491 492
492table.diff td div.hunk { 493div#cgit table.diff td div.hunk {
493 color: #009; 494 color: #009;
494} 495}
495 496
496table.diff td div.add { 497div#cgit table.diff td div.add {
497 color: green; 498 color: green;
498} 499}
499 500
500table.diff td div.del { 501div#cgit table.diff td div.del {
501 color: red; 502 color: red;
502} 503}
503 504
504.sha1 { 505div#cgit .sha1 {
505 font-family: monospace; 506 font-family: monospace;
506 font-size: 90%; 507 font-size: 90%;
507} 508}
508 509
509.left { 510div#cgit .left {
510 text-align: left; 511 text-align: left;
511} 512}
512 513
513.right { 514div#cgit .right {
514 text-align: right; 515 text-align: right;
515} 516}
516 517
517table.list td.reposection { 518div#cgit table.list td.reposection {
518 font-style: italic; 519 font-style: italic;
519 color: #888; 520 color: #888;
520} 521}
521 522
522a.button { 523div#cgit a.button {
523 font-size: 80%; 524 font-size: 80%;
524 padding: 0em 0.5em; 525 padding: 0em 0.5em;
525} 526}
526 527
527a.primary { 528div#cgit a.primary {
528 font-size: 100%; 529 font-size: 100%;
529} 530}
530 531
531a.secondary { 532div#cgit a.secondary {
532 font-size: 90%; 533 font-size: 90%;
533} 534}
534 535
535td.toplevel-repo { 536div#cgit td.toplevel-repo {
536 537
537} 538}
538 539
539table.list td.sublevel-repo { 540div#cgit table.list td.sublevel-repo {
540 padding-left: 1.5em; 541 padding-left: 1.5em;
541} 542}
542 543
543div.pager { 544div#cgit div.pager {
544 text-align: center; 545 text-align: center;
545 margin: 1em 0em 0em 0em; 546 margin: 1em 0em 0em 0em;
546} 547}
547 548
548div.pager a { 549div#cgit div.pager a {
549 color: #777; 550 color: #777;
550 margin: 0em 0.5em; 551 margin: 0em 0.5em;
551} 552}
552 553
553span.age-mins { 554div#cgit span.age-mins {
554 font-weight: bold; 555 font-weight: bold;
555 color: #080; 556 color: #080;
556} 557}
557 558
558span.age-hours { 559div#cgit span.age-hours {
559 color: #080; 560 color: #080;
560} 561}
561 562
562span.age-days { 563div#cgit span.age-days {
563 color: #040; 564 color: #040;
564} 565}
565 566
566span.age-weeks { 567div#cgit span.age-weeks {
567 color: #444; 568 color: #444;
568} 569}
569 570
570span.age-months { 571div#cgit span.age-months {
571 color: #888; 572 color: #888;
572} 573}
573 574
574span.age-years { 575div#cgit span.age-years {
575 color: #bbb; 576 color: #bbb;
576} 577}
577div.footer { 578div#cgit div.footer {
578 margin-top: 0.5em; 579 margin-top: 0.5em;
579 text-align: center; 580 text-align: center;
580 font-size: 80%; 581 font-size: 80%;
581 color: #ccc; 582 color: #ccc;
582} 583}
583a.branch-deco { 584div#cgit a.branch-deco {
585 color: #000;
584 margin: 0px 0.5em; 586 margin: 0px 0.5em;
585 padding: 0px 0.25em; 587 padding: 0px 0.25em;
586 background-color: #88ff88; 588 background-color: #88ff88;
587 border: solid 1px #007700; 589 border: solid 1px #007700;
588} 590}
589a.tag-deco { 591div#cgit a.tag-deco {
592 color: #000;
590 margin: 0px 0.5em; 593 margin: 0px 0.5em;
591 padding: 0px 0.25em; 594 padding: 0px 0.25em;
592 background-color: #ffff88; 595 background-color: #ffff88;
593 border: solid 1px #777700; 596 border: solid 1px #777700;
594} 597}
595a.remote-deco { 598div#cgit a.remote-deco {
599 color: #000;
596 margin: 0px 0.5em; 600 margin: 0px 0.5em;
597 padding: 0px 0.25em; 601 padding: 0px 0.25em;
598 background-color: #ccccff; 602 background-color: #ccccff;
599 border: solid 1px #000077; 603 border: solid 1px #000077;
600} 604}
601a.deco { 605div#cgit a.deco {
606 color: #000;
602 margin: 0px 0.5em; 607 margin: 0px 0.5em;
603 padding: 0px 0.25em; 608 padding: 0px 0.25em;
604 background-color: #ff8888; 609 background-color: #ff8888;
605 border: solid 1px #770000; 610 border: solid 1px #770000;
606} 611}
607 612
608div.commit-subject a.branch-deco, 613div#cgit div.commit-subject a.branch-deco,
609div.commit-subject a.tag-deco, 614div#cgit div.commit-subject a.tag-deco,
610div.commit-subject a.remote-deco, 615div#cgit div.commit-subject a.remote-deco,
611div.commit-subject a.deco { 616div#cgit div.commit-subject a.deco {
612 margin-left: 1em; 617 margin-left: 1em;
613 font-size: 75%; 618 font-size: 75%;
614} 619}
615 620
616table.stats { 621div#cgit table.stats {
617 border: solid 1px black; 622 border: solid 1px black;
618 border-collapse: collapse; 623 border-collapse: collapse;
619} 624}
620 625
621table.stats th { 626div#cgit table.stats th {
622 text-align: left; 627 text-align: left;
623 padding: 1px 0.5em; 628 padding: 1px 0.5em;
624 background-color: #eee; 629 background-color: #eee;
625 border: solid 1px black; 630 border: solid 1px black;
626} 631}
627 632
628table.stats td { 633div#cgit table.stats td {
629 text-align: right; 634 text-align: right;
630 padding: 1px 0.5em; 635 padding: 1px 0.5em;
631 border: solid 1px black; 636 border: solid 1px black;
632} 637}
633 638
634table.stats td.total { 639div#cgit table.stats td.total {
635 font-weight: bold; 640 font-weight: bold;
636 text-align: left; 641 text-align: left;
637} 642}
638 643
639table.stats td.sum { 644div#cgit table.stats td.sum {
640 color: #c00; 645 color: #c00;
641 font-weight: bold; 646 font-weight: bold;
642/* background-color: #eee; */ 647/* background-color: #eee; */
643} 648}
644 649
645table.stats td.left { 650div#cgit table.stats td.left {
646 text-align: left; 651 text-align: left;
647} 652}
648 653
649table.vgraph { 654div#cgit table.vgraph {
650 border-collapse: separate; 655 border-collapse: separate;
651 border: solid 1px black; 656 border: solid 1px black;
652 height: 200px; 657 height: 200px;
653} 658}
654 659
655table.vgraph th { 660div#cgit table.vgraph th {
656 background-color: #eee; 661 background-color: #eee;
657 font-weight: bold; 662 font-weight: bold;
658 border: solid 1px white; 663 border: solid 1px white;
659 padding: 1px 0.5em; 664 padding: 1px 0.5em;
660} 665}
661 666
662table.vgraph td { 667div#cgit table.vgraph td {
663 vertical-align: bottom; 668 vertical-align: bottom;
664 padding: 0px 10px; 669 padding: 0px 10px;
665} 670}
666 671
667table.vgraph div.bar { 672div#cgit table.vgraph div.bar {
668 background-color: #eee; 673 background-color: #eee;
669} 674}
670 675
671table.hgraph { 676div#cgit table.hgraph {
672 border: solid 1px black; 677 border: solid 1px black;
673 width: 800px; 678 width: 800px;
674} 679}
675 680
676table.hgraph th { 681div#cgit table.hgraph th {
677 background-color: #eee; 682 background-color: #eee;
678 font-weight: bold; 683 font-weight: bold;
679 border: solid 1px black; 684 border: solid 1px black;
680 padding: 1px 0.5em; 685 padding: 1px 0.5em;
681} 686}
682 687
683table.hgraph td { 688div#cgit table.hgraph td {
684 vertical-align: center; 689 vertical-align: middle;
685 padding: 2px 2px; 690 padding: 2px 2px;
686} 691}
687 692
688table.hgraph div.bar { 693div#cgit table.hgraph div.bar {
689 background-color: #eee; 694 background-color: #eee;
690 height: 1em; 695 height: 1em;
691} 696}
692 697
693table.ssdiff { 698div#cgit table.ssdiff {
694 width: 100%; 699 width: 100%;
695} 700}
696 701
697table.ssdiff td { 702div#cgit table.ssdiff td {
698 font-size: 75%; 703 font-size: 75%;
699 font-family: monospace; 704 font-family: monospace;
700 white-space: pre; 705 white-space: pre;
@@ -703,53 +708,53 @@ table.ssdiff td {
703 border-right: solid 1px #aaa; 708 border-right: solid 1px #aaa;
704} 709}
705 710
706table.ssdiff td.add { 711div#cgit table.ssdiff td.add {
707 color: black; 712 color: black;
708 background: #cfc; 713 background: #cfc;
709 min-width: 50%; 714 min-width: 50%;
710} 715}
711 716
712table.ssdiff td.add_dark { 717div#cgit table.ssdiff td.add_dark {
713 color: black; 718 color: black;
714 background: #aca; 719 background: #aca;
715 min-width: 50%; 720 min-width: 50%;
716} 721}
717 722
718table.ssdiff span.add { 723div#cgit table.ssdiff span.add {
719 background: #cfc; 724 background: #cfc;
720 font-weight: bold; 725 font-weight: bold;
721} 726}
722 727
723table.ssdiff td.del { 728div#cgit table.ssdiff td.del {
724 color: black; 729 color: black;
725 background: #fcc; 730 background: #fcc;
726 min-width: 50%; 731 min-width: 50%;
727} 732}
728 733
729table.ssdiff td.del_dark { 734div#cgit table.ssdiff td.del_dark {
730 color: black; 735 color: black;
731 background: #caa; 736 background: #caa;
732 min-width: 50%; 737 min-width: 50%;
733} 738}
734 739
735table.ssdiff span.del { 740div#cgit table.ssdiff span.del {
736 background: #fcc; 741 background: #fcc;
737 font-weight: bold; 742 font-weight: bold;
738} 743}
739 744
740table.ssdiff td.changed { 745div#cgit table.ssdiff td.changed {
741 color: black; 746 color: black;
742 background: #ffc; 747 background: #ffc;
743 min-width: 50%; 748 min-width: 50%;
744} 749}
745 750
746table.ssdiff td.changed_dark { 751div#cgit table.ssdiff td.changed_dark {
747 color: black; 752 color: black;
748 background: #cca; 753 background: #cca;
749 min-width: 50%; 754 min-width: 50%;
750} 755}
751 756
752table.ssdiff td.lineno { 757div#cgit table.ssdiff td.lineno {
753 color: black; 758 color: black;
754 background: #eee; 759 background: #eee;
755 text-align: right; 760 text-align: right;
@@ -757,48 +762,48 @@ table.ssdiff td.lineno {
757 min-width: 3em; 762 min-width: 3em;
758} 763}
759 764
760table.ssdiff td.hunk { 765div#cgit table.ssdiff td.hunk {
761 color: #black; 766 color: black;
762 background: #ccf; 767 background: #ccf;
763 border-top: solid 1px #aaa; 768 border-top: solid 1px #aaa;
764 border-bottom: solid 1px #aaa; 769 border-bottom: solid 1px #aaa;
765} 770}
766 771
767table.ssdiff td.head { 772div#cgit table.ssdiff td.head {
768 border-top: solid 1px #aaa; 773 border-top: solid 1px #aaa;
769 border-bottom: solid 1px #aaa; 774 border-bottom: solid 1px #aaa;
770} 775}
771 776
772table.ssdiff td.head div.head { 777div#cgit table.ssdiff td.head div.head {
773 font-weight: bold; 778 font-weight: bold;
774 color: black; 779 color: black;
775} 780}
776 781
777table.ssdiff td.foot { 782div#cgit table.ssdiff td.foot {
778 border-top: solid 1px #aaa; 783 border-top: solid 1px #aaa;
779 border-left: none; 784 border-left: none;
780 border-right: none; 785 border-right: none;
781 border-bottom: none; 786 border-bottom: none;
782} 787}
783 788
784table.ssdiff td.space { 789div#cgit table.ssdiff td.space {
785 border: none; 790 border: none;
786} 791}
787 792
788table.ssdiff td.space div { 793div#cgit table.ssdiff td.space div {
789 min-height: 3em; 794 min-height: 3em;
790} 795}
791 796
792/* Syntax highlighting */ 797/* Syntax highlighting */
793table.blob .num { color:#2928ff; } 798div#cgit table.blob .num { color:#2928ff; }
794table.blob .esc { color:#ff00ff; } 799div#cgit table.blob .esc { color:#ff00ff; }
795table.blob .str { color:#ff0000; } 800div#cgit table.blob .str { color:#ff0000; }
796table.blob .dstr { color:#818100; } 801div#cgit table.blob .dstr { color:#818100; }
797table.blob .slc { color:#838183; font-style:italic; } 802div#cgit table.blob .slc { color:#838183; font-style:italic; }
798table.blob .com { color:#838183; font-style:italic; } 803div#cgit table.blob .com { color:#838183; font-style:italic; }
799table.blob .dir { color:#008200; } 804div#cgit table.blob .dir { color:#008200; }
800table.blob .sym { color:#000000; } 805div#cgit table.blob .sym { color:#000000; }
801table.blob .kwa { color:#000000; font-weight:bold; } 806div#cgit table.blob .kwa { color:#000000; font-weight:bold; }
802table.blob .kwb { color:#830000; } 807div#cgit table.blob .kwb { color:#830000; }
803table.blob .kwc { color:#000000; font-weight:bold; } 808div#cgit table.blob .kwc { color:#000000; font-weight:bold; }
804table.blob .kwd { color:#010181; } 809div#cgit table.blob .kwd { color:#010181; }
diff --git a/cgit.h b/cgit.h
index db24941..6ee6769 100644
--- a/cgit.h
+++ b/cgit.h
@@ -88,6 +88,7 @@ struct cgit_repo {
88 struct cgit_filter *about_filter; 88 struct cgit_filter *about_filter;
89 struct cgit_filter *commit_filter; 89 struct cgit_filter *commit_filter;
90 struct cgit_filter *source_filter; 90 struct cgit_filter *source_filter;
91 struct string_list submodules;
91}; 92};
92 93
93typedef void (*repo_config_fn)(struct cgit_repo *repo, const char *name, 94typedef void (*repo_config_fn)(struct cgit_repo *repo, const char *name,
@@ -137,6 +138,7 @@ struct reflist {
137struct cgit_query { 138struct cgit_query {
138 int has_symref; 139 int has_symref;
139 int has_sha1; 140 int has_sha1;
141 int has_ssdiff;
140 char *raw; 142 char *raw;
141 char *repo; 143 char *repo;
142 char *page; 144 char *page;
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 22a0dc3..a72241f 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -241,7 +241,7 @@ module-link::
241 Text which will be used as the formatstring for a hyperlink when a 241 Text which will be used as the formatstring for a hyperlink when a
242 submodule is printed in a directory listing. The arguments for the 242 submodule is printed in a directory listing. The arguments for the
243 formatstring are the path and SHA1 of the submodule commit. Default 243 formatstring are the path and SHA1 of the submodule commit. Default
244 value: "./?repo=%s&page=commit&id=%s" 244 value: none.
245 245
246nocache:: 246nocache::
247 If set to the value "1" caching will be disabled. This settings is 247 If set to the value "1" caching will be disabled. This settings is
@@ -388,7 +388,8 @@ repo.commit-filter::
388repo.defbranch:: 388repo.defbranch::
389 The name of the default branch for this repository. If no such branch 389 The name of the default branch for this repository. If no such branch
390 exists in the repository, the first branch name (when sorted) is used 390 exists in the repository, the first branch name (when sorted) is used
391 as default instead. Default value: "master". 391 as default instead. Default value: branch pointed to by HEAD, or
392 "master" if there is no suitable HEAD.
392 393
393repo.desc:: 394repo.desc::
394 The value to show as repository description. Default value: none. 395 The value to show as repository description. Default value: none.
@@ -428,6 +429,12 @@ repo.module-link::
428 formatstring are the path and SHA1 of the submodule commit. Default 429 formatstring are the path and SHA1 of the submodule commit. Default
429 value: <module-link> 430 value: <module-link>
430 431
432repo.module-link.<path>::
433 Text which will be used as the formatstring for a hyperlink when a
434 submodule with the specified subdirectory path is printed in a
435 directory listing. The only argument for the formatstring is the SHA1
436 of the submodule commit. Default value: none.
437
431repo.max-stats:: 438repo.max-stats::
432 Override the default maximum statistics period. Valid values are equal 439 Override the default maximum statistics period. Valid values are equal
433 to the values specified for the global "max-stats" setting. Default 440 to the values specified for the global "max-stats" setting. Default
@@ -511,7 +518,7 @@ Also, all filters are handed the following environment variables:
511 518
512If a setting is not defined for a repository and the corresponding global 519If a setting is not defined for a repository and the corresponding global
513setting is also not defined (if applicable), then the corresponding 520setting is also not defined (if applicable), then the corresponding
514environment variable will be an empty string. 521environment variable will be unset.
515 522
516 523
517MACRO EXPANSION 524MACRO EXPANSION
diff --git a/filters/syntax-highlighting.sh b/filters/syntax-highlighting.sh
index 6283ce9..5fcc9c9 100755
--- a/filters/syntax-highlighting.sh
+++ b/filters/syntax-highlighting.sh
@@ -42,4 +42,32 @@ EXTENSION="${BASENAME##*.}"
42# map Makefile and Makefile.* to .mk 42# map Makefile and Makefile.* to .mk
43[ "${BASENAME%%.*}" == "Makefile" ] && EXTENSION=mk 43[ "${BASENAME%%.*}" == "Makefile" ] && EXTENSION=mk
44 44
45# highlight versions 2 and 3 have different commandline options. Specifically,
46# the -X option that is used for version 2 is replaced by the -O xhtml option
47# for version 3.
48#
49# Version 2 can be found (for example) on EPEL 5, while version 3 can be
50# found (for example) on EPEL 6.
51#
52# This is for version 2
45exec highlight --force -f -I -X -S $EXTENSION 2>/dev/null 53exec highlight --force -f -I -X -S $EXTENSION 2>/dev/null
54
55# This is for version 3
56#
57# On CentOS 6.2 (using highlight from EPEL), when highlight doesn't know about
58# an EXTENSION, it outputs a lua error and _no_ text, even when the --force
59# option is used.
60#
61# Also see the bug reports at:
62# http://sourceforge.net/tracker/?func=detail&aid=3490017&group_id=215618&atid=1034391
63# https://bugzilla.redhat.com/show_bug.cgi?id=795567
64#
65# This workaround can be removed when the bug is fixed upstream and the new
66# version is packaged in most distributions.
67#
68# The workaround is to set the extension to 'txt' (plain text) when highlight
69# exits with an error (doesn't know the format).
70#
71#echo "test" | highlight -f -I -O xhtml -S $EXTENSION &>/dev/null
72#[ ${?} -ne 0 ] && EXTENSION="txt"
73#exec highlight --force -f -I -O xhtml -S $EXTENSION 2>/dev/null
diff --git a/html.c b/html.c
index eb1c25d..8f6e4f6 100644
--- a/html.c
+++ b/html.c
@@ -162,7 +162,7 @@ void html_url_path(const char *txt)
162{ 162{
163 const char *t = txt; 163 const char *t = txt;
164 while(t && *t){ 164 while(t && *t){
165 int c = *t; 165 unsigned char c = *t;
166 const char *e = url_escape_table[c]; 166 const char *e = url_escape_table[c];
167 if (e && c!='+' && c!='&') { 167 if (e && c!='+' && c!='&') {
168 html_raw(txt, t - txt); 168 html_raw(txt, t - txt);
@@ -179,7 +179,7 @@ void html_url_arg(const char *txt)
179{ 179{
180 const char *t = txt; 180 const char *t = txt;
181 while(t && *t){ 181 while(t && *t){
182 int c = *t; 182 unsigned char c = *t;
183 const char *e = url_escape_table[c]; 183 const char *e = url_escape_table[c];
184 if (c == ' ') 184 if (c == ' ')
185 e = "+"; 185 e = "+";
diff --git a/parsing.c b/parsing.c
index 151c0fe..602e3de 100644
--- a/parsing.c
+++ b/parsing.c
@@ -125,7 +125,7 @@ const char *reencode(char **txt, const char *src_enc, const char *dst_enc)
125struct commitinfo *cgit_parse_commit(struct commit *commit) 125struct commitinfo *cgit_parse_commit(struct commit *commit)
126{ 126{
127 struct commitinfo *ret; 127 struct commitinfo *ret;
128 char *p = commit->buffer, *t = commit->buffer; 128 char *p = commit->buffer, *t;
129 129
130 ret = xmalloc(sizeof(*ret)); 130 ret = xmalloc(sizeof(*ret));
131 ret->commit = commit; 131 ret->commit = commit;
diff --git a/shared.c b/shared.c
index 699c362..0a0e22e 100644
--- a/shared.c
+++ b/shared.c
@@ -8,7 +8,6 @@
8 8
9#include "cgit.h" 9#include "cgit.h"
10#include <stdio.h> 10#include <stdio.h>
11#include <linux/limits.h>
12 11
13struct cgit_repolist cgit_repolist; 12struct cgit_repolist cgit_repolist;
14struct cgit_context ctx; 13struct cgit_context ctx;
@@ -56,7 +55,6 @@ struct cgit_repo *cgit_add_repo(const char *url)
56 ret->desc = "[no description]"; 55 ret->desc = "[no description]";
57 ret->owner = NULL; 56 ret->owner = NULL;
58 ret->section = ctx.cfg.section; 57 ret->section = ctx.cfg.section;
59 ret->defbranch = "master";
60 ret->snapshots = ctx.cfg.snapshots; 58 ret->snapshots = ctx.cfg.snapshots;
61 ret->enable_commit_graph = ctx.cfg.enable_commit_graph; 59 ret->enable_commit_graph = ctx.cfg.enable_commit_graph;
62 ret->enable_log_filecount = ctx.cfg.enable_log_filecount; 60 ret->enable_log_filecount = ctx.cfg.enable_log_filecount;
@@ -71,6 +69,7 @@ struct cgit_repo *cgit_add_repo(const char *url)
71 ret->commit_filter = ctx.cfg.commit_filter; 69 ret->commit_filter = ctx.cfg.commit_filter;
72 ret->source_filter = ctx.cfg.source_filter; 70 ret->source_filter = ctx.cfg.source_filter;
73 ret->clone_url = ctx.cfg.clone_url; 71 ret->clone_url = ctx.cfg.clone_url;
72 ret->submodules.strdup_strings = 1;
74 return ret; 73 return ret;
75} 74}
76 75
@@ -393,7 +392,7 @@ void cgit_prepare_repo_env(struct cgit_repo * repo)
393 p = env_vars; 392 p = env_vars;
394 q = p + env_var_count; 393 q = p + env_var_count;
395 for (; p < q; p++) 394 for (; p < q; p++)
396 if (setenv(p->name, p->value, 1)) 395 if (p->value && setenv(p->name, p->value, 1))
397 fprintf(stderr, warn, p->name, p->value); 396 fprintf(stderr, warn, p->name, p->value);
398} 397}
399 398
diff --git a/tests/setup.sh b/tests/setup.sh
index 1e06107..e3c6c17 100755
--- a/tests/setup.sh
+++ b/tests/setup.sh
@@ -15,13 +15,14 @@
15# run_test 'repo index' 'cgit_url "/" | tidy -e' 15# run_test 'repo index' 'cgit_url "/" | tidy -e'
16# run_test 'repo summary' 'cgit_url "/foo" | tidy -e' 16# run_test 'repo summary' 'cgit_url "/foo" | tidy -e'
17 17
18unset CDPATH
18 19
19mkrepo() { 20mkrepo() {
20 name=$1 21 name=$1
21 count=$2 22 count=$2
22 dir=$PWD 23 dir=$PWD
23 test -d "$name" && return 24 test -d "$name" && return
24 printf "Creating testrepo %s\n" $name 25 printf "Creating testrepo %s\n" "$name"
25 mkdir -p "$name" 26 mkdir -p "$name"
26 cd "$name" 27 cd "$name"
27 git init 28 git init
@@ -40,7 +41,7 @@ mkrepo() {
40 git commit -m "add a+b" 41 git commit -m "add a+b"
41 git branch "1+2" 42 git branch "1+2"
42 fi 43 fi
43 cd $dir 44 cd "$dir"
44} 45}
45 46
46setup_repos() 47setup_repos()
diff --git a/tests/t0108-patch.sh b/tests/t0108-patch.sh
index e608104..6ee70b3 100755
--- a/tests/t0108-patch.sh
+++ b/tests/t0108-patch.sh
@@ -25,7 +25,7 @@ run_test 'find `cgit` signature' '
25' 25'
26 26
27run_test 'find initial commit' ' 27run_test 'find initial commit' '
28 root=$(git --git-dir=$PWD/trash/repos/foo/.git rev-list HEAD | tail -1) 28 root=$(git --git-dir="$PWD/trash/repos/foo/.git" rev-list HEAD | tail -1)
29' 29'
30 30
31run_test 'generate patch for initial commit' ' 31run_test 'generate patch for initial commit' '
diff --git a/ui-diff.c b/ui-diff.c
index 868ceec..c6bad63 100644
--- a/ui-diff.c
+++ b/ui-diff.c
@@ -97,10 +97,12 @@ static void print_fileinfo(struct fileinfo *info)
97 htmlf("</td><td class='%s'>", class); 97 htmlf("</td><td class='%s'>", class);
98 cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, ctx.qry.sha1, 98 cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, ctx.qry.sha1,
99 ctx.qry.sha2, info->new_path, 0); 99 ctx.qry.sha2, info->new_path, 0);
100 if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED) 100 if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED) {
101 htmlf(" (%s from %s)", 101 htmlf(" (%s from ",
102 info->status == DIFF_STATUS_COPIED ? "copied" : "renamed", 102 info->status == DIFF_STATUS_COPIED ? "copied" : "renamed");
103 info->old_path); 103 html_txt(info->old_path);
104 html(")");
105 }
104 html("</td><td class='right'>"); 106 html("</td><td class='right'>");
105 if (info->binary) { 107 if (info->binary) {
106 htmlf("bin</td><td class='graph'>%ld -> %ld bytes", 108 htmlf("bin</td><td class='graph'>%ld -> %ld bytes",
@@ -339,9 +341,7 @@ void cgit_print_diff_ctrls()
339 html("<td class='label'>mode:</td>"); 341 html("<td class='label'>mode:</td>");
340 html("<td class='ctrl'>"); 342 html("<td class='ctrl'>");
341 html("<select name='ss' onchange='this.form.submit();'>"); 343 html("<select name='ss' onchange='this.form.submit();'>");
342 curr = ctx.qry.ssdiff; 344 curr = ctx.qry.has_ssdiff ? ctx.qry.ssdiff : ctx.cfg.ssdiff;
343 if (!curr && ctx.cfg.ssdiff)
344 curr = 1;
345 html_intoption(0, "unified", curr); 345 html_intoption(0, "unified", curr);
346 html_intoption(1, "ssdiff", curr); 346 html_intoption(1, "ssdiff", curr);
347 html("</select></td></tr>"); 347 html("</select></td></tr>");
@@ -393,8 +393,7 @@ void cgit_print_diff(const char *new_rev, const char *old_rev,
393 } 393 }
394 } 394 }
395 395
396 if ((ctx.qry.ssdiff && !ctx.cfg.ssdiff) || (!ctx.qry.ssdiff && ctx.cfg.ssdiff)) 396 use_ssdiff = ctx.qry.has_ssdiff ? ctx.qry.ssdiff : ctx.cfg.ssdiff;
397 use_ssdiff = 1;
398 397
399 if (show_ctrls) 398 if (show_ctrls)
400 cgit_print_diff_ctrls(); 399 cgit_print_diff_ctrls();
diff --git a/ui-log.c b/ui-log.c
index 4a295bd..6b12ca2 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -76,6 +76,8 @@ void show_commit_decorations(struct commit *commit)
76 cgit_tag_link(buf, NULL, "tag-deco", ctx.qry.head, buf); 76 cgit_tag_link(buf, NULL, "tag-deco", ctx.qry.head, buf);
77 } 77 }
78 else if (!prefixcmp(deco->name, "refs/remotes/")) { 78 else if (!prefixcmp(deco->name, "refs/remotes/")) {
79 if (!ctx.repo->enable_remote_branches)
80 goto next;
79 strncpy(buf, deco->name + 13, sizeof(buf) - 1); 81 strncpy(buf, deco->name + 13, sizeof(buf) - 1);
80 cgit_log_link(buf, NULL, "remote-deco", NULL, 82 cgit_log_link(buf, NULL, "remote-deco", NULL,
81 sha1_to_hex(commit->object.sha1), 83 sha1_to_hex(commit->object.sha1),
@@ -88,6 +90,7 @@ void show_commit_decorations(struct commit *commit)
88 sha1_to_hex(commit->object.sha1), 90 sha1_to_hex(commit->object.sha1),
89 ctx.qry.vpath, 0); 91 ctx.qry.vpath, 0);
90 } 92 }
93next:
91 deco = deco->next; 94 deco = deco->next;
92 } 95 }
93} 96}
diff --git a/ui-plain.c b/ui-plain.c
index 7fecc32..85877d7 100644
--- a/ui-plain.c
+++ b/ui-plain.c
@@ -147,11 +147,14 @@ static void print_dir_entry(const unsigned char *sha1, const char *base,
147 char *fullpath; 147 char *fullpath;
148 148
149 fullpath = buildpath(base, baselen, path); 149 fullpath = buildpath(base, baselen, path);
150 if (!S_ISDIR(mode)) 150 if (!S_ISDIR(mode) && !S_ISGITLINK(mode))
151 fullpath[strlen(fullpath) - 1] = 0; 151 fullpath[strlen(fullpath) - 1] = 0;
152 html(" <li>"); 152 html(" <li>");
153 cgit_plain_link(path, NULL, NULL, ctx.qry.head, ctx.qry.sha1, 153 if (S_ISGITLINK(mode)) {
154 fullpath); 154 cgit_submodule_link(NULL, fullpath, sha1_to_hex(sha1));
155 } else
156 cgit_plain_link(path, NULL, NULL, ctx.qry.head, ctx.qry.sha1,
157 fullpath);
155 html("</li>\n"); 158 html("</li>\n");
156 match = 2; 159 match = 2;
157} 160}
diff --git a/ui-repolist.c b/ui-repolist.c
index 25c36ce..d946f32 100644
--- a/ui-repolist.c
+++ b/ui-repolist.c
@@ -45,7 +45,8 @@ static int get_repo_modtime(const struct cgit_repo *repo, time_t *mtime)
45 return 1; 45 return 1;
46 } 46 }
47 47
48 path = fmt("%s/refs/heads/%s", repo->path, repo->defbranch); 48 path = fmt("%s/refs/heads/%s", repo->path, repo->defbranch ?
49 repo->defbranch : "master");
49 if (stat(path, &s) == 0) { 50 if (stat(path, &s) == 0) {
50 *mtime = s.st_mtime; 51 *mtime = s.st_mtime;
51 r->mtime = *mtime; 52 r->mtime = *mtime;
@@ -118,13 +119,13 @@ void print_header(int columns)
118} 119}
119 120
120 121
121void print_pager(int items, int pagelen, char *search) 122void print_pager(int items, int pagelen, char *search, char *sort)
122{ 123{
123 int i; 124 int i;
124 html("<div class='pager'>"); 125 html("<div class='pager'>");
125 for(i = 0; i * pagelen < items; i++) 126 for(i = 0; i * pagelen < items; i++)
126 cgit_index_link(fmt("[%d]", i+1), fmt("Page %d", i+1), NULL, 127 cgit_index_link(fmt("[%d]", i+1), fmt("Page %d", i+1), NULL,
127 search, i * pagelen); 128 search, sort, i * pagelen);
128 html("</div>"); 129 html("</div>");
129} 130}
130 131
@@ -291,7 +292,7 @@ void cgit_print_repolist()
291 if (!hits) 292 if (!hits)
292 cgit_print_error("No repositories found"); 293 cgit_print_error("No repositories found");
293 else if (hits > ctx.cfg.max_repo_count) 294 else if (hits > ctx.cfg.max_repo_count)
294 print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search); 295 print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search, ctx.qry.sort);
295 cgit_print_docend(); 296 cgit_print_docend();
296} 297}
297 298
diff --git a/ui-shared.c b/ui-shared.c
index 5aa9119..43166af 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -133,7 +133,7 @@ char *cgit_currurl()
133 return fmt("%s/", ctx.cfg.virtual_root); 133 return fmt("%s/", ctx.cfg.virtual_root);
134} 134}
135 135
136static void site_url(const char *page, const char *search, int ofs) 136static void site_url(const char *page, const char *search, const char *sort, int ofs)
137{ 137{
138 char *delim = "?"; 138 char *delim = "?";
139 139
@@ -154,6 +154,12 @@ static void site_url(const char *page, const char *search, int ofs)
154 html_attr(search); 154 html_attr(search);
155 delim = "&"; 155 delim = "&";
156 } 156 }
157 if (sort) {
158 html(delim);
159 html("s=");
160 html_attr(sort);
161 delim = "&";
162 }
157 if (ofs) { 163 if (ofs) {
158 html(delim); 164 html(delim);
159 htmlf("ofs=%d", ofs); 165 htmlf("ofs=%d", ofs);
@@ -161,7 +167,7 @@ static void site_url(const char *page, const char *search, int ofs)
161} 167}
162 168
163static void site_link(const char *page, const char *name, const char *title, 169static void site_link(const char *page, const char *name, const char *title,
164 const char *class, const char *search, int ofs) 170 const char *class, const char *search, const char *sort, int ofs)
165{ 171{
166 html("<a"); 172 html("<a");
167 if (title) { 173 if (title) {
@@ -175,16 +181,16 @@ static void site_link(const char *page, const char *name, const char *title,
175 html("'"); 181 html("'");
176 } 182 }
177 html(" href='"); 183 html(" href='");
178 site_url(page, search, ofs); 184 site_url(page, search, sort, ofs);
179 html("'>"); 185 html("'>");
180 html_txt(name); 186 html_txt(name);
181 html("</a>"); 187 html("</a>");
182} 188}
183 189
184void cgit_index_link(const char *name, const char *title, const char *class, 190void cgit_index_link(const char *name, const char *title, const char *class,
185 const char *pattern, int ofs) 191 const char *pattern, const char *sort, int ofs)
186{ 192{
187 site_link(NULL, name, title, class, pattern, ofs); 193 site_link(NULL, name, title, class, pattern, sort, ofs);
188} 194}
189 195
190static char *repolink(const char *title, const char *class, const char *page, 196static char *repolink(const char *title, const char *class, const char *page,
@@ -288,7 +294,7 @@ void cgit_log_link(const char *name, const char *title, const char *class,
288 char *delim; 294 char *delim;
289 295
290 delim = repolink(title, class, "log", head, path); 296 delim = repolink(title, class, "log", head, path);
291 if (rev && strcmp(rev, ctx.qry.head)) { 297 if (rev && ctx.qry.head && strcmp(rev, ctx.qry.head)) {
292 html(delim); 298 html(delim);
293 html("id="); 299 html("id=");
294 html_url_arg(rev); 300 html_url_arg(rev);
@@ -332,7 +338,7 @@ void cgit_commit_link(char *name, const char *title, const char *class,
332 char *delim; 338 char *delim;
333 339
334 delim = repolink(title, class, "commit", head, path); 340 delim = repolink(title, class, "commit", head, path);
335 if (rev && strcmp(rev, ctx.qry.head)) { 341 if (rev && ctx.qry.head && strcmp(rev, ctx.qry.head)) {
336 html(delim); 342 html(delim);
337 html("id="); 343 html("id=");
338 html_url_arg(rev); 344 html_url_arg(rev);
@@ -428,7 +434,7 @@ void cgit_self_link(char *name, const char *title, const char *class,
428 struct cgit_context *ctx) 434 struct cgit_context *ctx)
429{ 435{
430 if (!strcmp(ctx->qry.page, "repolist")) 436 if (!strcmp(ctx->qry.page, "repolist"))
431 return cgit_index_link(name, title, class, ctx->qry.search, 437 return cgit_index_link(name, title, class, ctx->qry.search, ctx->qry.sort,
432 ctx->qry.ofs); 438 ctx->qry.ofs);
433 else if (!strcmp(ctx->qry.page, "summary")) 439 else if (!strcmp(ctx->qry.page, "summary"))
434 return cgit_summary_link(name, title, class, ctx->qry.head); 440 return cgit_summary_link(name, title, class, ctx->qry.head);
@@ -503,6 +509,62 @@ void cgit_object_link(struct object *obj)
503 reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL); 509 reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL);
504} 510}
505 511
512struct string_list_item *lookup_path(struct string_list *list,
513 const char *path)
514{
515 struct string_list_item *item;
516
517 while (path && path[0]) {
518 if ((item = string_list_lookup(list, path)))
519 return item;
520 if (!(path = strchr(path, '/')))
521 break;
522 path++;
523 }
524 return NULL;
525}
526
527void cgit_submodule_link(const char *class, char *path, const char *rev)
528{
529 struct string_list *list;
530 struct string_list_item *item;
531 char tail, *dir;
532 size_t len;
533
534 tail = 0;
535 list = &ctx.repo->submodules;
536 item = lookup_path(list, path);
537 if (!item) {
538 len = strlen(path);
539 tail = path[len - 1];
540 if (tail == '/') {
541 path[len - 1] = 0;
542 item = lookup_path(list, path);
543 }
544 }
545 html("<a ");
546 if (class)
547 htmlf("class='%s' ", class);
548 html("href='");
549 if (item) {
550 html_attr(fmt(item->util, rev));
551 } else if (ctx.repo->module_link) {
552 dir = strrchr(path, '/');
553 if (dir)
554 dir++;
555 else
556 dir = path;
557 html_attr(fmt(ctx.repo->module_link, dir, rev));
558 } else {
559 html("#");
560 }
561 html("'>");
562 html_txt(path);
563 html("</a>");
564 if (item && tail)
565 path[len - 1] = tail;
566}
567
506void cgit_print_date(time_t secs, const char *format, int local_time) 568void cgit_print_date(time_t secs, const char *format, int local_time)
507{ 569{
508 char buf[64]; 570 char buf[64];
@@ -613,7 +675,7 @@ void cgit_print_docstart(struct cgit_context *ctx)
613 html_attr(ctx->cfg.favicon); 675 html_attr(ctx->cfg.favicon);
614 html("'/>\n"); 676 html("'/>\n");
615 } 677 }
616 if (host && ctx->repo) { 678 if (host && ctx->repo && ctx->qry.head) {
617 html("<link rel='alternate' title='Atom feed' href='"); 679 html("<link rel='alternate' title='Atom feed' href='");
618 html(cgit_httpscheme()); 680 html(cgit_httpscheme());
619 html_attr(cgit_hosturl()); 681 html_attr(cgit_hosturl());
@@ -782,7 +844,7 @@ static void print_header(struct cgit_context *ctx)
782 844
783 html("<td class='main'>"); 845 html("<td class='main'>");
784 if (ctx->repo) { 846 if (ctx->repo) {
785 cgit_index_link("index", NULL, NULL, NULL, 0); 847 cgit_index_link("index", NULL, NULL, NULL, NULL, 0);
786 html(" : "); 848 html(" : ");
787 cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL); 849 cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL);
788 html("</td><td class='form'>"); 850 html("</td><td class='form'>");
@@ -858,10 +920,10 @@ void cgit_print_pageheader(struct cgit_context *ctx)
858 html("<input type='submit' value='search'/>\n"); 920 html("<input type='submit' value='search'/>\n");
859 html("</form>\n"); 921 html("</form>\n");
860 } else { 922 } else {
861 site_link(NULL, "index", NULL, hc(ctx, "repolist"), NULL, 0); 923 site_link(NULL, "index", NULL, hc(ctx, "repolist"), NULL, NULL, 0);
862 if (ctx->cfg.root_readme) 924 if (ctx->cfg.root_readme)
863 site_link("about", "about", NULL, hc(ctx, "about"), 925 site_link("about", "about", NULL, hc(ctx, "about"),
864 NULL, 0); 926 NULL, NULL, 0);
865 html("</td><td class='form'>"); 927 html("</td><td class='form'>");
866 html("<form method='get' action='"); 928 html("<form method='get' action='");
867 html_attr(cgit_rooturl()); 929 html_attr(cgit_rooturl());
diff --git a/ui-shared.h b/ui-shared.h
index 3cc1258..87a7dac 100644
--- a/ui-shared.h
+++ b/ui-shared.h
@@ -11,7 +11,7 @@ extern char *cgit_pageurl(const char *reponame, const char *pagename,
11 const char *query); 11 const char *query);
12 12
13extern void cgit_index_link(const char *name, const char *title, 13extern void cgit_index_link(const char *name, const char *title,
14 const char *class, const char *pattern, int ofs); 14 const char *class, const char *pattern, const char *sort, int ofs);
15extern void cgit_summary_link(const char *name, const char *title, 15extern void cgit_summary_link(const char *name, const char *title,
16 const char *class, const char *head); 16 const char *class, const char *head);
17extern void cgit_tag_link(const char *name, const char *title, 17extern void cgit_tag_link(const char *name, const char *title,
@@ -51,6 +51,9 @@ extern void cgit_self_link(char *name, const char *title,
51 const char *class, struct cgit_context *ctx); 51 const char *class, struct cgit_context *ctx);
52extern void cgit_object_link(struct object *obj); 52extern void cgit_object_link(struct object *obj);
53 53
54extern void cgit_submodule_link(const char *class, char *path,
55 const char *rev);
56
54extern void cgit_print_error(const char *msg); 57extern void cgit_print_error(const char *msg);
55extern void cgit_print_date(time_t secs, const char *format, int local_time); 58extern void cgit_print_date(time_t secs, const char *format, int local_time);
56extern void cgit_print_age(time_t t, time_t max_relative, const char *format); 59extern void cgit_print_age(time_t t, time_t max_relative, const char *format);
diff --git a/ui-ssdiff.c b/ui-ssdiff.c
index 2481585..0cff4b8 100644
--- a/ui-ssdiff.c
+++ b/ui-ssdiff.c
@@ -2,10 +2,12 @@
2#include "html.h" 2#include "html.h"
3#include "ui-shared.h" 3#include "ui-shared.h"
4#include "ui-diff.h" 4#include "ui-diff.h"
5#include "ui-ssdiff.h"
5 6
6extern int use_ssdiff; 7extern int use_ssdiff;
7 8
8static int current_old_line, current_new_line; 9static int current_old_line, current_new_line;
10static int **L = NULL;
9 11
10struct deferred_lines { 12struct deferred_lines {
11 int line_no; 13 int line_no;
@@ -16,16 +18,40 @@ struct deferred_lines {
16static struct deferred_lines *deferred_old, *deferred_old_last; 18static struct deferred_lines *deferred_old, *deferred_old_last;
17static struct deferred_lines *deferred_new, *deferred_new_last; 19static struct deferred_lines *deferred_new, *deferred_new_last;
18 20
21static void create_or_reset_lcs_table()
22{
23 int i;
24
25 if (L != NULL) {
26 memset(*L, 0, sizeof(int) * MAX_SSDIFF_SIZE);
27 return;
28 }
29
30 // xcalloc will die if we ran out of memory;
31 // not very helpful for debugging
32 L = (int**)xcalloc(MAX_SSDIFF_M, sizeof(int *));
33 *L = (int*)xcalloc(MAX_SSDIFF_SIZE, sizeof(int));
34
35 for (i = 1; i < MAX_SSDIFF_M; i++) {
36 L[i] = *L + i * MAX_SSDIFF_N;
37 }
38}
39
19static char *longest_common_subsequence(char *A, char *B) 40static char *longest_common_subsequence(char *A, char *B)
20{ 41{
21 int i, j, ri; 42 int i, j, ri;
22 int m = strlen(A); 43 int m = strlen(A);
23 int n = strlen(B); 44 int n = strlen(B);
24 int L[m + 1][n + 1];
25 int tmp1, tmp2; 45 int tmp1, tmp2;
26 int lcs_length; 46 int lcs_length;
27 char *result; 47 char *result;
28 48
49 // We bail if the lines are too long
50 if (m >= MAX_SSDIFF_M || n >= MAX_SSDIFF_N)
51 return NULL;
52
53 create_or_reset_lcs_table();
54
29 for (i = m; i >= 0; i--) { 55 for (i = m; i >= 0; i--) {
30 for (j = n; j >= 0; j--) { 56 for (j = n; j >= 0; j--) {
31 if (A[i] == '\0' || B[j] == '\0') { 57 if (A[i] == '\0' || B[j] == '\0') {
@@ -59,6 +85,7 @@ static char *longest_common_subsequence(char *A, char *B)
59 j += 1; 85 j += 1;
60 } 86 }
61 } 87 }
88
62 return result; 89 return result;
63} 90}
64 91
diff --git a/ui-ssdiff.h b/ui-ssdiff.h
index 64b4b12..88627e2 100644
--- a/ui-ssdiff.h
+++ b/ui-ssdiff.h
@@ -1,6 +1,18 @@
1#ifndef UI_SSDIFF_H 1#ifndef UI_SSDIFF_H
2#define UI_SSDIFF_H 2#define UI_SSDIFF_H
3 3
4/*
5 * ssdiff line limits
6 */
7#ifndef MAX_SSDIFF_M
8#define MAX_SSDIFF_M 128
9#endif
10
11#ifndef MAX_SSDIFF_N
12#define MAX_SSDIFF_N 128
13#endif
14#define MAX_SSDIFF_SIZE ((MAX_SSDIFF_M) * (MAX_SSDIFF_N))
15
4extern void cgit_ssdiff_print_deferred_lines(); 16extern void cgit_ssdiff_print_deferred_lines();
5 17
6extern void cgit_ssdiff_line_cb(char *line, int len); 18extern void cgit_ssdiff_line_cb(char *line, int len);
diff --git a/ui-tree.c b/ui-tree.c
index 442b6be..b1adcc7 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -150,13 +150,7 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen,
150 cgit_print_filemode(mode); 150 cgit_print_filemode(mode);
151 html("</td><td>"); 151 html("</td><td>");
152 if (S_ISGITLINK(mode)) { 152 if (S_ISGITLINK(mode)) {
153 htmlf("<a class='ls-mod' href='"); 153 cgit_submodule_link("ls-mod", fullpath, sha1_to_hex(sha1));
154 html_attr(fmt(ctx.repo->module_link,
155 name,
156 sha1_to_hex(sha1)));
157 html("'>");
158 html_txt(name);
159 html("</a>");
160 } else if (S_ISDIR(mode)) { 154 } else if (S_ISDIR(mode)) {
161 cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, 155 cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head,
162 curr_rev, fullpath); 156 curr_rev, fullpath);
@@ -177,8 +171,9 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen,
177 if (ctx.repo->max_stats) 171 if (ctx.repo->max_stats)
178 cgit_stats_link("stats", NULL, "button", ctx.qry.head, 172 cgit_stats_link("stats", NULL, "button", ctx.qry.head,
179 fullpath); 173 fullpath);
180 cgit_plain_link("plain", NULL, "button", ctx.qry.head, curr_rev, 174 if (!S_ISGITLINK(mode))
181 fullpath); 175 cgit_plain_link("plain", NULL, "button", ctx.qry.head, curr_rev,
176 fullpath);
182 html("</td></tr>\n"); 177 html("</td></tr>\n");
183 free(name); 178 free(name);
184 return 0; 179 return 0;