Fossil SCM

Add the --webpage option to the various "diff" commands. This option causes the diff output to be in the form of a stand-alone webpage that can be sent to a remote collaborator (for example via a chat attachment).

drh 2021-08-25 16:10 trunk
Commit ea52b7d06cf7c0493c7e5c74b8925173e2d8689e5d81b964ab54bdbeb7b64f28
+8
--- src/diff.c
+++ src/diff.c
@@ -42,10 +42,11 @@
4242
#define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
4343
#define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
4444
#define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */
4545
#define DIFF_STRIP_EOLCR (((u64)0x10)<<32) /* Strip trailing CR */
4646
#define DIFF_SLOW_SBS (((u64)0x20)<<32) /* Better but slower side-by-side */
47
+#define DIFF_WEBPAGE (((u64)0x40)<<32) /* Complete webpage */
4748
4849
/*
4950
** These error messages are shared in multiple locations. They are defined
5051
** here for consistency.
5152
*/
@@ -365,10 +366,11 @@
365366
int showDivider = 0; /* True to show the divider between diff blocks */
366367
367368
nContext = diff_context_lines(diffFlags);
368369
showLn = (diffFlags & DIFF_LINENO)!=0;
369370
html = (diffFlags & DIFF_HTML)!=0;
371
+ if( html ) blob_append(pOut, "<pre class=\"udiff\">\n", -1);
370372
A = p->aFrom;
371373
B = p->aTo;
372374
R = p->aEdit;
373375
mxr = p->nEdit;
374376
while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -500,10 +502,11 @@
500502
for(j=0; j<m; j++){
501503
if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
502504
appendDiffLine(pOut, ' ', &A[a+j], html, 0);
503505
}
504506
}
507
+ if( html ) blob_append(pOut, "</pre>\n", -1);
505508
}
506509
507510
/*
508511
** Status of a single output line
509512
*/
@@ -2035,10 +2038,13 @@
20352038
if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO;
20362039
if( find_option("noopt",0,0)!=0 ) diffFlags |= DIFF_NOOPT;
20372040
if( find_option("numstat",0,0)!=0 ) diffFlags |= DIFF_NUMSTAT;
20382041
if( find_option("invert",0,0)!=0 ) diffFlags |= DIFF_INVERT;
20392042
if( find_option("brief",0,0)!=0 ) diffFlags |= DIFF_BRIEF;
2043
+ if( find_option("webpage",0,0)!=0 ){
2044
+ diffFlags |= DIFF_HTML|DIFF_WEBPAGE|DIFF_LINENO;
2045
+ }
20402046
return diffFlags;
20412047
}
20422048
20432049
/*
20442050
** COMMAND: test-rawdiff
@@ -2094,15 +2100,17 @@
20942100
if( zErr ) fossil_fatal("regex error: %s", zErr);
20952101
}
20962102
diffFlag = diff_options();
20972103
verify_all_options();
20982104
if( g.argc!=4 ) usage("FILE1 FILE2");
2105
+ diff_header(diffFlag);
20992106
diff_print_filenames(g.argv[2], g.argv[3], diffFlag, 0);
21002107
blob_read_from_file(&a, g.argv[2], ExtFILE);
21012108
blob_read_from_file(&b, g.argv[3], ExtFILE);
21022109
blob_zero(&out);
21032110
text_diff(&a, &b, &out, pRe, diffFlag);
2111
+ diff_footer(diffFlag);
21042112
blob_write_to_file(&out, "-");
21052113
re_free(pRe);
21062114
}
21072115
21082116
/**************************************************************************
21092117
--- src/diff.c
+++ src/diff.c
@@ -42,10 +42,11 @@
42 #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
43 #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
44 #define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */
45 #define DIFF_STRIP_EOLCR (((u64)0x10)<<32) /* Strip trailing CR */
46 #define DIFF_SLOW_SBS (((u64)0x20)<<32) /* Better but slower side-by-side */
 
47
48 /*
49 ** These error messages are shared in multiple locations. They are defined
50 ** here for consistency.
51 */
@@ -365,10 +366,11 @@
365 int showDivider = 0; /* True to show the divider between diff blocks */
366
367 nContext = diff_context_lines(diffFlags);
368 showLn = (diffFlags & DIFF_LINENO)!=0;
369 html = (diffFlags & DIFF_HTML)!=0;
 
370 A = p->aFrom;
371 B = p->aTo;
372 R = p->aEdit;
373 mxr = p->nEdit;
374 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -500,10 +502,11 @@
500 for(j=0; j<m; j++){
501 if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
502 appendDiffLine(pOut, ' ', &A[a+j], html, 0);
503 }
504 }
 
505 }
506
507 /*
508 ** Status of a single output line
509 */
@@ -2035,10 +2038,13 @@
2035 if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO;
2036 if( find_option("noopt",0,0)!=0 ) diffFlags |= DIFF_NOOPT;
2037 if( find_option("numstat",0,0)!=0 ) diffFlags |= DIFF_NUMSTAT;
2038 if( find_option("invert",0,0)!=0 ) diffFlags |= DIFF_INVERT;
2039 if( find_option("brief",0,0)!=0 ) diffFlags |= DIFF_BRIEF;
 
 
 
2040 return diffFlags;
2041 }
2042
2043 /*
2044 ** COMMAND: test-rawdiff
@@ -2094,15 +2100,17 @@
2094 if( zErr ) fossil_fatal("regex error: %s", zErr);
2095 }
2096 diffFlag = diff_options();
2097 verify_all_options();
2098 if( g.argc!=4 ) usage("FILE1 FILE2");
 
2099 diff_print_filenames(g.argv[2], g.argv[3], diffFlag, 0);
2100 blob_read_from_file(&a, g.argv[2], ExtFILE);
2101 blob_read_from_file(&b, g.argv[3], ExtFILE);
2102 blob_zero(&out);
2103 text_diff(&a, &b, &out, pRe, diffFlag);
 
2104 blob_write_to_file(&out, "-");
2105 re_free(pRe);
2106 }
2107
2108 /**************************************************************************
2109
--- src/diff.c
+++ src/diff.c
@@ -42,10 +42,11 @@
42 #define DIFF_INVERT (((u64)0x02)<<32) /* Invert the diff (debug) */
43 #define DIFF_CONTEXT_EX (((u64)0x04)<<32) /* Use context even if zero */
44 #define DIFF_NOTTOOBIG (((u64)0x08)<<32) /* Only display if not too big */
45 #define DIFF_STRIP_EOLCR (((u64)0x10)<<32) /* Strip trailing CR */
46 #define DIFF_SLOW_SBS (((u64)0x20)<<32) /* Better but slower side-by-side */
47 #define DIFF_WEBPAGE (((u64)0x40)<<32) /* Complete webpage */
48
49 /*
50 ** These error messages are shared in multiple locations. They are defined
51 ** here for consistency.
52 */
@@ -365,10 +366,11 @@
366 int showDivider = 0; /* True to show the divider between diff blocks */
367
368 nContext = diff_context_lines(diffFlags);
369 showLn = (diffFlags & DIFF_LINENO)!=0;
370 html = (diffFlags & DIFF_HTML)!=0;
371 if( html ) blob_append(pOut, "<pre class=\"udiff\">\n", -1);
372 A = p->aFrom;
373 B = p->aTo;
374 R = p->aEdit;
375 mxr = p->nEdit;
376 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -500,10 +502,11 @@
502 for(j=0; j<m; j++){
503 if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
504 appendDiffLine(pOut, ' ', &A[a+j], html, 0);
505 }
506 }
507 if( html ) blob_append(pOut, "</pre>\n", -1);
508 }
509
510 /*
511 ** Status of a single output line
512 */
@@ -2035,10 +2038,13 @@
2038 if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO;
2039 if( find_option("noopt",0,0)!=0 ) diffFlags |= DIFF_NOOPT;
2040 if( find_option("numstat",0,0)!=0 ) diffFlags |= DIFF_NUMSTAT;
2041 if( find_option("invert",0,0)!=0 ) diffFlags |= DIFF_INVERT;
2042 if( find_option("brief",0,0)!=0 ) diffFlags |= DIFF_BRIEF;
2043 if( find_option("webpage",0,0)!=0 ){
2044 diffFlags |= DIFF_HTML|DIFF_WEBPAGE|DIFF_LINENO;
2045 }
2046 return diffFlags;
2047 }
2048
2049 /*
2050 ** COMMAND: test-rawdiff
@@ -2094,15 +2100,17 @@
2100 if( zErr ) fossil_fatal("regex error: %s", zErr);
2101 }
2102 diffFlag = diff_options();
2103 verify_all_options();
2104 if( g.argc!=4 ) usage("FILE1 FILE2");
2105 diff_header(diffFlag);
2106 diff_print_filenames(g.argv[2], g.argv[3], diffFlag, 0);
2107 blob_read_from_file(&a, g.argv[2], ExtFILE);
2108 blob_read_from_file(&b, g.argv[3], ExtFILE);
2109 blob_zero(&out);
2110 text_diff(&a, &b, &out, pRe, diffFlag);
2111 diff_footer(diffFlag);
2112 blob_write_to_file(&out, "-");
2113 re_free(pRe);
2114 }
2115
2116 /**************************************************************************
2117
+89 -3
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -107,11 +107,11 @@
107107
108108
/*
109109
** Print the "Index:" message that patches wants to see at the top of a diff.
110110
*/
111111
void diff_print_index(const char *zFile, u64 diffFlags, Blob *diffBlob){
112
- if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT))==0 ){
112
+ if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_WEBPAGE))==0 ){
113113
char *z = mprintf("Index: %s\n%.66c\n", zFile, '=');
114114
if( !diffBlob ){
115115
fossil_print("%s", z);
116116
}else{
117117
blob_appendf(diffBlob, "%s", z);
@@ -126,10 +126,16 @@
126126
void diff_print_filenames(const char *zLeft, const char *zRight,
127127
u64 diffFlags, Blob *diffBlob){
128128
char *z = 0;
129129
if( diffFlags & DIFF_BRIEF ){
130130
/* no-op */
131
+ }else if( diffFlags & DIFF_WEBPAGE ){
132
+ if( fossil_strcmp(zLeft,zRight)==0 ){
133
+ z = mprintf("<h1>%h</h1>\n", zLeft);
134
+ }else{
135
+ z = mprintf("<h1>%h &lrarr; %h</h1>\n", zLeft, zRight);
136
+ }
131137
}else if( diffFlags & DIFF_SIDEBYSIDE ){
132138
int w = diff_width(diffFlags);
133139
int n1 = strlen(zLeft);
134140
int n2 = strlen(zRight);
135141
int x;
@@ -154,10 +160,87 @@
154160
}else{
155161
blob_appendf(diffBlob, "%s", z);
156162
}
157163
fossil_free(z);
158164
}
165
+
166
+/*
167
+** Default header text for diff with --webpage
168
+*/
169
+static const char zWebpageHdr[] =
170
+@ <!DOCTYPE html>
171
+@ <html>
172
+@ <head>
173
+@ <style>
174
+@ table.sbsdiffcols {
175
+@ width: 90%;
176
+@ border-spacing: 0;
177
+@ font-size: xx-small;
178
+@ }
179
+@ table.sbsdiffcols td {
180
+@ padding: 0;
181
+@ vertical-align: top;
182
+@ }
183
+@ table.sbsdiffcols pre {
184
+@ margin: 0;
185
+@ padding: 0;
186
+@ border: 0;
187
+@ font-size: inherit;
188
+@ background: inherit;
189
+@ color: inherit;
190
+@ }
191
+@ div.difflncol {
192
+@ padding-right: 1em;
193
+@ text-align: right;
194
+@ color: #a0a0a0;
195
+@ }
196
+@ div.difftxtcol {
197
+@ width: 45em;
198
+@ overflow-x: auto;
199
+@ }
200
+@ div.diffmkrcol {
201
+@ padding: 0 1em;
202
+@ }
203
+@ span.diffchng {
204
+@ background-color: #c0c0ff;
205
+@ }
206
+@ span.diffadd {
207
+@ background-color: #c0ffc0;
208
+@ }
209
+@ span.diffrm {
210
+@ background-color: #ffc8c8;
211
+@ }
212
+@ span.diffhr {
213
+@ display: inline-block;
214
+@ margin: .5em 0 1em;
215
+@ color: #0000ff;
216
+@ }
217
+@ span.diffln {
218
+@ color: #a0a0a0;
219
+@ }
220
+@ </style>
221
+@ </head>
222
+@ <body>
223
+;
224
+
225
+/*
226
+** Print a header or footer on the overall diff output.
227
+**
228
+** This is only a factor for --webpage, in which case the header
229
+** is the HTML header CSS definitions and the footer is the HTML
230
+** close tags.
231
+*/
232
+void diff_header(u64 diffFlags){
233
+ if( (diffFlags & DIFF_WEBPAGE)!=0 ){
234
+ fossil_print("%s", zWebpageHdr);
235
+ }
236
+}
237
+void diff_footer(u64 diffFlags){
238
+ if( (diffFlags & DIFF_WEBPAGE)!=0 ){
239
+ fossil_print("</body></html>\n");
240
+ }
241
+}
159242
160243
/*
161244
** Show the difference between two files, one in memory and one on disk.
162245
**
163246
** The difference is the set of edits needed to transform pFile1 into
@@ -847,22 +930,23 @@
847930
** -c|--context N Use N lines of context
848931
** --diff-binary BOOL Include binary files with external commands
849932
** --exec-abs-paths Force absolute path names on external commands
850933
** --exec-rel-paths Force relative path names on external commands
851934
** -r|--from VERSION Select VERSION as source for the diff
935
+** -w|--ignore-all-space Ignore white space when comparing lines
852936
** -i|--internal Use internal diff logic
937
+** -N|--new-file Alias for --verbose
853938
** --numstat Show only the number of lines delete and added
854939
** -y|--side-by-side Side-by-side diff
855940
** --strip-trailing-cr Strip trailing CR
856941
** --tclsh PATH Tcl/Tk used for --tk (default: "tclsh")
857942
** --tk Launch a Tcl/Tk GUI for display
858943
** --to VERSION Select VERSION as target for the diff
859944
** --undo Diff against the "undo" buffer
860945
** --unified Unified diff
861946
** -v|--verbose Output complete text of added or deleted files
862
-** -N|--new-file Alias for --verbose
863
-** -w|--ignore-all-space Ignore white space when comparing lines
947
+** --webpage Format output as a stand-alone HTML webpage
864948
** -W|--width N Width of lines in side-by-side diff
865949
** -Z|--ignore-trailing-space Ignore changes to end-of-line whitespace
866950
*/
867951
void diff_cmd(void){
868952
int isGDiff; /* True for gdiff. False for normal diff */
@@ -953,10 +1037,11 @@
9531037
ridTo);
9541038
if( zFrom==0 ){
9551039
fossil_fatal("check-in %s has no parent", zTo);
9561040
}
9571041
}
1042
+ diff_header(diffFlags);
9581043
if( againstUndo ){
9591044
if( db_lget_int("undo_available",0)==0 ){
9601045
fossil_print("No undo or redo is available\n");
9611046
return;
9621047
}
@@ -980,10 +1065,11 @@
9801065
}
9811066
fossil_free(pFileDir[i].zName);
9821067
}
9831068
fossil_free(pFileDir);
9841069
}
1070
+ diff_footer(diffFlags);
9851071
if ( diffFlags & DIFF_NUMSTAT ){
9861072
fossil_print("%10d %10d TOTAL over %d changed files\n",
9871073
g.diffCnt[1], g.diffCnt[2], g.diffCnt[0]);
9881074
}
9891075
}
9901076
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -107,11 +107,11 @@
107
108 /*
109 ** Print the "Index:" message that patches wants to see at the top of a diff.
110 */
111 void diff_print_index(const char *zFile, u64 diffFlags, Blob *diffBlob){
112 if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT))==0 ){
113 char *z = mprintf("Index: %s\n%.66c\n", zFile, '=');
114 if( !diffBlob ){
115 fossil_print("%s", z);
116 }else{
117 blob_appendf(diffBlob, "%s", z);
@@ -126,10 +126,16 @@
126 void diff_print_filenames(const char *zLeft, const char *zRight,
127 u64 diffFlags, Blob *diffBlob){
128 char *z = 0;
129 if( diffFlags & DIFF_BRIEF ){
130 /* no-op */
 
 
 
 
 
 
131 }else if( diffFlags & DIFF_SIDEBYSIDE ){
132 int w = diff_width(diffFlags);
133 int n1 = strlen(zLeft);
134 int n2 = strlen(zRight);
135 int x;
@@ -154,10 +160,87 @@
154 }else{
155 blob_appendf(diffBlob, "%s", z);
156 }
157 fossil_free(z);
158 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
160 /*
161 ** Show the difference between two files, one in memory and one on disk.
162 **
163 ** The difference is the set of edits needed to transform pFile1 into
@@ -847,22 +930,23 @@
847 ** -c|--context N Use N lines of context
848 ** --diff-binary BOOL Include binary files with external commands
849 ** --exec-abs-paths Force absolute path names on external commands
850 ** --exec-rel-paths Force relative path names on external commands
851 ** -r|--from VERSION Select VERSION as source for the diff
 
852 ** -i|--internal Use internal diff logic
 
853 ** --numstat Show only the number of lines delete and added
854 ** -y|--side-by-side Side-by-side diff
855 ** --strip-trailing-cr Strip trailing CR
856 ** --tclsh PATH Tcl/Tk used for --tk (default: "tclsh")
857 ** --tk Launch a Tcl/Tk GUI for display
858 ** --to VERSION Select VERSION as target for the diff
859 ** --undo Diff against the "undo" buffer
860 ** --unified Unified diff
861 ** -v|--verbose Output complete text of added or deleted files
862 ** -N|--new-file Alias for --verbose
863 ** -w|--ignore-all-space Ignore white space when comparing lines
864 ** -W|--width N Width of lines in side-by-side diff
865 ** -Z|--ignore-trailing-space Ignore changes to end-of-line whitespace
866 */
867 void diff_cmd(void){
868 int isGDiff; /* True for gdiff. False for normal diff */
@@ -953,10 +1037,11 @@
953 ridTo);
954 if( zFrom==0 ){
955 fossil_fatal("check-in %s has no parent", zTo);
956 }
957 }
 
958 if( againstUndo ){
959 if( db_lget_int("undo_available",0)==0 ){
960 fossil_print("No undo or redo is available\n");
961 return;
962 }
@@ -980,10 +1065,11 @@
980 }
981 fossil_free(pFileDir[i].zName);
982 }
983 fossil_free(pFileDir);
984 }
 
985 if ( diffFlags & DIFF_NUMSTAT ){
986 fossil_print("%10d %10d TOTAL over %d changed files\n",
987 g.diffCnt[1], g.diffCnt[2], g.diffCnt[0]);
988 }
989 }
990
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -107,11 +107,11 @@
107
108 /*
109 ** Print the "Index:" message that patches wants to see at the top of a diff.
110 */
111 void diff_print_index(const char *zFile, u64 diffFlags, Blob *diffBlob){
112 if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_WEBPAGE))==0 ){
113 char *z = mprintf("Index: %s\n%.66c\n", zFile, '=');
114 if( !diffBlob ){
115 fossil_print("%s", z);
116 }else{
117 blob_appendf(diffBlob, "%s", z);
@@ -126,10 +126,16 @@
126 void diff_print_filenames(const char *zLeft, const char *zRight,
127 u64 diffFlags, Blob *diffBlob){
128 char *z = 0;
129 if( diffFlags & DIFF_BRIEF ){
130 /* no-op */
131 }else if( diffFlags & DIFF_WEBPAGE ){
132 if( fossil_strcmp(zLeft,zRight)==0 ){
133 z = mprintf("<h1>%h</h1>\n", zLeft);
134 }else{
135 z = mprintf("<h1>%h &lrarr; %h</h1>\n", zLeft, zRight);
136 }
137 }else if( diffFlags & DIFF_SIDEBYSIDE ){
138 int w = diff_width(diffFlags);
139 int n1 = strlen(zLeft);
140 int n2 = strlen(zRight);
141 int x;
@@ -154,10 +160,87 @@
160 }else{
161 blob_appendf(diffBlob, "%s", z);
162 }
163 fossil_free(z);
164 }
165
166 /*
167 ** Default header text for diff with --webpage
168 */
169 static const char zWebpageHdr[] =
170 @ <!DOCTYPE html>
171 @ <html>
172 @ <head>
173 @ <style>
174 @ table.sbsdiffcols {
175 @ width: 90%;
176 @ border-spacing: 0;
177 @ font-size: xx-small;
178 @ }
179 @ table.sbsdiffcols td {
180 @ padding: 0;
181 @ vertical-align: top;
182 @ }
183 @ table.sbsdiffcols pre {
184 @ margin: 0;
185 @ padding: 0;
186 @ border: 0;
187 @ font-size: inherit;
188 @ background: inherit;
189 @ color: inherit;
190 @ }
191 @ div.difflncol {
192 @ padding-right: 1em;
193 @ text-align: right;
194 @ color: #a0a0a0;
195 @ }
196 @ div.difftxtcol {
197 @ width: 45em;
198 @ overflow-x: auto;
199 @ }
200 @ div.diffmkrcol {
201 @ padding: 0 1em;
202 @ }
203 @ span.diffchng {
204 @ background-color: #c0c0ff;
205 @ }
206 @ span.diffadd {
207 @ background-color: #c0ffc0;
208 @ }
209 @ span.diffrm {
210 @ background-color: #ffc8c8;
211 @ }
212 @ span.diffhr {
213 @ display: inline-block;
214 @ margin: .5em 0 1em;
215 @ color: #0000ff;
216 @ }
217 @ span.diffln {
218 @ color: #a0a0a0;
219 @ }
220 @ </style>
221 @ </head>
222 @ <body>
223 ;
224
225 /*
226 ** Print a header or footer on the overall diff output.
227 **
228 ** This is only a factor for --webpage, in which case the header
229 ** is the HTML header CSS definitions and the footer is the HTML
230 ** close tags.
231 */
232 void diff_header(u64 diffFlags){
233 if( (diffFlags & DIFF_WEBPAGE)!=0 ){
234 fossil_print("%s", zWebpageHdr);
235 }
236 }
237 void diff_footer(u64 diffFlags){
238 if( (diffFlags & DIFF_WEBPAGE)!=0 ){
239 fossil_print("</body></html>\n");
240 }
241 }
242
243 /*
244 ** Show the difference between two files, one in memory and one on disk.
245 **
246 ** The difference is the set of edits needed to transform pFile1 into
@@ -847,22 +930,23 @@
930 ** -c|--context N Use N lines of context
931 ** --diff-binary BOOL Include binary files with external commands
932 ** --exec-abs-paths Force absolute path names on external commands
933 ** --exec-rel-paths Force relative path names on external commands
934 ** -r|--from VERSION Select VERSION as source for the diff
935 ** -w|--ignore-all-space Ignore white space when comparing lines
936 ** -i|--internal Use internal diff logic
937 ** -N|--new-file Alias for --verbose
938 ** --numstat Show only the number of lines delete and added
939 ** -y|--side-by-side Side-by-side diff
940 ** --strip-trailing-cr Strip trailing CR
941 ** --tclsh PATH Tcl/Tk used for --tk (default: "tclsh")
942 ** --tk Launch a Tcl/Tk GUI for display
943 ** --to VERSION Select VERSION as target for the diff
944 ** --undo Diff against the "undo" buffer
945 ** --unified Unified diff
946 ** -v|--verbose Output complete text of added or deleted files
947 ** --webpage Format output as a stand-alone HTML webpage
 
948 ** -W|--width N Width of lines in side-by-side diff
949 ** -Z|--ignore-trailing-space Ignore changes to end-of-line whitespace
950 */
951 void diff_cmd(void){
952 int isGDiff; /* True for gdiff. False for normal diff */
@@ -953,10 +1037,11 @@
1037 ridTo);
1038 if( zFrom==0 ){
1039 fossil_fatal("check-in %s has no parent", zTo);
1040 }
1041 }
1042 diff_header(diffFlags);
1043 if( againstUndo ){
1044 if( db_lget_int("undo_available",0)==0 ){
1045 fossil_print("No undo or redo is available\n");
1046 return;
1047 }
@@ -980,10 +1065,11 @@
1065 }
1066 fossil_free(pFileDir[i].zName);
1067 }
1068 fossil_free(pFileDir);
1069 }
1070 diff_footer(diffFlags);
1071 if ( diffFlags & DIFF_NUMSTAT ){
1072 fossil_print("%10d %10d TOTAL over %d changed files\n",
1073 g.diffCnt[1], g.diffCnt[2], g.diffCnt[0]);
1074 }
1075 }
1076
+4 -10
--- src/info.c
+++ src/info.c
@@ -335,11 +335,11 @@
335335
u64 diffFlags, /* Diff formatting flags */
336336
ReCompiled *pRe /* Only show change matching this regex */
337337
){
338338
int fromid;
339339
int toid;
340
- Blob from, to, out;
340
+ Blob from, to;
341341
if( zFrom ){
342342
fromid = uuid_to_rid(zFrom, 0);
343343
content_get(fromid, &from);
344344
}else{
345345
blob_zero(&from);
@@ -348,24 +348,18 @@
348348
toid = uuid_to_rid(zTo, 0);
349349
content_get(toid, &to);
350350
}else{
351351
blob_zero(&to);
352352
}
353
- blob_zero(&out);
354353
if( diffFlags & DIFF_SIDEBYSIDE ){
355
- text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
356
- @ %s(blob_str(&out))
354
+ diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;
357355
}else{
358
- text_diff(&from, &to, &out, pRe,
359
- diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG);
360
- @ <pre class="udiff">
361
- @ %s(blob_str(&out))
362
- @ </pre>
356
+ diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG;
363357
}
358
+ text_diff(&from, &to, cgi_output_blob(), pRe, diffFlags);
364359
blob_reset(&from);
365360
blob_reset(&to);
366
- blob_reset(&out);
367361
}
368362
369363
/*
370364
** Write a line of web-page output that shows changes that have occurred
371365
** to a file between two check-ins.
372366
--- src/info.c
+++ src/info.c
@@ -335,11 +335,11 @@
335 u64 diffFlags, /* Diff formatting flags */
336 ReCompiled *pRe /* Only show change matching this regex */
337 ){
338 int fromid;
339 int toid;
340 Blob from, to, out;
341 if( zFrom ){
342 fromid = uuid_to_rid(zFrom, 0);
343 content_get(fromid, &from);
344 }else{
345 blob_zero(&from);
@@ -348,24 +348,18 @@
348 toid = uuid_to_rid(zTo, 0);
349 content_get(toid, &to);
350 }else{
351 blob_zero(&to);
352 }
353 blob_zero(&out);
354 if( diffFlags & DIFF_SIDEBYSIDE ){
355 text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
356 @ %s(blob_str(&out))
357 }else{
358 text_diff(&from, &to, &out, pRe,
359 diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG);
360 @ <pre class="udiff">
361 @ %s(blob_str(&out))
362 @ </pre>
363 }
 
364 blob_reset(&from);
365 blob_reset(&to);
366 blob_reset(&out);
367 }
368
369 /*
370 ** Write a line of web-page output that shows changes that have occurred
371 ** to a file between two check-ins.
372
--- src/info.c
+++ src/info.c
@@ -335,11 +335,11 @@
335 u64 diffFlags, /* Diff formatting flags */
336 ReCompiled *pRe /* Only show change matching this regex */
337 ){
338 int fromid;
339 int toid;
340 Blob from, to;
341 if( zFrom ){
342 fromid = uuid_to_rid(zFrom, 0);
343 content_get(fromid, &from);
344 }else{
345 blob_zero(&from);
@@ -348,24 +348,18 @@
348 toid = uuid_to_rid(zTo, 0);
349 content_get(toid, &to);
350 }else{
351 blob_zero(&to);
352 }
 
353 if( diffFlags & DIFF_SIDEBYSIDE ){
354 diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;
 
355 }else{
356 diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG;
 
 
 
 
357 }
358 text_diff(&from, &to, cgi_output_blob(), pRe, diffFlags);
359 blob_reset(&from);
360 blob_reset(&to);
 
361 }
362
363 /*
364 ** Write a line of web-page output that shows changes that have occurred
365 ** to a file between two check-ins.
366
+6 -3
--- src/patch.c
+++ src/patch.c
@@ -724,10 +724,11 @@
724724
int fIncludeBinary, /* Do diffs against binary files */
725725
u64 diffFlags /* Other diff flags */
726726
){
727727
int nErr = 0;
728728
Stmt q;
729
+ int bWebpage = (diffFlags && DIFF_WEBPAGE)!=0;
729730
Blob empty;
730731
blob_zero(&empty);
731732
732733
if( (mFlags & PATCH_FORCE)==0 ){
733734
/* Check to ensure that the patch is against the repository that
@@ -762,11 +763,12 @@
762763
fossil_fatal("the baseline of the patch (check-in %S) is not found "
763764
"in the %s repository", zBaseline, g.zRepositoryName);
764765
}
765766
}
766767
}
767
-
768
+
769
+ diff_header(diffFlags);
768770
db_prepare(&q,
769771
"SELECT"
770772
" (SELECT blob.rid FROM blob WHERE blob.uuid=chng.hash),"
771773
" pathname," /* 1: new pathname */
772774
" origname," /* 2: original pathname. Null if not renamed */
@@ -801,21 +803,21 @@
801803
}
802804
zName = db_column_text(&q, 1);
803805
rid = db_column_int(&q, 0);
804806
805807
if( db_column_type(&q,3)==SQLITE_NULL ){
806
- fossil_print("DELETE %s\n", zName);
808
+ if( !bWebpage ) fossil_print("DELETE %s\n", zName);
807809
diff_print_index(zName, diffFlags, 0);
808810
isBin2 = 0;
809811
content_get(rid, &a);
810812
isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
811813
diff_file_mem(&a, &empty, isBin1, isBin2, zName, zDiffCmd,
812814
zBinGlob, fIncludeBinary, diffFlags);
813815
}else if( rid==0 ){
814816
db_ephemeral_blob(&q, 3, &a);
815817
blob_uncompress(&a, &a);
816
- fossil_print("ADDED %s\n", zName);
818
+ if( !bWebpage ) fossil_print("ADDED %s\n", zName);
817819
diff_print_index(zName, diffFlags, 0);
818820
isBin1 = 0;
819821
isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
820822
diff_file_mem(&empty, &a, isBin1, isBin2, zName, zDiffCmd,
821823
zBinGlob, fIncludeBinary, diffFlags);
@@ -834,10 +836,11 @@
834836
blob_reset(&b);
835837
blob_reset(&delta);
836838
}
837839
}
838840
db_finalize(&q);
841
+ diff_footer(diffFlags);
839842
if( nErr ) fossil_fatal("abort due to prior errors");
840843
}
841844
842845
843846
/*
844847
--- src/patch.c
+++ src/patch.c
@@ -724,10 +724,11 @@
724 int fIncludeBinary, /* Do diffs against binary files */
725 u64 diffFlags /* Other diff flags */
726 ){
727 int nErr = 0;
728 Stmt q;
 
729 Blob empty;
730 blob_zero(&empty);
731
732 if( (mFlags & PATCH_FORCE)==0 ){
733 /* Check to ensure that the patch is against the repository that
@@ -762,11 +763,12 @@
762 fossil_fatal("the baseline of the patch (check-in %S) is not found "
763 "in the %s repository", zBaseline, g.zRepositoryName);
764 }
765 }
766 }
767
 
768 db_prepare(&q,
769 "SELECT"
770 " (SELECT blob.rid FROM blob WHERE blob.uuid=chng.hash),"
771 " pathname," /* 1: new pathname */
772 " origname," /* 2: original pathname. Null if not renamed */
@@ -801,21 +803,21 @@
801 }
802 zName = db_column_text(&q, 1);
803 rid = db_column_int(&q, 0);
804
805 if( db_column_type(&q,3)==SQLITE_NULL ){
806 fossil_print("DELETE %s\n", zName);
807 diff_print_index(zName, diffFlags, 0);
808 isBin2 = 0;
809 content_get(rid, &a);
810 isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
811 diff_file_mem(&a, &empty, isBin1, isBin2, zName, zDiffCmd,
812 zBinGlob, fIncludeBinary, diffFlags);
813 }else if( rid==0 ){
814 db_ephemeral_blob(&q, 3, &a);
815 blob_uncompress(&a, &a);
816 fossil_print("ADDED %s\n", zName);
817 diff_print_index(zName, diffFlags, 0);
818 isBin1 = 0;
819 isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
820 diff_file_mem(&empty, &a, isBin1, isBin2, zName, zDiffCmd,
821 zBinGlob, fIncludeBinary, diffFlags);
@@ -834,10 +836,11 @@
834 blob_reset(&b);
835 blob_reset(&delta);
836 }
837 }
838 db_finalize(&q);
 
839 if( nErr ) fossil_fatal("abort due to prior errors");
840 }
841
842
843 /*
844
--- src/patch.c
+++ src/patch.c
@@ -724,10 +724,11 @@
724 int fIncludeBinary, /* Do diffs against binary files */
725 u64 diffFlags /* Other diff flags */
726 ){
727 int nErr = 0;
728 Stmt q;
729 int bWebpage = (diffFlags && DIFF_WEBPAGE)!=0;
730 Blob empty;
731 blob_zero(&empty);
732
733 if( (mFlags & PATCH_FORCE)==0 ){
734 /* Check to ensure that the patch is against the repository that
@@ -762,11 +763,12 @@
763 fossil_fatal("the baseline of the patch (check-in %S) is not found "
764 "in the %s repository", zBaseline, g.zRepositoryName);
765 }
766 }
767 }
768
769 diff_header(diffFlags);
770 db_prepare(&q,
771 "SELECT"
772 " (SELECT blob.rid FROM blob WHERE blob.uuid=chng.hash),"
773 " pathname," /* 1: new pathname */
774 " origname," /* 2: original pathname. Null if not renamed */
@@ -801,21 +803,21 @@
803 }
804 zName = db_column_text(&q, 1);
805 rid = db_column_int(&q, 0);
806
807 if( db_column_type(&q,3)==SQLITE_NULL ){
808 if( !bWebpage ) fossil_print("DELETE %s\n", zName);
809 diff_print_index(zName, diffFlags, 0);
810 isBin2 = 0;
811 content_get(rid, &a);
812 isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
813 diff_file_mem(&a, &empty, isBin1, isBin2, zName, zDiffCmd,
814 zBinGlob, fIncludeBinary, diffFlags);
815 }else if( rid==0 ){
816 db_ephemeral_blob(&q, 3, &a);
817 blob_uncompress(&a, &a);
818 if( !bWebpage ) fossil_print("ADDED %s\n", zName);
819 diff_print_index(zName, diffFlags, 0);
820 isBin1 = 0;
821 isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
822 diff_file_mem(&empty, &a, isBin1, isBin2, zName, zDiffCmd,
823 zBinGlob, fIncludeBinary, diffFlags);
@@ -834,10 +836,11 @@
836 blob_reset(&b);
837 blob_reset(&delta);
838 }
839 }
840 db_finalize(&q);
841 diff_footer(diffFlags);
842 if( nErr ) fossil_fatal("abort due to prior errors");
843 }
844
845
846 /*
847
+6 -3
--- src/stash.c
+++ src/stash.c
@@ -410,11 +410,13 @@
410410
int fIncludeBinary, /* Do diffs against binary files */
411411
u64 diffFlags /* Other diff flags */
412412
){
413413
Stmt q;
414414
Blob empty;
415
+ int bWebpage = (diffFlags & DIFF_WEBPAGE)!=0;
415416
blob_zero(&empty);
417
+ diff_header(diffFlags);
416418
db_prepare(&q,
417419
"SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta"
418420
" FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash",
419421
stashid
420422
);
@@ -427,18 +429,18 @@
427429
const char *zNew = db_column_text(&q, 5);
428430
char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
429431
Blob a, b;
430432
if( rid==0 ){
431433
db_ephemeral_blob(&q, 6, &a);
432
- fossil_print("ADDED %s\n", zNew);
434
+ if( !bWebpage ) fossil_print("ADDED %s\n", zNew);
433435
diff_print_index(zNew, diffFlags, 0);
434436
isBin1 = 0;
435437
isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
436438
diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd,
437439
zBinGlob, fIncludeBinary, diffFlags);
438440
}else if( isRemoved ){
439
- fossil_print("DELETE %s\n", zOrig);
441
+ if( !bWebpage) fossil_print("DELETE %s\n", zOrig);
440442
diff_print_index(zNew, diffFlags, 0);
441443
isBin2 = 0;
442444
if( fBaseline ){
443445
content_get(rid, &a);
444446
isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
@@ -447,11 +449,11 @@
447449
}
448450
}else{
449451
Blob delta;
450452
int isOrigLink = file_islink(zOPath);
451453
db_ephemeral_blob(&q, 6, &delta);
452
- fossil_print("CHANGED %s\n", zNew);
454
+ if( !bWebpage ) fossil_print("CHANGED %s\n", zNew);
453455
if( !isOrigLink != !isLink ){
454456
diff_print_index(zNew, diffFlags, 0);
455457
diff_print_filenames(zOrig, zNew, diffFlags, 0);
456458
printf(DIFF_CANNOT_COMPUTE_SYMLINK);
457459
}else{
@@ -473,10 +475,11 @@
473475
}
474476
blob_reset(&delta);
475477
}
476478
}
477479
db_finalize(&q);
480
+ diff_footer(diffFlags);
478481
}
479482
480483
/*
481484
** Drop the indicated stash
482485
*/
483486
--- src/stash.c
+++ src/stash.c
@@ -410,11 +410,13 @@
410 int fIncludeBinary, /* Do diffs against binary files */
411 u64 diffFlags /* Other diff flags */
412 ){
413 Stmt q;
414 Blob empty;
 
415 blob_zero(&empty);
 
416 db_prepare(&q,
417 "SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta"
418 " FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash",
419 stashid
420 );
@@ -427,18 +429,18 @@
427 const char *zNew = db_column_text(&q, 5);
428 char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
429 Blob a, b;
430 if( rid==0 ){
431 db_ephemeral_blob(&q, 6, &a);
432 fossil_print("ADDED %s\n", zNew);
433 diff_print_index(zNew, diffFlags, 0);
434 isBin1 = 0;
435 isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
436 diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd,
437 zBinGlob, fIncludeBinary, diffFlags);
438 }else if( isRemoved ){
439 fossil_print("DELETE %s\n", zOrig);
440 diff_print_index(zNew, diffFlags, 0);
441 isBin2 = 0;
442 if( fBaseline ){
443 content_get(rid, &a);
444 isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
@@ -447,11 +449,11 @@
447 }
448 }else{
449 Blob delta;
450 int isOrigLink = file_islink(zOPath);
451 db_ephemeral_blob(&q, 6, &delta);
452 fossil_print("CHANGED %s\n", zNew);
453 if( !isOrigLink != !isLink ){
454 diff_print_index(zNew, diffFlags, 0);
455 diff_print_filenames(zOrig, zNew, diffFlags, 0);
456 printf(DIFF_CANNOT_COMPUTE_SYMLINK);
457 }else{
@@ -473,10 +475,11 @@
473 }
474 blob_reset(&delta);
475 }
476 }
477 db_finalize(&q);
 
478 }
479
480 /*
481 ** Drop the indicated stash
482 */
483
--- src/stash.c
+++ src/stash.c
@@ -410,11 +410,13 @@
410 int fIncludeBinary, /* Do diffs against binary files */
411 u64 diffFlags /* Other diff flags */
412 ){
413 Stmt q;
414 Blob empty;
415 int bWebpage = (diffFlags & DIFF_WEBPAGE)!=0;
416 blob_zero(&empty);
417 diff_header(diffFlags);
418 db_prepare(&q,
419 "SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta"
420 " FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash",
421 stashid
422 );
@@ -427,18 +429,18 @@
429 const char *zNew = db_column_text(&q, 5);
430 char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
431 Blob a, b;
432 if( rid==0 ){
433 db_ephemeral_blob(&q, 6, &a);
434 if( !bWebpage ) fossil_print("ADDED %s\n", zNew);
435 diff_print_index(zNew, diffFlags, 0);
436 isBin1 = 0;
437 isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
438 diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd,
439 zBinGlob, fIncludeBinary, diffFlags);
440 }else if( isRemoved ){
441 if( !bWebpage) fossil_print("DELETE %s\n", zOrig);
442 diff_print_index(zNew, diffFlags, 0);
443 isBin2 = 0;
444 if( fBaseline ){
445 content_get(rid, &a);
446 isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
@@ -447,11 +449,11 @@
449 }
450 }else{
451 Blob delta;
452 int isOrigLink = file_islink(zOPath);
453 db_ephemeral_blob(&q, 6, &delta);
454 if( !bWebpage ) fossil_print("CHANGED %s\n", zNew);
455 if( !isOrigLink != !isLink ){
456 diff_print_index(zNew, diffFlags, 0);
457 diff_print_filenames(zOrig, zNew, diffFlags, 0);
458 printf(DIFF_CANNOT_COMPUTE_SYMLINK);
459 }else{
@@ -473,10 +475,11 @@
475 }
476 blob_reset(&delta);
477 }
478 }
479 db_finalize(&q);
480 diff_footer(diffFlags);
481 }
482
483 /*
484 ** Drop the indicated stash
485 */
486

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button