pickaxe: use textconv for -S counting

We currently just look at raw blob data when using "-S" to pickaxe. This is mostly historical, as pickaxe predates the textconv feature. If the user has bothered to define a textconv filter, it is more likely that their search string will be on the textconv output, as that is what they will see in the diff (and we do not even provide a mechanism for them to search for binary needles that contain NUL characters). This patch teaches "-S" to use textconv, just as we already do for "-G". Signed-off-by: Jeff King <peff@peff.net>

Jeff King committed Oct 28, 2012 at 08:27 UTC ef90ab66e8eaa863777a8d383c5af2ff43a426d2
2 files changed +51 -17
diffcore-pickaxe.c
+39 -17
@@ -157,17 +157,15 @@ static void diffcore_pickaxe_grep(struct diff_options *o)
157 return;
158 }
159
160 -static unsigned int contains(struct diff_filespec *one, struct diff_options *o,
160 +static unsigned int contains(mmfile_t *mf, struct diff_options *o,
161 regex_t *regexp, kwset_t kws)
162 {
163 unsigned int cnt;
164 unsigned long sz;
165 const char *data;
166 - if (diff_populate_filespec(one, 0))
167 - return 0;
166
169 - sz = one->size;
170 - data = one->data;
167 + sz = mf->size;
168 + data = mf->ptr;
169 cnt = 0;
170
171 if (regexp) {
@@ -197,29 +195,53 @@ static unsigned int contains(struct diff_filespec *one, struct diff_options *o,
195 cnt++;
196 }
197 }
200 - diff_free_filespec_data(one);
198 return cnt;
199 }
200
201 static int has_changes(struct diff_filepair *p, struct diff_options *o,
202 regex_t *regexp, kwset_t kws)
203 {
204 + struct userdiff_driver *textconv_one = get_textconv(p->one);
205 + struct userdiff_driver *textconv_two = get_textconv(p->two);
206 + mmfile_t mf1, mf2;
207 + int ret;
208 +
209 if (!o->pickaxe[0])
210 return 0;
211
210 - if (!DIFF_FILE_VALID(p->one)) {
211 - if (!DIFF_FILE_VALID(p->two))
212 - return 0; /* ignore unmerged */
212 + /*
213 + * If we have an unmodified pair, we know that the count will be the
214 + * same and don't even have to load the blobs. Unless textconv is in
215 + * play, _and_ we are using two different textconv filters (e.g.,
216 + * because a pair is an exact rename with different textconv attributes
217 + * for each side, which might generate different content).
218 + */
219 + if (textconv_one == textconv_two && diff_unmodified_pair(p))
220 + return 0;
221 +
222 + fill_one(p->one, &mf1, &textconv_one);
223 + fill_one(p->two, &mf2, &textconv_two);
224 +
225 + if (!mf1.ptr) {
226 + if (!mf2.ptr)
227 + ret = 0; /* ignore unmerged */
228 /* created */
214 - return contains(p->two, o, regexp, kws) != 0;
215 - }
216 - if (!DIFF_FILE_VALID(p->two))
217 - return contains(p->one, o, regexp, kws) != 0;
218 - if (!diff_unmodified_pair(p)) {
219 - return contains(p->one, o, regexp, kws) !=
220 - contains(p->two, o, regexp, kws);
229 + ret = contains(&mf2, o, regexp, kws) != 0;
230 }
222 - return 0;
231 + else if (!mf2.ptr) /* removed */
232 + ret = contains(&mf1, o, regexp, kws) != 0;
233 + else
234 + ret = contains(&mf1, o, regexp, kws) !=
235 + contains(&mf2, o, regexp, kws);
236 +
237 + if (textconv_one)
238 + free(mf1.ptr);
239 + if (textconv_two)
240 + free(mf2.ptr);
241 + diff_free_filespec_data(p->one);
242 + diff_free_filespec_data(p->two);
243 +
244 + return ret;
245 }
246
247 static void diffcore_pickaxe_count(struct diff_options *o)
t/t4030-diff-textconv.sh
+12
@@ -96,6 +96,18 @@ test_expect_success 'grep-diff (-G) operates on textconv data (modification)' '
96 test_cmp expect actual
97 '
98
99 +test_expect_success 'pickaxe (-S) operates on textconv data (add)' '
100 + echo one >expect &&
101 + git log --root --format=%s -S0 >actual &&
102 + test_cmp expect actual
103 +'
104 +
105 +test_expect_success 'pickaxe (-S) operates on textconv data (modification)' '
106 + echo two >expect &&
107 + git log --root --format=%s -S1 >actual &&
108 + test_cmp expect actual
109 +'
110 +
111 cat >expect.stat <<'EOF'
112 file | Bin 2 -> 4 bytes
113 1 file changed, 0 insertions(+), 0 deletions(-)