Skip to content

Commit 1830b57

Browse files
committed
fixup! built-in add -p: implement hunk editing
Phillip Wood pointed out, long ago, that the code is underdocumented and could use a helper for calling the editor. Somehow, this change only made it into gitgitgadget#173 but not into Git for Windows' `master`. Signed-off-by: Johannes Schindelin <[email protected]>
1 parent f6556be commit 1830b57

File tree

1 file changed

+47
-62
lines changed

1 file changed

+47
-62
lines changed

add-patch.c

Lines changed: 47 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,10 @@ static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
688688
< next->new_offset + merged->delta)
689689
break;
690690

691+
/*
692+
* If the hunks were not edited, and overlap, we can simply
693+
* extend the line range.
694+
*/
691695
if (merged->start < hunk->start && merged->end > hunk->start) {
692696
merged->end = hunk->end;
693697
merged->colored_end = hunk->colored_end;
@@ -699,16 +703,17 @@ static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
699703
- next->new_offset;
700704
size_t overlap_end = hunk->start;
701705
size_t overlap_start = overlap_end;
702-
size_t overlap_next, len, i;
706+
size_t overlap_next, len, j;
703707

704708
/*
705-
* One of the hunks was edited; let's ensure that at
706-
* least the last context line of the first hunk
707-
* overlaps with the corresponding line of the second
708-
* 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.
709715
*/
710-
711-
for (i = 0; i < overlapping_line_count; i++) {
716+
for (j = 0; j < overlapping_line_count; j++) {
712717
overlap_next = find_next_line(&s->plain,
713718
overlap_end);
714719

@@ -722,7 +727,7 @@ static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
722727
if (plain[overlap_end] != ' ')
723728
return error(_("expected context line "
724729
"#%d in\n%.*s"),
725-
(int)(i + 1),
730+
(int)(j + 1),
726731
(int)(hunk->end
727732
- hunk->start),
728733
plain + hunk->start);
@@ -1004,21 +1009,13 @@ static void recolor_hunk(struct add_p_state *s, struct hunk *hunk)
10041009

10051010
static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
10061011
{
1007-
char *path = xstrdup(git_path("addp-hunk-edit.diff"));
1008-
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
1009-
struct strbuf buf = STRBUF_INIT;
1010-
size_t i, j;
1011-
int res, copy;
1012-
1013-
if (fd < 0) {
1014-
res = error_errno(_("could not open '%s' for writing"), path);
1015-
goto edit_hunk_manually_finish;
1016-
}
1012+
size_t i;
10171013

1018-
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 "
10191016
"a quick guide.\n"));
1020-
render_hunk(s, hunk, 0, 0, &buf);
1021-
strbuf_commented_addf(&buf,
1017+
render_hunk(s, hunk, 0, 0, &s->buf);
1018+
strbuf_commented_addf(&s->buf,
10221019
_("---\n"
10231020
"To remove '%c' lines, make them ' ' lines "
10241021
"(context).\n"
@@ -1027,63 +1024,51 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
10271024
s->mode->is_reverse ? '+' : '-',
10281025
s->mode->is_reverse ? '-' : '+',
10291026
comment_line_char);
1030-
strbuf_commented_addf(&buf, "%s", _(s->mode->edit_hunk_hint));
1027+
strbuf_commented_addf(&s->buf, "%s", _(s->mode->edit_hunk_hint));
10311028
/*
10321029
* TRANSLATORS: 'it' refers to the patch mentioned in the previous
10331030
* messages.
10341031
*/
1035-
strbuf_commented_addf(&buf,
1032+
strbuf_commented_addf(&s->buf,
10361033
_("If it does not apply cleanly, you will be "
10371034
"given an opportunity to\n"
10381035
"edit again. If all lines of the hunk are "
10391036
"removed, then the edit is\n"
10401037
"aborted and the hunk is left unchanged.\n"));
1041-
if (write_in_full(fd, buf.buf, buf.len) < 0) {
1042-
res = error_errno(_("could not write to '%s'"), path);
1043-
goto edit_hunk_manually_finish;
1044-
}
10451038

1046-
res = close(fd);
1047-
fd = -1;
1048-
if (res < 0)
1049-
goto edit_hunk_manually_finish;
1050-
1051-
hunk->start = s->plain.len;
1052-
if (launch_editor(path, &s->plain, NULL) < 0) {
1053-
res = error_errno(_("could not edit '%s'"), path);
1054-
goto edit_hunk_manually_finish;
1055-
}
1056-
unlink(path);
1039+
if (strbuf_edit_interactively(&s->buf, "addp-hunk-edit.diff", NULL) < 0)
1040+
return -1;
10571041

10581042
/* strip out commented lines */
1059-
copy = s->plain.buf[hunk->start] != comment_line_char;
1060-
for (i = j = hunk->start; i < s->plain.len; ) {
1061-
if (copy)
1062-
s->plain.buf[j++] = s->plain.buf[i];
1063-
if (s->plain.buf[i++] == '\n')
1064-
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;
10651053
}
10661054

1067-
if (j == hunk->start)
1068-
/* User aborted by deleting everything */
1069-
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;
10701059

1071-
res = 1;
1072-
strbuf_setlen(&s->plain, j);
1073-
hunk->end = j;
10741060
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+
*/
10751067
if (s->plain.buf[hunk->start] == '@' &&
1076-
/* If the hunk header was deleted, simply use the original one. */
10771068
parse_hunk_header(s, hunk) < 0)
1078-
res = -1;
1069+
return error(_("could not parse hunk header"));
10791070

1080-
edit_hunk_manually_finish:
1081-
if (fd >= 0)
1082-
close(fd);
1083-
free(path);
1084-
strbuf_release(&buf);
1085-
1086-
return res;
1071+
return 1;
10871072
}
10881073

10891074
static ssize_t recount_edited_hunk(struct add_p_state *s, struct hunk *hunk,
@@ -1165,13 +1150,13 @@ static int edit_hunk_loop(struct add_p_state *s,
11651150
size_t plain_len = s->plain.len, colored_len = s->colored.len;
11661151
struct hunk backup;
11671152

1168-
memcpy(&backup, hunk, sizeof(backup));
1153+
backup = *hunk;
11691154

11701155
for (;;) {
11711156
int res = edit_hunk_manually(s, hunk);
11721157
if (res == 0) {
11731158
/* abandonded */
1174-
memcpy(hunk, &backup, sizeof(backup));
1159+
*hunk = backup;
11751160
return -1;
11761161
}
11771162

@@ -1187,7 +1172,7 @@ static int edit_hunk_loop(struct add_p_state *s,
11871172
/* Drop edits (they were appended to s->plain) */
11881173
strbuf_setlen(&s->plain, plain_len);
11891174
strbuf_setlen(&s->colored, colored_len);
1190-
memcpy(hunk, &backup, sizeof(backup));
1175+
*hunk = backup;
11911176

11921177
/*
11931178
* TRANSLATORS: do not translate [y/n]

0 commit comments

Comments
 (0)