about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorLars Hjemli2007-05-13 22:25:14 +0200
committerLars Hjemli2007-05-13 22:31:11 +0200
commit8a3685bcf2612206fc24a2421acb53dd83aeab85 (patch)
tree4628d87e55e87ead2e097cdacf8b4160cd0fc118
parentAdd max-commit-count parameter to cgitrc (diff)
downloadcgit-8a3685bcf2612206fc24a2421acb53dd83aeab85.tar.gz
cgit-8a3685bcf2612206fc24a2421acb53dd83aeab85.zip
Add graphical diffstat to commit view
The diffstat is calculated against the leftmost parent of the commit. This
gives nice information for "normal" merges while octopus merges are less
than optimal, so the diffstat isn't calculated for those merges.

Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r--Makefile1
-rw-r--r--add.pngbin0 -> 168 bytes
-rw-r--r--cgit.css30
-rw-r--r--del.pngbin0 -> 168 bytes
-rw-r--r--ui-commit.c132
5 files changed, 130 insertions, 33 deletions
diff --git a/Makefile b/Makefile index ccc7582..ea4d818 100644 --- a/Makefile +++ b/Makefile
@@ -55,6 +55,7 @@ install: all clean-cache
55 mkdir -p $(prefix) 55 mkdir -p $(prefix)
56 install cgit $(prefix)/cgit.cgi 56 install cgit $(prefix)/cgit.cgi
57 install cgit.css $(prefix)/cgit.css 57 install cgit.css $(prefix)/cgit.css
58 install add.png del.png $(prefix)/
58 59
59clean-cgit: 60clean-cgit:
60 rm -f cgit *.o 61 rm -f cgit *.o
diff --git a/add.png b/add.png new file mode 100644 index 0000000..c550388 --- /dev/null +++ b/add.png
Binary files differ
diff --git a/cgit.css b/cgit.css index cded981..b736b19 100644 --- a/cgit.css +++ b/cgit.css
@@ -26,6 +26,13 @@ h3 {
26 font-weight: normal; 26 font-weight: normal;
27} 27}
28 28
29h4 {
30 margin-top: 1.5em;
31 margin-bottom: 0.1em;
32 font-size: 100%;
33 font-weight: bold;
34}
35
29a { 36a {
30 color: blue; 37 color: blue;
31 text-decoration: none; 38 text-decoration: none;
@@ -227,6 +234,12 @@ div.commit-msg {
227table.diffstat { 234table.diffstat {
228 border-collapse: collapse; 235 border-collapse: collapse;
229 margin-top: 1.5em; 236 margin-top: 1.5em;
237 width: 100%;
238 border: solid 1px #aaa;
239}
240
241table.diffstat tr:hover {
242 background-color: #eee;
230} 243}
231 244
232table.diffstat th { 245table.diffstat th {
@@ -238,8 +251,11 @@ table.diffstat th {
238} 251}
239 252
240table.diffstat td { 253table.diffstat td {
241 padding: 0.1em 1em 0.1em 0.1em; 254 padding: 0.2em 0.2em 0.1em 0.1em;
242 font-size: 100%; 255 font-size: 100%;
256 border: none;
257 border-top: solid 1px #aaa;
258 border-bottom: solid 1px #aaa;
243} 259}
244 260
245table.diffstat td span.modechange { 261table.diffstat td span.modechange {
@@ -259,7 +275,17 @@ table.diffstat td.upd a {
259 color: blue; 275 color: blue;
260} 276}
261 277
262table.diffstat td.summary { 278table.diffstat td.graph {
279 width: 75%;
280 vertical-align: center;
281}
282
283table.diffstat td.graph img {
284 border: none;
285 height: 11pt;
286}
287
288div.diffstat-summary {
263 color: #888; 289 color: #888;
264 padding-top: 0.5em; 290 padding-top: 0.5em;
265} 291}
diff --git a/del.png b/del.png new file mode 100644 index 0000000..5c73e82 --- /dev/null +++ b/del.png
Binary files differ
diff --git a/ui-commit.c b/ui-commit.c index f1a22d3..ce33cf9 100644 --- a/ui-commit.c +++ b/ui-commit.c
@@ -8,14 +8,30 @@
8 8
9#include "cgit.h" 9#include "cgit.h"
10 10
11int files = 0; 11int files = 0, slots = 0;
12int total_adds = 0, total_rems = 0, max_changes = 0;
13int lines_added, lines_removed;
12 14
13void print_filepair(struct diff_filepair *pair) 15struct fileinfo {
16 char status;
17 unsigned char old_sha1[20];
18 unsigned char new_sha1[20];
19 unsigned short old_mode;
20 unsigned short new_mode;
21 char *old_path;
22 char *new_path;
23 unsigned int added;
24 unsigned int removed;
25} *items;
26
27
28void print_fileinfo(struct fileinfo *info)
14{ 29{
15 char *query; 30 char *query, *query2;
16 char *class; 31 char *class;
32 double width;
17 33
18 switch (pair->status) { 34 switch (info->status) {
19 case DIFF_STATUS_ADDED: 35 case DIFF_STATUS_ADDED:
20 class = "add"; 36 class = "add";
21 break; 37 break;
@@ -41,51 +57,98 @@ void print_filepair(struct diff_filepair *pair)
41 class = "stg"; 57 class = "stg";
42 break; 58 break;
43 default: 59 default:
44 die("bug: unhandled diff status %c", pair->status); 60 die("bug: unhandled diff status %c", info->status);
45 } 61 }
46 62
47 html("<tr>"); 63 html("<tr>");
48 htmlf("<td class='mode'>"); 64 htmlf("<td class='mode'>");
49 if (is_null_sha1(pair->two->sha1)) { 65 if (is_null_sha1(info->new_sha1)) {
50 html_filemode(pair->one->mode); 66 html_filemode(info->old_mode);
51 } else { 67 } else {
52 html_filemode(pair->two->mode); 68 html_filemode(info->new_mode);
53 } 69 }
54 70
55 if (pair->one->mode != pair->two->mode && 71 if (info->old_mode != info->new_mode &&
56 !is_null_sha1(pair->one->sha1) && 72 !is_null_sha1(info->old_sha1) &&
57 !is_null_sha1(pair->two->sha1)) { 73 !is_null_sha1(info->new_sha1)) {
58 html("<span class='modechange'>["); 74 html("<span class='modechange'>[");
59 html_filemode(pair->one->mode); 75 html_filemode(info->old_mode);
60 html("]</span>"); 76 html("]</span>");
61 } 77 }
62 htmlf("</td><td class='%s'>", class); 78 htmlf("</td><td class='%s'>", class);
63 query = fmt("id=%s&id2=%s", sha1_to_hex(pair->one->sha1), 79 query = fmt("id=%s&id2=%s", sha1_to_hex(info->old_sha1),
64 sha1_to_hex(pair->two->sha1)); 80 sha1_to_hex(info->new_sha1));
65 html_link_open(cgit_pageurl(cgit_query_repo, "diff", query), 81 html_link_open(cgit_pageurl(cgit_query_repo, "diff", query),
66 NULL, NULL); 82 NULL, NULL);
67 if (pair->status == DIFF_STATUS_COPIED || 83 if (info->status == DIFF_STATUS_COPIED ||
68 pair->status == DIFF_STATUS_RENAMED) { 84 info->status == DIFF_STATUS_RENAMED) {
69 html_txt(pair->two->path); 85 html_txt(info->new_path);
70 htmlf("</a> (%s from ", pair->status == DIFF_STATUS_COPIED ? 86 htmlf("</a> (%s from ", info->status == DIFF_STATUS_COPIED ?
71 "copied" : "renamed"); 87 "copied" : "renamed");
72 query = fmt("id=%s", sha1_to_hex(pair->one->sha1)); 88 query2 = fmt("id=%s", sha1_to_hex(info->old_sha1));
73 html_link_open(cgit_pageurl(cgit_query_repo, "view", query), 89 html_link_open(cgit_pageurl(cgit_query_repo, "view", query2),
74 NULL, NULL); 90 NULL, NULL);
75 html_txt(pair->one->path); 91 html_txt(info->old_path);
76 html("</a>)"); 92 html("</a>)");
77 } else { 93 } else {
78 html_txt(pair->two->path); 94 html_txt(info->new_path);
79 html("</a>"); 95 html("</a>");
80 } 96 }
81 html("<td>"); 97 html("</td><td class='right'>");
98 htmlf("%d", info->added + info->removed);
82 99
83 //TODO: diffstat graph 100 html("</td><td class='graph'>");
101 width = (info->added + info->removed) * 100.0 / max_changes;
102 if (width < 0.1)
103 width = 0.1;
104 html_link_open(cgit_pageurl(cgit_query_repo, "diff", query),
105 NULL, NULL);
106 htmlf("<img src='/cgit/add.png' style='width: %.1f%%;'/>",
107 info->added * width / (info->added + info->removed));
108 htmlf("<img src='/cgit/del.png' style='width: %.1f%%;'/>",
109 info->removed * width / (info->added + info->removed));
110 html("</a></td></tr>\n");
111}
84 112
85 html("</td></tr>\n"); 113void cgit_count_diff_lines(char *line, int len)
114{
115 if (line && (len > 0)) {
116 if (line[0] == '+')
117 lines_added++;
118 else if (line[0] == '-')
119 lines_removed++;
120 }
121}
122
123void inspect_filepair(struct diff_filepair *pair)
124{
86 files++; 125 files++;
126 lines_added = 0;
127 lines_removed = 0;
128 cgit_diff_files(pair->one->sha1, pair->two->sha1, cgit_count_diff_lines);
129 if (files >= slots) {
130 if (slots == 0)
131 slots = 4;
132 else
133 slots = slots * 2;
134 items = xrealloc(items, slots * sizeof(struct fileinfo));
135 }
136 items[files-1].status = pair->status;
137 hashcpy(items[files-1].old_sha1, pair->one->sha1);
138 hashcpy(items[files-1].new_sha1, pair->two->sha1);
139 items[files-1].old_mode = pair->one->mode;
140 items[files-1].new_mode = pair->two->mode;
141 items[files-1].old_path = xstrdup(pair->one->path);
142 items[files-1].new_path = xstrdup(pair->two->path);
143 items[files-1].added = lines_added;
144 items[files-1].removed = lines_removed;
145 if (lines_added + lines_removed > max_changes)
146 max_changes = lines_added + lines_removed;
147 total_adds += lines_added;
148 total_rems += lines_removed;
87} 149}
88 150
151
89void cgit_print_commit(const char *hex) 152void cgit_print_commit(const char *hex)
90{ 153{
91 struct commit *commit; 154 struct commit *commit;
@@ -94,6 +157,7 @@ void cgit_print_commit(const char *hex)
94 unsigned char sha1[20]; 157 unsigned char sha1[20];
95 char *query; 158 char *query;
96 char *filename; 159 char *filename;
160 int i;
97 161
98 if (get_sha1(hex, sha1)) { 162 if (get_sha1(hex, sha1)) {
99 cgit_print_error(fmt("Bad object id: %s", hex)); 163 cgit_print_error(fmt("Bad object id: %s", hex));
@@ -148,11 +212,17 @@ void cgit_print_commit(const char *hex)
148 html("<div class='commit-msg'>"); 212 html("<div class='commit-msg'>");
149 html_txt(info->msg); 213 html_txt(info->msg);
150 html("</div>"); 214 html("</div>");
151 html("<table class='diffstat'>"); 215 if (!(commit->parents && commit->parents->next && commit->parents->next->next)) {
152 html("<tr><th colspan='3'>Affected files</tr>\n"); 216 html("<table class='diffstat'>");
153 cgit_diff_commit(commit, print_filepair); 217 max_changes = 0;
154 htmlf("<tr><td colspan='3' class='summary'>" 218 cgit_diff_commit(commit, inspect_filepair);
155 "%d file%s changed</td></tr>\n", files, files > 1 ? "s" : ""); 219 for(i = 0; i<files; i++)
156 html("</table>"); 220 print_fileinfo(&items[i]);
221 html("</table>");
222 html("<div class='diffstat-summary'>");
223 htmlf("%d files changed, %d insertions, %d deletions\n",
224 files, total_adds, total_rems);
225 html("</div>");
226 }
157 cgit_free_commitinfo(info); 227 cgit_free_commitinfo(info);
158} 228}