Skip to content

Commit a4c71cf

Browse files
authored
Merge pull request #2402 from dscho/add-i-in-c-status-and-help-gfw
built-in add -i/-p: update to latest iteration
2 parents 02af2cc + 1a5ab6a commit a4c71cf

File tree

5 files changed

+135
-97
lines changed

5 files changed

+135
-97
lines changed

add-interactive.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ static ssize_t list_and_choose(struct add_i_state *s,
279279
find_unique_prefixes(items);
280280

281281
for (;;) {
282-
char *p, *endp;
282+
char *p;
283283

284284
strbuf_reset(&input);
285285

@@ -330,7 +330,16 @@ static ssize_t list_and_choose(struct add_i_state *s,
330330
from = 0;
331331
to = items->items.nr;
332332
} else if (isdigit(*p)) {
333-
/* A range can be specified like 5-7 or 5-. */
333+
char *endp;
334+
/*
335+
* A range can be specified like 5-7 or 5-.
336+
*
337+
* Note: `from` is 0-based while the user input
338+
* is 1-based, hence we have to decrement by
339+
* one. We do not have to decrement `to` even
340+
* if it is 0-based because it is an exclusive
341+
* boundary.
342+
*/
334343
from = strtoul(p, &endp, 10) - 1;
335344
if (endp == p + sep)
336345
to = from + 1;
@@ -342,7 +351,8 @@ static ssize_t list_and_choose(struct add_i_state *s,
342351
}
343352
}
344353

345-
p[sep] = '\0';
354+
if (p[sep])
355+
p[sep++] = '\0';
346356
if (from < 0) {
347357
from = find_unique(p, items);
348358
if (from >= 0)
@@ -368,7 +378,7 @@ static ssize_t list_and_choose(struct add_i_state *s,
368378
res += choose ? +1 : -1;
369379
}
370380

371-
p += sep + 1;
381+
p += sep;
372382
}
373383

374384
if ((immediate && res != LIST_AND_CHOOSE_ERROR) ||
@@ -980,7 +990,7 @@ static int run_diff(struct add_i_state *s, const struct pathspec *ps,
980990

981991
static int run_help(struct add_i_state *s, const struct pathspec *unused_ps,
982992
struct prefix_item_list *unused_files,
983-
struct list_and_choose_options *opts)
993+
struct list_and_choose_options *unused_opts)
984994
{
985995
color_fprintf_ln(stdout, s->help_color, "status - %s",
986996
_("show paths with changes"));

add-patch.c

Lines changed: 81 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -658,50 +658,62 @@ static void render_diff_header(struct add_p_state *s,
658658

659659
/* Coalesce hunks again that were split */
660660
static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
661-
size_t *hunk_index, int use_all, struct hunk *temp)
661+
size_t *hunk_index, int use_all, struct hunk *merged)
662662
{
663663
size_t i = *hunk_index, delta;
664664
struct hunk *hunk = file_diff->hunk + i;
665-
struct hunk_header *header = &temp->header, *next;
665+
/* `header` corresponds to the merged hunk */
666+
struct hunk_header *header = &merged->header, *next;
666667

667668
if (!use_all && hunk->use != USE_HUNK)
668669
return 0;
669670

670-
memcpy(temp, hunk, sizeof(*temp));
671+
*merged = *hunk;
671672
/* We simply skip the colored part (if any) when merging hunks */
672-
temp->colored_start = temp->colored_end = 0;
673+
merged->colored_start = merged->colored_end = 0;
673674

674675
for (; i + 1 < file_diff->hunk_nr; i++) {
675676
hunk++;
676677
next = &hunk->header;
677678

679+
/*
680+
* Stop merging hunks when:
681+
*
682+
* - the hunk is not selected for use, or
683+
* - the hunk does not overlap with the already-merged hunk(s)
684+
*/
678685
if ((!use_all && hunk->use != USE_HUNK) ||
679-
header->new_offset >= next->new_offset + temp->delta ||
686+
header->new_offset >= next->new_offset + merged->delta ||
680687
header->new_offset + header->new_count
681-
< next->new_offset + temp->delta)
688+
< next->new_offset + merged->delta)
682689
break;
683690

684-
if (temp->start < hunk->start && temp->end > hunk->start) {
685-
temp->end = hunk->end;
686-
temp->colored_end = hunk->colored_end;
691+
/*
692+
* If the hunks were not edited, and overlap, we can simply
693+
* extend the line range.
694+
*/
695+
if (merged->start < hunk->start && merged->end > hunk->start) {
696+
merged->end = hunk->end;
697+
merged->colored_end = hunk->colored_end;
687698
delta = 0;
688699
} else {
689700
const char *plain = s->plain.buf;
690701
size_t overlapping_line_count = header->new_offset
691-
+ header->new_count - temp->delta
702+
+ header->new_count - merged->delta
692703
- next->new_offset;
693704
size_t overlap_end = hunk->start;
694705
size_t overlap_start = overlap_end;
695-
size_t overlap_next, len, i;
706+
size_t overlap_next, len, j;
696707

697708
/*
698-
* One of the hunks was edited; let's ensure that at
699-
* least the last context line of the first hunk
700-
* overlaps with the corresponding line of the second
701-
* hunk, and then merge.
709+
* One of the hunks was edited: the modified hunk was
710+
* appended to the strbuf `s->plain`.
711+
*
712+
* Let's ensure that at least the last context line of
713+
* the first hunk overlaps with the corresponding line
714+
* of the second hunk, and then merge.
702715
*/
703-
704-
for (i = 0; i < overlapping_line_count; i++) {
716+
for (j = 0; j < overlapping_line_count; j++) {
705717
overlap_next = find_next_line(&s->plain,
706718
overlap_end);
707719

@@ -715,7 +727,7 @@ static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
715727
if (plain[overlap_end] != ' ')
716728
return error(_("expected context line "
717729
"#%d in\n%.*s"),
718-
(int)(i + 1),
730+
(int)(j + 1),
719731
(int)(hunk->end
720732
- hunk->start),
721733
plain + hunk->start);
@@ -725,13 +737,13 @@ static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
725737
}
726738
len = overlap_end - overlap_start;
727739

728-
if (len > temp->end - temp->start ||
729-
memcmp(plain + temp->end - len,
740+
if (len > merged->end - merged->start ||
741+
memcmp(plain + merged->end - len,
730742
plain + overlap_start, len))
731743
return error(_("hunks do not overlap:\n%.*s\n"
732744
"\tdoes not end with:\n%.*s"),
733-
(int)(temp->end - temp->start),
734-
plain + temp->start,
745+
(int)(merged->end - merged->start),
746+
plain + merged->start,
735747
(int)len, plain + overlap_start);
736748

737749
/*
@@ -740,23 +752,23 @@ static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
740752
* address that, we temporarily append the union of the
741753
* lines to the `plain` strbuf.
742754
*/
743-
if (temp->end != s->plain.len) {
755+
if (merged->end != s->plain.len) {
744756
size_t start = s->plain.len;
745757

746-
strbuf_add(&s->plain, plain + temp->start,
747-
temp->end - temp->start);
758+
strbuf_add(&s->plain, plain + merged->start,
759+
merged->end - merged->start);
748760
plain = s->plain.buf;
749-
temp->start = start;
750-
temp->end = s->plain.len;
761+
merged->start = start;
762+
merged->end = s->plain.len;
751763
}
752764

753765
strbuf_add(&s->plain,
754766
plain + overlap_end,
755767
hunk->end - overlap_end);
756-
temp->end = s->plain.len;
757-
temp->splittable_into += hunk->splittable_into;
758-
delta = temp->delta;
759-
temp->delta += hunk->delta;
768+
merged->end = s->plain.len;
769+
merged->splittable_into += hunk->splittable_into;
770+
delta = merged->delta;
771+
merged->delta += hunk->delta;
760772
}
761773

762774
header->old_count = next->old_offset + next->old_count
@@ -783,16 +795,16 @@ static void reassemble_patch(struct add_p_state *s,
783795
render_diff_header(s, file_diff, 0, out);
784796

785797
for (i = file_diff->mode_change; i < file_diff->hunk_nr; i++) {
786-
struct hunk temp = { 0 };
798+
struct hunk merged = { 0 };
787799

788800
hunk = file_diff->hunk + i;
789801
if (!use_all && hunk->use != USE_HUNK)
790802
delta += hunk->header.old_count
791803
- hunk->header.new_count;
792804
else {
793805
/* merge overlapping hunks into a temporary hunk */
794-
if (merge_hunks(s, file_diff, &i, use_all, &temp))
795-
hunk = &temp;
806+
if (merge_hunks(s, file_diff, &i, use_all, &merged))
807+
hunk = &merged;
796808

797809
render_hunk(s, hunk, delta, 0, out);
798810

@@ -829,7 +841,7 @@ static int split_hunk(struct add_p_state *s, struct file_diff *file_diff,
829841
end = hunk->end;
830842
colored_end = hunk->colored_end;
831843

832-
memcpy(&remaining, &hunk->header, sizeof(remaining));
844+
remaining = hunk->header;
833845

834846
file_diff->hunk_nr += splittable_into - 1;
835847
ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr, file_diff->hunk_alloc);
@@ -997,21 +1009,13 @@ static void recolor_hunk(struct add_p_state *s, struct hunk *hunk)
9971009

9981010
static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
9991011
{
1000-
char *path = xstrdup(git_path("addp-hunk-edit.diff"));
1001-
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
1002-
struct strbuf buf = STRBUF_INIT;
1003-
size_t i, j;
1004-
int res, copy;
1005-
1006-
if (fd < 0) {
1007-
res = error_errno(_("could not open '%s' for writing"), path);
1008-
goto edit_hunk_manually_finish;
1009-
}
1012+
size_t i;
10101013

1011-
strbuf_commented_addf(&buf, _("Manual hunk edit mode -- see bottom for "
1014+
strbuf_reset(&s->buf);
1015+
strbuf_commented_addf(&s->buf, _("Manual hunk edit mode -- see bottom for "
10121016
"a quick guide.\n"));
1013-
render_hunk(s, hunk, 0, 0, &buf);
1014-
strbuf_commented_addf(&buf,
1017+
render_hunk(s, hunk, 0, 0, &s->buf);
1018+
strbuf_commented_addf(&s->buf,
10151019
_("---\n"
10161020
"To remove '%c' lines, make them ' ' lines "
10171021
"(context).\n"
@@ -1020,63 +1024,51 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
10201024
s->mode->is_reverse ? '+' : '-',
10211025
s->mode->is_reverse ? '-' : '+',
10221026
comment_line_char);
1023-
strbuf_commented_addf(&buf, "%s", _(s->mode->edit_hunk_hint));
1027+
strbuf_commented_addf(&s->buf, "%s", _(s->mode->edit_hunk_hint));
10241028
/*
10251029
* TRANSLATORS: 'it' refers to the patch mentioned in the previous
10261030
* messages.
10271031
*/
1028-
strbuf_commented_addf(&buf,
1032+
strbuf_commented_addf(&s->buf,
10291033
_("If it does not apply cleanly, you will be "
10301034
"given an opportunity to\n"
10311035
"edit again. If all lines of the hunk are "
10321036
"removed, then the edit is\n"
10331037
"aborted and the hunk is left unchanged.\n"));
1034-
if (write_in_full(fd, buf.buf, buf.len) < 0) {
1035-
res = error_errno(_("could not write to '%s'"), path);
1036-
goto edit_hunk_manually_finish;
1037-
}
1038-
1039-
res = close(fd);
1040-
fd = -1;
1041-
if (res < 0)
1042-
goto edit_hunk_manually_finish;
10431038

1044-
hunk->start = s->plain.len;
1045-
if (launch_editor(path, &s->plain, NULL) < 0) {
1046-
res = error_errno(_("could not edit '%s'"), path);
1047-
goto edit_hunk_manually_finish;
1048-
}
1049-
unlink(path);
1039+
if (strbuf_edit_interactively(&s->buf, "addp-hunk-edit.diff", NULL) < 0)
1040+
return -1;
10501041

10511042
/* strip out commented lines */
1052-
copy = s->plain.buf[hunk->start] != comment_line_char;
1053-
for (i = j = hunk->start; i < s->plain.len; ) {
1054-
if (copy)
1055-
s->plain.buf[j++] = s->plain.buf[i];
1056-
if (s->plain.buf[i++] == '\n')
1057-
copy = s->plain.buf[i] != comment_line_char;
1043+
hunk->start = s->plain.len;
1044+
for (i = 0; i < s->buf.len; ) {
1045+
const char *bol = s->buf.buf + i;
1046+
size_t rest = s->buf.len - i;
1047+
const char *eol = memchr(bol, '\n', rest);
1048+
size_t len = eol ? eol + 1 - bol : rest;
1049+
1050+
if (*bol != comment_line_char)
1051+
strbuf_add(&s->plain, bol, len);
1052+
i += len;
10581053
}
10591054

1060-
if (j == hunk->start)
1061-
/* User aborted by deleting everything */
1062-
goto edit_hunk_manually_finish;
1055+
hunk->end = s->plain.len;
1056+
if (hunk->end == hunk->start)
1057+
/* The user aborted editing by deleting everything */
1058+
return 0;
10631059

1064-
res = 1;
1065-
strbuf_setlen(&s->plain, j);
1066-
hunk->end = j;
10671060
recolor_hunk(s, hunk);
1061+
1062+
/*
1063+
* If the hunk header is intact, parse it, otherwise simply use the
1064+
* hunk header prior to editing (which will adjust `hunk->start` to
1065+
* skip the hunk header).
1066+
*/
10681067
if (s->plain.buf[hunk->start] == '@' &&
1069-
/* If the hunk header was deleted, simply use the original one. */
10701068
parse_hunk_header(s, hunk) < 0)
1071-
res = -1;
1069+
return error(_("could not parse hunk header"));
10721070

1073-
edit_hunk_manually_finish:
1074-
if (fd >= 0)
1075-
close(fd);
1076-
free(path);
1077-
strbuf_release(&buf);
1078-
1079-
return res;
1071+
return 1;
10801072
}
10811073

10821074
static ssize_t recount_edited_hunk(struct add_p_state *s, struct hunk *hunk,
@@ -1158,13 +1150,13 @@ static int edit_hunk_loop(struct add_p_state *s,
11581150
size_t plain_len = s->plain.len, colored_len = s->colored.len;
11591151
struct hunk backup;
11601152

1161-
memcpy(&backup, hunk, sizeof(backup));
1153+
backup = *hunk;
11621154

11631155
for (;;) {
11641156
int res = edit_hunk_manually(s, hunk);
11651157
if (res == 0) {
11661158
/* abandonded */
1167-
memcpy(hunk, &backup, sizeof(backup));
1159+
*hunk = backup;
11681160
return -1;
11691161
}
11701162

@@ -1180,7 +1172,7 @@ static int edit_hunk_loop(struct add_p_state *s,
11801172
/* Drop edits (they were appended to s->plain) */
11811173
strbuf_setlen(&s->plain, plain_len);
11821174
strbuf_setlen(&s->colored, colored_len);
1183-
memcpy(hunk, &backup, sizeof(backup));
1175+
*hunk = backup;
11841176

11851177
/*
11861178
* TRANSLATORS: do not translate [y/n]

builtin/add.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,6 @@ int run_add_interactive(const char *revision, const char *patch_mode,
191191
struct argv_array argv = ARGV_ARRAY_INIT;
192192
int use_builtin_add_i =
193193
git_env_bool("GIT_TEST_ADD_I_USE_BUILTIN", -1);
194-
if (use_builtin_add_i < 0)
195-
git_config_get_bool("add.interactive.usebuiltin",
196-
&use_builtin_add_i);
197194

198195
if (use_builtin_add_i == 1) {
199196
enum add_p_mode mode;

0 commit comments

Comments
 (0)