@matheusbsbs / matheus-bagliano / commits / d6cf873340
Fork 0

built-in add -p: implement the '/' ("search regex") command

This patch implements the hunk searching feature in the C version of `git add -p`. A test is added to verify that this behavior matches the one of the Perl version of `git add -p`. Note that this involves a change of behavior: the Perl version uses (of course) the Perl flavor of regular expressions, while this patch uses the regcomp()/regexec(), i.e. POSIX extended regular expressions. In practice, this behavior change is unlikely to matter. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Dec 13, 2019 at 08:08 UTC d6cf873340703098f2d7f54be457e4db1b32cf7b
2 files changed +63 -1
add-patch.c
+49 -1
@@ -1013,6 +1013,7 @@ N_("y - stage this hunk\n"
1013 "k - leave this hunk undecided, see previous undecided hunk\n"
1014 "K - leave this hunk undecided, see previous hunk\n"
1015 "g - select a hunk to go to\n"
1016 + "/ - search for a hunk matching the given regex\n"
1017 "s - split the current hunk into smaller hunks\n"
1018 "e - manually edit the current hunk\n"
1019 "? - print help\n");
@@ -1072,7 +1073,7 @@ static int patch_update_file(struct add_p_state *s,
1073 if (hunk_index + 1 < file_diff->hunk_nr)
1074 strbuf_addstr(&s->buf, ",J");
1075 if (file_diff->hunk_nr > 1)
1075 - strbuf_addstr(&s->buf, ",g");
1076 + strbuf_addstr(&s->buf, ",g,/");
1077 if (hunk->splittable_into > 1)
1078 strbuf_addstr(&s->buf, ",s");
1079 if (hunk_index + 1 > file_diff->mode_change &&
@@ -1177,6 +1178,53 @@ soft_increment:
1178 "Sorry, only %d hunks available.",
1179 file_diff->hunk_nr),
1180 (int)file_diff->hunk_nr);
1181 + } else if (s->answer.buf[0] == '/') {
1182 + regex_t regex;
1183 + int ret;
1184 +
1185 + if (file_diff->hunk_nr < 2) {
1186 + err(s, _("No other hunks to search"));
1187 + continue;
1188 + }
1189 + strbuf_remove(&s->answer, 0, 1);
1190 + strbuf_trim_trailing_newline(&s->answer);
1191 + if (s->answer.len == 0) {
1192 + printf("%s", _("search for regex? "));
1193 + fflush(stdout);
1194 + if (strbuf_getline(&s->answer,
1195 + stdin) == EOF)
1196 + break;
1197 + strbuf_trim_trailing_newline(&s->answer);
1198 + if (s->answer.len == 0)
1199 + continue;
1200 + }
1201 + ret = regcomp(&regex, s->answer.buf,
1202 + REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
1203 + if (ret) {
1204 + char errbuf[1024];
1205 +
1206 + regerror(ret, &regex, errbuf, sizeof(errbuf));
1207 + err(s, _("Malformed search regexp %s: %s"),
1208 + s->answer.buf, errbuf);
1209 + continue;
1210 + }
1211 + i = hunk_index;
1212 + for (;;) {
1213 + /* render the hunk into a scratch buffer */
1214 + render_hunk(s, file_diff->hunk + i, 0, 0,
1215 + &s->buf);
1216 + if (regexec(&regex, s->buf.buf, 0, NULL, 0)
1217 + != REG_NOMATCH)
1218 + break;
1219 + i++;
1220 + if (i == file_diff->hunk_nr)
1221 + i = 0;
1222 + if (i != hunk_index)
1223 + continue;
1224 + err(s, _("No hunk matches the given pattern"));
1225 + break;
1226 + }
1227 + hunk_index = i;
1228 } else if (s->answer.buf[0] == 's') {
1229 size_t splittable_into = hunk->splittable_into;
1230 if (splittable_into < 2)
t/t3701-add-interactive.sh
+14
@@ -429,6 +429,20 @@ test_expect_success 'goto hunk' '
429 test_cmp expect actual.trimmed
430 '
431
432 +test_expect_success 'navigate to hunk via regex' '
433 + test_when_finished "git reset" &&
434 + tr _ " " >expect <<-EOF &&
435 + (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? @@ -1,2 +1,3 @@
436 + _10
437 + +15
438 + _20
439 + (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?_
440 + EOF
441 + test_write_lines s y /1,2 | git add -p >actual &&
442 + tail -n 5 <actual >actual.trimmed &&
443 + test_cmp expect actual.trimmed
444 +'
445 +
446 test_expect_success 'split hunk "add -p (edit)"' '
447 # Split, say Edit and do nothing. Then:
448 #