summaryrefslogtreecommitdiffabout
authorRagnar Ouchterlony <ragnar@lysator.liu.se>2009-09-14 18:19:02 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2009-09-16 18:17:56 (UTC)
commitc358aa3dfebf4fc1f3005dd960aa5c1c020eed76 (patch) (unidiff)
tree475fa421d673b270c7d1bde872b96425abfafce8
parent40e174d5364910750413d94b5417e57d108190ef (diff)
downloadcgit-c358aa3dfebf4fc1f3005dd960aa5c1c020eed76.zip
cgit-c358aa3dfebf4fc1f3005dd960aa5c1c020eed76.tar.gz
cgit-c358aa3dfebf4fc1f3005dd960aa5c1c020eed76.tar.bz2
Add possibility to switch between unidiff and side-by-side-diff.
A new config option side-by-side-diffs added, defaulting to 0, meaning unidiff. Also a query option (ss) is used toggle this. In the commit page you can switch between the two diff formats by clicking on the link on the "commit"-row, to the right of (patch). In the diff page you can switch by using the link at the start of the page. All commit-links and diff-links will remember the choice. Signed-off-by: Ragnar Ouchterlony <ragnar@lysator.liu.se> Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c5
-rw-r--r--cgit.h2
-rw-r--r--cgitrc.5.txt4
-rw-r--r--ui-commit.c11
-rw-r--r--ui-diff.c22
-rw-r--r--ui-log.c4
-rw-r--r--ui-refs.c2
-rw-r--r--ui-shared.c34
-rw-r--r--ui-shared.h5
9 files changed, 73 insertions, 16 deletions
diff --git a/cgit.c b/cgit.c
index bd37788..ff678fb 100644
--- a/cgit.c
+++ b/cgit.c
@@ -177,16 +177,18 @@ void config_cb(const char *name, const char *value)
177 else if (!strcmp(name, "source-filter")) 177 else if (!strcmp(name, "source-filter"))
178 ctx.cfg.source_filter = new_filter(value, 1); 178 ctx.cfg.source_filter = new_filter(value, 1);
179 else if (!strcmp(name, "summary-log")) 179 else if (!strcmp(name, "summary-log"))
180 ctx.cfg.summary_log = atoi(value); 180 ctx.cfg.summary_log = atoi(value);
181 else if (!strcmp(name, "summary-branches")) 181 else if (!strcmp(name, "summary-branches"))
182 ctx.cfg.summary_branches = atoi(value); 182 ctx.cfg.summary_branches = atoi(value);
183 else if (!strcmp(name, "summary-tags")) 183 else if (!strcmp(name, "summary-tags"))
184 ctx.cfg.summary_tags = atoi(value); 184 ctx.cfg.summary_tags = atoi(value);
185 else if (!strcmp(name, "side-by-side-diffs"))
186 ctx.cfg.ssdiff = atoi(value);
185 else if (!strcmp(name, "agefile")) 187 else if (!strcmp(name, "agefile"))
186 ctx.cfg.agefile = xstrdup(value); 188 ctx.cfg.agefile = xstrdup(value);
187 else if (!strcmp(name, "renamelimit")) 189 else if (!strcmp(name, "renamelimit"))
188 ctx.cfg.renamelimit = atoi(value); 190 ctx.cfg.renamelimit = atoi(value);
189 else if (!strcmp(name, "robots")) 191 else if (!strcmp(name, "robots"))
190 ctx.cfg.robots = xstrdup(value); 192 ctx.cfg.robots = xstrdup(value);
191 else if (!strcmp(name, "clone-prefix")) 193 else if (!strcmp(name, "clone-prefix"))
192 ctx.cfg.clone_prefix = xstrdup(value); 194 ctx.cfg.clone_prefix = xstrdup(value);
@@ -233,16 +235,18 @@ static void querystring_cb(const char *name, const char *value)
233 } else if (!strcmp(name, "mimetype")) { 235 } else if (!strcmp(name, "mimetype")) {
234 ctx.qry.mimetype = xstrdup(value); 236 ctx.qry.mimetype = xstrdup(value);
235 } else if (!strcmp(name, "s")){ 237 } else if (!strcmp(name, "s")){
236 ctx.qry.sort = xstrdup(value); 238 ctx.qry.sort = xstrdup(value);
237 } else if (!strcmp(name, "showmsg")) { 239 } else if (!strcmp(name, "showmsg")) {
238 ctx.qry.showmsg = atoi(value); 240 ctx.qry.showmsg = atoi(value);
239 } else if (!strcmp(name, "period")) { 241 } else if (!strcmp(name, "period")) {
240 ctx.qry.period = xstrdup(value); 242 ctx.qry.period = xstrdup(value);
243 } else if (!strcmp(name, "ss")) {
244 ctx.qry.ssdiff = atoi(value);
241 } 245 }
242} 246}
243 247
244char *xstrdupn(const char *str) 248char *xstrdupn(const char *str)
245{ 249{
246 return (str ? xstrdup(str) : NULL); 250 return (str ? xstrdup(str) : NULL);
247} 251}
248 252
@@ -274,16 +278,17 @@ static void prepare_context(struct cgit_context *ctx)
274 ctx->cfg.robots = "index, nofollow"; 278 ctx->cfg.robots = "index, nofollow";
275 ctx->cfg.root_title = "Git repository browser"; 279 ctx->cfg.root_title = "Git repository browser";
276 ctx->cfg.root_desc = "a fast webinterface for the git dscm"; 280 ctx->cfg.root_desc = "a fast webinterface for the git dscm";
277 ctx->cfg.script_name = CGIT_SCRIPT_NAME; 281 ctx->cfg.script_name = CGIT_SCRIPT_NAME;
278 ctx->cfg.section = ""; 282 ctx->cfg.section = "";
279 ctx->cfg.summary_branches = 10; 283 ctx->cfg.summary_branches = 10;
280 ctx->cfg.summary_log = 10; 284 ctx->cfg.summary_log = 10;
281 ctx->cfg.summary_tags = 10; 285 ctx->cfg.summary_tags = 10;
286 ctx->cfg.ssdiff = 0;
282 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG")); 287 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG"));
283 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST")); 288 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST"));
284 ctx->env.https = xstrdupn(getenv("HTTPS")); 289 ctx->env.https = xstrdupn(getenv("HTTPS"));
285 ctx->env.no_http = xstrdupn(getenv("NO_HTTP")); 290 ctx->env.no_http = xstrdupn(getenv("NO_HTTP"));
286 ctx->env.path_info = xstrdupn(getenv("PATH_INFO")); 291 ctx->env.path_info = xstrdupn(getenv("PATH_INFO"));
287 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING")); 292 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING"));
288 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD")); 293 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD"));
289 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME")); 294 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME"));
diff --git a/cgit.h b/cgit.h
index 6c6c460..b7b0adb 100644
--- a/cgit.h
+++ b/cgit.h
@@ -138,16 +138,17 @@ struct cgit_query {
138 char *name; 138 char *name;
139 char *mimetype; 139 char *mimetype;
140 char *url; 140 char *url;
141 char *period; 141 char *period;
142 int ofs; 142 int ofs;
143 int nohead; 143 int nohead;
144 char *sort; 144 char *sort;
145 int showmsg; 145 int showmsg;
146 int ssdiff;
146}; 147};
147 148
148struct cgit_config { 149struct cgit_config {
149 char *agefile; 150 char *agefile;
150 char *cache_root; 151 char *cache_root;
151 char *clone_prefix; 152 char *clone_prefix;
152 char *css; 153 char *css;
153 char *favicon; 154 char *favicon;
@@ -189,16 +190,17 @@ struct cgit_config {
189 int nocache; 190 int nocache;
190 int noplainemail; 191 int noplainemail;
191 int noheader; 192 int noheader;
192 int renamelimit; 193 int renamelimit;
193 int snapshots; 194 int snapshots;
194 int summary_branches; 195 int summary_branches;
195 int summary_log; 196 int summary_log;
196 int summary_tags; 197 int summary_tags;
198 int ssdiff;
197 struct string_list mimetypes; 199 struct string_list mimetypes;
198 struct cgit_filter *about_filter; 200 struct cgit_filter *about_filter;
199 struct cgit_filter *commit_filter; 201 struct cgit_filter *commit_filter;
200 struct cgit_filter *source_filter; 202 struct cgit_filter *source_filter;
201}; 203};
202 204
203struct cgit_page { 205struct cgit_page {
204 time_t modified; 206 time_t modified;
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 4dc383d..252d546 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -233,16 +233,20 @@ scan-path::
233 the result will be cached as a cgitrc include-file in the cache 233 the result will be cached as a cgitrc include-file in the cache
234 directory. Default value: none. See also: cache-scanrc-ttl. 234 directory. Default value: none. See also: cache-scanrc-ttl.
235 235
236section:: 236section::
237 The name of the current repository section - all repositories defined 237 The name of the current repository section - all repositories defined
238 after this option will inherit the current section name. Default value: 238 after this option will inherit the current section name. Default value:
239 none. 239 none.
240 240
241side-by-side-diffs::
242 If set to "1" shows side-by-side diffs instead of unidiffs per
243 default. Default value: "0".
244
241snapshots:: 245snapshots::
242 Text which specifies the default set of snapshot formats generated by 246 Text which specifies the default set of snapshot formats generated by
243 cgit. The value is a space-separated list of zero or more of the 247 cgit. The value is a space-separated list of zero or more of the
244 values "tar", "tar.gz", "tar.bz2" and "zip". Default value: none. 248 values "tar", "tar.gz", "tar.bz2" and "zip". Default value: none.
245 249
246source-filter:: 250source-filter::
247 Specifies a command which will be invoked to format plaintext blobs 251 Specifies a command which will be invoked to format plaintext blobs
248 in the tree view. The command will get the blob content on its STDIN 252 in the tree view. The command will get the blob content on its STDIN
diff --git a/ui-commit.c b/ui-commit.c
index f5b0ae5..b5e3c01 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -53,19 +53,24 @@ void cgit_print_commit(char *hex)
53 html(" "); 53 html(" ");
54 html_txt(info->committer_email); 54 html_txt(info->committer_email);
55 } 55 }
56 html("</td><td class='right'>"); 56 html("</td><td class='right'>");
57 cgit_print_date(info->committer_date, FMT_LONGDATE, ctx.cfg.local_time); 57 cgit_print_date(info->committer_date, FMT_LONGDATE, ctx.cfg.local_time);
58 html("</td></tr>\n"); 58 html("</td></tr>\n");
59 html("<tr><th>commit</th><td colspan='2' class='sha1'>"); 59 html("<tr><th>commit</th><td colspan='2' class='sha1'>");
60 tmp = sha1_to_hex(commit->object.sha1); 60 tmp = sha1_to_hex(commit->object.sha1);
61 cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp); 61 cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp, 0);
62 html(" ("); 62 html(" (");
63 cgit_patch_link("patch", NULL, NULL, NULL, tmp); 63 cgit_patch_link("patch", NULL, NULL, NULL, tmp);
64 html(") (");
65 if ((ctx.qry.ssdiff && !ctx.cfg.ssdiff) || (!ctx.qry.ssdiff && ctx.cfg.ssdiff))
66 cgit_commit_link("unidiff", NULL, NULL, ctx.qry.head, tmp, 1);
67 else
68 cgit_commit_link("side-by-side diff", NULL, NULL, ctx.qry.head, tmp, 1);
64 html(")</td></tr>\n"); 69 html(")</td></tr>\n");
65 html("<tr><th>tree</th><td colspan='2' class='sha1'>"); 70 html("<tr><th>tree</th><td colspan='2' class='sha1'>");
66 tmp = xstrdup(hex); 71 tmp = xstrdup(hex);
67 cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL, 72 cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL,
68 ctx.qry.head, tmp, NULL); 73 ctx.qry.head, tmp, NULL);
69 html("</td></tr>\n"); 74 html("</td></tr>\n");
70 for (p = commit->parents; p ; p = p->next) { 75 for (p = commit->parents; p ; p = p->next) {
71 parent = lookup_commit_reference(p->item->object.sha1); 76 parent = lookup_commit_reference(p->item->object.sha1);
@@ -73,20 +78,20 @@ void cgit_print_commit(char *hex)
73 html("<tr><td colspan='3'>"); 78 html("<tr><td colspan='3'>");
74 cgit_print_error("Error reading parent commit"); 79 cgit_print_error("Error reading parent commit");
75 html("</td></tr>"); 80 html("</td></tr>");
76 continue; 81 continue;
77 } 82 }
78 html("<tr><th>parent</th>" 83 html("<tr><th>parent</th>"
79 "<td colspan='2' class='sha1'>"); 84 "<td colspan='2' class='sha1'>");
80 cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL, 85 cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL,
81 ctx.qry.head, sha1_to_hex(p->item->object.sha1)); 86 ctx.qry.head, sha1_to_hex(p->item->object.sha1), 0);
82 html(" ("); 87 html(" (");
83 cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex, 88 cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex,
84 sha1_to_hex(p->item->object.sha1), NULL); 89 sha1_to_hex(p->item->object.sha1), NULL, 0);
85 html(")</td></tr>"); 90 html(")</td></tr>");
86 parents++; 91 parents++;
87 } 92 }
88 if (ctx.repo->snapshots) { 93 if (ctx.repo->snapshots) {
89 html("<tr><th>download</th><td colspan='2' class='sha1'>"); 94 html("<tr><th>download</th><td colspan='2' class='sha1'>");
90 cgit_print_snapshot_links(ctx.qry.repo, ctx.qry.head, 95 cgit_print_snapshot_links(ctx.qry.repo, ctx.qry.head,
91 hex, ctx.repo->snapshots); 96 hex, ctx.repo->snapshots);
92 html("</td></tr>"); 97 html("</td></tr>");
diff --git a/ui-diff.c b/ui-diff.c
index 0c6f8d7..42e81ac 100644
--- a/ui-diff.c
+++ b/ui-diff.c
@@ -80,17 +80,17 @@ static void print_fileinfo(struct fileinfo *info)
80 !is_null_sha1(info->old_sha1) && 80 !is_null_sha1(info->old_sha1) &&
81 !is_null_sha1(info->new_sha1)) { 81 !is_null_sha1(info->new_sha1)) {
82 html("<span class='modechange'>["); 82 html("<span class='modechange'>[");
83 cgit_print_filemode(info->old_mode); 83 cgit_print_filemode(info->old_mode);
84 html("]</span>"); 84 html("]</span>");
85 } 85 }
86 htmlf("</td><td class='%s'>", class); 86 htmlf("</td><td class='%s'>", class);
87 cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, ctx.qry.sha1, 87 cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, ctx.qry.sha1,
88 ctx.qry.sha2, info->new_path); 88 ctx.qry.sha2, info->new_path, 0);
89 if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED) 89 if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED)
90 htmlf(" (%s from %s)", 90 htmlf(" (%s from %s)",
91 info->status == DIFF_STATUS_COPIED ? "copied" : "renamed", 91 info->status == DIFF_STATUS_COPIED ? "copied" : "renamed",
92 info->old_path); 92 info->old_path);
93 html("</td><td class='right'>"); 93 html("</td><td class='right'>");
94 if (info->binary) { 94 if (info->binary) {
95 htmlf("bin</td><td class='graph'>%d -> %d bytes", 95 htmlf("bin</td><td class='graph'>%d -> %d bytes",
96 info->old_size, info->new_size); 96 info->old_size, info->new_size);
@@ -155,17 +155,17 @@ static void inspect_filepair(struct diff_filepair *pair)
155 155
156void cgit_print_diffstat(const unsigned char *old_sha1, 156void cgit_print_diffstat(const unsigned char *old_sha1,
157 const unsigned char *new_sha1) 157 const unsigned char *new_sha1)
158{ 158{
159 int i; 159 int i;
160 160
161 html("<div class='diffstat-header'>"); 161 html("<div class='diffstat-header'>");
162 cgit_diff_link("Diffstat", NULL, NULL, ctx.qry.head, ctx.qry.sha1, 162 cgit_diff_link("Diffstat", NULL, NULL, ctx.qry.head, ctx.qry.sha1,
163 ctx.qry.sha2, NULL); 163 ctx.qry.sha2, NULL, 0);
164 html("</div>"); 164 html("</div>");
165 html("<table summary='diffstat' class='diffstat'>"); 165 html("<table summary='diffstat' class='diffstat'>");
166 max_changes = 0; 166 max_changes = 0;
167 cgit_diff_tree(old_sha1, new_sha1, inspect_filepair, NULL); 167 cgit_diff_tree(old_sha1, new_sha1, inspect_filepair, NULL);
168 for(i = 0; i<files; i++) 168 for(i = 0; i<files; i++)
169 print_fileinfo(&items[i]); 169 print_fileinfo(&items[i]);
170 html("</table>"); 170 html("</table>");
171 html("<div class='diffstat-summary'>"); 171 html("<div class='diffstat-summary'>");
@@ -245,16 +245,29 @@ static void header(unsigned char *sha1, char *path1, int mode1,
245 else 245 else
246 html_txt(path2); 246 html_txt(path2);
247 } 247 }
248 html("</div>"); 248 html("</div>");
249 if (use_ssdiff) 249 if (use_ssdiff)
250 cgit_ssdiff_header(); 250 cgit_ssdiff_header();
251} 251}
252 252
253static void print_ssdiff_link()
254{
255 if (!strcmp(ctx.qry.page, "diff")) {
256 if (use_ssdiff)
257 cgit_diff_link("Unidiff", NULL, NULL, ctx.qry.head,
258 ctx.qry.sha1, ctx.qry.sha2, NULL, 1);
259 else
260 cgit_diff_link("Side-by-side diff", NULL, NULL,
261 ctx.qry.head, ctx.qry.sha1,
262 ctx.qry.sha2, NULL, 1);
263 }
264}
265
253static void filepair_cb(struct diff_filepair *pair) 266static void filepair_cb(struct diff_filepair *pair)
254{ 267{
255 unsigned long old_size = 0; 268 unsigned long old_size = 0;
256 unsigned long new_size = 0; 269 unsigned long new_size = 0;
257 int binary = 0; 270 int binary = 0;
258 linediff_fn print_line_fn = print_line; 271 linediff_fn print_line_fn = print_line;
259 272
260 header(pair->one->sha1, pair->one->path, pair->one->mode, 273 header(pair->one->sha1, pair->one->path, pair->one->mode,
@@ -309,16 +322,21 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, const char *prefi
309 if (type == OBJ_BAD) { 322 if (type == OBJ_BAD) {
310 cgit_print_error(fmt("Bad object name: %s", sha1_to_hex(old_rev_sha1))); 323 cgit_print_error(fmt("Bad object name: %s", sha1_to_hex(old_rev_sha1)));
311 return; 324 return;
312 } 325 }
313 commit2 = lookup_commit_reference(old_rev_sha1); 326 commit2 = lookup_commit_reference(old_rev_sha1);
314 if (!commit2 || parse_commit(commit2)) 327 if (!commit2 || parse_commit(commit2))
315 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(old_rev_sha1))); 328 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(old_rev_sha1)));
316 } 329 }
330
331 if ((ctx.qry.ssdiff && !ctx.cfg.ssdiff) || (!ctx.qry.ssdiff && ctx.cfg.ssdiff))
332 use_ssdiff = 1;
333
334 print_ssdiff_link();
317 cgit_print_diffstat(old_rev_sha1, new_rev_sha1); 335 cgit_print_diffstat(old_rev_sha1, new_rev_sha1);
318 336
319 html("<table summary='diff' class='diff'>"); 337 html("<table summary='diff' class='diff'>");
320 html("<tr><td>"); 338 html("<tr><td>");
321 cgit_diff_tree(old_rev_sha1, new_rev_sha1, filepair_cb, prefix); 339 cgit_diff_tree(old_rev_sha1, new_rev_sha1, filepair_cb, prefix);
322 html("</td></tr>"); 340 html("</td></tr>");
323 html("</table>"); 341 html("</table>");
324} 342}
diff --git a/ui-log.c b/ui-log.c
index f3132c9..0947604 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -61,17 +61,17 @@ void show_commit_decorations(struct commit *commit)
61 strncpy(buf, deco->name + 13, sizeof(buf) - 1); 61 strncpy(buf, deco->name + 13, sizeof(buf) - 1);
62 cgit_log_link(buf, NULL, "remote-deco", NULL, 62 cgit_log_link(buf, NULL, "remote-deco", NULL,
63 sha1_to_hex(commit->object.sha1), NULL, 63 sha1_to_hex(commit->object.sha1), NULL,
64 0, NULL, NULL, ctx.qry.showmsg); 64 0, NULL, NULL, ctx.qry.showmsg);
65 } 65 }
66 else { 66 else {
67 strncpy(buf, deco->name, sizeof(buf) - 1); 67 strncpy(buf, deco->name, sizeof(buf) - 1);
68 cgit_commit_link(buf, NULL, "deco", ctx.qry.head, 68 cgit_commit_link(buf, NULL, "deco", ctx.qry.head,
69 sha1_to_hex(commit->object.sha1)); 69 sha1_to_hex(commit->object.sha1), 0);
70 } 70 }
71 deco = deco->next; 71 deco = deco->next;
72 } 72 }
73} 73}
74 74
75void print_commit(struct commit *commit) 75void print_commit(struct commit *commit)
76{ 76{
77 struct commitinfo *info; 77 struct commitinfo *info;
@@ -84,17 +84,17 @@ void print_commit(struct commit *commit)
84 tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1)); 84 tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1));
85 tmp = cgit_pageurl(ctx.repo->url, "commit", tmp); 85 tmp = cgit_pageurl(ctx.repo->url, "commit", tmp);
86 html_link_open(tmp, NULL, NULL); 86 html_link_open(tmp, NULL, NULL);
87 cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE); 87 cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);
88 html_link_close(); 88 html_link_close();
89 htmlf("</td><td%s>", 89 htmlf("</td><td%s>",
90 ctx.qry.showmsg ? " class='logsubject'" : ""); 90 ctx.qry.showmsg ? " class='logsubject'" : "");
91 cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, 91 cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head,
92 sha1_to_hex(commit->object.sha1)); 92 sha1_to_hex(commit->object.sha1), 0);
93 show_commit_decorations(commit); 93 show_commit_decorations(commit);
94 html("</td><td>"); 94 html("</td><td>");
95 html_txt(info->author); 95 html_txt(info->author);
96 if (ctx.repo->enable_log_filecount) { 96 if (ctx.repo->enable_log_filecount) {
97 files = 0; 97 files = 0;
98 add_lines = 0; 98 add_lines = 0;
99 rem_lines = 0; 99 rem_lines = 0;
100 cgit_diff_commit(commit, inspect_files); 100 cgit_diff_commit(commit, inspect_files);
diff --git a/ui-refs.c b/ui-refs.c
index d3b4f6e..33d9bec 100644
--- a/ui-refs.c
+++ b/ui-refs.c
@@ -69,17 +69,17 @@ static int print_branch(struct refinfo *ref)
69 if (!info) 69 if (!info)
70 return 1; 70 return 1;
71 html("<tr><td>"); 71 html("<tr><td>");
72 cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL, 72 cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL,
73 ctx.qry.showmsg); 73 ctx.qry.showmsg);
74 html("</td><td>"); 74 html("</td><td>");
75 75
76 if (ref->object->type == OBJ_COMMIT) { 76 if (ref->object->type == OBJ_COMMIT) {
77 cgit_commit_link(info->subject, NULL, NULL, name, NULL); 77 cgit_commit_link(info->subject, NULL, NULL, name, NULL, 0);
78 html("</td><td>"); 78 html("</td><td>");
79 html_txt(info->author); 79 html_txt(info->author);
80 html("</td><td colspan='2'>"); 80 html("</td><td colspan='2'>");
81 cgit_print_age(info->commit->date, -1, NULL); 81 cgit_print_age(info->commit->date, -1, NULL);
82 } else { 82 } else {
83 html("</td><td></td><td>"); 83 html("</td><td></td><td>");
84 cgit_object_link(ref->object); 84 cgit_object_link(ref->object);
85 } 85 }
diff --git a/ui-shared.c b/ui-shared.c
index 07d5dd4..de55eff 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -312,55 +312,77 @@ void cgit_log_link(char *name, char *title, char *class, char *head,
312 html("showmsg=1"); 312 html("showmsg=1");
313 } 313 }
314 html("'>"); 314 html("'>");
315 html_txt(name); 315 html_txt(name);
316 html("</a>"); 316 html("</a>");
317} 317}
318 318
319void cgit_commit_link(char *name, char *title, char *class, char *head, 319void cgit_commit_link(char *name, char *title, char *class, char *head,
320 char *rev) 320 char *rev, int toggle_ssdiff)
321{ 321{
322 if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) { 322 if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) {
323 name[ctx.cfg.max_msg_len] = '\0'; 323 name[ctx.cfg.max_msg_len] = '\0';
324 name[ctx.cfg.max_msg_len - 1] = '.'; 324 name[ctx.cfg.max_msg_len - 1] = '.';
325 name[ctx.cfg.max_msg_len - 2] = '.'; 325 name[ctx.cfg.max_msg_len - 2] = '.';
326 name[ctx.cfg.max_msg_len - 3] = '.'; 326 name[ctx.cfg.max_msg_len - 3] = '.';
327 } 327 }
328 reporevlink("commit", name, title, class, head, rev, NULL); 328
329 char *delim;
330
331 delim = repolink(title, class, "commit", head, NULL);
332 if (rev && strcmp(rev, ctx.qry.head)) {
333 html(delim);
334 html("id=");
335 html_url_arg(rev);
336 delim = "&amp;";
337 }
338 if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) {
339 html(delim);
340 html("ss=1");
341 }
342 html("'>");
343 html_txt(name);
344 html("</a>");
329} 345}
330 346
331void cgit_refs_link(char *name, char *title, char *class, char *head, 347void cgit_refs_link(char *name, char *title, char *class, char *head,
332 char *rev, char *path) 348 char *rev, char *path)
333{ 349{
334 reporevlink("refs", name, title, class, head, rev, path); 350 reporevlink("refs", name, title, class, head, rev, path);
335} 351}
336 352
337void cgit_snapshot_link(char *name, char *title, char *class, char *head, 353void cgit_snapshot_link(char *name, char *title, char *class, char *head,
338 char *rev, char *archivename) 354 char *rev, char *archivename)
339{ 355{
340 reporevlink("snapshot", name, title, class, head, rev, archivename); 356 reporevlink("snapshot", name, title, class, head, rev, archivename);
341} 357}
342 358
343void cgit_diff_link(char *name, char *title, char *class, char *head, 359void cgit_diff_link(char *name, char *title, char *class, char *head,
344 char *new_rev, char *old_rev, char *path) 360 char *new_rev, char *old_rev, char *path,
361 int toggle_ssdiff)
345{ 362{
346 char *delim; 363 char *delim;
347 364
348 delim = repolink(title, class, "diff", head, path); 365 delim = repolink(title, class, "diff", head, path);
349 if (new_rev && strcmp(new_rev, ctx.qry.head)) { 366 if (new_rev && strcmp(new_rev, ctx.qry.head)) {
350 html(delim); 367 html(delim);
351 html("id="); 368 html("id=");
352 html_url_arg(new_rev); 369 html_url_arg(new_rev);
353 delim = "&amp;"; 370 delim = "&amp;";
354 } 371 }
355 if (old_rev) { 372 if (old_rev) {
356 html(delim); 373 html(delim);
357 html("id2="); 374 html("id2=");
358 html_url_arg(old_rev); 375 html_url_arg(old_rev);
376 delim = "&amp;";
377 }
378 if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) {
379 html(delim);
380 html("ss=1");
359 } 381 }
360 html("'>"); 382 html("'>");
361 html_txt(name); 383 html_txt(name);
362 html("</a>"); 384 html("</a>");
363} 385}
364 386
365void cgit_patch_link(char *name, char *title, char *class, char *head, 387void cgit_patch_link(char *name, char *title, char *class, char *head,
366 char *rev) 388 char *rev)
@@ -378,17 +400,17 @@ void cgit_object_link(struct object *obj)
378{ 400{
379 char *page, *shortrev, *fullrev, *name; 401 char *page, *shortrev, *fullrev, *name;
380 402
381 fullrev = sha1_to_hex(obj->sha1); 403 fullrev = sha1_to_hex(obj->sha1);
382 shortrev = xstrdup(fullrev); 404 shortrev = xstrdup(fullrev);
383 shortrev[10] = '\0'; 405 shortrev[10] = '\0';
384 if (obj->type == OBJ_COMMIT) { 406 if (obj->type == OBJ_COMMIT) {
385 cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL, 407 cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL,
386 ctx.qry.head, fullrev); 408 ctx.qry.head, fullrev, 0);
387 return; 409 return;
388 } else if (obj->type == OBJ_TREE) 410 } else if (obj->type == OBJ_TREE)
389 page = "tree"; 411 page = "tree";
390 else if (obj->type == OBJ_TAG) 412 else if (obj->type == OBJ_TAG)
391 page = "tag"; 413 page = "tag";
392 else 414 else
393 page = "blob"; 415 page = "blob";
394 name = fmt("%s %s...", typename(obj->type), shortrev); 416 name = fmt("%s %s...", typename(obj->type), shortrev);
@@ -690,19 +712,19 @@ void cgit_print_pageheader(struct cgit_context *ctx)
690 ctx->qry.head); 712 ctx->qry.head);
691 cgit_refs_link("refs", NULL, hc(cmd, "refs"), ctx->qry.head, 713 cgit_refs_link("refs", NULL, hc(cmd, "refs"), ctx->qry.head,
692 ctx->qry.sha1, NULL); 714 ctx->qry.sha1, NULL);
693 cgit_log_link("log", NULL, hc(cmd, "log"), ctx->qry.head, 715 cgit_log_link("log", NULL, hc(cmd, "log"), ctx->qry.head,
694 NULL, NULL, 0, NULL, NULL, ctx->qry.showmsg); 716 NULL, NULL, 0, NULL, NULL, ctx->qry.showmsg);
695 cgit_tree_link("tree", NULL, hc(cmd, "tree"), ctx->qry.head, 717 cgit_tree_link("tree", NULL, hc(cmd, "tree"), ctx->qry.head,
696 ctx->qry.sha1, NULL); 718 ctx->qry.sha1, NULL);
697 cgit_commit_link("commit", NULL, hc(cmd, "commit"), 719 cgit_commit_link("commit", NULL, hc(cmd, "commit"),
698 ctx->qry.head, ctx->qry.sha1); 720 ctx->qry.head, ctx->qry.sha1, 0);
699 cgit_diff_link("diff", NULL, hc(cmd, "diff"), ctx->qry.head, 721 cgit_diff_link("diff", NULL, hc(cmd, "diff"), ctx->qry.head,
700 ctx->qry.sha1, ctx->qry.sha2, NULL); 722 ctx->qry.sha1, ctx->qry.sha2, NULL, 0);
701 if (ctx->repo->max_stats) 723 if (ctx->repo->max_stats)
702 cgit_stats_link("stats", NULL, hc(cmd, "stats"), 724 cgit_stats_link("stats", NULL, hc(cmd, "stats"),
703 ctx->qry.head, NULL); 725 ctx->qry.head, NULL);
704 if (ctx->repo->readme) 726 if (ctx->repo->readme)
705 reporevlink("about", "about", NULL, 727 reporevlink("about", "about", NULL,
706 hc(cmd, "about"), ctx->qry.head, NULL, 728 hc(cmd, "about"), ctx->qry.head, NULL,
707 NULL); 729 NULL);
708 html("</td><td class='form'>"); 730 html("</td><td class='form'>");
diff --git a/ui-shared.h b/ui-shared.h
index bff4826..166246d 100644
--- a/ui-shared.h
+++ b/ui-shared.h
@@ -17,25 +17,26 @@ extern void cgit_tag_link(char *name, char *title, char *class, char *head,
17extern void cgit_tree_link(char *name, char *title, char *class, char *head, 17extern void cgit_tree_link(char *name, char *title, char *class, char *head,
18 char *rev, char *path); 18 char *rev, char *path);
19extern void cgit_plain_link(char *name, char *title, char *class, char *head, 19extern void cgit_plain_link(char *name, char *title, char *class, char *head,
20 char *rev, char *path); 20 char *rev, char *path);
21extern void cgit_log_link(char *name, char *title, char *class, char *head, 21extern void cgit_log_link(char *name, char *title, char *class, char *head,
22 char *rev, char *path, int ofs, char *grep, 22 char *rev, char *path, int ofs, char *grep,
23 char *pattern, int showmsg); 23 char *pattern, int showmsg);
24extern void cgit_commit_link(char *name, char *title, char *class, char *head, 24extern void cgit_commit_link(char *name, char *title, char *class, char *head,
25 char *rev); 25 char *rev, int toggle_ssdiff);
26extern void cgit_patch_link(char *name, char *title, char *class, char *head, 26extern void cgit_patch_link(char *name, char *title, char *class, char *head,
27 char *rev); 27 char *rev);
28extern void cgit_refs_link(char *name, char *title, char *class, char *head, 28extern void cgit_refs_link(char *name, char *title, char *class, char *head,
29 char *rev, char *path); 29 char *rev, char *path);
30extern void cgit_snapshot_link(char *name, char *title, char *class, 30extern void cgit_snapshot_link(char *name, char *title, char *class,
31 char *head, char *rev, char *archivename); 31 char *head, char *rev, char *archivename);
32extern void cgit_diff_link(char *name, char *title, char *class, char *head, 32extern void cgit_diff_link(char *name, char *title, char *class, char *head,
33 char *new_rev, char *old_rev, char *path); 33 char *new_rev, char *old_rev, char *path,
34 int toggle_ssdiff);
34extern void cgit_stats_link(char *name, char *title, char *class, char *head, 35extern void cgit_stats_link(char *name, char *title, char *class, char *head,
35 char *path); 36 char *path);
36extern void cgit_object_link(struct object *obj); 37extern void cgit_object_link(struct object *obj);
37 38
38extern void cgit_print_error(char *msg); 39extern void cgit_print_error(char *msg);
39extern void cgit_print_date(time_t secs, char *format, int local_time); 40extern void cgit_print_date(time_t secs, char *format, int local_time);
40extern void cgit_print_age(time_t t, time_t max_relative, char *format); 41extern void cgit_print_age(time_t t, time_t max_relative, char *format);
41extern void cgit_print_http_headers(struct cgit_context *ctx); 42extern void cgit_print_http_headers(struct cgit_context *ctx);