summaryrefslogtreecommitdiffabout
path: root/ui-commit.c
authorLars Hjemli <hjemli@gmail.com>2007-06-17 16:12:03 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2007-06-17 16:12:03 (UTC)
commit4a0be586662843382ecfa53af34a13b291312bc0 (patch) (unidiff)
tree01e0cd725fe249df3449bb089aad9f8d58081f89 /ui-commit.c
parentfaaca447b071592c9a1e1f14b4d0d2a39b4c795a (diff)
downloadcgit-4a0be586662843382ecfa53af34a13b291312bc0.zip
cgit-4a0be586662843382ecfa53af34a13b291312bc0.tar.gz
cgit-4a0be586662843382ecfa53af34a13b291312bc0.tar.bz2
Add cgit_diff_link()
This adds a new function used to generate links to the diff page and uses it everywhere such links appear (expect for single files in the diffstat displayed on the commit page: this is now a link to the tree page). The updated diff-page now expects zero, one or two revision specifiers, in parameters head, id and id2. Id defaults to head unless otherwise specified, while head (as usual) defaults to repo.defbranch. If id2 isn't specified, it defaults to the first parent of id1. The most important change is of course that now all repo pages (summary, log, tree, commit and diff) has support for passing on the current branch and revision, i.e. the road is now open for a 'static' menu with links to all of these pages. 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.c46
1 files changed, 16 insertions, 30 deletions
diff --git a/ui-commit.c b/ui-commit.c
index d489d7c..2679b59 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -1,242 +1,228 @@
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;
14static char *curr_rev;
14 15
15static struct fileinfo { 16static struct fileinfo {
16 char status; 17 char status;
17 unsigned char old_sha1[20]; 18 unsigned char old_sha1[20];
18 unsigned char new_sha1[20]; 19 unsigned char new_sha1[20];
19 unsigned short old_mode; 20 unsigned short old_mode;
20 unsigned short new_mode; 21 unsigned short new_mode;
21 char *old_path; 22 char *old_path;
22 char *new_path; 23 char *new_path;
23 unsigned int added; 24 unsigned int added;
24 unsigned int removed; 25 unsigned int removed;
25} *items; 26} *items;
26 27
27 28
28void print_fileinfo(struct fileinfo *info) 29void print_fileinfo(struct fileinfo *info)
29{ 30{
30 char *query, *query2;
31 char *class; 31 char *class;
32 32
33 switch (info->status) { 33 switch (info->status) {
34 case DIFF_STATUS_ADDED: 34 case DIFF_STATUS_ADDED:
35 class = "add"; 35 class = "add";
36 break; 36 break;
37 case DIFF_STATUS_COPIED: 37 case DIFF_STATUS_COPIED:
38 class = "cpy"; 38 class = "cpy";
39 break; 39 break;
40 case DIFF_STATUS_DELETED: 40 case DIFF_STATUS_DELETED:
41 class = "del"; 41 class = "del";
42 break; 42 break;
43 case DIFF_STATUS_MODIFIED: 43 case DIFF_STATUS_MODIFIED:
44 class = "upd"; 44 class = "upd";
45 break; 45 break;
46 case DIFF_STATUS_RENAMED: 46 case DIFF_STATUS_RENAMED:
47 class = "mov"; 47 class = "mov";
48 break; 48 break;
49 case DIFF_STATUS_TYPE_CHANGED: 49 case DIFF_STATUS_TYPE_CHANGED:
50 class = "typ"; 50 class = "typ";
51 break; 51 break;
52 case DIFF_STATUS_UNKNOWN: 52 case DIFF_STATUS_UNKNOWN:
53 class = "unk"; 53 class = "unk";
54 break; 54 break;
55 case DIFF_STATUS_UNMERGED: 55 case DIFF_STATUS_UNMERGED:
56 class = "stg"; 56 class = "stg";
57 break; 57 break;
58 default: 58 default:
59 die("bug: unhandled diff status %c", info->status); 59 die("bug: unhandled diff status %c", info->status);
60 } 60 }
61 61
62 html("<tr>"); 62 html("<tr>");
63 htmlf("<td class='mode'>"); 63 htmlf("<td class='mode'>");
64 if (is_null_sha1(info->new_sha1)) { 64 if (is_null_sha1(info->new_sha1)) {
65 html_filemode(info->old_mode); 65 html_filemode(info->old_mode);
66 } else { 66 } else {
67 html_filemode(info->new_mode); 67 html_filemode(info->new_mode);
68 } 68 }
69 69
70 if (info->old_mode != info->new_mode && 70 if (info->old_mode != info->new_mode &&
71 !is_null_sha1(info->old_sha1) && 71 !is_null_sha1(info->old_sha1) &&
72 !is_null_sha1(info->new_sha1)) { 72 !is_null_sha1(info->new_sha1)) {
73 html("<span class='modechange'>["); 73 html("<span class='modechange'>[");
74 html_filemode(info->old_mode); 74 html_filemode(info->old_mode);
75 html("]</span>"); 75 html("]</span>");
76 } 76 }
77 htmlf("</td><td class='%s'>", class); 77 htmlf("</td><td class='%s'>", class);
78 query = fmt("id=%s&amp;id2=%s&amp;path=%s", sha1_to_hex(info->old_sha1), 78 cgit_tree_link(info->new_path, NULL, NULL, cgit_query_head, curr_rev,
79 sha1_to_hex(info->new_sha1), info->new_path); 79 info->new_path);
80 html_link_open(cgit_pageurl(cgit_query_repo, "diff", query), 80 if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED)
81 NULL, NULL); 81 htmlf(" (%s from %s)",
82 if (info->status == DIFF_STATUS_COPIED || 82 info->status == DIFF_STATUS_COPIED ? "copied" : "renamed",
83 info->status == DIFF_STATUS_RENAMED) { 83 info->old_path);
84 html_txt(info->new_path);
85 htmlf("</a> (%s from ", info->status == DIFF_STATUS_COPIED ?
86 "copied" : "renamed");
87 query2 = fmt("id=%s", sha1_to_hex(info->old_sha1));
88 html_link_open(cgit_pageurl(cgit_query_repo, "view", query2),
89 NULL, NULL);
90 html_txt(info->old_path);
91 html("</a>)");
92 } else {
93 html_txt(info->new_path);
94 html("</a>");
95 }
96 html("</td><td class='right'>"); 84 html("</td><td class='right'>");
97 htmlf("%d", info->added + info->removed); 85 htmlf("%d", info->added + info->removed);
98 html("</td><td class='graph'>"); 86 html("</td><td class='graph'>");
99 htmlf("<table width='%d%%'><tr>", (max_changes > 100 ? 100 : max_changes)); 87 htmlf("<table width='%d%%'><tr>", (max_changes > 100 ? 100 : max_changes));
100 htmlf("<td class='add' style='width: %.1f%%;'/>", 88 htmlf("<td class='add' style='width: %.1f%%;'/>",
101 info->added * 100.0 / max_changes); 89 info->added * 100.0 / max_changes);
102 htmlf("<td class='rem' style='width: %.1f%%;'/>", 90 htmlf("<td class='rem' style='width: %.1f%%;'/>",
103 info->removed * 100.0 / max_changes); 91 info->removed * 100.0 / max_changes);
104 htmlf("<td class='none' style='width: %.1f%%;'/>", 92 htmlf("<td class='none' style='width: %.1f%%;'/>",
105 (max_changes - info->removed - info->added) * 100.0 / max_changes); 93 (max_changes - info->removed - info->added) * 100.0 / max_changes);
106 html("</tr></table></td></tr>\n"); 94 html("</tr></table></td></tr>\n");
107} 95}
108 96
109void cgit_count_diff_lines(char *line, int len) 97void cgit_count_diff_lines(char *line, int len)
110{ 98{
111 if (line && (len > 0)) { 99 if (line && (len > 0)) {
112 if (line[0] == '+') 100 if (line[0] == '+')
113 lines_added++; 101 lines_added++;
114 else if (line[0] == '-') 102 else if (line[0] == '-')
115 lines_removed++; 103 lines_removed++;
116 } 104 }
117} 105}
118 106
119void inspect_filepair(struct diff_filepair *pair) 107void inspect_filepair(struct diff_filepair *pair)
120{ 108{
121 files++; 109 files++;
122 lines_added = 0; 110 lines_added = 0;
123 lines_removed = 0; 111 lines_removed = 0;
124 cgit_diff_files(pair->one->sha1, pair->two->sha1, cgit_count_diff_lines); 112 cgit_diff_files(pair->one->sha1, pair->two->sha1, cgit_count_diff_lines);
125 if (files >= slots) { 113 if (files >= slots) {
126 if (slots == 0) 114 if (slots == 0)
127 slots = 4; 115 slots = 4;
128 else 116 else
129 slots = slots * 2; 117 slots = slots * 2;
130 items = xrealloc(items, slots * sizeof(struct fileinfo)); 118 items = xrealloc(items, slots * sizeof(struct fileinfo));
131 } 119 }
132 items[files-1].status = pair->status; 120 items[files-1].status = pair->status;
133 hashcpy(items[files-1].old_sha1, pair->one->sha1); 121 hashcpy(items[files-1].old_sha1, pair->one->sha1);
134 hashcpy(items[files-1].new_sha1, pair->two->sha1); 122 hashcpy(items[files-1].new_sha1, pair->two->sha1);
135 items[files-1].old_mode = pair->one->mode; 123 items[files-1].old_mode = pair->one->mode;
136 items[files-1].new_mode = pair->two->mode; 124 items[files-1].new_mode = pair->two->mode;
137 items[files-1].old_path = xstrdup(pair->one->path); 125 items[files-1].old_path = xstrdup(pair->one->path);
138 items[files-1].new_path = xstrdup(pair->two->path); 126 items[files-1].new_path = xstrdup(pair->two->path);
139 items[files-1].added = lines_added; 127 items[files-1].added = lines_added;
140 items[files-1].removed = lines_removed; 128 items[files-1].removed = lines_removed;
141 if (lines_added + lines_removed > max_changes) 129 if (lines_added + lines_removed > max_changes)
142 max_changes = lines_added + lines_removed; 130 max_changes = lines_added + lines_removed;
143 total_adds += lines_added; 131 total_adds += lines_added;
144 total_rems += lines_removed; 132 total_rems += lines_removed;
145} 133}
146 134
147 135
148void cgit_print_commit(const char *hex) 136void cgit_print_commit(char *hex)
149{ 137{
150 struct commit *commit, *parent; 138 struct commit *commit, *parent;
151 struct commitinfo *info; 139 struct commitinfo *info;
152 struct commit_list *p; 140 struct commit_list *p;
153 unsigned char sha1[20]; 141 unsigned char sha1[20];
154 char *query;
155 char *filename; 142 char *filename;
156 char *tmp; 143 char *tmp;
157 int i; 144 int i;
158 145
159 if (!hex) 146 if (!hex)
160 hex = cgit_query_head; 147 hex = cgit_query_head;
148 curr_rev = hex;
161 149
162 if (get_sha1(hex, sha1)) { 150 if (get_sha1(hex, sha1)) {
163 cgit_print_error(fmt("Bad object id: %s", hex)); 151 cgit_print_error(fmt("Bad object id: %s", hex));
164 return; 152 return;
165 } 153 }
166 commit = lookup_commit_reference(sha1); 154 commit = lookup_commit_reference(sha1);
167 if (!commit) { 155 if (!commit) {
168 cgit_print_error(fmt("Bad commit reference: %s", hex)); 156 cgit_print_error(fmt("Bad commit reference: %s", hex));
169 return; 157 return;
170 } 158 }
171 info = cgit_parse_commit(commit); 159 info = cgit_parse_commit(commit);
172 160
173 html("<table class='commit-info'>\n"); 161 html("<table class='commit-info'>\n");
174 html("<tr><th>author</th><td>"); 162 html("<tr><th>author</th><td>");
175 html_txt(info->author); 163 html_txt(info->author);
176 html(" "); 164 html(" ");
177 html_txt(info->author_email); 165 html_txt(info->author_email);
178 html("</td><td class='right'>"); 166 html("</td><td class='right'>");
179 cgit_print_date(info->author_date, FMT_LONGDATE); 167 cgit_print_date(info->author_date, FMT_LONGDATE);
180 html("</td></tr>\n"); 168 html("</td></tr>\n");
181 html("<tr><th>committer</th><td>"); 169 html("<tr><th>committer</th><td>");
182 html_txt(info->committer); 170 html_txt(info->committer);
183 html(" "); 171 html(" ");
184 html_txt(info->committer_email); 172 html_txt(info->committer_email);
185 html("</td><td class='right'>"); 173 html("</td><td class='right'>");
186 cgit_print_date(info->committer_date, FMT_LONGDATE); 174 cgit_print_date(info->committer_date, FMT_LONGDATE);
187 html("</td></tr>\n"); 175 html("</td></tr>\n");
188 html("<tr><th>tree</th><td colspan='2' class='sha1'>"); 176 html("<tr><th>tree</th><td colspan='2' class='sha1'>");
189 tmp = xstrdup(hex); 177 tmp = xstrdup(hex);
190 cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL, 178 cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL,
191 cgit_query_head, tmp, NULL); 179 cgit_query_head, tmp, NULL);
192 html("</td></tr>\n"); 180 html("</td></tr>\n");
193 for (p = commit->parents; p ; p = p->next) { 181 for (p = commit->parents; p ; p = p->next) {
194 parent = lookup_commit_reference(p->item->object.sha1); 182 parent = lookup_commit_reference(p->item->object.sha1);
195 if (!parent) { 183 if (!parent) {
196 html("<tr><td colspan='3'>"); 184 html("<tr><td colspan='3'>");
197 cgit_print_error("Error reading parent commit"); 185 cgit_print_error("Error reading parent commit");
198 html("</td></tr>"); 186 html("</td></tr>");
199 continue; 187 continue;
200 } 188 }
201 html("<tr><th>parent</th>" 189 html("<tr><th>parent</th>"
202 "<td colspan='2' class='sha1'>"); 190 "<td colspan='2' class='sha1'>");
203 cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL, 191 cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL,
204 cgit_query_head, sha1_to_hex(p->item->object.sha1)); 192 cgit_query_head, sha1_to_hex(p->item->object.sha1));
205 html(" (<a href='"); 193 html(" (");
206 query = fmt("id=%s&amp;id2=%s", sha1_to_hex(parent->tree->object.sha1), 194 cgit_diff_link("diff", NULL, NULL, cgit_query_head, hex,
207 sha1_to_hex(commit->tree->object.sha1)); 195 sha1_to_hex(p->item->object.sha1), NULL);
208 html_attr(cgit_pageurl(cgit_query_repo, "diff", query)); 196 html(")</td></tr>");
209 html("'>diff</a>)</td></tr>");
210 } 197 }
211 if (cgit_repo->snapshots) { 198 if (cgit_repo->snapshots) {
212 htmlf("<tr><th>download</th><td colspan='2' class='sha1'><a href='"); 199 htmlf("<tr><th>download</th><td colspan='2' class='sha1'><a href='");
213 filename = fmt("%s-%s.zip", cgit_query_repo, hex); 200 filename = fmt("%s-%s.zip", cgit_query_repo, hex);
214 html_attr(cgit_pageurl(cgit_query_repo, "snapshot", 201 html_attr(cgit_pageurl(cgit_query_repo, "snapshot",
215 fmt("id=%s&amp;name=%s", hex, filename))); 202 fmt("id=%s&amp;name=%s", hex, filename)));
216 htmlf("'>%s</a></td></tr>", filename); 203 htmlf("'>%s</a></td></tr>", filename);
217 } 204 }
218 html("</table>\n"); 205 html("</table>\n");
219 html("<div class='commit-subject'>"); 206 html("<div class='commit-subject'>");
220 html_txt(info->subject); 207 html_txt(info->subject);
221 html("</div>"); 208 html("</div>");
222 html("<div class='commit-msg'>"); 209 html("<div class='commit-msg'>");
223 html_txt(info->msg); 210 html_txt(info->msg);
224 html("</div>"); 211 html("</div>");
225 if (!(commit->parents && commit->parents->next && commit->parents->next->next)) { 212 if (!(commit->parents && commit->parents->next && commit->parents->next->next)) {
226 html("<div class='diffstat-header'>Diffstat</div>"); 213 html("<div class='diffstat-header'>Diffstat</div>");
227 html("<table class='diffstat'>"); 214 html("<table class='diffstat'>");
228 max_changes = 0; 215 max_changes = 0;
229 cgit_diff_commit(commit, inspect_filepair); 216 cgit_diff_commit(commit, inspect_filepair);
230 for(i = 0; i<files; i++) 217 for(i = 0; i<files; i++)
231 print_fileinfo(&items[i]); 218 print_fileinfo(&items[i]);
232 html("</table>"); 219 html("</table>");
233 html("<div class='diffstat-summary'>"); 220 html("<div class='diffstat-summary'>");
234 htmlf("%d files changed, %d insertions, %d deletions (", 221 htmlf("%d files changed, %d insertions, %d deletions (",
235 files, total_adds, total_rems); 222 files, total_adds, total_rems);
236 query = fmt("h=%s", hex); 223 cgit_diff_link("show diff", NULL, NULL, cgit_query_head, hex,
237 html_link_open(cgit_pageurl(cgit_query_repo, "diff", query), NULL, NULL); 224 NULL, NULL);
238 html("show diff</a>)"); 225 html(")</div>");
239 html("</div>");
240 } 226 }
241 cgit_free_commitinfo(info); 227 cgit_free_commitinfo(info);
242} 228}