Skip to content

Commit d6cf873

Browse files
dschogitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 9254bdf commit d6cf873

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

add-patch.c

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,7 @@ N_("y - stage this hunk\n"
10131013
"k - leave this hunk undecided, see previous undecided hunk\n"
10141014
"K - leave this hunk undecided, see previous hunk\n"
10151015
"g - select a hunk to go to\n"
1016+
"/ - search for a hunk matching the given regex\n"
10161017
"s - split the current hunk into smaller hunks\n"
10171018
"e - manually edit the current hunk\n"
10181019
"? - print help\n");
@@ -1072,7 +1073,7 @@ static int patch_update_file(struct add_p_state *s,
10721073
if (hunk_index + 1 < file_diff->hunk_nr)
10731074
strbuf_addstr(&s->buf, ",J");
10741075
if (file_diff->hunk_nr > 1)
1075-
strbuf_addstr(&s->buf, ",g");
1076+
strbuf_addstr(&s->buf, ",g,/");
10761077
if (hunk->splittable_into > 1)
10771078
strbuf_addstr(&s->buf, ",s");
10781079
if (hunk_index + 1 > file_diff->mode_change &&
@@ -1177,6 +1178,53 @@ static int patch_update_file(struct add_p_state *s,
11771178
"Sorry, only %d hunks available.",
11781179
file_diff->hunk_nr),
11791180
(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;
11801228
} else if (s->answer.buf[0] == 's') {
11811229
size_t splittable_into = hunk->splittable_into;
11821230
if (splittable_into < 2)

t/t3701-add-interactive.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,20 @@ test_expect_success 'goto hunk' '
429429
test_cmp expect actual.trimmed
430430
'
431431

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+
432446
test_expect_success 'split hunk "add -p (edit)"' '
433447
# Split, say Edit and do nothing. Then:
434448
#

0 commit comments

Comments
 (0)