diff options
author | Lars Hjemli | 2006-12-20 22:48:27 +0100 |
---|---|---|
committer | Lars Hjemli | 2006-12-20 22:48:27 +0100 |
commit | 36aba00273e7af1b94bf8c5dd5068709d983d01e (patch) | |
tree | d9be4e6f27b115a799af40cad43445f63fbf2238 | |
parent | a53042865a4ac8b1fa1d6b37720787601e181495 (diff) | |
download | cgit-36aba00273e7af1b94bf8c5dd5068709d983d01e.tar.gz cgit-36aba00273e7af1b94bf8c5dd5068709d983d01e.tar.bz2 cgit-36aba00273e7af1b94bf8c5dd5068709d983d01e.zip |
Add basic diff view
Finally, xdiff is used to show per-file diffs via commit view.
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | cgit.c | 2 | ||||
-rw-r--r-- | cgit.css | 25 | ||||
-rw-r--r-- | cgit.h | 2 | ||||
-rw-r--r-- | shared.c | 4 | ||||
-rw-r--r-- | ui-diff.c | 131 | ||||
-rw-r--r-- | xdiff.h | 105 |
7 files changed, 270 insertions, 1 deletions
@@ -6,7 +6,7 @@ CACHE_ROOT = /var/cache/cgit | |||
6 | 6 | ||
7 | EXTLIBS = ../git/libgit.a ../git/xdiff/lib.a -lz -lcrypto | 7 | EXTLIBS = ../git/libgit.a ../git/xdiff/lib.a -lz -lcrypto |
8 | OBJECTS = shared.o cache.o parsing.o html.o ui-shared.o ui-repolist.o \ | 8 | OBJECTS = shared.o cache.o parsing.o html.o ui-shared.o ui-repolist.o \ |
9 | ui-summary.o ui-log.o ui-view.c ui-tree.c ui-commit.c | 9 | ui-summary.o ui-log.o ui-view.c ui-tree.c ui-commit.c ui-diff.o |
10 | 10 | ||
11 | CFLAGS += -Wall | 11 | CFLAGS += -Wall |
12 | 12 | ||
@@ -36,6 +36,8 @@ static void cgit_print_repo_page(struct cacheitem *item) | |||
36 | cgit_print_commit(cgit_query_sha1); | 36 | cgit_print_commit(cgit_query_sha1); |
37 | } else if (!strcmp(cgit_query_page, "view")) { | 37 | } else if (!strcmp(cgit_query_page, "view")) { |
38 | cgit_print_view(cgit_query_sha1); | 38 | cgit_print_view(cgit_query_sha1); |
39 | } else if (!strcmp(cgit_query_page, "diff")) { | ||
40 | cgit_print_diff(cgit_query_sha1, cgit_query_sha2); | ||
39 | } | 41 | } |
40 | cgit_print_docend(); | 42 | cgit_print_docend(); |
41 | } | 43 | } |
@@ -77,12 +77,18 @@ div.error { | |||
77 | font-weight: bold; | 77 | font-weight: bold; |
78 | margin: 1em 2em; | 78 | margin: 1em 2em; |
79 | } | 79 | } |
80 | div.ls-blob, div.ls-dir { | ||
81 | font-family: monospace; | ||
82 | } | ||
80 | div.ls-dir a { | 83 | div.ls-dir a { |
81 | font-weight: bold; | 84 | font-weight: bold; |
82 | } | 85 | } |
83 | th.filesize, td.filesize { | 86 | th.filesize, td.filesize { |
84 | text-align: right; | 87 | text-align: right; |
85 | } | 88 | } |
89 | td.filesize { | ||
90 | font-family: monospace; | ||
91 | } | ||
86 | td.filemode { | 92 | td.filemode { |
87 | font-family: monospace; | 93 | font-family: monospace; |
88 | } | 94 | } |
@@ -154,6 +160,25 @@ table.diffstat td.summary { | |||
154 | color: #888; | 160 | color: #888; |
155 | padding-top: 0.5em; | 161 | padding-top: 0.5em; |
156 | } | 162 | } |
163 | |||
164 | table.diff td { | ||
165 | border: solid 1px black; | ||
166 | font-family: monospace; | ||
167 | white-space: pre; | ||
168 | } | ||
169 | |||
170 | table.diff td div.hunk { | ||
171 | background: #ccc; | ||
172 | } | ||
173 | |||
174 | table.diff td div.add { | ||
175 | color: green; | ||
176 | } | ||
177 | |||
178 | table.diff td div.del { | ||
179 | color: red; | ||
180 | } | ||
181 | |||
157 | .sha1 { | 182 | .sha1 { |
158 | font-family: courier; | 183 | font-family: courier; |
159 | font-size: 90%; | 184 | font-size: 90%; |
@@ -57,6 +57,7 @@ extern char *cgit_query_repo; | |||
57 | extern char *cgit_query_page; | 57 | extern char *cgit_query_page; |
58 | extern char *cgit_query_head; | 58 | extern char *cgit_query_head; |
59 | extern char *cgit_query_sha1; | 59 | extern char *cgit_query_sha1; |
60 | extern char *cgit_query_sha2; | ||
60 | extern int cgit_query_ofs; | 61 | extern int cgit_query_ofs; |
61 | 62 | ||
62 | extern int htmlfd; | 63 | extern int htmlfd; |
@@ -104,5 +105,6 @@ extern void cgit_print_log(const char *tip, int ofs, int cnt); | |||
104 | extern void cgit_print_view(const char *hex); | 105 | extern void cgit_print_view(const char *hex); |
105 | extern void cgit_print_tree(const char *hex); | 106 | extern void cgit_print_tree(const char *hex); |
106 | extern void cgit_print_commit(const char *hex); | 107 | extern void cgit_print_commit(const char *hex); |
108 | extern void cgit_print_diff(const char *old_hex, const char *new_hex); | ||
107 | 109 | ||
108 | #endif /* CGIT_H */ | 110 | #endif /* CGIT_H */ |
@@ -37,6 +37,7 @@ char *cgit_query_repo = NULL; | |||
37 | char *cgit_query_page = NULL; | 37 | char *cgit_query_page = NULL; |
38 | char *cgit_query_head = NULL; | 38 | char *cgit_query_head = NULL; |
39 | char *cgit_query_sha1 = NULL; | 39 | char *cgit_query_sha1 = NULL; |
40 | char *cgit_query_sha2 = NULL; | ||
40 | int cgit_query_ofs = 0; | 41 | int cgit_query_ofs = 0; |
41 | 42 | ||
42 | int htmlfd = 0; | 43 | int htmlfd = 0; |
@@ -83,6 +84,9 @@ void cgit_querystring_cb(const char *name, const char *value) | |||
83 | } else if (!strcmp(name, "id")) { | 84 | } else if (!strcmp(name, "id")) { |
84 | cgit_query_sha1 = xstrdup(value); | 85 | cgit_query_sha1 = xstrdup(value); |
85 | cgit_query_has_sha1 = 1; | 86 | cgit_query_has_sha1 = 1; |
87 | } else if (!strcmp(name, "id2")) { | ||
88 | cgit_query_sha2 = xstrdup(value); | ||
89 | cgit_query_has_sha1 = 1; | ||
86 | } else if (!strcmp(name, "ofs")) { | 90 | } else if (!strcmp(name, "ofs")) { |
87 | cgit_query_ofs = atoi(value); | 91 | cgit_query_ofs = atoi(value); |
88 | } | 92 | } |
diff --git a/ui-diff.c b/ui-diff.c new file mode 100644 index 0000000..0bd9ade --- /dev/null +++ b/ui-diff.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /* ui-diff.c: show diff between two blobs | ||
2 | * | ||
3 | * Copyright (C) 2006 Lars Hjemli | ||
4 | * | ||
5 | * Licensed under GNU General Public License v2 | ||
6 | * (see COPYING for full license text) | ||
7 | */ | ||
8 | |||
9 | #include "cgit.h" | ||
10 | #include "xdiff.h" | ||
11 | |||
12 | char *diff_buffer; | ||
13 | int diff_buffer_size; | ||
14 | |||
15 | |||
16 | /* | ||
17 | * print a single line returned from xdiff | ||
18 | */ | ||
19 | static void print_line(char *line, int len) | ||
20 | { | ||
21 | char *class = "ctx"; | ||
22 | char c = line[len-1]; | ||
23 | |||
24 | if (line[0] == '+') | ||
25 | class = "add"; | ||
26 | else if (line[0] == '-') | ||
27 | class = "del"; | ||
28 | else if (line[0] == '@') | ||
29 | class = "hunk"; | ||
30 | |||
31 | htmlf("<div class='%s'>", class); | ||
32 | line[len-1] = '\0'; | ||
33 | html_txt(line); | ||
34 | html("</div>"); | ||
35 | line[len-1] = c; | ||
36 | } | ||
37 | |||
38 | /* | ||
39 | * Receive diff-buffers from xdiff and concatenate them as | ||
40 | * needed across multiple callbacks. | ||
41 | * | ||
42 | * This is basically a copy of xdiff-interface.c/xdiff_outf(), | ||
43 | * ripped from git and modified to use globals instead of | ||
44 | * a special callback-struct. | ||
45 | */ | ||
46 | int diff_cb(void *priv_, mmbuffer_t *mb, int nbuf) | ||
47 | { | ||
48 | int i; | ||
49 | |||
50 | for (i = 0; i < nbuf; i++) { | ||
51 | if (mb[i].ptr[mb[i].size-1] != '\n') { | ||
52 | /* Incomplete line */ | ||
53 | diff_buffer = xrealloc(diff_buffer, | ||
54 | diff_buffer_size + mb[i].size); | ||
55 | memcpy(diff_buffer + diff_buffer_size, | ||
56 | mb[i].ptr, mb[i].size); | ||
57 | diff_buffer_size += mb[i].size; | ||
58 | continue; | ||
59 | } | ||
60 | |||
61 | /* we have a complete line */ | ||
62 | if (!diff_buffer) { | ||
63 | print_line(mb[i].ptr, mb[i].size); | ||
64 | continue; | ||
65 | } | ||
66 | diff_buffer = xrealloc(diff_buffer, | ||
67 | diff_buffer_size + mb[i].size); | ||
68 | memcpy(diff_buffer + diff_buffer_size, mb[i].ptr, mb[i].size); | ||
69 | print_line(diff_buffer, diff_buffer_size + mb[i].size); | ||
70 | free(diff_buffer); | ||
71 | diff_buffer = NULL; | ||
72 | diff_buffer_size = 0; | ||
73 | } | ||
74 | if (diff_buffer) { | ||
75 | print_line(diff_buffer, diff_buffer_size); | ||
76 | free(diff_buffer); | ||
77 | diff_buffer = NULL; | ||
78 | diff_buffer_size = 0; | ||
79 | } | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int load_mmfile(mmfile_t *file, const unsigned char *sha1) | ||
84 | { | ||
85 | char type[20]; | ||
86 | |||
87 | if (is_null_sha1(sha1)) { | ||
88 | file->ptr = (char *)""; | ||
89 | file->size = 0; | ||
90 | } else { | ||
91 | file->ptr = read_sha1_file(sha1, type, &file->size); | ||
92 | } | ||
93 | return 1; | ||
94 | } | ||
95 | |||
96 | static void run_diff(const unsigned char *sha1, const unsigned char *sha2) | ||
97 | { | ||
98 | mmfile_t file1, file2; | ||
99 | xpparam_t diff_params; | ||
100 | xdemitconf_t emit_params; | ||
101 | xdemitcb_t emit_cb; | ||
102 | |||
103 | if (!load_mmfile(&file1, sha1) || !load_mmfile(&file2, sha2)) { | ||
104 | cgit_print_error("Unable to load files for diff"); | ||
105 | return; | ||
106 | } | ||
107 | |||
108 | diff_params.flags = XDF_NEED_MINIMAL; | ||
109 | |||
110 | emit_params.ctxlen = 3; | ||
111 | emit_params.flags = XDL_EMIT_FUNCNAMES; | ||
112 | |||
113 | emit_cb.outf = diff_cb; | ||
114 | |||
115 | xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb); | ||
116 | } | ||
117 | |||
118 | |||
119 | |||
120 | void cgit_print_diff(const char *old_hex, const char *new_hex) | ||
121 | { | ||
122 | unsigned char sha1[20], sha2[20]; | ||
123 | |||
124 | get_sha1(old_hex, sha1); | ||
125 | get_sha1(new_hex, sha2); | ||
126 | |||
127 | html("<h2>diff</h2>\n"); | ||
128 | html("<table class='diff'><tr><td>"); | ||
129 | run_diff(sha1, sha2); | ||
130 | html("</td></tr></table>"); | ||
131 | } | ||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * LibXDiff by Davide Libenzi ( File Differential Library ) | ||
3 | * Copyright (C) 2003 Davide Libenzi | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2.1 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | * Davide Libenzi <davidel@xmailserver.org> | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #if !defined(XDIFF_H) | ||
24 | #define XDIFF_H | ||
25 | |||
26 | #ifdef __cplusplus | ||
27 | extern "C" { | ||
28 | #endif /* #ifdef __cplusplus */ | ||
29 | |||
30 | |||
31 | #define XDF_NEED_MINIMAL (1 << 1) | ||
32 | #define XDF_IGNORE_WHITESPACE (1 << 2) | ||
33 | #define XDF_IGNORE_WHITESPACE_CHANGE (1 << 3) | ||
34 | #define XDF_WHITESPACE_FLAGS (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE) | ||
35 | |||
36 | #define XDL_PATCH_NORMAL '-' | ||
37 | #define XDL_PATCH_REVERSE '+' | ||
38 | #define XDL_PATCH_MODEMASK ((1 << 8) - 1) | ||
39 | #define XDL_PATCH_IGNOREBSPACE (1 << 8) | ||
40 | |||
41 | #define XDL_EMIT_FUNCNAMES (1 << 0) | ||
42 | #define XDL_EMIT_COMMON (1 << 1) | ||
43 | |||
44 | #define XDL_MMB_READONLY (1 << 0) | ||
45 | |||
46 | #define XDL_MMF_ATOMIC (1 << 0) | ||
47 | |||
48 | #define XDL_BDOP_INS 1 | ||
49 | #define XDL_BDOP_CPY 2 | ||
50 | #define XDL_BDOP_INSB 3 | ||
51 | |||
52 | #define XDL_MERGE_MINIMAL 0 | ||
53 | #define XDL_MERGE_EAGER 1 | ||
54 | #define XDL_MERGE_ZEALOUS 2 | ||
55 | |||
56 | typedef struct s_mmfile { | ||
57 | char *ptr; | ||
58 | long size; | ||
59 | } mmfile_t; | ||
60 | |||
61 | typedef struct s_mmbuffer { | ||
62 | char *ptr; | ||
63 | long size; | ||
64 | } mmbuffer_t; | ||
65 | |||
66 | typedef struct s_xpparam { | ||
67 | unsigned long flags; | ||
68 | } xpparam_t; | ||
69 | |||
70 | typedef struct s_xdemitcb { | ||
71 | void *priv; | ||
72 | int (*outf)(void *, mmbuffer_t *, int); | ||
73 | } xdemitcb_t; | ||
74 | |||
75 | typedef struct s_xdemitconf { | ||
76 | long ctxlen; | ||
77 | unsigned long flags; | ||
78 | } xdemitconf_t; | ||
79 | |||
80 | typedef struct s_bdiffparam { | ||
81 | long bsize; | ||
82 | } bdiffparam_t; | ||
83 | |||
84 | |||
85 | #define xdl_malloc(x) malloc(x) | ||
86 | #define xdl_free(ptr) free(ptr) | ||
87 | #define xdl_realloc(ptr,x) realloc(ptr,x) | ||
88 | |||
89 | void *xdl_mmfile_first(mmfile_t *mmf, long *size); | ||
90 | void *xdl_mmfile_next(mmfile_t *mmf, long *size); | ||
91 | long xdl_mmfile_size(mmfile_t *mmf); | ||
92 | |||
93 | int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, | ||
94 | xdemitconf_t const *xecfg, xdemitcb_t *ecb); | ||
95 | |||
96 | int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1, | ||
97 | mmfile_t *mf2, const char *name2, | ||
98 | xpparam_t const *xpp, int level, mmbuffer_t *result); | ||
99 | |||
100 | #ifdef __cplusplus | ||
101 | } | ||
102 | #endif /* #ifdef __cplusplus */ | ||
103 | |||
104 | #endif /* #if !defined(XDIFF_H) */ | ||
105 | |||