diff options
author | Lars Hjemli <hjemli@gmail.com> | 2006-12-20 21:48:27 +0000 |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2006-12-20 21:48:27 +0000 |
commit | 36aba00273e7af1b94bf8c5dd5068709d983d01e (patch) | |
tree | d9be4e6f27b115a799af40cad43445f63fbf2238 /ui-diff.c | |
parent | a53042865a4ac8b1fa1d6b37720787601e181495 (diff) | |
download | cgit-36aba00273e7af1b94bf8c5dd5068709d983d01e.tar cgit-36aba00273e7af1b94bf8c5dd5068709d983d01e.tar.gz 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>
Diffstat (limited to 'ui-diff.c')
-rw-r--r-- | ui-diff.c | 131 |
1 files changed, 131 insertions, 0 deletions
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 @@ +/* ui-diff.c: show diff between two blobs + * + * Copyright (C) 2006 Lars Hjemli + * + * Licensed under GNU General Public License v2 + * (see COPYING for full license text) + */ + +#include "cgit.h" +#include "xdiff.h" + +char *diff_buffer; +int diff_buffer_size; + + +/* + * print a single line returned from xdiff + */ +static void print_line(char *line, int len) +{ + char *class = "ctx"; + char c = line[len-1]; + + if (line[0] == '+') + class = "add"; + else if (line[0] == '-') + class = "del"; + else if (line[0] == '@') + class = "hunk"; + + htmlf("<div class='%s'>", class); + line[len-1] = '\0'; + html_txt(line); + html("</div>"); + line[len-1] = c; +} + +/* + * Receive diff-buffers from xdiff and concatenate them as + * needed across multiple callbacks. + * + * This is basically a copy of xdiff-interface.c/xdiff_outf(), + * ripped from git and modified to use globals instead of + * a special callback-struct. + */ +int diff_cb(void *priv_, mmbuffer_t *mb, int nbuf) +{ + int i; + + for (i = 0; i < nbuf; i++) { + if (mb[i].ptr[mb[i].size-1] != '\n') { + /* Incomplete line */ + diff_buffer = xrealloc(diff_buffer, + diff_buffer_size + mb[i].size); + memcpy(diff_buffer + diff_buffer_size, + mb[i].ptr, mb[i].size); + diff_buffer_size += mb[i].size; + continue; + } + + /* we have a complete line */ + if (!diff_buffer) { + print_line(mb[i].ptr, mb[i].size); + continue; + } + diff_buffer = xrealloc(diff_buffer, + diff_buffer_size + mb[i].size); + memcpy(diff_buffer + diff_buffer_size, mb[i].ptr, mb[i].size); + print_line(diff_buffer, diff_buffer_size + mb[i].size); + free(diff_buffer); + diff_buffer = NULL; + diff_buffer_size = 0; + } + if (diff_buffer) { + print_line(diff_buffer, diff_buffer_size); + free(diff_buffer); + diff_buffer = NULL; + diff_buffer_size = 0; + } + return 0; +} + +static int load_mmfile(mmfile_t *file, const unsigned char *sha1) +{ + char type[20]; + + if (is_null_sha1(sha1)) { + file->ptr = (char *)""; + file->size = 0; + } else { + file->ptr = read_sha1_file(sha1, type, &file->size); + } + return 1; +} + +static void run_diff(const unsigned char *sha1, const unsigned char *sha2) +{ + mmfile_t file1, file2; + xpparam_t diff_params; + xdemitconf_t emit_params; + xdemitcb_t emit_cb; + + if (!load_mmfile(&file1, sha1) || !load_mmfile(&file2, sha2)) { + cgit_print_error("Unable to load files for diff"); + return; + } + + diff_params.flags = XDF_NEED_MINIMAL; + + emit_params.ctxlen = 3; + emit_params.flags = XDL_EMIT_FUNCNAMES; + + emit_cb.outf = diff_cb; + + xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb); +} + + + +void cgit_print_diff(const char *old_hex, const char *new_hex) +{ + unsigned char sha1[20], sha2[20]; + + get_sha1(old_hex, sha1); + get_sha1(new_hex, sha2); + + html("<h2>diff</h2>\n"); + html("<table class='diff'><tr><td>"); + run_diff(sha1, sha2); + html("</td></tr></table>"); +} |