History

Integrate diffstat with diff

This creates a generic diffstat function in ui-diff, which then is invoked from cgit_print_diff with the result that both commit and diff- view gets a diffstat.

Lars Hjemli committed 18 years ago

Commit fe1230d1 parent 9ec5cd73 files · +152 −142Browse files

Unified · Split

3 files
  1. ui-commit.c +4 −142
  2. ui-diff.c +145 −0
  3. ui-diff.h +3 −0
ui-commit.c+4−142
@@ -11,131 +11,6 @@ · 10 unmodified lines
1111 #include "ui-shared.h"
1212 #include "ui-diff.h"
1313
14−static int files, slots;
15−static int total_adds, total_rems, max_changes;
16−static int lines_added, lines_removed;
17−static char *curr_rev;
18−
19−static struct fileinfo {
20− char status;
21− unsigned char old_sha1[20];
22− unsigned char new_sha1[20];
23− unsigned short old_mode;
24− unsigned short new_mode;
25− char *old_path;
26− char *new_path;
27− unsigned int added;
28− unsigned int removed;
29−} *items;
30−
31−
32−void print_fileinfo(struct fileinfo *info)
33−{
34− char *class;
35−
36− switch (info->status) {
37− case DIFF_STATUS_ADDED:
38− class = "add";
39− break;
40− case DIFF_STATUS_COPIED:
41− class = "cpy";
42− break;
43− case DIFF_STATUS_DELETED:
44− class = "del";
45− break;
46− case DIFF_STATUS_MODIFIED:
47− class = "upd";
48− break;
49− case DIFF_STATUS_RENAMED:
50− class = "mov";
51− break;
52− case DIFF_STATUS_TYPE_CHANGED:
53− class = "typ";
54− break;
55− case DIFF_STATUS_UNKNOWN:
56− class = "unk";
57− break;
58− case DIFF_STATUS_UNMERGED:
59− class = "stg";
60− break;
61− default:
62− die("bug: unhandled diff status %c", info->status);
63− }
64−
65− html("<tr>");
66− htmlf("<td class='mode'>");
67− if (is_null_sha1(info->new_sha1)) {
68− cgit_print_filemode(info->old_mode);
69− } else {
70− cgit_print_filemode(info->new_mode);
71− }
72−
73− if (info->old_mode != info->new_mode &&
74− !is_null_sha1(info->old_sha1) &&
75− !is_null_sha1(info->new_sha1)) {
76− html("<span class='modechange'>[");
77− cgit_print_filemode(info->old_mode);
78− html("]</span>");
79− }
80− htmlf("</td><td class='%s'>", class);
81− cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, curr_rev,
82− NULL, info->new_path);
83− if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED)
84− htmlf(" (%s from %s)",
85− info->status == DIFF_STATUS_COPIED ? "copied" : "renamed",
86− info->old_path);
87− html("</td><td class='right'>");
88− htmlf("%d", info->added + info->removed);
89− html("</td><td class='graph'>");
90− htmlf("<table summary='file diffstat' width='%d%%'><tr>", (max_changes > 100 ? 100 : max_changes));
91− htmlf("<td class='add' style='width: %.1f%%;'/>",
92− info->added * 100.0 / max_changes);
93− htmlf("<td class='rem' style='width: %.1f%%;'/>",
94− info->removed * 100.0 / max_changes);
95− htmlf("<td class='none' style='width: %.1f%%;'/>",
96− (max_changes - info->removed - info->added) * 100.0 / max_changes);
97− html("</tr></table></td></tr>\n");
98−}
99−
100−void cgit_count_diff_lines(char *line, int len)
101−{
102− if (line && (len > 0)) {
103− if (line[0] == '+')
104− lines_added++;
105− else if (line[0] == '-')
106− lines_removed++;
107− }
108−}
109−
110−void inspect_filepair(struct diff_filepair *pair)
111−{
112− files++;
113− lines_added = 0;
114− lines_removed = 0;
115− cgit_diff_files(pair->one->sha1, pair->two->sha1, cgit_count_diff_lines);
116− if (files >= slots) {
117− if (slots == 0)
118− slots = 4;
119− else
120− slots = slots * 2;
121− items = xrealloc(items, slots * sizeof(struct fileinfo));
122− }
123− items[files-1].status = pair->status;
124− hashcpy(items[files-1].old_sha1, pair->one->sha1);
125− hashcpy(items[files-1].new_sha1, pair->two->sha1);
126− items[files-1].old_mode = pair->one->mode;
127− items[files-1].new_mode = pair->two->mode;
128− items[files-1].old_path = xstrdup(pair->one->path);
129− items[files-1].new_path = xstrdup(pair->two->path);
130− items[files-1].added = lines_added;
131− items[files-1].removed = lines_removed;
132− if (lines_added + lines_removed > max_changes)
133− max_changes = lines_added + lines_removed;
134− total_adds += lines_added;
135− total_rems += lines_removed;
136−}
137−
138−
13914 void cgit_print_commit(char *hex)
14015 {
14116 struct commit *commit, *parent;
@@ -143,11 +18,9 @@ void cgit_print_commit(char *hex) · 1 unmodified line
14318 struct commit_list *p;
14419 unsigned char sha1[20];
14520 char *tmp;
146− int i;
14721
14822 if (!hex)
14923 hex = ctx.qry.head;
150− curr_rev = hex;
15124
15225 if (get_sha1(hex, sha1)) {
15326 cgit_print_error(fmt("Bad object id: %s", hex));
@@ -216,21 +89,10 @@ void cgit_print_commit(char *hex) · 62 unmodified lines
21689 html("<div class='commit-msg'>");
21790 html_txt(info->msg);
21891 html("</div>");
219− if (!(commit->parents && commit->parents->next && commit->parents->next->next)) {
220− html("<div class='diffstat-header'>Diffstat</div>");
221− html("<table summary='diffstat' class='diffstat'>");
222− max_changes = 0;
223− cgit_diff_commit(commit, inspect_filepair);
224− for(i = 0; i<files; i++)
225− print_fileinfo(&items[i]);
226− html("</table>");
227− html("<div class='diffstat-summary'>");
228− htmlf("%d files changed, %d insertions, %d deletions",
229− files, total_adds, total_rems);
230− html("</div>");
231− cgit_print_diff(ctx.qry.sha1,
232− sha1_to_hex(commit->parents->item->object.sha1),
233− NULL);
92+ if (!(commit->parents && commit->parents->next &&
93+ commit->parents->next->next)) {
94+ tmp = sha1_to_hex(commit->parents->item->object.sha1);
95+ cgit_print_diff(ctx.qry.sha1, tmp, NULL);
23496 }
23597 cgit_free_commitinfo(info);
23698 }
ui-diff.c+145−0
@@ -13,6 +13,149 @@ · 12 unmodified lines
1313 unsigned char old_rev_sha1[20];
1414 unsigned char new_rev_sha1[20];
1515
16+static int files, slots;
17+static int total_adds, total_rems, max_changes;
18+static int lines_added, lines_removed;
19+static char *curr_rev;
20+
21+static struct fileinfo {
22+ char status;
23+ unsigned char old_sha1[20];
24+ unsigned char new_sha1[20];
25+ unsigned short old_mode;
26+ unsigned short new_mode;
27+ char *old_path;
28+ char *new_path;
29+ unsigned int added;
30+ unsigned int removed;
31+} *items;
32+
33+
34+static void print_fileinfo(struct fileinfo *info)
35+{
36+ char *class;
37+
38+ switch (info->status) {
39+ case DIFF_STATUS_ADDED:
40+ class = "add";
41+ break;
42+ case DIFF_STATUS_COPIED:
43+ class = "cpy";
44+ break;
45+ case DIFF_STATUS_DELETED:
46+ class = "del";
47+ break;
48+ case DIFF_STATUS_MODIFIED:
49+ class = "upd";
50+ break;
51+ case DIFF_STATUS_RENAMED:
52+ class = "mov";
53+ break;
54+ case DIFF_STATUS_TYPE_CHANGED:
55+ class = "typ";
56+ break;
57+ case DIFF_STATUS_UNKNOWN:
58+ class = "unk";
59+ break;
60+ case DIFF_STATUS_UNMERGED:
61+ class = "stg";
62+ break;
63+ default:
64+ die("bug: unhandled diff status %c", info->status);
65+ }
66+
67+ html("<tr>");
68+ htmlf("<td class='mode'>");
69+ if (is_null_sha1(info->new_sha1)) {
70+ cgit_print_filemode(info->old_mode);
71+ } else {
72+ cgit_print_filemode(info->new_mode);
73+ }
74+
75+ if (info->old_mode != info->new_mode &&
76+ !is_null_sha1(info->old_sha1) &&
77+ !is_null_sha1(info->new_sha1)) {
78+ html("<span class='modechange'>[");
79+ cgit_print_filemode(info->old_mode);
80+ html("]</span>");
81+ }
82+ htmlf("</td><td class='%s'>", class);
83+ cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, curr_rev,
84+ NULL, info->new_path);
85+ if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED)
86+ htmlf(" (%s from %s)",
87+ info->status == DIFF_STATUS_COPIED ? "copied" : "renamed",
88+ info->old_path);
89+ html("</td><td class='right'>");
90+ htmlf("%d", info->added + info->removed);
91+ html("</td><td class='graph'>");
92+ htmlf("<table summary='file diffstat' width='%d%%'><tr>", (max_changes > 100 ? 100 : max_changes));
93+ htmlf("<td class='add' style='width: %.1f%%;'/>",
94+ info->added * 100.0 / max_changes);
95+ htmlf("<td class='rem' style='width: %.1f%%;'/>",
96+ info->removed * 100.0 / max_changes);
97+ htmlf("<td class='none' style='width: %.1f%%;'/>",
98+ (max_changes - info->removed - info->added) * 100.0 / max_changes);
99+ html("</tr></table></td></tr>\n");
100+}
101+
102+static void count_diff_lines(char *line, int len)
103+{
104+ if (line && (len > 0)) {
105+ if (line[0] == '+')
106+ lines_added++;
107+ else if (line[0] == '-')
108+ lines_removed++;
109+ }
110+}
111+
112+static void inspect_filepair(struct diff_filepair *pair)
113+{
114+ files++;
115+ lines_added = 0;
116+ lines_removed = 0;
117+ cgit_diff_files(pair->one->sha1, pair->two->sha1, count_diff_lines);
118+ if (files >= slots) {
119+ if (slots == 0)
120+ slots = 4;
121+ else
122+ slots = slots * 2;
123+ items = xrealloc(items, slots * sizeof(struct fileinfo));
124+ }
125+ items[files-1].status = pair->status;
126+ hashcpy(items[files-1].old_sha1, pair->one->sha1);
127+ hashcpy(items[files-1].new_sha1, pair->two->sha1);
128+ items[files-1].old_mode = pair->one->mode;
129+ items[files-1].new_mode = pair->two->mode;
130+ items[files-1].old_path = xstrdup(pair->one->path);
131+ items[files-1].new_path = xstrdup(pair->two->path);
132+ items[files-1].added = lines_added;
133+ items[files-1].removed = lines_removed;
134+ if (lines_added + lines_removed > max_changes)
135+ max_changes = lines_added + lines_removed;
136+ total_adds += lines_added;
137+ total_rems += lines_removed;
138+}
139+
140+void cgit_print_diffstat(const unsigned char *old_sha1,
141+ const unsigned char *new_sha1)
142+{
143+ int i;
144+
145+ html("<div class='diffstat-header'>Diffstat</div>");
146+ html("<table summary='diffstat' class='diffstat'>");
147+ max_changes = 0;
148+ cgit_diff_tree(old_sha1, new_sha1, inspect_filepair, NULL);
149+ for(i = 0; i<files; i++)
150+ print_fileinfo(&items[i]);
151+ html("</table>");
152+ html("<div class='diffstat-summary'>");
153+ htmlf("%d files changed, %d insertions, %d deletions",
154+ files, total_adds, total_rems);
155+ html("</div>");
156+}
157+
158+
16159 /*
17160 * print a single line returned from xdiff
18161 */
@@ -142,6 +285,8 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, const char *prefi · 123 unmodified lines
142285 if (!commit2 || parse_commit(commit2))
143286 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(old_rev_sha1)));
144287 }
288+ cgit_print_diffstat(old_rev_sha1, new_rev_sha1);
289+
145290 html("<table summary='diff' class='diff'>");
146291 html("<tr><td>");
147292 cgit_diff_tree(old_rev_sha1, new_rev_sha1, filepair_cb, prefix);
ui-diff.h+3−0
@@ -1,6 +1,9 @@
11 #ifndef UI_DIFF_H
22 #define UI_DIFF_H
33
4+extern void cgit_print_diffstat(const unsigned char *old_sha1,
5+ const unsigned char *new_sha1);
6+
47 extern void cgit_print_diff(const char *new_hex, const char *old_hex,
58 const char *prefix);
69