aboutsummaryrefslogtreecommitdiffstats
path: root/ui-commit.c
diff options
context:
space:
mode:
authorLars Hjemli2007-05-13 22:25:14 +0200
committerLars Hjemli2007-05-13 22:31:11 +0200
commit8a3685bcf2612206fc24a2421acb53dd83aeab85 (patch)
tree4628d87e55e87ead2e097cdacf8b4160cd0fc118 /ui-commit.c
parentc6cf3a424a0860d69b290254d9b19d35527b2d27 (diff)
downloadcgit-8a3685bcf2612206fc24a2421acb53dd83aeab85.tar.gz
cgit-8a3685bcf2612206fc24a2421acb53dd83aeab85.tar.bz2
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>
Diffstat (limited to 'ui-commit.c')
-rw-r--r--ui-commit.c132
1 files changed, 101 insertions, 31 deletions
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}