-rw-r--r-- | Makefile | 18 | ||||
-rw-r--r-- | cgit.c | 14 | ||||
-rw-r--r-- | cgit.css | 104 | ||||
-rw-r--r-- | cgit.h | 5 | ||||
-rw-r--r-- | cgitrc.5.txt | 17 | ||||
-rwxr-xr-x | filters/syntax-highlighting.sh | 29 | ||||
m--------- | git | 0 | ||||
-rw-r--r-- | html.c | 70 | ||||
-rw-r--r-- | html.h | 18 | ||||
-rw-r--r-- | shared.c | 1 | ||||
-rw-r--r-- | ui-commit.c | 11 | ||||
-rw-r--r-- | ui-diff.c | 62 | ||||
-rw-r--r-- | ui-log.c | 4 | ||||
-rw-r--r-- | ui-refs.c | 4 | ||||
-rw-r--r-- | ui-shared.c | 43 | ||||
-rw-r--r-- | ui-shared.h | 5 | ||||
-rw-r--r-- | ui-snapshot.c | 14 | ||||
-rw-r--r-- | ui-ssdiff.c | 369 | ||||
-rw-r--r-- | ui-ssdiff.h | 13 | ||||
-rw-r--r-- | ui-tag.c | 24 | ||||
-rw-r--r-- | ui-tree.c | 8 |
21 files changed, 745 insertions, 88 deletions
@@ -7,3 +7,3 @@ CACHE_ROOT = /var/cache/cgit | |||
7 | SHA1_HEADER = <openssl/sha.h> | 7 | SHA1_HEADER = <openssl/sha.h> |
8 | GIT_VER = 1.6.4.3 | 8 | GIT_VER = 1.7.0 |
9 | GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 | 9 | GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 |
@@ -13,2 +13,5 @@ INSTALL = install | |||
13 | # | 13 | # |
14 | # Define NO_OPENSSL to disable linking with OpenSSL and use bundled SHA1 | ||
15 | # implementation (slower). | ||
16 | # | ||
14 | # Define NEEDS_LIBICONV if linking with libc is not enough (eg. Darwin). | 17 | # Define NEEDS_LIBICONV if linking with libc is not enough (eg. Darwin). |
@@ -70,3 +73,3 @@ endif | |||
70 | 73 | ||
71 | EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lcrypto | 74 | EXTLIBS = git/libgit.a git/xdiff/lib.a -lz |
72 | OBJECTS = | 75 | OBJECTS = |
@@ -92,2 +95,3 @@ OBJECTS += ui-shared.o | |||
92 | OBJECTS += ui-snapshot.o | 95 | OBJECTS += ui-snapshot.o |
96 | OBJECTS += ui-ssdiff.o | ||
93 | OBJECTS += ui-stats.o | 97 | OBJECTS += ui-stats.o |
@@ -125,2 +129,8 @@ ifdef NO_STRCASESTR | |||
125 | endif | 129 | endif |
130 | ifdef NO_OPENSSL | ||
131 | CFLAGS += -DNO_OPENSSL | ||
132 | GIT_OPTIONS += NO_OPENSSL=1 | ||
133 | else | ||
134 | EXTLIBS += -lcrypto | ||
135 | endif | ||
126 | 136 | ||
@@ -134,4 +144,4 @@ cgit.o: VERSION | |||
134 | libgit: | 144 | libgit: |
135 | $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 libgit.a | 145 | $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 $(GIT_OPTIONS) libgit.a |
136 | $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 xdiff/lib.a | 146 | $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 $(GIT_OPTIONS) xdiff/lib.a |
137 | 147 | ||
@@ -62,2 +62,4 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value) | |||
62 | repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); | 62 | repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); |
63 | else if (!strcmp(name, "enable-remote-branches")) | ||
64 | repo->enable_remote_branches = atoi(value); | ||
63 | else if (!strcmp(name, "max-stats")) | 65 | else if (!strcmp(name, "max-stats")) |
@@ -139,2 +141,4 @@ void config_cb(const char *name, const char *value) | |||
139 | ctx.cfg.enable_log_linecount = atoi(value); | 141 | ctx.cfg.enable_log_linecount = atoi(value); |
142 | else if (!strcmp(name, "enable-remote-branches")) | ||
143 | ctx.cfg.enable_remote_branches = atoi(value); | ||
140 | else if (!strcmp(name, "enable-tree-linenumbers")) | 144 | else if (!strcmp(name, "enable-tree-linenumbers")) |
@@ -167,2 +171,4 @@ void config_cb(const char *name, const char *value) | |||
167 | ctx.cfg.max_repodesc_len = atoi(value); | 171 | ctx.cfg.max_repodesc_len = atoi(value); |
172 | else if (!strcmp(name, "max-blob-size")) | ||
173 | ctx.cfg.max_blob_size = atoi(value); | ||
168 | else if (!strcmp(name, "max-repo-count")) | 174 | else if (!strcmp(name, "max-repo-count")) |
@@ -184,2 +190,4 @@ void config_cb(const char *name, const char *value) | |||
184 | ctx.cfg.summary_tags = atoi(value); | 190 | ctx.cfg.summary_tags = atoi(value); |
191 | else if (!strcmp(name, "side-by-side-diffs")) | ||
192 | ctx.cfg.ssdiff = atoi(value); | ||
185 | else if (!strcmp(name, "agefile")) | 193 | else if (!strcmp(name, "agefile")) |
@@ -211,2 +219,4 @@ static void querystring_cb(const char *name, const char *value) | |||
211 | } else if (!strcmp(name, "url")) { | 219 | } else if (!strcmp(name, "url")) { |
220 | if (*value == '/') | ||
221 | value++; | ||
212 | ctx.qry.url = xstrdup(value); | 222 | ctx.qry.url = xstrdup(value); |
@@ -240,2 +250,4 @@ static void querystring_cb(const char *name, const char *value) | |||
240 | ctx.qry.period = xstrdup(value); | 250 | ctx.qry.period = xstrdup(value); |
251 | } else if (!strcmp(name, "ss")) { | ||
252 | ctx.qry.ssdiff = atoi(value); | ||
241 | } | 253 | } |
@@ -270,2 +282,3 @@ static void prepare_context(struct cgit_context *ctx) | |||
270 | ctx->cfg.max_repodesc_len = 80; | 282 | ctx->cfg.max_repodesc_len = 80; |
283 | ctx->cfg.max_blob_size = 0; | ||
271 | ctx->cfg.max_stats = 0; | 284 | ctx->cfg.max_stats = 0; |
@@ -281,2 +294,3 @@ static void prepare_context(struct cgit_context *ctx) | |||
281 | ctx->cfg.summary_tags = 10; | 294 | ctx->cfg.summary_tags = 10; |
295 | ctx->cfg.ssdiff = 0; | ||
282 | ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG")); | 296 | ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG")); |
@@ -164,2 +164,7 @@ table.list td a { | |||
164 | 164 | ||
165 | table.list td a.ls-dir { | ||
166 | font-weight: bold; | ||
167 | color: #00f; | ||
168 | } | ||
169 | |||
165 | table.list td a:hover { | 170 | table.list td a:hover { |
@@ -603 +608,100 @@ table.hgraph div.bar { | |||
603 | } | 608 | } |
609 | |||
610 | table.ssdiff { | ||
611 | width: 100%; | ||
612 | } | ||
613 | |||
614 | table.ssdiff td { | ||
615 | font-size: 75%; | ||
616 | font-family: monospace; | ||
617 | white-space: pre; | ||
618 | padding: 1px 4px 1px 4px; | ||
619 | border-left: solid 1px #aaa; | ||
620 | border-right: solid 1px #aaa; | ||
621 | } | ||
622 | |||
623 | table.ssdiff td.add { | ||
624 | color: black; | ||
625 | background: #cfc; | ||
626 | min-width: 50%; | ||
627 | } | ||
628 | |||
629 | table.ssdiff td.add_dark { | ||
630 | color: black; | ||
631 | background: #aca; | ||
632 | min-width: 50%; | ||
633 | } | ||
634 | |||
635 | table.ssdiff span.add { | ||
636 | background: #cfc; | ||
637 | font-weight: bold; | ||
638 | } | ||
639 | |||
640 | table.ssdiff td.del { | ||
641 | color: black; | ||
642 | background: #fcc; | ||
643 | min-width: 50%; | ||
644 | } | ||
645 | |||
646 | table.ssdiff td.del_dark { | ||
647 | color: black; | ||
648 | background: #caa; | ||
649 | min-width: 50%; | ||
650 | } | ||
651 | |||
652 | table.ssdiff span.del { | ||
653 | background: #fcc; | ||
654 | font-weight: bold; | ||
655 | } | ||
656 | |||
657 | table.ssdiff td.changed { | ||
658 | color: black; | ||
659 | background: #ffc; | ||
660 | min-width: 50%; | ||
661 | } | ||
662 | |||
663 | table.ssdiff td.changed_dark { | ||
664 | color: black; | ||
665 | background: #cca; | ||
666 | min-width: 50%; | ||
667 | } | ||
668 | |||
669 | table.ssdiff td.lineno { | ||
670 | color: black; | ||
671 | background: #eee; | ||
672 | text-align: right; | ||
673 | width: 3em; | ||
674 | min-width: 3em; | ||
675 | } | ||
676 | |||
677 | table.ssdiff td.hunk { | ||
678 | color: #black; | ||
679 | background: #ccf; | ||
680 | border-top: solid 1px #aaa; | ||
681 | border-bottom: solid 1px #aaa; | ||
682 | } | ||
683 | |||
684 | table.ssdiff td.head { | ||
685 | border-top: solid 1px #aaa; | ||
686 | border-bottom: solid 1px #aaa; | ||
687 | } | ||
688 | |||
689 | table.ssdiff td.head div.head { | ||
690 | font-weight: bold; | ||
691 | color: black; | ||
692 | } | ||
693 | |||
694 | table.ssdiff td.foot { | ||
695 | border-top: solid 1px #aaa; | ||
696 | border-left: none; | ||
697 | border-right: none; | ||
698 | border-bottom: none; | ||
699 | } | ||
700 | |||
701 | table.ssdiff td.space { | ||
702 | border: none; | ||
703 | } | ||
704 | |||
705 | table.ssdiff td.space div { | ||
706 | min-height: 3em; | ||
707 | } \ No newline at end of file | ||
@@ -74,2 +74,3 @@ struct cgit_repo { | |||
74 | int enable_log_linecount; | 74 | int enable_log_linecount; |
75 | int enable_remote_branches; | ||
75 | int max_stats; | 76 | int max_stats; |
@@ -145,2 +146,3 @@ struct cgit_query { | |||
145 | int showmsg; | 146 | int showmsg; |
147 | int ssdiff; | ||
146 | }; | 148 | }; |
@@ -180,2 +182,3 @@ struct cgit_config { | |||
180 | int enable_log_linecount; | 182 | int enable_log_linecount; |
183 | int enable_remote_branches; | ||
181 | int enable_tree_linenumbers; | 184 | int enable_tree_linenumbers; |
@@ -187,2 +190,3 @@ struct cgit_config { | |||
187 | int max_repodesc_len; | 190 | int max_repodesc_len; |
191 | int max_blob_size; | ||
188 | int max_stats; | 192 | int max_stats; |
@@ -196,2 +200,3 @@ struct cgit_config { | |||
196 | int summary_tags; | 200 | int summary_tags; |
201 | int ssdiff; | ||
197 | struct string_list mimetypes; | 202 | struct string_list mimetypes; |
diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 0c13485..d74d9e7 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt | |||
@@ -112,2 +112,7 @@ enable-log-linecount:: | |||
112 | 112 | ||
113 | enable-remote-branches:: | ||
114 | Flag which, when set to "1", will make cgit display remote branches | ||
115 | in the summary and refs views. Default value: "0". See also: | ||
116 | "repo.enable-remote-branches". | ||
117 | |||
113 | enable-tree-linenumbers:: | 118 | enable-tree-linenumbers:: |
@@ -179,2 +184,6 @@ max-repodesc-length:: | |||
179 | 184 | ||
185 | max-blob-size:: | ||
186 | Specifies the maximum size of a blob to display HTML for in KBytes. | ||
187 | Default value: "0" (limit disabled). | ||
188 | |||
180 | max-stats:: | 189 | max-stats:: |
@@ -243,2 +252,6 @@ section:: | |||
243 | 252 | ||
253 | side-by-side-diffs:: | ||
254 | If set to "1" shows side-by-side diffs instead of unidiffs per | ||
255 | default. Default value: "0". | ||
256 | |||
244 | snapshots:: | 257 | snapshots:: |
@@ -306,2 +319,6 @@ repo.enable-log-linecount:: | |||
306 | 319 | ||
320 | repo.enable-remote-branches:: | ||
321 | Flag which, when set to "1", will make cgit display remote branches | ||
322 | in the summary and refs views. Default value: <enable-remote-branches>. | ||
323 | |||
307 | repo.max-stats:: | 324 | repo.max-stats:: |
diff --git a/filters/syntax-highlighting.sh b/filters/syntax-highlighting.sh index 999ad0c..6b1c576 100755 --- a/filters/syntax-highlighting.sh +++ b/filters/syntax-highlighting.sh | |||
@@ -5,2 +5,6 @@ | |||
5 | # | 5 | # |
6 | # This script requires a shell supporting the ${var##pattern} syntax. | ||
7 | # It is supported by at least dash and bash, however busybox environments | ||
8 | # might have to use an external call to sed instead. | ||
9 | # | ||
6 | # Note: the highlight command (http://www.andre-simon.de/) uses css for syntax | 10 | # Note: the highlight command (http://www.andre-simon.de/) uses css for syntax |
@@ -22,18 +26,9 @@ | |||
22 | 26 | ||
23 | case "$1" in | 27 | # store filename and extension in local vars |
24 | *.c) | 28 | BASENAME="$1" |
25 | highlight -f -I -X -S c | 29 | EXTENSION="${BASENAME##*.}" |
26 | ;; | 30 | |
27 | *.h) | 31 | # map Makefile and Makefile.* to .mk |
28 | highlight -f -I -X -S c | 32 | [ "${BASENAME%%.*}" == "Makefile" ] && EXTENSION=mk |
29 | ;; | 33 | |
30 | *.sh) | 34 | exec highlight --force -f -I -X -S $EXTENSION 2>/dev/null |
31 | highlight -f -I -X -S sh | ||
32 | ;; | ||
33 | *.css) | ||
34 | highlight -f -I -X -S css | ||
35 | ;; | ||
36 | *) | ||
37 | highlight -f -I -X -S txt | ||
38 | ;; | ||
39 | esac | ||
diff --git a/git b/git | |||
Subproject 7fb6bcff2dece2ff9fbc5ebfe526d9b2a7e764c | Subproject e923eaeb901ff056421b9007adcbbce271caa7b | ||
@@ -15,2 +15,28 @@ | |||
15 | 15 | ||
16 | /* Percent-encoding of each character, except: a-zA-Z0-9!$()*,./:;@- */ | ||
17 | static const char* url_escape_table[256] = { | ||
18 | "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07", "%08", "%09", | ||
19 | "%0a", "%0b", "%0c", "%0d", "%0e", "%0f", "%10", "%11", "%12", "%13", | ||
20 | "%14", "%15", "%16", "%17", "%18", "%19", "%1a", "%1b", "%1c", "%1d", | ||
21 | "%1e", "%1f", "%20", 0, "%22", "%23", 0, "%25", "%26", "%27", 0, 0, 0, | ||
22 | "%2b", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "%3c", "%3d", | ||
23 | "%3e", "%3f", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
24 | 0, 0, 0, 0, 0, 0, 0, 0, 0, "%5c", 0, "%5e", 0, "%60", 0, 0, 0, 0, 0, | ||
25 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "%7b", | ||
26 | "%7c", "%7d", 0, "%7f", "%80", "%81", "%82", "%83", "%84", "%85", | ||
27 | "%86", "%87", "%88", "%89", "%8a", "%8b", "%8c", "%8d", "%8e", "%8f", | ||
28 | "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97", "%98", "%99", | ||
29 | "%9a", "%9b", "%9c", "%9d", "%9e", "%9f", "%a0", "%a1", "%a2", "%a3", | ||
30 | "%a4", "%a5", "%a6", "%a7", "%a8", "%a9", "%aa", "%ab", "%ac", "%ad", | ||
31 | "%ae", "%af", "%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7", | ||
32 | "%b8", "%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf", "%c0", "%c1", | ||
33 | "%c2", "%c3", "%c4", "%c5", "%c6", "%c7", "%c8", "%c9", "%ca", "%cb", | ||
34 | "%cc", "%cd", "%ce", "%cf", "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", | ||
35 | "%d6", "%d7", "%d8", "%d9", "%da", "%db", "%dc", "%dd", "%de", "%df", | ||
36 | "%e0", "%e1", "%e2", "%e3", "%e4", "%e5", "%e6", "%e7", "%e8", "%e9", | ||
37 | "%ea", "%eb", "%ec", "%ed", "%ee", "%ef", "%f0", "%f1", "%f2", "%f3", | ||
38 | "%f4", "%f5", "%f6", "%f7", "%f8", "%f9", "%fa", "%fb", "%fc", "%fd", | ||
39 | "%fe", "%ff" | ||
40 | }; | ||
41 | |||
16 | int htmlfd = STDOUT_FILENO; | 42 | int htmlfd = STDOUT_FILENO; |
@@ -65,5 +91,5 @@ void html_status(int code, const char *msg, int more_headers) | |||
65 | 91 | ||
66 | void html_txt(char *txt) | 92 | void html_txt(const char *txt) |
67 | { | 93 | { |
68 | char *t = txt; | 94 | const char *t = txt; |
69 | while(t && *t){ | 95 | while(t && *t){ |
@@ -86,5 +112,5 @@ void html_txt(char *txt) | |||
86 | 112 | ||
87 | void html_ntxt(int len, char *txt) | 113 | void html_ntxt(int len, const char *txt) |
88 | { | 114 | { |
89 | char *t = txt; | 115 | const char *t = txt; |
90 | while(t && *t && len--){ | 116 | while(t && *t && len--){ |
@@ -109,5 +135,5 @@ void html_ntxt(int len, char *txt) | |||
109 | 135 | ||
110 | void html_attr(char *txt) | 136 | void html_attr(const char *txt) |
111 | { | 137 | { |
112 | char *t = txt; | 138 | const char *t = txt; |
113 | while(t && *t){ | 139 | while(t && *t){ |
@@ -132,10 +158,11 @@ void html_attr(char *txt) | |||
132 | 158 | ||
133 | void html_url_path(char *txt) | 159 | void html_url_path(const char *txt) |
134 | { | 160 | { |
135 | char *t = txt; | 161 | const char *t = txt; |
136 | while(t && *t){ | 162 | while(t && *t){ |
137 | int c = *t; | 163 | int c = *t; |
138 | if (c=='"' || c=='#' || c=='\'' || c=='?') { | 164 | const char *e = url_escape_table[c]; |
165 | if (e && c!='+' && c!='&' && c!='+') { | ||
139 | write(htmlfd, txt, t - txt); | 166 | write(htmlfd, txt, t - txt); |
140 | write(htmlfd, fmt("%%%2x", c), 3); | 167 | write(htmlfd, e, 3); |
141 | txt = t+1; | 168 | txt = t+1; |
@@ -148,10 +175,11 @@ void html_url_path(char *txt) | |||
148 | 175 | ||
149 | void html_url_arg(char *txt) | 176 | void html_url_arg(const char *txt) |
150 | { | 177 | { |
151 | char *t = txt; | 178 | const char *t = txt; |
152 | while(t && *t){ | 179 | while(t && *t){ |
153 | int c = *t; | 180 | int c = *t; |
154 | if (c=='"' || c=='#' || c=='%' || c=='&' || c=='\'' || c=='+' || c=='?') { | 181 | const char *e = url_escape_table[c]; |
182 | if (e) { | ||
155 | write(htmlfd, txt, t - txt); | 183 | write(htmlfd, txt, t - txt); |
156 | write(htmlfd, fmt("%%%2x", c), 3); | 184 | write(htmlfd, e, 3); |
157 | txt = t+1; | 185 | txt = t+1; |
@@ -164,3 +192,3 @@ void html_url_arg(char *txt) | |||
164 | 192 | ||
165 | void html_hidden(char *name, char *value) | 193 | void html_hidden(const char *name, const char *value) |
166 | { | 194 | { |
@@ -173,3 +201,3 @@ void html_hidden(char *name, char *value) | |||
173 | 201 | ||
174 | void html_option(char *value, char *text, char *selected_value) | 202 | void html_option(const char *value, const char *text, const char *selected_value) |
175 | { | 203 | { |
@@ -185,3 +213,3 @@ void html_option(char *value, char *text, char *selected_value) | |||
185 | 213 | ||
186 | void html_link_open(char *url, char *title, char *class) | 214 | void html_link_open(const char *url, const char *title, const char *class) |
187 | { | 215 | { |
@@ -259,10 +287,10 @@ char *convert_query_hexchar(char *txt) | |||
259 | 287 | ||
260 | int http_parse_querystring(char *txt, void (*fn)(const char *name, const char *value)) | 288 | int http_parse_querystring(const char *txt_, void (*fn)(const char *name, const char *value)) |
261 | { | 289 | { |
262 | char *t, *value = NULL, c; | 290 | char *t, *txt, *value = NULL, c; |
263 | 291 | ||
264 | if (!txt) | 292 | if (!txt_) |
265 | return 0; | 293 | return 0; |
266 | 294 | ||
267 | t = txt = strdup(txt); | 295 | t = txt = strdup(txt_); |
268 | if (t == NULL) { | 296 | if (t == NULL) { |
@@ -9,10 +9,10 @@ extern void htmlf(const char *format,...); | |||
9 | extern void html_status(int code, const char *msg, int more_headers); | 9 | extern void html_status(int code, const char *msg, int more_headers); |
10 | extern void html_txt(char *txt); | 10 | extern void html_txt(const char *txt); |
11 | extern void html_ntxt(int len, char *txt); | 11 | extern void html_ntxt(int len, const char *txt); |
12 | extern void html_attr(char *txt); | 12 | extern void html_attr(const char *txt); |
13 | extern void html_url_path(char *txt); | 13 | extern void html_url_path(const char *txt); |
14 | extern void html_url_arg(char *txt); | 14 | extern void html_url_arg(const char *txt); |
15 | extern void html_hidden(char *name, char *value); | 15 | extern void html_hidden(const char *name, const char *value); |
16 | extern void html_option(char *value, char *text, char *selected_value); | 16 | extern void html_option(const char *value, const char *text, const char *selected_value); |
17 | extern void html_link_open(char *url, char *title, char *class); | 17 | extern void html_link_open(const char *url, const char *title, const char *class); |
18 | extern void html_link_close(void); | 18 | extern void html_link_close(void); |
@@ -21,3 +21,3 @@ extern int html_include(const char *filename); | |||
21 | 21 | ||
22 | extern int http_parse_querystring(char *txt, void (*fn)(const char *name, const char *value)); | 22 | extern int http_parse_querystring(const char *txt, void (*fn)(const char *name, const char *value)); |
23 | 23 | ||
@@ -61,2 +61,3 @@ struct cgit_repo *cgit_add_repo(const char *url) | |||
61 | ret->enable_log_linecount = ctx.cfg.enable_log_linecount; | 61 | ret->enable_log_linecount = ctx.cfg.enable_log_linecount; |
62 | ret->enable_remote_branches = ctx.cfg.enable_remote_branches; | ||
62 | ret->max_stats = ctx.cfg.max_stats; | 63 | ret->max_stats = ctx.cfg.max_stats; |
diff --git a/ui-commit.c b/ui-commit.c index f5b0ae5..b5e3c01 100644 --- a/ui-commit.c +++ b/ui-commit.c | |||
@@ -60,5 +60,10 @@ void cgit_print_commit(char *hex) | |||
60 | tmp = sha1_to_hex(commit->object.sha1); | 60 | tmp = sha1_to_hex(commit->object.sha1); |
61 | cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp); | 61 | cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp, 0); |
62 | html(" ("); | 62 | html(" ("); |
63 | cgit_patch_link("patch", NULL, NULL, NULL, tmp); | 63 | cgit_patch_link("patch", NULL, NULL, NULL, tmp); |
64 | html(") ("); | ||
65 | if ((ctx.qry.ssdiff && !ctx.cfg.ssdiff) || (!ctx.qry.ssdiff && ctx.cfg.ssdiff)) | ||
66 | cgit_commit_link("unidiff", NULL, NULL, ctx.qry.head, tmp, 1); | ||
67 | else | ||
68 | cgit_commit_link("side-by-side diff", NULL, NULL, ctx.qry.head, tmp, 1); | ||
64 | html(")</td></tr>\n"); | 69 | html(")</td></tr>\n"); |
@@ -80,6 +85,6 @@ void cgit_print_commit(char *hex) | |||
80 | cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL, | 85 | cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL, |
81 | ctx.qry.head, sha1_to_hex(p->item->object.sha1)); | 86 | ctx.qry.head, sha1_to_hex(p->item->object.sha1), 0); |
82 | html(" ("); | 87 | html(" ("); |
83 | cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex, | 88 | cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex, |
84 | sha1_to_hex(p->item->object.sha1), NULL); | 89 | sha1_to_hex(p->item->object.sha1), NULL, 0); |
85 | html(")</td></tr>"); | 90 | html(")</td></tr>"); |
@@ -11,2 +11,3 @@ | |||
11 | #include "ui-shared.h" | 11 | #include "ui-shared.h" |
12 | #include "ui-ssdiff.h" | ||
12 | 13 | ||
@@ -34,2 +35,3 @@ static struct fileinfo { | |||
34 | 35 | ||
36 | static int use_ssdiff = 0; | ||
35 | 37 | ||
@@ -85,3 +87,3 @@ static void print_fileinfo(struct fileinfo *info) | |||
85 | cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, ctx.qry.sha1, | 87 | cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, ctx.qry.sha1, |
86 | ctx.qry.sha2, info->new_path); | 88 | ctx.qry.sha2, info->new_path, 0); |
87 | if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED) | 89 | if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED) |
@@ -160,3 +162,3 @@ void cgit_print_diffstat(const unsigned char *old_sha1, | |||
160 | cgit_diff_link("Diffstat", NULL, NULL, ctx.qry.head, ctx.qry.sha1, | 162 | cgit_diff_link("Diffstat", NULL, NULL, ctx.qry.head, ctx.qry.sha1, |
161 | ctx.qry.sha2, NULL); | 163 | ctx.qry.sha2, NULL, 0); |
162 | html("</div>"); | 164 | html("</div>"); |
@@ -248,2 +250,15 @@ static void header(unsigned char *sha1, char *path1, int mode1, | |||
248 | 250 | ||
251 | static void print_ssdiff_link() | ||
252 | { | ||
253 | if (!strcmp(ctx.qry.page, "diff")) { | ||
254 | if (use_ssdiff) | ||
255 | cgit_diff_link("Unidiff", NULL, NULL, ctx.qry.head, | ||
256 | ctx.qry.sha1, ctx.qry.sha2, ctx.qry.path, 1); | ||
257 | else | ||
258 | cgit_diff_link("Side-by-side diff", NULL, NULL, | ||
259 | ctx.qry.head, ctx.qry.sha1, | ||
260 | ctx.qry.sha2, ctx.qry.path, 1); | ||
261 | } | ||
262 | } | ||
263 | |||
249 | static void filepair_cb(struct diff_filepair *pair) | 264 | static void filepair_cb(struct diff_filepair *pair) |
@@ -253,17 +268,32 @@ static void filepair_cb(struct diff_filepair *pair) | |||
253 | int binary = 0; | 268 | int binary = 0; |
269 | linediff_fn print_line_fn = print_line; | ||
254 | 270 | ||
271 | if (use_ssdiff) { | ||
272 | cgit_ssdiff_header_begin(); | ||
273 | print_line_fn = cgit_ssdiff_line_cb; | ||
274 | } | ||
255 | header(pair->one->sha1, pair->one->path, pair->one->mode, | 275 | header(pair->one->sha1, pair->one->path, pair->one->mode, |
256 | pair->two->sha1, pair->two->path, pair->two->mode); | 276 | pair->two->sha1, pair->two->path, pair->two->mode); |
277 | if (use_ssdiff) | ||
278 | cgit_ssdiff_header_end(); | ||
257 | if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) { | 279 | if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) { |
258 | if (S_ISGITLINK(pair->one->mode)) | 280 | if (S_ISGITLINK(pair->one->mode)) |
259 | print_line(fmt("-Subproject %s", sha1_to_hex(pair->one->sha1)), 52); | 281 | print_line_fn(fmt("-Subproject %s", sha1_to_hex(pair->one->sha1)), 52); |
260 | if (S_ISGITLINK(pair->two->mode)) | 282 | if (S_ISGITLINK(pair->two->mode)) |
261 | print_line(fmt("+Subproject %s", sha1_to_hex(pair->two->sha1)), 52); | 283 | print_line_fn(fmt("+Subproject %s", sha1_to_hex(pair->two->sha1)), 52); |
284 | if (use_ssdiff) | ||
285 | cgit_ssdiff_footer(); | ||
262 | return; | 286 | return; |
263 | } | 287 | } |
264 | if (cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size, | 288 | if (cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size, |
265 | &new_size, &binary, print_line)) | 289 | &new_size, &binary, print_line_fn)) |
266 | cgit_print_error("Error running diff"); | 290 | cgit_print_error("Error running diff"); |
267 | if (binary) | 291 | if (binary) { |
268 | html("Binary files differ"); | 292 | if (use_ssdiff) |
293 | html("<tr><td colspan='4'>Binary files differ</td></tr>"); | ||
294 | else | ||
295 | html("Binary files differ"); | ||
296 | } | ||
297 | if (use_ssdiff) | ||
298 | cgit_ssdiff_footer(); | ||
269 | } | 299 | } |
@@ -305,8 +335,18 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, const char *prefi | |||
305 | } | 335 | } |
336 | |||
337 | if ((ctx.qry.ssdiff && !ctx.cfg.ssdiff) || (!ctx.qry.ssdiff && ctx.cfg.ssdiff)) | ||
338 | use_ssdiff = 1; | ||
339 | |||
340 | print_ssdiff_link(); | ||
306 | cgit_print_diffstat(old_rev_sha1, new_rev_sha1); | 341 | cgit_print_diffstat(old_rev_sha1, new_rev_sha1); |
307 | 342 | ||
308 | html("<table summary='diff' class='diff'>"); | 343 | if (use_ssdiff) { |
309 | html("<tr><td>"); | 344 | html("<table summary='ssdiff' class='ssdiff'>"); |
345 | } else { | ||
346 | html("<table summary='diff' class='diff'>"); | ||
347 | html("<tr><td>"); | ||
348 | } | ||
310 | cgit_diff_tree(old_rev_sha1, new_rev_sha1, filepair_cb, prefix); | 349 | cgit_diff_tree(old_rev_sha1, new_rev_sha1, filepair_cb, prefix); |
311 | html("</td></tr>"); | 350 | if (!use_ssdiff) |
351 | html("</td></tr>"); | ||
312 | html("</table>"); | 352 | html("</table>"); |
@@ -68,3 +68,3 @@ void show_commit_decorations(struct commit *commit) | |||
68 | cgit_commit_link(buf, NULL, "deco", ctx.qry.head, | 68 | cgit_commit_link(buf, NULL, "deco", ctx.qry.head, |
69 | sha1_to_hex(commit->object.sha1)); | 69 | sha1_to_hex(commit->object.sha1), 0); |
70 | } | 70 | } |
@@ -91,3 +91,3 @@ void print_commit(struct commit *commit) | |||
91 | cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, | 91 | cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, |
92 | sha1_to_hex(commit->object.sha1)); | 92 | sha1_to_hex(commit->object.sha1), 0); |
93 | show_commit_decorations(commit); | 93 | show_commit_decorations(commit); |
@@ -76,3 +76,3 @@ static int print_branch(struct refinfo *ref) | |||
76 | if (ref->object->type == OBJ_COMMIT) { | 76 | if (ref->object->type == OBJ_COMMIT) { |
77 | cgit_commit_link(info->subject, NULL, NULL, name, NULL); | 77 | cgit_commit_link(info->subject, NULL, NULL, name, NULL, 0); |
78 | html("</td><td>"); | 78 | html("</td><td>"); |
@@ -189,2 +189,4 @@ void cgit_print_branches(int maxcount) | |||
189 | for_each_branch_ref(cgit_refs_cb, &list); | 189 | for_each_branch_ref(cgit_refs_cb, &list); |
190 | if (ctx.repo->enable_remote_branches) | ||
191 | for_each_remote_ref(cgit_refs_cb, &list); | ||
190 | 192 | ||
diff --git a/ui-shared.c b/ui-shared.c index 8a7cc32..8827fff 100644 --- a/ui-shared.c +++ b/ui-shared.c | |||
@@ -319,3 +319,3 @@ void cgit_log_link(char *name, char *title, char *class, char *head, | |||
319 | void cgit_commit_link(char *name, char *title, char *class, char *head, | 319 | void cgit_commit_link(char *name, char *title, char *class, char *head, |
320 | char *rev) | 320 | char *rev, int toggle_ssdiff) |
321 | { | 321 | { |
@@ -327,3 +327,19 @@ void cgit_commit_link(char *name, char *title, char *class, char *head, | |||
327 | } | 327 | } |
328 | reporevlink("commit", name, title, class, head, rev, NULL); | 328 | |
329 | char *delim; | ||
330 | |||
331 | delim = repolink(title, class, "commit", head, NULL); | ||
332 | if (rev && strcmp(rev, ctx.qry.head)) { | ||
333 | html(delim); | ||
334 | html("id="); | ||
335 | html_url_arg(rev); | ||
336 | delim = "&"; | ||
337 | } | ||
338 | if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) { | ||
339 | html(delim); | ||
340 | html("ss=1"); | ||
341 | } | ||
342 | html("'>"); | ||
343 | html_txt(name); | ||
344 | html("</a>"); | ||
329 | } | 345 | } |
@@ -343,3 +359,4 @@ void cgit_snapshot_link(char *name, char *title, char *class, char *head, | |||
343 | void cgit_diff_link(char *name, char *title, char *class, char *head, | 359 | void cgit_diff_link(char *name, char *title, char *class, char *head, |
344 | char *new_rev, char *old_rev, char *path) | 360 | char *new_rev, char *old_rev, char *path, |
361 | int toggle_ssdiff) | ||
345 | { | 362 | { |
@@ -358,2 +375,7 @@ void cgit_diff_link(char *name, char *title, char *class, char *head, | |||
358 | html_url_arg(old_rev); | 375 | html_url_arg(old_rev); |
376 | delim = "&"; | ||
377 | } | ||
378 | if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) { | ||
379 | html(delim); | ||
380 | html("ss=1"); | ||
359 | } | 381 | } |
@@ -385,3 +407,3 @@ void cgit_object_link(struct object *obj) | |||
385 | cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL, | 407 | cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL, |
386 | ctx.qry.head, fullrev); | 408 | ctx.qry.head, fullrev, 0); |
387 | return; | 409 | return; |
@@ -697,5 +719,5 @@ void cgit_print_pageheader(struct cgit_context *ctx) | |||
697 | cgit_commit_link("commit", NULL, hc(cmd, "commit"), | 719 | cgit_commit_link("commit", NULL, hc(cmd, "commit"), |
698 | ctx->qry.head, ctx->qry.sha1); | 720 | ctx->qry.head, ctx->qry.sha1, 0); |
699 | cgit_diff_link("diff", NULL, hc(cmd, "diff"), ctx->qry.head, | 721 | cgit_diff_link("diff", NULL, hc(cmd, "diff"), ctx->qry.head, |
700 | ctx->qry.sha1, ctx->qry.sha2, NULL); | 722 | ctx->qry.sha1, ctx->qry.sha2, NULL, 0); |
701 | if (ctx->repo->max_stats) | 723 | if (ctx->repo->max_stats) |
@@ -762,4 +784,10 @@ void cgit_print_snapshot_links(const char *repo, const char *head, | |||
762 | const struct cgit_snapshot_format* f; | 784 | const struct cgit_snapshot_format* f; |
785 | char *prefix; | ||
763 | char *filename; | 786 | char *filename; |
787 | unsigned char sha1[20]; | ||
764 | 788 | ||
789 | if (get_sha1(fmt("refs/tags/%s", hex), sha1) == 0 && | ||
790 | (hex[0] == 'v' || hex[0] == 'V') && isdigit(hex[1])) | ||
791 | hex++; | ||
792 | prefix = xstrdup(fmt("%s-%s", cgit_repobasename(repo), hex)); | ||
765 | for (f = cgit_snapshot_formats; f->suffix; f++) { | 793 | for (f = cgit_snapshot_formats; f->suffix; f++) { |
@@ -767,4 +795,3 @@ void cgit_print_snapshot_links(const char *repo, const char *head, | |||
767 | continue; | 795 | continue; |
768 | filename = fmt("%s-%s%s", cgit_repobasename(repo), hex, | 796 | filename = fmt("%s%s", prefix, f->suffix); |
769 | f->suffix); | ||
770 | cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename); | 797 | cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename); |
diff --git a/ui-shared.h b/ui-shared.h index b12aa89..9ebc1f9 100644 --- a/ui-shared.h +++ b/ui-shared.h | |||
@@ -25,3 +25,3 @@ extern void cgit_log_link(char *name, char *title, char *class, char *head, | |||
25 | extern void cgit_commit_link(char *name, char *title, char *class, char *head, | 25 | extern void cgit_commit_link(char *name, char *title, char *class, char *head, |
26 | char *rev); | 26 | char *rev, int toggle_ssdiff); |
27 | extern void cgit_patch_link(char *name, char *title, char *class, char *head, | 27 | extern void cgit_patch_link(char *name, char *title, char *class, char *head, |
@@ -33,3 +33,4 @@ extern void cgit_snapshot_link(char *name, char *title, char *class, | |||
33 | extern void cgit_diff_link(char *name, char *title, char *class, char *head, | 33 | extern void cgit_diff_link(char *name, char *title, char *class, char *head, |
34 | char *new_rev, char *old_rev, char *path); | 34 | char *new_rev, char *old_rev, char *path, |
35 | int toggle_ssdiff); | ||
35 | extern void cgit_stats_link(char *name, char *title, char *class, char *head, | 36 | extern void cgit_stats_link(char *name, char *title, char *class, char *head, |
diff --git a/ui-snapshot.c b/ui-snapshot.c index 4136b3e..1b25dca 100644 --- a/ui-snapshot.c +++ b/ui-snapshot.c | |||
@@ -37,7 +37,13 @@ static int write_tar_bzip2_archive(struct archiver_args *args) | |||
37 | 37 | ||
38 | static int write_tar_xz_archive(struct archiver_args *args) | ||
39 | { | ||
40 | return write_compressed_tar_archive(args,"xz"); | ||
41 | } | ||
42 | |||
38 | const struct cgit_snapshot_format cgit_snapshot_formats[] = { | 43 | const struct cgit_snapshot_format cgit_snapshot_formats[] = { |
39 | { ".zip", "application/x-zip", write_zip_archive, 0x1 }, | 44 | { ".zip", "application/x-zip", write_zip_archive, 0x01 }, |
40 | { ".tar.gz", "application/x-gzip", write_tar_gzip_archive, 0x2 }, | 45 | { ".tar.gz", "application/x-gzip", write_tar_gzip_archive, 0x02 }, |
41 | { ".tar.bz2", "application/x-bzip2", write_tar_bzip2_archive, 0x4 }, | 46 | { ".tar.bz2", "application/x-bzip2", write_tar_bzip2_archive, 0x04 }, |
42 | { ".tar", "application/x-tar", write_tar_archive, 0x8 }, | 47 | { ".tar", "application/x-tar", write_tar_archive, 0x08 }, |
48 | { ".tar.xz", "application/x-xz", write_tar_xz_archive, 0x10 }, | ||
43 | {} | 49 | {} |
diff --git a/ui-ssdiff.c b/ui-ssdiff.c new file mode 100644 index 0000000..408e620 --- a/dev/null +++ b/ui-ssdiff.c | |||
@@ -0,0 +1,369 @@ | |||
1 | #include "cgit.h" | ||
2 | #include "html.h" | ||
3 | #include "ui-shared.h" | ||
4 | |||
5 | extern int use_ssdiff; | ||
6 | |||
7 | static int current_old_line, current_new_line; | ||
8 | |||
9 | struct deferred_lines { | ||
10 | int line_no; | ||
11 | char *line; | ||
12 | struct deferred_lines *next; | ||
13 | }; | ||
14 | |||
15 | static struct deferred_lines *deferred_old, *deferred_old_last; | ||
16 | static struct deferred_lines *deferred_new, *deferred_new_last; | ||
17 | |||
18 | static char *longest_common_subsequence(char *A, char *B) | ||
19 | { | ||
20 | int i, j, ri; | ||
21 | int m = strlen(A); | ||
22 | int n = strlen(B); | ||
23 | int L[m + 1][n + 1]; | ||
24 | int tmp1, tmp2; | ||
25 | int lcs_length; | ||
26 | char *result; | ||
27 | |||
28 | for (i = m; i >= 0; i--) { | ||
29 | for (j = n; j >= 0; j--) { | ||
30 | if (A[i] == '\0' || B[j] == '\0') { | ||
31 | L[i][j] = 0; | ||
32 | } else if (A[i] == B[j]) { | ||
33 | L[i][j] = 1 + L[i + 1][j + 1]; | ||
34 | } else { | ||
35 | tmp1 = L[i + 1][j]; | ||
36 | tmp2 = L[i][j + 1]; | ||
37 | L[i][j] = (tmp1 > tmp2 ? tmp1 : tmp2); | ||
38 | } | ||
39 | } | ||
40 | } | ||
41 | |||
42 | lcs_length = L[0][0]; | ||
43 | result = xmalloc(lcs_length + 2); | ||
44 | memset(result, 0, sizeof(*result) * (lcs_length + 2)); | ||
45 | |||
46 | ri = 0; | ||
47 | i = 0; | ||
48 | j = 0; | ||
49 | while (i < m && j < n) { | ||
50 | if (A[i] == B[j]) { | ||
51 | result[ri] = A[i]; | ||
52 | ri += 1; | ||
53 | i += 1; | ||
54 | j += 1; | ||
55 | } else if (L[i + 1][j] >= L[i][j + 1]) { | ||
56 | i += 1; | ||
57 | } else { | ||
58 | j += 1; | ||
59 | } | ||
60 | } | ||
61 | return result; | ||
62 | } | ||
63 | |||
64 | static int line_from_hunk(char *line, char type) | ||
65 | { | ||
66 | char *buf1, *buf2; | ||
67 | int len; | ||
68 | |||
69 | buf1 = strchr(line, type); | ||
70 | if (buf1 == NULL) | ||
71 | return 0; | ||
72 | buf1 += 1; | ||
73 | buf2 = strchr(buf1, ','); | ||
74 | if (buf2 == NULL) | ||
75 | return 0; | ||
76 | len = buf2 - buf1; | ||
77 | buf2 = xmalloc(len + 1); | ||
78 | strncpy(buf2, buf1, len); | ||
79 | buf2[len] = '\0'; | ||
80 | int res = atoi(buf2); | ||
81 | free(buf2); | ||
82 | return res; | ||
83 | } | ||
84 | |||
85 | static char *replace_tabs(char *line) | ||
86 | { | ||
87 | char *prev_buf = line; | ||
88 | char *cur_buf; | ||
89 | int linelen = strlen(line); | ||
90 | int n_tabs = 0; | ||
91 | int i; | ||
92 | char *result; | ||
93 | char *spaces = " "; | ||
94 | |||
95 | if (linelen == 0) { | ||
96 | result = xmalloc(1); | ||
97 | result[0] = '\0'; | ||
98 | return result; | ||
99 | } | ||
100 | |||
101 | for (i = 0; i < linelen; i++) | ||
102 | if (line[i] == '\t') | ||
103 | n_tabs += 1; | ||
104 | result = xmalloc(linelen + n_tabs * 8 + 1); | ||
105 | result[0] = '\0'; | ||
106 | |||
107 | while (1) { | ||
108 | cur_buf = strchr(prev_buf, '\t'); | ||
109 | if (!cur_buf) { | ||
110 | strcat(result, prev_buf); | ||
111 | break; | ||
112 | } else { | ||
113 | strcat(result, " "); | ||
114 | strncat(result, spaces, 8 - (strlen(result) % 8)); | ||
115 | strncat(result, prev_buf, cur_buf - prev_buf); | ||
116 | } | ||
117 | prev_buf = cur_buf + 1; | ||
118 | } | ||
119 | return result; | ||
120 | } | ||
121 | |||
122 | static int calc_deferred_lines(struct deferred_lines *start) | ||
123 | { | ||
124 | struct deferred_lines *item = start; | ||
125 | int result = 0; | ||
126 | while (item) { | ||
127 | result += 1; | ||
128 | item = item->next; | ||
129 | } | ||
130 | return result; | ||
131 | } | ||
132 | |||
133 | static void deferred_old_add(char *line, int line_no) | ||
134 | { | ||
135 | struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines)); | ||
136 | item->line = xstrdup(line); | ||
137 | item->line_no = line_no; | ||
138 | item->next = NULL; | ||
139 | if (deferred_old) { | ||
140 | deferred_old_last->next = item; | ||
141 | deferred_old_last = item; | ||
142 | } else { | ||
143 | deferred_old = deferred_old_last = item; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | static void deferred_new_add(char *line, int line_no) | ||
148 | { | ||
149 | struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines)); | ||
150 | item->line = xstrdup(line); | ||
151 | item->line_no = line_no; | ||
152 | item->next = NULL; | ||
153 | if (deferred_new) { | ||
154 | deferred_new_last->next = item; | ||
155 | deferred_new_last = item; | ||
156 | } else { | ||
157 | deferred_new = deferred_new_last = item; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | static void print_part_with_lcs(char *class, char *line, char *lcs) | ||
162 | { | ||
163 | int line_len = strlen(line); | ||
164 | int i, j; | ||
165 | char c[2] = " "; | ||
166 | int same = 1; | ||
167 | |||
168 | j = 0; | ||
169 | for (i = 0; i < line_len; i++) { | ||
170 | c[0] = line[i]; | ||
171 | if (same) { | ||
172 | if (line[i] == lcs[j]) | ||
173 | j += 1; | ||
174 | else { | ||
175 | same = 0; | ||
176 | htmlf("<span class='%s'>", class); | ||
177 | } | ||
178 | } else if (line[i] == lcs[j]) { | ||
179 | same = 1; | ||
180 | htmlf("</span>"); | ||
181 | j += 1; | ||
182 | } | ||
183 | html_txt(c); | ||
184 | } | ||
185 | } | ||
186 | |||
187 | static void print_ssdiff_line(char *class, | ||
188 | int old_line_no, | ||
189 | char *old_line, | ||
190 | int new_line_no, | ||
191 | char *new_line, int individual_chars) | ||
192 | { | ||
193 | char *lcs = NULL; | ||
194 | if (old_line) | ||
195 | old_line = replace_tabs(old_line + 1); | ||
196 | if (new_line) | ||
197 | new_line = replace_tabs(new_line + 1); | ||
198 | if (individual_chars && old_line && new_line) | ||
199 | lcs = longest_common_subsequence(old_line, new_line); | ||
200 | html("<tr>"); | ||
201 | if (old_line_no > 0) | ||
202 | htmlf("<td class='lineno'>%d</td><td class='%s'>", | ||
203 | old_line_no, class); | ||
204 | else if (old_line) | ||
205 | htmlf("<td class='lineno'></td><td class='%s'>", class); | ||
206 | else | ||
207 | htmlf("<td class='lineno'></td><td class='%s_dark'>", class); | ||
208 | if (old_line) { | ||
209 | if (lcs) | ||
210 | print_part_with_lcs("del", old_line, lcs); | ||
211 | else | ||
212 | html_txt(old_line); | ||
213 | } | ||
214 | |||
215 | html("</td>"); | ||
216 | if (new_line_no > 0) | ||
217 | htmlf("<td class='lineno'>%d</td><td class='%s'>", | ||
218 | new_line_no, class); | ||
219 | else if (new_line) | ||
220 | htmlf("<td class='lineno'></td><td class='%s'>", class); | ||
221 | else | ||
222 | htmlf("<td class='lineno'></td><td class='%s_dark'>", class); | ||
223 | if (new_line) { | ||
224 | if (lcs) | ||
225 | print_part_with_lcs("add", new_line, lcs); | ||
226 | else | ||
227 | html_txt(new_line); | ||
228 | } | ||
229 | |||
230 | html("</td></tr>"); | ||
231 | if (lcs) | ||
232 | free(lcs); | ||
233 | if (new_line) | ||
234 | free(new_line); | ||
235 | if (old_line) | ||
236 | free(old_line); | ||
237 | } | ||
238 | |||
239 | static void print_deferred_old_lines() | ||
240 | { | ||
241 | struct deferred_lines *iter_old, *tmp; | ||
242 | iter_old = deferred_old; | ||
243 | while (iter_old) { | ||
244 | print_ssdiff_line("del", iter_old->line_no, | ||
245 | iter_old->line, -1, NULL, 0); | ||
246 | tmp = iter_old->next; | ||
247 | free(iter_old); | ||
248 | iter_old = tmp; | ||
249 | } | ||
250 | } | ||
251 | |||
252 | static void print_deferred_new_lines() | ||
253 | { | ||
254 | struct deferred_lines *iter_new, *tmp; | ||
255 | iter_new = deferred_new; | ||
256 | while (iter_new) { | ||
257 | print_ssdiff_line("add", -1, NULL, | ||
258 | iter_new->line_no, iter_new->line, 0); | ||
259 | tmp = iter_new->next; | ||
260 | free(iter_new); | ||
261 | iter_new = tmp; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | static void print_deferred_changed_lines() | ||
266 | { | ||
267 | struct deferred_lines *iter_old, *iter_new, *tmp; | ||
268 | int n_old_lines = calc_deferred_lines(deferred_old); | ||
269 | int n_new_lines = calc_deferred_lines(deferred_new); | ||
270 | int individual_chars = (n_old_lines == n_new_lines ? 1 : 0); | ||
271 | |||
272 | iter_old = deferred_old; | ||
273 | iter_new = deferred_new; | ||
274 | while (iter_old || iter_new) { | ||
275 | if (iter_old && iter_new) | ||
276 | print_ssdiff_line("changed", iter_old->line_no, | ||
277 | iter_old->line, | ||
278 | iter_new->line_no, iter_new->line, | ||
279 | individual_chars); | ||
280 | else if (iter_old) | ||
281 | print_ssdiff_line("changed", iter_old->line_no, | ||
282 | iter_old->line, -1, NULL, 0); | ||
283 | else if (iter_new) | ||
284 | print_ssdiff_line("changed", -1, NULL, | ||
285 | iter_new->line_no, iter_new->line, 0); | ||
286 | if (iter_old) { | ||
287 | tmp = iter_old->next; | ||
288 | free(iter_old); | ||
289 | iter_old = tmp; | ||
290 | } | ||
291 | |||
292 | if (iter_new) { | ||
293 | tmp = iter_new->next; | ||
294 | free(iter_new); | ||
295 | iter_new = tmp; | ||
296 | } | ||
297 | } | ||
298 | } | ||
299 | |||
300 | void cgit_ssdiff_print_deferred_lines() | ||
301 | { | ||
302 | if (!deferred_old && !deferred_new) | ||
303 | return; | ||
304 | if (deferred_old && !deferred_new) | ||
305 | print_deferred_old_lines(); | ||
306 | else if (!deferred_old && deferred_new) | ||
307 | print_deferred_new_lines(); | ||
308 | else | ||
309 | print_deferred_changed_lines(); | ||
310 | deferred_old = deferred_old_last = NULL; | ||
311 | deferred_new = deferred_new_last = NULL; | ||
312 | } | ||
313 | |||
314 | /* | ||
315 | * print a single line returned from xdiff | ||
316 | */ | ||
317 | void cgit_ssdiff_line_cb(char *line, int len) | ||
318 | { | ||
319 | char c = line[len - 1]; | ||
320 | line[len - 1] = '\0'; | ||
321 | if (line[0] == '@') { | ||
322 | current_old_line = line_from_hunk(line, '-'); | ||
323 | current_new_line = line_from_hunk(line, '+'); | ||
324 | } | ||
325 | |||
326 | if (line[0] == ' ') { | ||
327 | if (deferred_old || deferred_new) | ||
328 | cgit_ssdiff_print_deferred_lines(); | ||
329 | print_ssdiff_line("ctx", current_old_line, line, | ||
330 | current_new_line, line, 0); | ||
331 | current_old_line += 1; | ||
332 | current_new_line += 1; | ||
333 | } else if (line[0] == '+') { | ||
334 | deferred_new_add(line, current_new_line); | ||
335 | current_new_line += 1; | ||
336 | } else if (line[0] == '-') { | ||
337 | deferred_old_add(line, current_old_line); | ||
338 | current_old_line += 1; | ||
339 | } else if (line[0] == '@') { | ||
340 | html("<tr><td colspan='4' class='hunk'>"); | ||
341 | html_txt(line); | ||
342 | html("</td></tr>"); | ||
343 | } else { | ||
344 | html("<tr><td colspan='4' class='ctx'>"); | ||
345 | html_txt(line); | ||
346 | html("</td></tr>"); | ||
347 | } | ||
348 | line[len - 1] = c; | ||
349 | } | ||
350 | |||
351 | void cgit_ssdiff_header_begin() | ||
352 | { | ||
353 | current_old_line = -1; | ||
354 | current_new_line = -1; | ||
355 | html("<tr><td class='space' colspan='4'><div></div></td></tr>"); | ||
356 | html("<tr><td class='head' colspan='4'>"); | ||
357 | } | ||
358 | |||
359 | void cgit_ssdiff_header_end() | ||
360 | { | ||
361 | html("</td><tr>"); | ||
362 | } | ||
363 | |||
364 | void cgit_ssdiff_footer() | ||
365 | { | ||
366 | if (deferred_old || deferred_new) | ||
367 | cgit_ssdiff_print_deferred_lines(); | ||
368 | html("<tr><td class='foot' colspan='4'></td></tr>"); | ||
369 | } | ||
diff --git a/ui-ssdiff.h b/ui-ssdiff.h new file mode 100644 index 0000000..64b4b12 --- a/dev/null +++ b/ui-ssdiff.h | |||
@@ -0,0 +1,13 @@ | |||
1 | #ifndef UI_SSDIFF_H | ||
2 | #define UI_SSDIFF_H | ||
3 | |||
4 | extern void cgit_ssdiff_print_deferred_lines(); | ||
5 | |||
6 | extern void cgit_ssdiff_line_cb(char *line, int len); | ||
7 | |||
8 | extern void cgit_ssdiff_header_begin(); | ||
9 | extern void cgit_ssdiff_header_end(); | ||
10 | |||
11 | extern void cgit_ssdiff_footer(); | ||
12 | |||
13 | #endif /* UI_SSDIFF_H */ | ||
@@ -32,2 +32,10 @@ static void print_tag_content(char *buf) | |||
32 | 32 | ||
33 | void print_download_links(char *revname) | ||
34 | { | ||
35 | html("<tr><th>download</th><td class='sha1'>"); | ||
36 | cgit_print_snapshot_links(ctx.qry.repo, ctx.qry.head, | ||
37 | revname, ctx.repo->snapshots); | ||
38 | html("</td></tr>"); | ||
39 | } | ||
40 | |||
33 | void cgit_print_tag(char *revname) | 41 | void cgit_print_tag(char *revname) |
@@ -58,3 +66,3 @@ void cgit_print_tag(char *revname) | |||
58 | html("<table class='commit-info'>\n"); | 66 | html("<table class='commit-info'>\n"); |
59 | htmlf("<tr><td>Tag name</td><td>"); | 67 | htmlf("<tr><td>tag name</td><td>"); |
60 | html_txt(revname); | 68 | html_txt(revname); |
@@ -62,3 +70,3 @@ void cgit_print_tag(char *revname) | |||
62 | if (info->tagger_date > 0) { | 70 | if (info->tagger_date > 0) { |
63 | html("<tr><td>Tag date</td><td>"); | 71 | html("<tr><td>tag date</td><td>"); |
64 | cgit_print_date(info->tagger_date, FMT_LONGDATE, ctx.cfg.local_time); | 72 | cgit_print_date(info->tagger_date, FMT_LONGDATE, ctx.cfg.local_time); |
@@ -67,3 +75,3 @@ void cgit_print_tag(char *revname) | |||
67 | if (info->tagger) { | 75 | if (info->tagger) { |
68 | html("<tr><td>Tagged by</td><td>"); | 76 | html("<tr><td>tagged by</td><td>"); |
69 | html_txt(info->tagger); | 77 | html_txt(info->tagger); |
@@ -75,5 +83,7 @@ void cgit_print_tag(char *revname) | |||
75 | } | 83 | } |
76 | html("<tr><td>Tagged object</td><td>"); | 84 | html("<tr><td>tagged object</td><td class='sha1'>"); |
77 | cgit_object_link(tag->tagged); | 85 | cgit_object_link(tag->tagged); |
78 | html("</td></tr>\n"); | 86 | html("</td></tr>\n"); |
87 | if (ctx.repo->snapshots) | ||
88 | print_download_links(revname); | ||
79 | html("</table>\n"); | 89 | html("</table>\n"); |
@@ -82,8 +92,10 @@ void cgit_print_tag(char *revname) | |||
82 | html("<table class='commit-info'>\n"); | 92 | html("<table class='commit-info'>\n"); |
83 | htmlf("<tr><td>Tag name</td><td>"); | 93 | htmlf("<tr><td>tag name</td><td>"); |
84 | html_txt(revname); | 94 | html_txt(revname); |
85 | html("</td></tr>\n"); | 95 | html("</td></tr>\n"); |
86 | html("<tr><td>Tagged object</td><td>"); | 96 | html("<tr><td>Tagged object</td><td class='sha1'>"); |
87 | cgit_object_link(obj); | 97 | cgit_object_link(obj); |
88 | html("</td></tr>\n"); | 98 | html("</td></tr>\n"); |
99 | if (ctx.repo->snapshots) | ||
100 | print_download_links(revname); | ||
89 | html("</table>\n"); | 101 | html("</table>\n"); |
@@ -109,2 +109,8 @@ static void print_object(const unsigned char *sha1, char *path, const char *base | |||
109 | 109 | ||
110 | if (ctx.cfg.max_blob_size && size / 1024 > ctx.cfg.max_blob_size) { | ||
111 | htmlf("<div class='error'>blob size (%dKB) exceeds display size limit (%dKB).</div>", | ||
112 | size / 1024, ctx.cfg.max_blob_size); | ||
113 | return; | ||
114 | } | ||
115 | |||
110 | if (buffer_is_binary(buf, size)) | 116 | if (buffer_is_binary(buf, size)) |
@@ -171,2 +177,4 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen, | |||
171 | fullpath); | 177 | fullpath); |
178 | cgit_plain_link("plain", NULL, "button", ctx.qry.head, curr_rev, | ||
179 | fullpath); | ||
172 | html("</td></tr>\n"); | 180 | html("</td></tr>\n"); |