summaryrefslogtreecommitdiffabout
path: root/ui-commit.c
authorLars Hjemli <hjemli@gmail.com>2007-05-15 00:13:11 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2007-05-15 07:09:42 (UTC)
commite903011c4457c24c0095f270ca5e78c40729434f (patch) (unidiff)
tree255f128dfaf81f2fd03bb2216039bbf8f38ef167 /ui-commit.c
parentcfd2aa079770ddb4c93d5995b2cd7b5f25da3681 (diff)
downloadcgit-e903011c4457c24c0095f270ca5e78c40729434f.zip
cgit-e903011c4457c24c0095f270ca5e78c40729434f.tar.gz
cgit-e903011c4457c24c0095f270ca5e78c40729434f.tar.bz2
Use tables and css to create the diffstat graph, fix scaling
There was no need to use image-files for the graphs, so lets drop them. At the same time, fix scaling of the graphs so that the full width is used only if atleast 100 LOC are changed in one of the files. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (limited to 'ui-commit.c') (more/less context) (ignore whitespace changes)
-rw-r--r--ui-commit.c20
1 files changed, 8 insertions, 12 deletions
diff --git a/ui-commit.c b/ui-commit.c
index b6a106f..8011dfc 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -1,240 +1,236 @@
1/* ui-commit.c: generate commit view 1/* ui-commit.c: generate commit view
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10 10
11static int files, slots; 11static int files, slots;
12static int total_adds, total_rems, max_changes; 12static int total_adds, total_rems, max_changes;
13static int lines_added, lines_removed; 13static int lines_added, lines_removed;
14 14
15static struct fileinfo { 15static struct fileinfo {
16 char status; 16 char status;
17 unsigned char old_sha1[20]; 17 unsigned char old_sha1[20];
18 unsigned char new_sha1[20]; 18 unsigned char new_sha1[20];
19 unsigned short old_mode; 19 unsigned short old_mode;
20 unsigned short new_mode; 20 unsigned short new_mode;
21 char *old_path; 21 char *old_path;
22 char *new_path; 22 char *new_path;
23 unsigned int added; 23 unsigned int added;
24 unsigned int removed; 24 unsigned int removed;
25} *items; 25} *items;
26 26
27 27
28void print_fileinfo(struct fileinfo *info) 28void print_fileinfo(struct fileinfo *info)
29{ 29{
30 char *query, *query2; 30 char *query, *query2;
31 char *class; 31 char *class;
32 double width;
33 32
34 switch (info->status) { 33 switch (info->status) {
35 case DIFF_STATUS_ADDED: 34 case DIFF_STATUS_ADDED:
36 class = "add"; 35 class = "add";
37 break; 36 break;
38 case DIFF_STATUS_COPIED: 37 case DIFF_STATUS_COPIED:
39 class = "cpy"; 38 class = "cpy";
40 break; 39 break;
41 case DIFF_STATUS_DELETED: 40 case DIFF_STATUS_DELETED:
42 class = "del"; 41 class = "del";
43 break; 42 break;
44 case DIFF_STATUS_MODIFIED: 43 case DIFF_STATUS_MODIFIED:
45 class = "upd"; 44 class = "upd";
46 break; 45 break;
47 case DIFF_STATUS_RENAMED: 46 case DIFF_STATUS_RENAMED:
48 class = "mov"; 47 class = "mov";
49 break; 48 break;
50 case DIFF_STATUS_TYPE_CHANGED: 49 case DIFF_STATUS_TYPE_CHANGED:
51 class = "typ"; 50 class = "typ";
52 break; 51 break;
53 case DIFF_STATUS_UNKNOWN: 52 case DIFF_STATUS_UNKNOWN:
54 class = "unk"; 53 class = "unk";
55 break; 54 break;
56 case DIFF_STATUS_UNMERGED: 55 case DIFF_STATUS_UNMERGED:
57 class = "stg"; 56 class = "stg";
58 break; 57 break;
59 default: 58 default:
60 die("bug: unhandled diff status %c", info->status); 59 die("bug: unhandled diff status %c", info->status);
61 } 60 }
62 61
63 html("<tr>"); 62 html("<tr>");
64 htmlf("<td class='mode'>"); 63 htmlf("<td class='mode'>");
65 if (is_null_sha1(info->new_sha1)) { 64 if (is_null_sha1(info->new_sha1)) {
66 html_filemode(info->old_mode); 65 html_filemode(info->old_mode);
67 } else { 66 } else {
68 html_filemode(info->new_mode); 67 html_filemode(info->new_mode);
69 } 68 }
70 69
71 if (info->old_mode != info->new_mode && 70 if (info->old_mode != info->new_mode &&
72 !is_null_sha1(info->old_sha1) && 71 !is_null_sha1(info->old_sha1) &&
73 !is_null_sha1(info->new_sha1)) { 72 !is_null_sha1(info->new_sha1)) {
74 html("<span class='modechange'>["); 73 html("<span class='modechange'>[");
75 html_filemode(info->old_mode); 74 html_filemode(info->old_mode);
76 html("]</span>"); 75 html("]</span>");
77 } 76 }
78 htmlf("</td><td class='%s'>", class); 77 htmlf("</td><td class='%s'>", class);
79 query = fmt("id=%s&id2=%s&path=%s", sha1_to_hex(info->old_sha1), 78 query = fmt("id=%s&id2=%s&path=%s", sha1_to_hex(info->old_sha1),
80 sha1_to_hex(info->new_sha1), info->new_path); 79 sha1_to_hex(info->new_sha1), info->new_path);
81 html_link_open(cgit_pageurl(cgit_query_repo, "diff", query), 80 html_link_open(cgit_pageurl(cgit_query_repo, "diff", query),
82 NULL, NULL); 81 NULL, NULL);
83 if (info->status == DIFF_STATUS_COPIED || 82 if (info->status == DIFF_STATUS_COPIED ||
84 info->status == DIFF_STATUS_RENAMED) { 83 info->status == DIFF_STATUS_RENAMED) {
85 html_txt(info->new_path); 84 html_txt(info->new_path);
86 htmlf("</a> (%s from ", info->status == DIFF_STATUS_COPIED ? 85 htmlf("</a> (%s from ", info->status == DIFF_STATUS_COPIED ?
87 "copied" : "renamed"); 86 "copied" : "renamed");
88 query2 = fmt("id=%s", sha1_to_hex(info->old_sha1)); 87 query2 = fmt("id=%s", sha1_to_hex(info->old_sha1));
89 html_link_open(cgit_pageurl(cgit_query_repo, "view", query2), 88 html_link_open(cgit_pageurl(cgit_query_repo, "view", query2),
90 NULL, NULL); 89 NULL, NULL);
91 html_txt(info->old_path); 90 html_txt(info->old_path);
92 html("</a>)"); 91 html("</a>)");
93 } else { 92 } else {
94 html_txt(info->new_path); 93 html_txt(info->new_path);
95 html("</a>"); 94 html("</a>");
96 } 95 }
97 html("</td><td class='right'>"); 96 html("</td><td class='right'>");
98 htmlf("%d", info->added + info->removed); 97 htmlf("%d", info->added + info->removed);
99
100 html("</td><td class='graph'>"); 98 html("</td><td class='graph'>");
101 width = (info->added + info->removed) * 100.0 / max_changes; 99 htmlf("<table width='%d%%'><tr>", (max_changes > 100 ? 100 : max_changes));
102 if (width < 0.1) 100 htmlf("<td class='add' style='width: %.1f%%;'/>",
103 width = 0.1; 101 info->added * 100.0 / max_changes);
104 html_link_open(cgit_pageurl(cgit_query_repo, "diff", query), 102 htmlf("<td class='rem' style='width: %.1f%%;'/>",
105 NULL, NULL); 103 info->removed * 100.0 / max_changes);
106 htmlf("<img src='/cgit/add.png' style='width: %.1f%%;'/>", 104 htmlf("<td class='none' style='width: %.1f%%;'/>",
107 info->added * width / (info->added + info->removed)); 105 (max_changes - info->removed - info->added) * 100.0 / max_changes);
108 htmlf("<img src='/cgit/del.png' style='width: %.1f%%;'/>", 106 html("</tr></table></a></td></tr>\n");
109 info->removed * width / (info->added + info->removed));
110 html("</a></td></tr>\n");
111} 107}
112 108
113void cgit_count_diff_lines(char *line, int len) 109void cgit_count_diff_lines(char *line, int len)
114{ 110{
115 if (line && (len > 0)) { 111 if (line && (len > 0)) {
116 if (line[0] == '+') 112 if (line[0] == '+')
117 lines_added++; 113 lines_added++;
118 else if (line[0] == '-') 114 else if (line[0] == '-')
119 lines_removed++; 115 lines_removed++;
120 } 116 }
121} 117}
122 118
123void inspect_filepair(struct diff_filepair *pair) 119void inspect_filepair(struct diff_filepair *pair)
124{ 120{
125 files++; 121 files++;
126 lines_added = 0; 122 lines_added = 0;
127 lines_removed = 0; 123 lines_removed = 0;
128 cgit_diff_files(pair->one->sha1, pair->two->sha1, cgit_count_diff_lines); 124 cgit_diff_files(pair->one->sha1, pair->two->sha1, cgit_count_diff_lines);
129 if (files >= slots) { 125 if (files >= slots) {
130 if (slots == 0) 126 if (slots == 0)
131 slots = 4; 127 slots = 4;
132 else 128 else
133 slots = slots * 2; 129 slots = slots * 2;
134 items = xrealloc(items, slots * sizeof(struct fileinfo)); 130 items = xrealloc(items, slots * sizeof(struct fileinfo));
135 } 131 }
136 items[files-1].status = pair->status; 132 items[files-1].status = pair->status;
137 hashcpy(items[files-1].old_sha1, pair->one->sha1); 133 hashcpy(items[files-1].old_sha1, pair->one->sha1);
138 hashcpy(items[files-1].new_sha1, pair->two->sha1); 134 hashcpy(items[files-1].new_sha1, pair->two->sha1);
139 items[files-1].old_mode = pair->one->mode; 135 items[files-1].old_mode = pair->one->mode;
140 items[files-1].new_mode = pair->two->mode; 136 items[files-1].new_mode = pair->two->mode;
141 items[files-1].old_path = xstrdup(pair->one->path); 137 items[files-1].old_path = xstrdup(pair->one->path);
142 items[files-1].new_path = xstrdup(pair->two->path); 138 items[files-1].new_path = xstrdup(pair->two->path);
143 items[files-1].added = lines_added; 139 items[files-1].added = lines_added;
144 items[files-1].removed = lines_removed; 140 items[files-1].removed = lines_removed;
145 if (lines_added + lines_removed > max_changes) 141 if (lines_added + lines_removed > max_changes)
146 max_changes = lines_added + lines_removed; 142 max_changes = lines_added + lines_removed;
147 total_adds += lines_added; 143 total_adds += lines_added;
148 total_rems += lines_removed; 144 total_rems += lines_removed;
149} 145}
150 146
151 147
152void cgit_print_commit(const char *hex) 148void cgit_print_commit(const char *hex)
153{ 149{
154 struct commit *commit, *parent; 150 struct commit *commit, *parent;
155 struct commitinfo *info; 151 struct commitinfo *info;
156 struct commit_list *p; 152 struct commit_list *p;
157 unsigned char sha1[20]; 153 unsigned char sha1[20];
158 char *query; 154 char *query;
159 char *filename; 155 char *filename;
160 int i; 156 int i;
161 157
162 if (get_sha1(hex, sha1)) { 158 if (get_sha1(hex, sha1)) {
163 cgit_print_error(fmt("Bad object id: %s", hex)); 159 cgit_print_error(fmt("Bad object id: %s", hex));
164 return; 160 return;
165 } 161 }
166 commit = lookup_commit_reference(sha1); 162 commit = lookup_commit_reference(sha1);
167 if (!commit) { 163 if (!commit) {
168 cgit_print_error(fmt("Bad commit reference: %s", hex)); 164 cgit_print_error(fmt("Bad commit reference: %s", hex));
169 return; 165 return;
170 } 166 }
171 info = cgit_parse_commit(commit); 167 info = cgit_parse_commit(commit);
172 168
173 html("<table class='commit-info'>\n"); 169 html("<table class='commit-info'>\n");
174 html("<tr><th>author</th><td>"); 170 html("<tr><th>author</th><td>");
175 html_txt(info->author); 171 html_txt(info->author);
176 html(" "); 172 html(" ");
177 html_txt(info->author_email); 173 html_txt(info->author_email);
178 html("</td><td class='right'>"); 174 html("</td><td class='right'>");
179 cgit_print_date(info->author_date); 175 cgit_print_date(info->author_date);
180 html("</td></tr>\n"); 176 html("</td></tr>\n");
181 html("<tr><th>committer</th><td>"); 177 html("<tr><th>committer</th><td>");
182 html_txt(info->committer); 178 html_txt(info->committer);
183 html(" "); 179 html(" ");
184 html_txt(info->committer_email); 180 html_txt(info->committer_email);
185 html("</td><td class='right'>"); 181 html("</td><td class='right'>");
186 cgit_print_date(info->committer_date); 182 cgit_print_date(info->committer_date);
187 html("</td></tr>\n"); 183 html("</td></tr>\n");
188 html("<tr><th>tree</th><td colspan='2' class='sha1'><a href='"); 184 html("<tr><th>tree</th><td colspan='2' class='sha1'><a href='");
189 query = fmt("h=%s&id=%s", sha1_to_hex(commit->object.sha1), 185 query = fmt("h=%s&id=%s", sha1_to_hex(commit->object.sha1),
190 sha1_to_hex(commit->tree->object.sha1)); 186 sha1_to_hex(commit->tree->object.sha1));
191 html_attr(cgit_pageurl(cgit_query_repo, "tree", query)); 187 html_attr(cgit_pageurl(cgit_query_repo, "tree", query));
192 htmlf("'>%s</a></td></tr>\n", sha1_to_hex(commit->tree->object.sha1)); 188 htmlf("'>%s</a></td></tr>\n", sha1_to_hex(commit->tree->object.sha1));
193 for (p = commit->parents; p ; p = p->next) { 189 for (p = commit->parents; p ; p = p->next) {
194 parent = lookup_commit_reference(p->item->object.sha1); 190 parent = lookup_commit_reference(p->item->object.sha1);
195 if (!parent) { 191 if (!parent) {
196 html("<tr><td colspan='3'>"); 192 html("<tr><td colspan='3'>");
197 cgit_print_error("Error reading parent commit"); 193 cgit_print_error("Error reading parent commit");
198 html("</td></tr>"); 194 html("</td></tr>");
199 continue; 195 continue;
200 } 196 }
201 html("<tr><th>parent</th>" 197 html("<tr><th>parent</th>"
202 "<td colspan='2' class='sha1'>" 198 "<td colspan='2' class='sha1'>"
203 "<a href='"); 199 "<a href='");
204 query = fmt("id=%s", sha1_to_hex(p->item->object.sha1)); 200 query = fmt("id=%s", sha1_to_hex(p->item->object.sha1));
205 html_attr(cgit_pageurl(cgit_query_repo, "commit", query)); 201 html_attr(cgit_pageurl(cgit_query_repo, "commit", query));
206 htmlf("'>%s</a> (<a href='", 202 htmlf("'>%s</a> (<a href='",
207 sha1_to_hex(p->item->object.sha1)); 203 sha1_to_hex(p->item->object.sha1));
208 query = fmt("id=%s&id2=%s", sha1_to_hex(parent->tree->object.sha1), 204 query = fmt("id=%s&id2=%s", sha1_to_hex(parent->tree->object.sha1),
209 sha1_to_hex(commit->tree->object.sha1)); 205 sha1_to_hex(commit->tree->object.sha1));
210 html_attr(cgit_pageurl(cgit_query_repo, "diff", query)); 206 html_attr(cgit_pageurl(cgit_query_repo, "diff", query));
211 html("'>diff</a>)</td></tr>"); 207 html("'>diff</a>)</td></tr>");
212 } 208 }
213 if (cgit_repo->snapshots) { 209 if (cgit_repo->snapshots) {
214 htmlf("<tr><th>download</th><td colspan='2' class='sha1'><a href='"); 210 htmlf("<tr><th>download</th><td colspan='2' class='sha1'><a href='");
215 filename = fmt("%s-%s.zip", cgit_query_repo, hex); 211 filename = fmt("%s-%s.zip", cgit_query_repo, hex);
216 html_attr(cgit_pageurl(cgit_query_repo, "snapshot", 212 html_attr(cgit_pageurl(cgit_query_repo, "snapshot",
217 fmt("id=%s&name=%s", hex, filename))); 213 fmt("id=%s&name=%s", hex, filename)));
218 htmlf("'>%s</a></td></tr>", filename); 214 htmlf("'>%s</a></td></tr>", filename);
219 } 215 }
220 html("</table>\n"); 216 html("</table>\n");
221 html("<div class='commit-subject'>"); 217 html("<div class='commit-subject'>");
222 html_txt(info->subject); 218 html_txt(info->subject);
223 html("</div>"); 219 html("</div>");
224 html("<div class='commit-msg'>"); 220 html("<div class='commit-msg'>");
225 html_txt(info->msg); 221 html_txt(info->msg);
226 html("</div>"); 222 html("</div>");
227 if (!(commit->parents && commit->parents->next && commit->parents->next->next)) { 223 if (!(commit->parents && commit->parents->next && commit->parents->next->next)) {
228 html("<table class='diffstat'>"); 224 html("<table class='diffstat'>");
229 max_changes = 0; 225 max_changes = 0;
230 cgit_diff_commit(commit, inspect_filepair); 226 cgit_diff_commit(commit, inspect_filepair);
231 for(i = 0; i<files; i++) 227 for(i = 0; i<files; i++)
232 print_fileinfo(&items[i]); 228 print_fileinfo(&items[i]);
233 html("</table>"); 229 html("</table>");
234 html("<div class='diffstat-summary'>"); 230 html("<div class='diffstat-summary'>");
235 htmlf("%d files changed, %d insertions, %d deletions\n", 231 htmlf("%d files changed, %d insertions, %d deletions\n",
236 files, total_adds, total_rems); 232 files, total_adds, total_rems);
237 html("</div>"); 233 html("</div>");
238 } 234 }
239 cgit_free_commitinfo(info); 235 cgit_free_commitinfo(info);
240} 236}