Fossil SCM
Add the "diff optimizer" which tries to shift inserts and deletes to align with natural boundaries in the text. The resulting diff is no more or less correct than the original; it just seems more natural to human readers.
Commit
98cf5c33bc1529e44ecde9fb5dbc680a7121ab09
Parent
032da543f0932e6…
2 files changed
+140
-22
+3
+140
-22
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -33,10 +33,12 @@ | ||
| 33 | 33 | #define DIFF_SIDEBYSIDE 0x02000000 /* Generate a side-by-side diff */ |
| 34 | 34 | #define DIFF_NEWFILE 0x04000000 /* Missing files are as empty files */ |
| 35 | 35 | #define DIFF_INLINE 0x08000000 /* Inline (not side-by-side) diff */ |
| 36 | 36 | #define DIFF_HTML 0x10000000 /* Render for HTML */ |
| 37 | 37 | #define DIFF_LINENO 0x20000000 /* Show line numbers in context diff */ |
| 38 | +#define DIFF_NOOPT 0x40000000 /* Suppress optimizations for debug */ | |
| 39 | +#define DIFF_INVERT 0x80000000 /* Invert the diff for debug */ | |
| 38 | 40 | |
| 39 | 41 | #endif /* INTERFACE */ |
| 40 | 42 | |
| 41 | 43 | /* |
| 42 | 44 | ** Maximum length of a line in a text file. (8192) |
| @@ -61,10 +63,15 @@ | ||
| 61 | 63 | ** above are one per line of input text. But each entry is also |
| 62 | 64 | ** a bucket in a hash table, as follows: */ |
| 63 | 65 | unsigned int iHash; /* 1+(first entry in the hash chain) */ |
| 64 | 66 | }; |
| 65 | 67 | |
| 68 | +/* | |
| 69 | +** Length of a dline | |
| 70 | +*/ | |
| 71 | +#define LENGTH(X) ((X)->h & LENGTH_MASK) | |
| 72 | + | |
| 66 | 73 | /* |
| 67 | 74 | ** A context for running a raw diff. |
| 68 | 75 | ** |
| 69 | 76 | ** The aEdit[] array describes the raw diff. Each triple of integers in |
| 70 | 77 | ** aEdit[] means: |
| @@ -876,10 +883,112 @@ | ||
| 876 | 883 | p->aEdit[p->nEdit++] = 0; |
| 877 | 884 | p->aEdit[p->nEdit++] = 0; |
| 878 | 885 | p->aEdit[p->nEdit++] = 0; |
| 879 | 886 | } |
| 880 | 887 | } |
| 888 | + | |
| 889 | +/* | |
| 890 | +** Attempt to shift insertion or deletion blocks so that they begin and | |
| 891 | +** end on lines that are pure whitespace. In other words, try to transform | |
| 892 | +** this: | |
| 893 | +** | |
| 894 | +** int func1(int x){ | |
| 895 | +** return x*10; | |
| 896 | +** +} | |
| 897 | +** + | |
| 898 | +** +int func2(int x){ | |
| 899 | +** + return x*20; | |
| 900 | +** } | |
| 901 | +** | |
| 902 | +** int func3(int x){ | |
| 903 | +** return x/5; | |
| 904 | +** } | |
| 905 | +** | |
| 906 | +** Into one of these: | |
| 907 | +** | |
| 908 | +** int func1(int x){ int func1(int x){ | |
| 909 | +** return x*10; return x*10; | |
| 910 | +** } } | |
| 911 | +** + | |
| 912 | +** +int func2(int x){ +int func2(int x){ | |
| 913 | +** + return x*20; + return x*20; | |
| 914 | +** +} +} | |
| 915 | +** + | |
| 916 | +** int func3(int x){ int func3(int x){ | |
| 917 | +** return x/5; return x/5; | |
| 918 | +** } } | |
| 919 | +*/ | |
| 920 | +static void diff_optimize(DContext *p){ | |
| 921 | + int r; /* Index of current triple */ | |
| 922 | + int lnFrom; /* Line number in p->aFrom */ | |
| 923 | + int lnTo; /* Line number in p->aTo */ | |
| 924 | + int cpy, del, ins; | |
| 925 | + | |
| 926 | + lnFrom = lnTo = 0; | |
| 927 | + for(r=0; r<p->nEdit; r += 3){ | |
| 928 | + cpy = p->aEdit[r]; | |
| 929 | + del = p->aEdit[r+1]; | |
| 930 | + ins = p->aEdit[r+2]; | |
| 931 | + lnFrom += cpy; | |
| 932 | + lnTo += cpy; | |
| 933 | + | |
| 934 | + /* Shift insertions toward the beginning of the file */ | |
| 935 | + while( cpy>0 && del==0 && ins>0 ){ | |
| 936 | + DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of insert */ | |
| 937 | + DLine *pBtm = &p->aTo[lnTo+ins-1]; /* Last line inserted */ | |
| 938 | + if( same_dline(pTop, pBtm)==0 ) break; | |
| 939 | + if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break; | |
| 940 | + lnFrom--; | |
| 941 | + lnTo--; | |
| 942 | + p->aEdit[r]--; | |
| 943 | + p->aEdit[r+3]++; | |
| 944 | + cpy--; | |
| 945 | + } | |
| 946 | + | |
| 947 | + /* Shift insertions toward the end of the file */ | |
| 948 | + while( p->aEdit[r+3]>0 && del==0 && ins>0 ){ | |
| 949 | + DLine *pTop = &p->aTo[lnTo]; /* First line inserted */ | |
| 950 | + DLine *pBtm = &p->aTo[lnTo+ins]; /* First line past end of insert */ | |
| 951 | + if( same_dline(pTop, pBtm)==0 ) break; | |
| 952 | + if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop+1)+LENGTH(pBtm) ) break; | |
| 953 | + lnFrom++; | |
| 954 | + lnTo++; | |
| 955 | + p->aEdit[r]++; | |
| 956 | + p->aEdit[r+3]--; | |
| 957 | + cpy++; | |
| 958 | + } | |
| 959 | + | |
| 960 | + /* Shift deletions toward the beginning of the file */ | |
| 961 | + while( cpy>0 && del>0 && ins==0 ){ | |
| 962 | + DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of delete */ | |
| 963 | + DLine *pBtm = &p->aFrom[lnFrom+del-1]; /* Last line deleted */ | |
| 964 | + if( same_dline(pTop, pBtm)==0 ) break; | |
| 965 | + if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break; | |
| 966 | + lnFrom--; | |
| 967 | + lnTo--; | |
| 968 | + p->aEdit[r]--; | |
| 969 | + p->aEdit[r+3]++; | |
| 970 | + cpy--; | |
| 971 | + } | |
| 972 | + | |
| 973 | + /* Shift deletions toward the end of the file */ | |
| 974 | + while( p->aEdit[r+3]>0 && del>0 && ins==0 ){ | |
| 975 | + DLine *pTop = &p->aFrom[lnFrom]; /* First line deleted */ | |
| 976 | + DLine *pBtm = &p->aFrom[lnFrom+del]; /* First line past end of delete */ | |
| 977 | + if( same_dline(pTop, pBtm)==0 ) break; | |
| 978 | + if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop)+LENGTH(pBtm) ) break; | |
| 979 | + lnFrom++; | |
| 980 | + lnTo++; | |
| 981 | + p->aEdit[r]++; | |
| 982 | + p->aEdit[r+3]--; | |
| 983 | + cpy++; | |
| 984 | + } | |
| 985 | + | |
| 986 | + lnFrom += del; | |
| 987 | + lnTo += ins; | |
| 988 | + } | |
| 989 | +} | |
| 881 | 990 | |
| 882 | 991 | /* |
| 883 | 992 | ** Extract the number of lines of context from diffFlags. Supply an |
| 884 | 993 | ** appropriate default if no context width is specified. |
| 885 | 994 | */ |
| @@ -921,10 +1030,15 @@ | ||
| 921 | 1030 | ){ |
| 922 | 1031 | int ignoreEolWs; /* Ignore whitespace at the end of lines */ |
| 923 | 1032 | int nContext; /* Amount of context to display */ |
| 924 | 1033 | DContext c; |
| 925 | 1034 | |
| 1035 | + if( diffFlags & DIFF_INVERT ){ | |
| 1036 | + Blob *pTemp = pA_Blob; | |
| 1037 | + pA_Blob = pB_Blob; | |
| 1038 | + pB_Blob = pTemp; | |
| 1039 | + } | |
| 926 | 1040 | nContext = diff_context_lines(diffFlags); |
| 927 | 1041 | ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0; |
| 928 | 1042 | |
| 929 | 1043 | /* Prepare the input files */ |
| 930 | 1044 | memset(&c, 0, sizeof(c)); |
| @@ -941,10 +1055,11 @@ | ||
| 941 | 1055 | return 0; |
| 942 | 1056 | } |
| 943 | 1057 | |
| 944 | 1058 | /* Compute the difference */ |
| 945 | 1059 | diff_all(&c); |
| 1060 | + if( (diffFlags & DIFF_NOOPT)==0 ) diff_optimize(&c); | |
| 946 | 1061 | |
| 947 | 1062 | if( pOut ){ |
| 948 | 1063 | /* Compute a context or side-by-side diff into pOut */ |
| 949 | 1064 | int escHtml = (diffFlags & DIFF_HTML)!=0; |
| 950 | 1065 | if( diffFlags & DIFF_SIDEBYSIDE ){ |
| @@ -966,32 +1081,10 @@ | ||
| 966 | 1081 | free(c.aTo); |
| 967 | 1082 | return c.aEdit; |
| 968 | 1083 | } |
| 969 | 1084 | } |
| 970 | 1085 | |
| 971 | -/* | |
| 972 | -** COMMAND: test-rawdiff | |
| 973 | -*/ | |
| 974 | -void test_rawdiff_cmd(void){ | |
| 975 | - Blob a, b; | |
| 976 | - int r; | |
| 977 | - int i; | |
| 978 | - int *R; | |
| 979 | - if( g.argc<4 ) usage("FILE1 FILE2 ..."); | |
| 980 | - blob_read_from_file(&a, g.argv[2]); | |
| 981 | - for(i=3; i<g.argc; i++){ | |
| 982 | - if( i>3 ) fossil_print("-------------------------------\n"); | |
| 983 | - blob_read_from_file(&b, g.argv[i]); | |
| 984 | - R = text_diff(&a, &b, 0, 0); | |
| 985 | - for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ | |
| 986 | - fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]); | |
| 987 | - } | |
| 988 | - /* free(R); */ | |
| 989 | - blob_reset(&b); | |
| 990 | - } | |
| 991 | -} | |
| 992 | - | |
| 993 | 1086 | /* |
| 994 | 1087 | ** Process diff-related command-line options and return an appropriate |
| 995 | 1088 | ** "diffFlags" integer. |
| 996 | 1089 | ** |
| 997 | 1090 | ** --side-by-side|-y Side-by-side diff. DIFF_SIDEBYSIDE |
| @@ -1014,12 +1107,37 @@ | ||
| 1014 | 1107 | if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK; |
| 1015 | 1108 | diffFlags |= f; |
| 1016 | 1109 | } |
| 1017 | 1110 | if( find_option("html",0,0)!=0 ) diffFlags |= DIFF_HTML; |
| 1018 | 1111 | if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO; |
| 1112 | + if( find_option("noopt",0,0)!=0 ) diffFlags |= DIFF_NOOPT; | |
| 1113 | + if( find_option("invert",0,0)!=0 ) diffFlags |= DIFF_INVERT; | |
| 1019 | 1114 | return diffFlags; |
| 1020 | 1115 | } |
| 1116 | + | |
| 1117 | +/* | |
| 1118 | +** COMMAND: test-rawdiff | |
| 1119 | +*/ | |
| 1120 | +void test_rawdiff_cmd(void){ | |
| 1121 | + Blob a, b; | |
| 1122 | + int r; | |
| 1123 | + int i; | |
| 1124 | + int *R; | |
| 1125 | + int diffFlags = diff_options(); | |
| 1126 | + if( g.argc<4 ) usage("FILE1 FILE2 ..."); | |
| 1127 | + blob_read_from_file(&a, g.argv[2]); | |
| 1128 | + for(i=3; i<g.argc; i++){ | |
| 1129 | + if( i>3 ) fossil_print("-------------------------------\n"); | |
| 1130 | + blob_read_from_file(&b, g.argv[i]); | |
| 1131 | + R = text_diff(&a, &b, 0, diffFlags); | |
| 1132 | + for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ | |
| 1133 | + fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]); | |
| 1134 | + } | |
| 1135 | + /* free(R); */ | |
| 1136 | + blob_reset(&b); | |
| 1137 | + } | |
| 1138 | +} | |
| 1021 | 1139 | |
| 1022 | 1140 | /* |
| 1023 | 1141 | ** COMMAND: test-udiff |
| 1024 | 1142 | ** |
| 1025 | 1143 | ** Print the difference between two files. The usual diff options apply. |
| 1026 | 1144 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -33,10 +33,12 @@ | |
| 33 | #define DIFF_SIDEBYSIDE 0x02000000 /* Generate a side-by-side diff */ |
| 34 | #define DIFF_NEWFILE 0x04000000 /* Missing files are as empty files */ |
| 35 | #define DIFF_INLINE 0x08000000 /* Inline (not side-by-side) diff */ |
| 36 | #define DIFF_HTML 0x10000000 /* Render for HTML */ |
| 37 | #define DIFF_LINENO 0x20000000 /* Show line numbers in context diff */ |
| 38 | |
| 39 | #endif /* INTERFACE */ |
| 40 | |
| 41 | /* |
| 42 | ** Maximum length of a line in a text file. (8192) |
| @@ -61,10 +63,15 @@ | |
| 61 | ** above are one per line of input text. But each entry is also |
| 62 | ** a bucket in a hash table, as follows: */ |
| 63 | unsigned int iHash; /* 1+(first entry in the hash chain) */ |
| 64 | }; |
| 65 | |
| 66 | /* |
| 67 | ** A context for running a raw diff. |
| 68 | ** |
| 69 | ** The aEdit[] array describes the raw diff. Each triple of integers in |
| 70 | ** aEdit[] means: |
| @@ -876,10 +883,112 @@ | |
| 876 | p->aEdit[p->nEdit++] = 0; |
| 877 | p->aEdit[p->nEdit++] = 0; |
| 878 | p->aEdit[p->nEdit++] = 0; |
| 879 | } |
| 880 | } |
| 881 | |
| 882 | /* |
| 883 | ** Extract the number of lines of context from diffFlags. Supply an |
| 884 | ** appropriate default if no context width is specified. |
| 885 | */ |
| @@ -921,10 +1030,15 @@ | |
| 921 | ){ |
| 922 | int ignoreEolWs; /* Ignore whitespace at the end of lines */ |
| 923 | int nContext; /* Amount of context to display */ |
| 924 | DContext c; |
| 925 | |
| 926 | nContext = diff_context_lines(diffFlags); |
| 927 | ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0; |
| 928 | |
| 929 | /* Prepare the input files */ |
| 930 | memset(&c, 0, sizeof(c)); |
| @@ -941,10 +1055,11 @@ | |
| 941 | return 0; |
| 942 | } |
| 943 | |
| 944 | /* Compute the difference */ |
| 945 | diff_all(&c); |
| 946 | |
| 947 | if( pOut ){ |
| 948 | /* Compute a context or side-by-side diff into pOut */ |
| 949 | int escHtml = (diffFlags & DIFF_HTML)!=0; |
| 950 | if( diffFlags & DIFF_SIDEBYSIDE ){ |
| @@ -966,32 +1081,10 @@ | |
| 966 | free(c.aTo); |
| 967 | return c.aEdit; |
| 968 | } |
| 969 | } |
| 970 | |
| 971 | /* |
| 972 | ** COMMAND: test-rawdiff |
| 973 | */ |
| 974 | void test_rawdiff_cmd(void){ |
| 975 | Blob a, b; |
| 976 | int r; |
| 977 | int i; |
| 978 | int *R; |
| 979 | if( g.argc<4 ) usage("FILE1 FILE2 ..."); |
| 980 | blob_read_from_file(&a, g.argv[2]); |
| 981 | for(i=3; i<g.argc; i++){ |
| 982 | if( i>3 ) fossil_print("-------------------------------\n"); |
| 983 | blob_read_from_file(&b, g.argv[i]); |
| 984 | R = text_diff(&a, &b, 0, 0); |
| 985 | for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ |
| 986 | fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]); |
| 987 | } |
| 988 | /* free(R); */ |
| 989 | blob_reset(&b); |
| 990 | } |
| 991 | } |
| 992 | |
| 993 | /* |
| 994 | ** Process diff-related command-line options and return an appropriate |
| 995 | ** "diffFlags" integer. |
| 996 | ** |
| 997 | ** --side-by-side|-y Side-by-side diff. DIFF_SIDEBYSIDE |
| @@ -1014,12 +1107,37 @@ | |
| 1014 | if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK; |
| 1015 | diffFlags |= f; |
| 1016 | } |
| 1017 | if( find_option("html",0,0)!=0 ) diffFlags |= DIFF_HTML; |
| 1018 | if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO; |
| 1019 | return diffFlags; |
| 1020 | } |
| 1021 | |
| 1022 | /* |
| 1023 | ** COMMAND: test-udiff |
| 1024 | ** |
| 1025 | ** Print the difference between two files. The usual diff options apply. |
| 1026 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -33,10 +33,12 @@ | |
| 33 | #define DIFF_SIDEBYSIDE 0x02000000 /* Generate a side-by-side diff */ |
| 34 | #define DIFF_NEWFILE 0x04000000 /* Missing files are as empty files */ |
| 35 | #define DIFF_INLINE 0x08000000 /* Inline (not side-by-side) diff */ |
| 36 | #define DIFF_HTML 0x10000000 /* Render for HTML */ |
| 37 | #define DIFF_LINENO 0x20000000 /* Show line numbers in context diff */ |
| 38 | #define DIFF_NOOPT 0x40000000 /* Suppress optimizations for debug */ |
| 39 | #define DIFF_INVERT 0x80000000 /* Invert the diff for debug */ |
| 40 | |
| 41 | #endif /* INTERFACE */ |
| 42 | |
| 43 | /* |
| 44 | ** Maximum length of a line in a text file. (8192) |
| @@ -61,10 +63,15 @@ | |
| 63 | ** above are one per line of input text. But each entry is also |
| 64 | ** a bucket in a hash table, as follows: */ |
| 65 | unsigned int iHash; /* 1+(first entry in the hash chain) */ |
| 66 | }; |
| 67 | |
| 68 | /* |
| 69 | ** Length of a dline |
| 70 | */ |
| 71 | #define LENGTH(X) ((X)->h & LENGTH_MASK) |
| 72 | |
| 73 | /* |
| 74 | ** A context for running a raw diff. |
| 75 | ** |
| 76 | ** The aEdit[] array describes the raw diff. Each triple of integers in |
| 77 | ** aEdit[] means: |
| @@ -876,10 +883,112 @@ | |
| 883 | p->aEdit[p->nEdit++] = 0; |
| 884 | p->aEdit[p->nEdit++] = 0; |
| 885 | p->aEdit[p->nEdit++] = 0; |
| 886 | } |
| 887 | } |
| 888 | |
| 889 | /* |
| 890 | ** Attempt to shift insertion or deletion blocks so that they begin and |
| 891 | ** end on lines that are pure whitespace. In other words, try to transform |
| 892 | ** this: |
| 893 | ** |
| 894 | ** int func1(int x){ |
| 895 | ** return x*10; |
| 896 | ** +} |
| 897 | ** + |
| 898 | ** +int func2(int x){ |
| 899 | ** + return x*20; |
| 900 | ** } |
| 901 | ** |
| 902 | ** int func3(int x){ |
| 903 | ** return x/5; |
| 904 | ** } |
| 905 | ** |
| 906 | ** Into one of these: |
| 907 | ** |
| 908 | ** int func1(int x){ int func1(int x){ |
| 909 | ** return x*10; return x*10; |
| 910 | ** } } |
| 911 | ** + |
| 912 | ** +int func2(int x){ +int func2(int x){ |
| 913 | ** + return x*20; + return x*20; |
| 914 | ** +} +} |
| 915 | ** + |
| 916 | ** int func3(int x){ int func3(int x){ |
| 917 | ** return x/5; return x/5; |
| 918 | ** } } |
| 919 | */ |
| 920 | static void diff_optimize(DContext *p){ |
| 921 | int r; /* Index of current triple */ |
| 922 | int lnFrom; /* Line number in p->aFrom */ |
| 923 | int lnTo; /* Line number in p->aTo */ |
| 924 | int cpy, del, ins; |
| 925 | |
| 926 | lnFrom = lnTo = 0; |
| 927 | for(r=0; r<p->nEdit; r += 3){ |
| 928 | cpy = p->aEdit[r]; |
| 929 | del = p->aEdit[r+1]; |
| 930 | ins = p->aEdit[r+2]; |
| 931 | lnFrom += cpy; |
| 932 | lnTo += cpy; |
| 933 | |
| 934 | /* Shift insertions toward the beginning of the file */ |
| 935 | while( cpy>0 && del==0 && ins>0 ){ |
| 936 | DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of insert */ |
| 937 | DLine *pBtm = &p->aTo[lnTo+ins-1]; /* Last line inserted */ |
| 938 | if( same_dline(pTop, pBtm)==0 ) break; |
| 939 | if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break; |
| 940 | lnFrom--; |
| 941 | lnTo--; |
| 942 | p->aEdit[r]--; |
| 943 | p->aEdit[r+3]++; |
| 944 | cpy--; |
| 945 | } |
| 946 | |
| 947 | /* Shift insertions toward the end of the file */ |
| 948 | while( p->aEdit[r+3]>0 && del==0 && ins>0 ){ |
| 949 | DLine *pTop = &p->aTo[lnTo]; /* First line inserted */ |
| 950 | DLine *pBtm = &p->aTo[lnTo+ins]; /* First line past end of insert */ |
| 951 | if( same_dline(pTop, pBtm)==0 ) break; |
| 952 | if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop+1)+LENGTH(pBtm) ) break; |
| 953 | lnFrom++; |
| 954 | lnTo++; |
| 955 | p->aEdit[r]++; |
| 956 | p->aEdit[r+3]--; |
| 957 | cpy++; |
| 958 | } |
| 959 | |
| 960 | /* Shift deletions toward the beginning of the file */ |
| 961 | while( cpy>0 && del>0 && ins==0 ){ |
| 962 | DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of delete */ |
| 963 | DLine *pBtm = &p->aFrom[lnFrom+del-1]; /* Last line deleted */ |
| 964 | if( same_dline(pTop, pBtm)==0 ) break; |
| 965 | if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break; |
| 966 | lnFrom--; |
| 967 | lnTo--; |
| 968 | p->aEdit[r]--; |
| 969 | p->aEdit[r+3]++; |
| 970 | cpy--; |
| 971 | } |
| 972 | |
| 973 | /* Shift deletions toward the end of the file */ |
| 974 | while( p->aEdit[r+3]>0 && del>0 && ins==0 ){ |
| 975 | DLine *pTop = &p->aFrom[lnFrom]; /* First line deleted */ |
| 976 | DLine *pBtm = &p->aFrom[lnFrom+del]; /* First line past end of delete */ |
| 977 | if( same_dline(pTop, pBtm)==0 ) break; |
| 978 | if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop)+LENGTH(pBtm) ) break; |
| 979 | lnFrom++; |
| 980 | lnTo++; |
| 981 | p->aEdit[r]++; |
| 982 | p->aEdit[r+3]--; |
| 983 | cpy++; |
| 984 | } |
| 985 | |
| 986 | lnFrom += del; |
| 987 | lnTo += ins; |
| 988 | } |
| 989 | } |
| 990 | |
| 991 | /* |
| 992 | ** Extract the number of lines of context from diffFlags. Supply an |
| 993 | ** appropriate default if no context width is specified. |
| 994 | */ |
| @@ -921,10 +1030,15 @@ | |
| 1030 | ){ |
| 1031 | int ignoreEolWs; /* Ignore whitespace at the end of lines */ |
| 1032 | int nContext; /* Amount of context to display */ |
| 1033 | DContext c; |
| 1034 | |
| 1035 | if( diffFlags & DIFF_INVERT ){ |
| 1036 | Blob *pTemp = pA_Blob; |
| 1037 | pA_Blob = pB_Blob; |
| 1038 | pB_Blob = pTemp; |
| 1039 | } |
| 1040 | nContext = diff_context_lines(diffFlags); |
| 1041 | ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0; |
| 1042 | |
| 1043 | /* Prepare the input files */ |
| 1044 | memset(&c, 0, sizeof(c)); |
| @@ -941,10 +1055,11 @@ | |
| 1055 | return 0; |
| 1056 | } |
| 1057 | |
| 1058 | /* Compute the difference */ |
| 1059 | diff_all(&c); |
| 1060 | if( (diffFlags & DIFF_NOOPT)==0 ) diff_optimize(&c); |
| 1061 | |
| 1062 | if( pOut ){ |
| 1063 | /* Compute a context or side-by-side diff into pOut */ |
| 1064 | int escHtml = (diffFlags & DIFF_HTML)!=0; |
| 1065 | if( diffFlags & DIFF_SIDEBYSIDE ){ |
| @@ -966,32 +1081,10 @@ | |
| 1081 | free(c.aTo); |
| 1082 | return c.aEdit; |
| 1083 | } |
| 1084 | } |
| 1085 | |
| 1086 | /* |
| 1087 | ** Process diff-related command-line options and return an appropriate |
| 1088 | ** "diffFlags" integer. |
| 1089 | ** |
| 1090 | ** --side-by-side|-y Side-by-side diff. DIFF_SIDEBYSIDE |
| @@ -1014,12 +1107,37 @@ | |
| 1107 | if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK; |
| 1108 | diffFlags |= f; |
| 1109 | } |
| 1110 | if( find_option("html",0,0)!=0 ) diffFlags |= DIFF_HTML; |
| 1111 | if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO; |
| 1112 | if( find_option("noopt",0,0)!=0 ) diffFlags |= DIFF_NOOPT; |
| 1113 | if( find_option("invert",0,0)!=0 ) diffFlags |= DIFF_INVERT; |
| 1114 | return diffFlags; |
| 1115 | } |
| 1116 | |
| 1117 | /* |
| 1118 | ** COMMAND: test-rawdiff |
| 1119 | */ |
| 1120 | void test_rawdiff_cmd(void){ |
| 1121 | Blob a, b; |
| 1122 | int r; |
| 1123 | int i; |
| 1124 | int *R; |
| 1125 | int diffFlags = diff_options(); |
| 1126 | if( g.argc<4 ) usage("FILE1 FILE2 ..."); |
| 1127 | blob_read_from_file(&a, g.argv[2]); |
| 1128 | for(i=3; i<g.argc; i++){ |
| 1129 | if( i>3 ) fossil_print("-------------------------------\n"); |
| 1130 | blob_read_from_file(&b, g.argv[i]); |
| 1131 | R = text_diff(&a, &b, 0, diffFlags); |
| 1132 | for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ |
| 1133 | fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]); |
| 1134 | } |
| 1135 | /* free(R); */ |
| 1136 | blob_reset(&b); |
| 1137 | } |
| 1138 | } |
| 1139 | |
| 1140 | /* |
| 1141 | ** COMMAND: test-udiff |
| 1142 | ** |
| 1143 | ** Print the difference between two files. The usual diff options apply. |
| 1144 |
+3
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -373,10 +373,13 @@ | ||
| 373 | 373 | |
| 374 | 374 | /* "dc" query parameter determines lines of context */ |
| 375 | 375 | x = atoi(PD("dc","7")); |
| 376 | 376 | if( x<0 || x>DIFF_CONTEXT_MASK ) x = DIFF_CONTEXT_MASK; |
| 377 | 377 | diffFlags += x; |
| 378 | + | |
| 379 | + /* The "noopt" parameter disables diff optimization */ | |
| 380 | + if( PD("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT; | |
| 378 | 381 | } |
| 379 | 382 | return diffFlags; |
| 380 | 383 | } |
| 381 | 384 | |
| 382 | 385 | |
| 383 | 386 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -373,10 +373,13 @@ | |
| 373 | |
| 374 | /* "dc" query parameter determines lines of context */ |
| 375 | x = atoi(PD("dc","7")); |
| 376 | if( x<0 || x>DIFF_CONTEXT_MASK ) x = DIFF_CONTEXT_MASK; |
| 377 | diffFlags += x; |
| 378 | } |
| 379 | return diffFlags; |
| 380 | } |
| 381 | |
| 382 | |
| 383 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -373,10 +373,13 @@ | |
| 373 | |
| 374 | /* "dc" query parameter determines lines of context */ |
| 375 | x = atoi(PD("dc","7")); |
| 376 | if( x<0 || x>DIFF_CONTEXT_MASK ) x = DIFF_CONTEXT_MASK; |
| 377 | diffFlags += x; |
| 378 | |
| 379 | /* The "noopt" parameter disables diff optimization */ |
| 380 | if( PD("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT; |
| 381 | } |
| 382 | return diffFlags; |
| 383 | } |
| 384 | |
| 385 | |
| 386 |