summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2011-02-19 13:51:00 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2011-02-19 13:51:00 (UTC)
commit979c460e7f71d153ae79da67b8b21c3412f0fe02 (patch) (unidiff)
tree6da9ffb66ed0a68205e6644cb7e2b4652d6684be
parentfb9e6d1594a24fe4e551fd57a9c91fd18b14806e (diff)
parent0141b9f889bbaa1fe474f9a98dd377138ac73054 (diff)
downloadcgit-979c460e7f71d153ae79da67b8b21c3412f0fe02.zip
cgit-979c460e7f71d153ae79da67b8b21c3412f0fe02.tar.gz
cgit-979c460e7f71d153ae79da67b8b21c3412f0fe02.tar.bz2
Merge branch 'br/misc'
* br/misc: Use transparent background for the cgit logo ssdiff: anchors for ssdiff implement repo.logo and repo.logo-link
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c8
-rw-r--r--cgit.css2
-rw-r--r--cgit.h2
-rw-r--r--cgit.pngbin1840 -> 1488 bytes
-rw-r--r--cgitrc.5.txt9
-rw-r--r--ui-diff.c12
-rw-r--r--ui-diff.h6
-rw-r--r--ui-shared.c18
-rw-r--r--ui-ssdiff.c34
9 files changed, 74 insertions, 17 deletions
diff --git a/cgit.c b/cgit.c
index 71f3fc8..916feb4 100644
--- a/cgit.c
+++ b/cgit.c
@@ -52,51 +52,55 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value)
52 else if (!strcmp(name, "desc")) 52 else if (!strcmp(name, "desc"))
53 repo->desc = xstrdup(value); 53 repo->desc = xstrdup(value);
54 else if (!strcmp(name, "owner")) 54 else if (!strcmp(name, "owner"))
55 repo->owner = xstrdup(value); 55 repo->owner = xstrdup(value);
56 else if (!strcmp(name, "defbranch")) 56 else if (!strcmp(name, "defbranch"))
57 repo->defbranch = xstrdup(value); 57 repo->defbranch = xstrdup(value);
58 else if (!strcmp(name, "snapshots")) 58 else if (!strcmp(name, "snapshots"))
59 repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); 59 repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value);
60 else if (!strcmp(name, "enable-commit-graph")) 60 else if (!strcmp(name, "enable-commit-graph"))
61 repo->enable_commit_graph = ctx.cfg.enable_commit_graph * atoi(value); 61 repo->enable_commit_graph = ctx.cfg.enable_commit_graph * atoi(value);
62 else if (!strcmp(name, "enable-log-filecount")) 62 else if (!strcmp(name, "enable-log-filecount"))
63 repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); 63 repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
64 else if (!strcmp(name, "enable-log-linecount")) 64 else if (!strcmp(name, "enable-log-linecount"))
65 repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); 65 repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
66 else if (!strcmp(name, "enable-remote-branches")) 66 else if (!strcmp(name, "enable-remote-branches"))
67 repo->enable_remote_branches = atoi(value); 67 repo->enable_remote_branches = atoi(value);
68 else if (!strcmp(name, "enable-subject-links")) 68 else if (!strcmp(name, "enable-subject-links"))
69 repo->enable_subject_links = atoi(value); 69 repo->enable_subject_links = atoi(value);
70 else if (!strcmp(name, "max-stats")) 70 else if (!strcmp(name, "max-stats"))
71 repo->max_stats = cgit_find_stats_period(value, NULL); 71 repo->max_stats = cgit_find_stats_period(value, NULL);
72 else if (!strcmp(name, "module-link")) 72 else if (!strcmp(name, "module-link"))
73 repo->module_link= xstrdup(value); 73 repo->module_link= xstrdup(value);
74 else if (!strcmp(name, "section")) 74 else if (!strcmp(name, "section"))
75 repo->section = xstrdup(value); 75 repo->section = xstrdup(value);
76 else if (!strcmp(name, "readme") && value != NULL) { 76 else if (!strcmp(name, "readme") && value != NULL)
77 repo->readme = xstrdup(value); 77 repo->readme = xstrdup(value);
78 } else if (ctx.cfg.enable_filter_overrides) { 78 else if (!strcmp(name, "logo") && value != NULL)
79 repo->logo = xstrdup(value);
80 else if (!strcmp(name, "logo-link") && value != NULL)
81 repo->logo_link = xstrdup(value);
82 else if (ctx.cfg.enable_filter_overrides) {
79 if (!strcmp(name, "about-filter")) 83 if (!strcmp(name, "about-filter"))
80 repo->about_filter = new_filter(value, 0); 84 repo->about_filter = new_filter(value, 0);
81 else if (!strcmp(name, "commit-filter")) 85 else if (!strcmp(name, "commit-filter"))
82 repo->commit_filter = new_filter(value, 0); 86 repo->commit_filter = new_filter(value, 0);
83 else if (!strcmp(name, "source-filter")) 87 else if (!strcmp(name, "source-filter"))
84 repo->source_filter = new_filter(value, 1); 88 repo->source_filter = new_filter(value, 1);
85 } 89 }
86} 90}
87 91
88void config_cb(const char *name, const char *value) 92void config_cb(const char *name, const char *value)
89{ 93{
90 if (!strcmp(name, "section") || !strcmp(name, "repo.group")) 94 if (!strcmp(name, "section") || !strcmp(name, "repo.group"))
91 ctx.cfg.section = xstrdup(value); 95 ctx.cfg.section = xstrdup(value);
92 else if (!strcmp(name, "repo.url")) 96 else if (!strcmp(name, "repo.url"))
93 ctx.repo = cgit_add_repo(value); 97 ctx.repo = cgit_add_repo(value);
94 else if (ctx.repo && !strcmp(name, "repo.path")) 98 else if (ctx.repo && !strcmp(name, "repo.path"))
95 ctx.repo->path = trim_end(value, '/'); 99 ctx.repo->path = trim_end(value, '/');
96 else if (ctx.repo && !prefixcmp(name, "repo.")) 100 else if (ctx.repo && !prefixcmp(name, "repo."))
97 repo_config(ctx.repo, name + 5, value); 101 repo_config(ctx.repo, name + 5, value);
98 else if (!strcmp(name, "readme")) 102 else if (!strcmp(name, "readme"))
99 ctx.cfg.readme = xstrdup(value); 103 ctx.cfg.readme = xstrdup(value);
100 else if (!strcmp(name, "root-title")) 104 else if (!strcmp(name, "root-title"))
101 ctx.cfg.root_title = xstrdup(value); 105 ctx.cfg.root_title = xstrdup(value);
102 else if (!strcmp(name, "root-desc")) 106 else if (!strcmp(name, "root-desc"))
diff --git a/cgit.css b/cgit.css
index 008cff8..1d90057 100644
--- a/cgit.css
+++ b/cgit.css
@@ -272,49 +272,49 @@ td.ls-mode {
272} 272}
273 273
274table.blob { 274table.blob {
275 margin-top: 0.5em; 275 margin-top: 0.5em;
276 border-top: solid 1px black; 276 border-top: solid 1px black;
277} 277}
278 278
279table.blob td.lines { 279table.blob td.lines {
280 margin: 0; padding: 0 0 0 0.5em; 280 margin: 0; padding: 0 0 0 0.5em;
281 vertical-align: top; 281 vertical-align: top;
282 color: black; 282 color: black;
283} 283}
284 284
285table.blob td.linenumbers { 285table.blob td.linenumbers {
286 margin: 0; padding: 0 0.5em 0 0.5em; 286 margin: 0; padding: 0 0.5em 0 0.5em;
287 vertical-align: top; 287 vertical-align: top;
288 text-align: right; 288 text-align: right;
289 border-right: 1px solid gray; 289 border-right: 1px solid gray;
290} 290}
291 291
292table.blob pre { 292table.blob pre {
293 padding: 0; margin: 0; 293 padding: 0; margin: 0;
294} 294}
295 295
296table.blob a.no { 296table.blob a.no, table.ssdiff a.no {
297 color: gray; 297 color: gray;
298 text-align: right; 298 text-align: right;
299 text-decoration: none; 299 text-decoration: none;
300} 300}
301 301
302table.blob a.no a:hover { 302table.blob a.no a:hover {
303 color: black; 303 color: black;
304} 304}
305 305
306table.bin-blob { 306table.bin-blob {
307 margin-top: 0.5em; 307 margin-top: 0.5em;
308 border: solid 1px black; 308 border: solid 1px black;
309} 309}
310 310
311table.bin-blob th { 311table.bin-blob th {
312 font-family: monospace; 312 font-family: monospace;
313 white-space: pre; 313 white-space: pre;
314 border: solid 1px #777; 314 border: solid 1px #777;
315 padding: 0.5em 1em; 315 padding: 0.5em 1em;
316} 316}
317 317
318table.bin-blob td { 318table.bin-blob td {
319 font-family: monospace; 319 font-family: monospace;
320 white-space: pre; 320 white-space: pre;
diff --git a/cgit.h b/cgit.h
index 74aa340..b5f00fc 100644
--- a/cgit.h
+++ b/cgit.h
@@ -50,48 +50,50 @@
50typedef void (*configfn)(const char *name, const char *value); 50typedef void (*configfn)(const char *name, const char *value);
51typedef void (*filepair_fn)(struct diff_filepair *pair); 51typedef void (*filepair_fn)(struct diff_filepair *pair);
52typedef void (*linediff_fn)(char *line, int len); 52typedef void (*linediff_fn)(char *line, int len);
53 53
54struct cgit_filter { 54struct cgit_filter {
55 char *cmd; 55 char *cmd;
56 char **argv; 56 char **argv;
57 int old_stdout; 57 int old_stdout;
58 int pipe_fh[2]; 58 int pipe_fh[2];
59 int pid; 59 int pid;
60 int exitstatus; 60 int exitstatus;
61}; 61};
62 62
63struct cgit_repo { 63struct cgit_repo {
64 char *url; 64 char *url;
65 char *name; 65 char *name;
66 char *path; 66 char *path;
67 char *desc; 67 char *desc;
68 char *owner; 68 char *owner;
69 char *defbranch; 69 char *defbranch;
70 char *module_link; 70 char *module_link;
71 char *readme; 71 char *readme;
72 char *section; 72 char *section;
73 char *clone_url; 73 char *clone_url;
74 char *logo;
75 char *logo_link;
74 int snapshots; 76 int snapshots;
75 int enable_commit_graph; 77 int enable_commit_graph;
76 int enable_log_filecount; 78 int enable_log_filecount;
77 int enable_log_linecount; 79 int enable_log_linecount;
78 int enable_remote_branches; 80 int enable_remote_branches;
79 int enable_subject_links; 81 int enable_subject_links;
80 int max_stats; 82 int max_stats;
81 time_t mtime; 83 time_t mtime;
82 struct cgit_filter *about_filter; 84 struct cgit_filter *about_filter;
83 struct cgit_filter *commit_filter; 85 struct cgit_filter *commit_filter;
84 struct cgit_filter *source_filter; 86 struct cgit_filter *source_filter;
85}; 87};
86 88
87typedef void (*repo_config_fn)(struct cgit_repo *repo, const char *name, 89typedef void (*repo_config_fn)(struct cgit_repo *repo, const char *name,
88 const char *value); 90 const char *value);
89 91
90struct cgit_repolist { 92struct cgit_repolist {
91 int length; 93 int length;
92 int count; 94 int count;
93 struct cgit_repo *repos; 95 struct cgit_repo *repos;
94}; 96};
95 97
96struct commitinfo { 98struct commitinfo {
97 struct commit *commit; 99 struct commit *commit;
diff --git a/cgit.png b/cgit.png
index d7f70bc..0bdf5a7 100644
--- a/cgit.png
+++ b/cgit.png
Binary files differ
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index a832830..c3698a6 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -366,48 +366,57 @@ repo.defbranch::
366 366
367repo.desc:: 367repo.desc::
368 The value to show as repository description. Default value: none. 368 The value to show as repository description. Default value: none.
369 369
370repo.enable-commit-graph:: 370repo.enable-commit-graph::
371 A flag which can be used to disable the global setting 371 A flag which can be used to disable the global setting
372 `enable-commit-graph'. Default value: none. 372 `enable-commit-graph'. Default value: none.
373 373
374repo.enable-log-filecount:: 374repo.enable-log-filecount::
375 A flag which can be used to disable the global setting 375 A flag which can be used to disable the global setting
376 `enable-log-filecount'. Default value: none. 376 `enable-log-filecount'. Default value: none.
377 377
378repo.enable-log-linecount:: 378repo.enable-log-linecount::
379 A flag which can be used to disable the global setting 379 A flag which can be used to disable the global setting
380 `enable-log-linecount'. Default value: none. 380 `enable-log-linecount'. Default value: none.
381 381
382repo.enable-remote-branches:: 382repo.enable-remote-branches::
383 Flag which, when set to "1", will make cgit display remote branches 383 Flag which, when set to "1", will make cgit display remote branches
384 in the summary and refs views. Default value: <enable-remote-branches>. 384 in the summary and refs views. Default value: <enable-remote-branches>.
385 385
386repo.enable-subject-links:: 386repo.enable-subject-links::
387 A flag which can be used to override the global setting 387 A flag which can be used to override the global setting
388 `enable-subject-links'. Default value: none. 388 `enable-subject-links'. Default value: none.
389 389
390repo.logo::
391 Url which specifies the source of an image which will be used as a logo
392 on this repo's pages. Default value: global logo.
393
394repo.logo-link::
395 Url loaded when clicking on the cgit logo image. If unspecified the
396 calculated url of the repository index page will be used. Default
397 value: global logo-link.
398
390repo.max-stats:: 399repo.max-stats::
391 Override the default maximum statistics period. Valid values are equal 400 Override the default maximum statistics period. Valid values are equal
392 to the values specified for the global "max-stats" setting. Default 401 to the values specified for the global "max-stats" setting. Default
393 value: none. 402 value: none.
394 403
395repo.name:: 404repo.name::
396 The value to show as repository name. Default value: <repo.url>. 405 The value to show as repository name. Default value: <repo.url>.
397 406
398repo.owner:: 407repo.owner::
399 A value used to identify the owner of the repository. Default value: 408 A value used to identify the owner of the repository. Default value:
400 none. 409 none.
401 410
402repo.path:: 411repo.path::
403 An absolute path to the repository directory. For non-bare repositories 412 An absolute path to the repository directory. For non-bare repositories
404 this is the .git-directory. Default value: none. 413 this is the .git-directory. Default value: none.
405 414
406repo.readme:: 415repo.readme::
407 A path (relative to <repo.path>) which specifies a file to include 416 A path (relative to <repo.path>) which specifies a file to include
408 verbatim as the "About" page for this repo. You may also specify a 417 verbatim as the "About" page for this repo. You may also specify a
409 git refspec by head or by hash by prepending the refspec followed by 418 git refspec by head or by hash by prepending the refspec followed by
410 a colon. For example, "master:docs/readme.mkd" Default value: <readme>. 419 a colon. For example, "master:docs/readme.mkd" Default value: <readme>.
411 420
412repo.snapshots:: 421repo.snapshots::
413 A mask of allowed snapshot-formats for this repo, restricted by the 422 A mask of allowed snapshot-formats for this repo, restricted by the
diff --git a/ui-diff.c b/ui-diff.c
index 7ff7e46..a53425d 100644
--- a/ui-diff.c
+++ b/ui-diff.c
@@ -13,48 +13,59 @@
13 13
14unsigned char old_rev_sha1[20]; 14unsigned char old_rev_sha1[20];
15unsigned char new_rev_sha1[20]; 15unsigned char new_rev_sha1[20];
16 16
17static int files, slots; 17static int files, slots;
18static int total_adds, total_rems, max_changes; 18static int total_adds, total_rems, max_changes;
19static int lines_added, lines_removed; 19static int lines_added, lines_removed;
20 20
21static struct fileinfo { 21static struct fileinfo {
22 char status; 22 char status;
23 unsigned char old_sha1[20]; 23 unsigned char old_sha1[20];
24 unsigned char new_sha1[20]; 24 unsigned char new_sha1[20];
25 unsigned short old_mode; 25 unsigned short old_mode;
26 unsigned short new_mode; 26 unsigned short new_mode;
27 char *old_path; 27 char *old_path;
28 char *new_path; 28 char *new_path;
29 unsigned int added; 29 unsigned int added;
30 unsigned int removed; 30 unsigned int removed;
31 unsigned long old_size; 31 unsigned long old_size;
32 unsigned long new_size; 32 unsigned long new_size;
33 int binary:1; 33 int binary:1;
34} *items; 34} *items;
35 35
36static int use_ssdiff = 0; 36static int use_ssdiff = 0;
37static struct diff_filepair *current_filepair;
38
39struct diff_filespec *cgit_get_current_old_file(void)
40{
41 return current_filepair->one;
42}
43
44struct diff_filespec *cgit_get_current_new_file(void)
45{
46 return current_filepair->two;
47}
37 48
38static void print_fileinfo(struct fileinfo *info) 49static void print_fileinfo(struct fileinfo *info)
39{ 50{
40 char *class; 51 char *class;
41 52
42 switch (info->status) { 53 switch (info->status) {
43 case DIFF_STATUS_ADDED: 54 case DIFF_STATUS_ADDED:
44 class = "add"; 55 class = "add";
45 break; 56 break;
46 case DIFF_STATUS_COPIED: 57 case DIFF_STATUS_COPIED:
47 class = "cpy"; 58 class = "cpy";
48 break; 59 break;
49 case DIFF_STATUS_DELETED: 60 case DIFF_STATUS_DELETED:
50 class = "del"; 61 class = "del";
51 break; 62 break;
52 case DIFF_STATUS_MODIFIED: 63 case DIFF_STATUS_MODIFIED:
53 class = "upd"; 64 class = "upd";
54 break; 65 break;
55 case DIFF_STATUS_RENAMED: 66 case DIFF_STATUS_RENAMED:
56 class = "mov"; 67 class = "mov";
57 break; 68 break;
58 case DIFF_STATUS_TYPE_CHANGED: 69 case DIFF_STATUS_TYPE_CHANGED:
59 class = "typ"; 70 class = "typ";
60 break; 71 break;
@@ -263,48 +274,49 @@ static void header(unsigned char *sha1, char *path1, int mode1,
263 } 274 }
264 html("</div>"); 275 html("</div>");
265} 276}
266 277
267static void print_ssdiff_link() 278static void print_ssdiff_link()
268{ 279{
269 if (!strcmp(ctx.qry.page, "diff")) { 280 if (!strcmp(ctx.qry.page, "diff")) {
270 if (use_ssdiff) 281 if (use_ssdiff)
271 cgit_diff_link("Unidiff", NULL, NULL, ctx.qry.head, 282 cgit_diff_link("Unidiff", NULL, NULL, ctx.qry.head,
272 ctx.qry.sha1, ctx.qry.sha2, ctx.qry.path, 1); 283 ctx.qry.sha1, ctx.qry.sha2, ctx.qry.path, 1);
273 else 284 else
274 cgit_diff_link("Side-by-side diff", NULL, NULL, 285 cgit_diff_link("Side-by-side diff", NULL, NULL,
275 ctx.qry.head, ctx.qry.sha1, 286 ctx.qry.head, ctx.qry.sha1,
276 ctx.qry.sha2, ctx.qry.path, 1); 287 ctx.qry.sha2, ctx.qry.path, 1);
277 } 288 }
278} 289}
279 290
280static void filepair_cb(struct diff_filepair *pair) 291static void filepair_cb(struct diff_filepair *pair)
281{ 292{
282 unsigned long old_size = 0; 293 unsigned long old_size = 0;
283 unsigned long new_size = 0; 294 unsigned long new_size = 0;
284 int binary = 0; 295 int binary = 0;
285 linediff_fn print_line_fn = print_line; 296 linediff_fn print_line_fn = print_line;
286 297
298 current_filepair = pair;
287 if (use_ssdiff) { 299 if (use_ssdiff) {
288 cgit_ssdiff_header_begin(); 300 cgit_ssdiff_header_begin();
289 print_line_fn = cgit_ssdiff_line_cb; 301 print_line_fn = cgit_ssdiff_line_cb;
290 } 302 }
291 header(pair->one->sha1, pair->one->path, pair->one->mode, 303 header(pair->one->sha1, pair->one->path, pair->one->mode,
292 pair->two->sha1, pair->two->path, pair->two->mode); 304 pair->two->sha1, pair->two->path, pair->two->mode);
293 if (use_ssdiff) 305 if (use_ssdiff)
294 cgit_ssdiff_header_end(); 306 cgit_ssdiff_header_end();
295 if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) { 307 if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) {
296 if (S_ISGITLINK(pair->one->mode)) 308 if (S_ISGITLINK(pair->one->mode))
297 print_line_fn(fmt("-Subproject %s", sha1_to_hex(pair->one->sha1)), 52); 309 print_line_fn(fmt("-Subproject %s", sha1_to_hex(pair->one->sha1)), 52);
298 if (S_ISGITLINK(pair->two->mode)) 310 if (S_ISGITLINK(pair->two->mode))
299 print_line_fn(fmt("+Subproject %s", sha1_to_hex(pair->two->sha1)), 52); 311 print_line_fn(fmt("+Subproject %s", sha1_to_hex(pair->two->sha1)), 52);
300 if (use_ssdiff) 312 if (use_ssdiff)
301 cgit_ssdiff_footer(); 313 cgit_ssdiff_footer();
302 return; 314 return;
303 } 315 }
304 if (cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size, 316 if (cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size,
305 &new_size, &binary, ctx.qry.context, 317 &new_size, &binary, ctx.qry.context,
306 ctx.qry.ignorews, print_line_fn)) 318 ctx.qry.ignorews, print_line_fn))
307 cgit_print_error("Error running diff"); 319 cgit_print_error("Error running diff");
308 if (binary) { 320 if (binary) {
309 if (use_ssdiff) 321 if (use_ssdiff)
310 html("<tr><td colspan='4'>Binary files differ</td></tr>"); 322 html("<tr><td colspan='4'>Binary files differ</td></tr>");
diff --git a/ui-diff.h b/ui-diff.h
index 70b2926..12d0c62 100644
--- a/ui-diff.h
+++ b/ui-diff.h
@@ -1,10 +1,16 @@
1#ifndef UI_DIFF_H 1#ifndef UI_DIFF_H
2#define UI_DIFF_H 2#define UI_DIFF_H
3 3
4extern void cgit_print_diffstat(const unsigned char *old_sha1, 4extern void cgit_print_diffstat(const unsigned char *old_sha1,
5 const unsigned char *new_sha1); 5 const unsigned char *new_sha1);
6 6
7extern void cgit_print_diff(const char *new_hex, const char *old_hex, 7extern void cgit_print_diff(const char *new_hex, const char *old_hex,
8 const char *prefix); 8 const char *prefix);
9 9
10extern struct diff_filespec *cgit_get_current_old_file(void);
11extern struct diff_filespec *cgit_get_current_new_file(void);
12
13extern unsigned char old_rev_sha1[20];
14extern unsigned char new_rev_sha1[20];
15
10#endif /* UI_DIFF_H */ 16#endif /* UI_DIFF_H */
diff --git a/ui-shared.c b/ui-shared.c
index ae29615..7efae7a 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -735,59 +735,69 @@ static const char *hc(struct cgit_context *ctx, const char *page)
735 735
736static void cgit_print_path_crumbs(struct cgit_context *ctx, char *path) 736static void cgit_print_path_crumbs(struct cgit_context *ctx, char *path)
737{ 737{
738 char *old_path = ctx->qry.path; 738 char *old_path = ctx->qry.path;
739 char *p = path, *q, *end = path + strlen(path); 739 char *p = path, *q, *end = path + strlen(path);
740 740
741 ctx->qry.path = NULL; 741 ctx->qry.path = NULL;
742 cgit_self_link("root", NULL, NULL, ctx); 742 cgit_self_link("root", NULL, NULL, ctx);
743 ctx->qry.path = p = path; 743 ctx->qry.path = p = path;
744 while (p < end) { 744 while (p < end) {
745 if (!(q = strchr(p, '/'))) 745 if (!(q = strchr(p, '/')))
746 q = end; 746 q = end;
747 *q = '\0'; 747 *q = '\0';
748 html_txt("/"); 748 html_txt("/");
749 cgit_self_link(p, NULL, NULL, ctx); 749 cgit_self_link(p, NULL, NULL, ctx);
750 if (q < end) 750 if (q < end)
751 *q = '/'; 751 *q = '/';
752 p = q + 1; 752 p = q + 1;
753 } 753 }
754 ctx->qry.path = old_path; 754 ctx->qry.path = old_path;
755} 755}
756 756
757static void print_header(struct cgit_context *ctx) 757static void print_header(struct cgit_context *ctx)
758{ 758{
759 char *logo = NULL, *logo_link = NULL;
760
759 html("<table id='header'>\n"); 761 html("<table id='header'>\n");
760 html("<tr>\n"); 762 html("<tr>\n");
761 763
762 if (ctx->cfg.logo && ctx->cfg.logo[0] != 0) { 764 if (ctx->repo && ctx->repo->logo && *ctx->repo->logo)
765 logo = ctx->repo->logo;
766 else
767 logo = ctx->cfg.logo;
768 if (ctx->repo && ctx->repo->logo_link && *ctx->repo->logo_link)
769 logo_link = ctx->repo->logo_link;
770 else
771 logo_link = ctx->cfg.logo_link;
772 if (logo && *logo) {
763 html("<td class='logo' rowspan='2'><a href='"); 773 html("<td class='logo' rowspan='2'><a href='");
764 if (ctx->cfg.logo_link) 774 if (logo_link && *logo_link)
765 html_attr(ctx->cfg.logo_link); 775 html_attr(logo_link);
766 else 776 else
767 html_attr(cgit_rooturl()); 777 html_attr(cgit_rooturl());
768 html("'><img src='"); 778 html("'><img src='");
769 html_attr(ctx->cfg.logo); 779 html_attr(logo);
770 html("' alt='cgit logo'/></a></td>\n"); 780 html("' alt='cgit logo'/></a></td>\n");
771 } 781 }
772 782
773 html("<td class='main'>"); 783 html("<td class='main'>");
774 if (ctx->repo) { 784 if (ctx->repo) {
775 cgit_index_link("index", NULL, NULL, NULL, 0); 785 cgit_index_link("index", NULL, NULL, NULL, 0);
776 html(" : "); 786 html(" : ");
777 cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL); 787 cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL);
778 html("</td><td class='form'>"); 788 html("</td><td class='form'>");
779 html("<form method='get' action=''>\n"); 789 html("<form method='get' action=''>\n");
780 cgit_add_hidden_formfields(0, 1, ctx->qry.page); 790 cgit_add_hidden_formfields(0, 1, ctx->qry.page);
781 html("<select name='h' onchange='this.form.submit();'>\n"); 791 html("<select name='h' onchange='this.form.submit();'>\n");
782 for_each_branch_ref(print_branch_option, ctx->qry.head); 792 for_each_branch_ref(print_branch_option, ctx->qry.head);
783 html("</select> "); 793 html("</select> ");
784 html("<input type='submit' name='' value='switch'/>"); 794 html("<input type='submit' name='' value='switch'/>");
785 html("</form>"); 795 html("</form>");
786 } else 796 } else
787 html_txt(ctx->cfg.root_title); 797 html_txt(ctx->cfg.root_title);
788 html("</td></tr>\n"); 798 html("</td></tr>\n");
789 799
790 html("<tr><td class='sub'>"); 800 html("<tr><td class='sub'>");
791 if (ctx->repo) { 801 if (ctx->repo) {
792 html_txt(ctx->repo->desc); 802 html_txt(ctx->repo->desc);
793 html("</td><td class='sub right'>"); 803 html("</td><td class='sub right'>");
diff --git a/ui-ssdiff.c b/ui-ssdiff.c
index 408e620..2481585 100644
--- a/ui-ssdiff.c
+++ b/ui-ssdiff.c
@@ -1,27 +1,28 @@
1#include "cgit.h" 1#include "cgit.h"
2#include "html.h" 2#include "html.h"
3#include "ui-shared.h" 3#include "ui-shared.h"
4#include "ui-diff.h"
4 5
5extern int use_ssdiff; 6extern int use_ssdiff;
6 7
7static int current_old_line, current_new_line; 8static int current_old_line, current_new_line;
8 9
9struct deferred_lines { 10struct deferred_lines {
10 int line_no; 11 int line_no;
11 char *line; 12 char *line;
12 struct deferred_lines *next; 13 struct deferred_lines *next;
13}; 14};
14 15
15static struct deferred_lines *deferred_old, *deferred_old_last; 16static struct deferred_lines *deferred_old, *deferred_old_last;
16static struct deferred_lines *deferred_new, *deferred_new_last; 17static struct deferred_lines *deferred_new, *deferred_new_last;
17 18
18static char *longest_common_subsequence(char *A, char *B) 19static char *longest_common_subsequence(char *A, char *B)
19{ 20{
20 int i, j, ri; 21 int i, j, ri;
21 int m = strlen(A); 22 int m = strlen(A);
22 int n = strlen(B); 23 int n = strlen(B);
23 int L[m + 1][n + 1]; 24 int L[m + 1][n + 1];
24 int tmp1, tmp2; 25 int tmp1, tmp2;
25 int lcs_length; 26 int lcs_length;
26 char *result; 27 char *result;
27 28
@@ -170,74 +171,87 @@ static void print_part_with_lcs(char *class, char *line, char *lcs)
170 c[0] = line[i]; 171 c[0] = line[i];
171 if (same) { 172 if (same) {
172 if (line[i] == lcs[j]) 173 if (line[i] == lcs[j])
173 j += 1; 174 j += 1;
174 else { 175 else {
175 same = 0; 176 same = 0;
176 htmlf("<span class='%s'>", class); 177 htmlf("<span class='%s'>", class);
177 } 178 }
178 } else if (line[i] == lcs[j]) { 179 } else if (line[i] == lcs[j]) {
179 same = 1; 180 same = 1;
180 htmlf("</span>"); 181 htmlf("</span>");
181 j += 1; 182 j += 1;
182 } 183 }
183 html_txt(c); 184 html_txt(c);
184 } 185 }
185} 186}
186 187
187static void print_ssdiff_line(char *class, 188static void print_ssdiff_line(char *class,
188 int old_line_no, 189 int old_line_no,
189 char *old_line, 190 char *old_line,
190 int new_line_no, 191 int new_line_no,
191 char *new_line, int individual_chars) 192 char *new_line, int individual_chars)
192{ 193{
193 char *lcs = NULL; 194 char *lcs = NULL;
195
194 if (old_line) 196 if (old_line)
195 old_line = replace_tabs(old_line + 1); 197 old_line = replace_tabs(old_line + 1);
196 if (new_line) 198 if (new_line)
197 new_line = replace_tabs(new_line + 1); 199 new_line = replace_tabs(new_line + 1);
198 if (individual_chars && old_line && new_line) 200 if (individual_chars && old_line && new_line)
199 lcs = longest_common_subsequence(old_line, new_line); 201 lcs = longest_common_subsequence(old_line, new_line);
200 html("<tr>"); 202 html("<tr>\n");
201 if (old_line_no > 0) 203 if (old_line_no > 0) {
202 htmlf("<td class='lineno'>%d</td><td class='%s'>", 204 struct diff_filespec *old_file = cgit_get_current_old_file();
203 old_line_no, class); 205 char *lineno_str = fmt("n%d", old_line_no);
204 else if (old_line) 206 char *id_str = fmt("%s#%s", is_null_sha1(old_file->sha1)?"HEAD":sha1_to_hex(old_rev_sha1), lineno_str);
207 html("<td class='lineno'><a class='no' href='");
208 html(cgit_fileurl(ctx.repo->url, "tree", old_file->path, id_str));
209 htmlf("' id='%s' name='%s'>%s</a>", lineno_str, lineno_str, lineno_str + 1);
210 html("</td>");
211 htmlf("<td class='%s'>", class);
212 } else if (old_line)
205 htmlf("<td class='lineno'></td><td class='%s'>", class); 213 htmlf("<td class='lineno'></td><td class='%s'>", class);
206 else 214 else
207 htmlf("<td class='lineno'></td><td class='%s_dark'>", class); 215 htmlf("<td class='lineno'></td><td class='%s_dark'>", class);
208 if (old_line) { 216 if (old_line) {
209 if (lcs) 217 if (lcs)
210 print_part_with_lcs("del", old_line, lcs); 218 print_part_with_lcs("del", old_line, lcs);
211 else 219 else
212 html_txt(old_line); 220 html_txt(old_line);
213 } 221 }
214 222
215 html("</td>"); 223 html("</td>\n");
216 if (new_line_no > 0) 224 if (new_line_no > 0) {
217 htmlf("<td class='lineno'>%d</td><td class='%s'>", 225 struct diff_filespec *new_file = cgit_get_current_new_file();
218 new_line_no, class); 226 char *lineno_str = fmt("n%d", new_line_no);
219 else if (new_line) 227 char *id_str = fmt("%s#%s", is_null_sha1(new_file->sha1)?"HEAD":sha1_to_hex(new_rev_sha1), lineno_str);
228 html("<td class='lineno'><a class='no' href='");
229 html(cgit_fileurl(ctx.repo->url, "tree", new_file->path, id_str));
230 htmlf("' id='%s' name='%s'>%s</a>", lineno_str, lineno_str, lineno_str + 1);
231 html("</td>");
232 htmlf("<td class='%s'>", class);
233 } else if (new_line)
220 htmlf("<td class='lineno'></td><td class='%s'>", class); 234 htmlf("<td class='lineno'></td><td class='%s'>", class);
221 else 235 else
222 htmlf("<td class='lineno'></td><td class='%s_dark'>", class); 236 htmlf("<td class='lineno'></td><td class='%s_dark'>", class);
223 if (new_line) { 237 if (new_line) {
224 if (lcs) 238 if (lcs)
225 print_part_with_lcs("add", new_line, lcs); 239 print_part_with_lcs("add", new_line, lcs);
226 else 240 else
227 html_txt(new_line); 241 html_txt(new_line);
228 } 242 }
229 243
230 html("</td></tr>"); 244 html("</td></tr>");
231 if (lcs) 245 if (lcs)
232 free(lcs); 246 free(lcs);
233 if (new_line) 247 if (new_line)
234 free(new_line); 248 free(new_line);
235 if (old_line) 249 if (old_line)
236 free(old_line); 250 free(old_line);
237} 251}
238 252
239static void print_deferred_old_lines() 253static void print_deferred_old_lines()
240{ 254{
241 struct deferred_lines *iter_old, *tmp; 255 struct deferred_lines *iter_old, *tmp;
242 iter_old = deferred_old; 256 iter_old = deferred_old;
243 while (iter_old) { 257 while (iter_old) {