diff options
Diffstat (limited to 'add-patch.c')
-rw-r--r-- | add-patch.c | 388 |
1 files changed, 238 insertions, 150 deletions
diff --git a/add-patch.c b/add-patch.c index a1d66c1..0997d4a 100644 --- a/add-patch.c +++ b/add-patch.c @@ -1,11 +1,17 @@ -#include "cache.h" +#include "git-compat-util.h" #include "add-interactive.h" +#include "advice.h" +#include "editor.h" +#include "environment.h" +#include "gettext.h" +#include "object-name.h" +#include "read-cache-ll.h" +#include "repository.h" #include "strbuf.h" #include "run-command.h" -#include "argv-array.h" +#include "strvec.h" #include "pathspec.h" #include "color.h" -#include "diff.h" #include "compat/terminal.h" #include "prompt.h" @@ -191,10 +197,10 @@ static struct patch_mode patch_mode_worktree_head = { .apply_check_args = { "-R", NULL }, .is_reverse = 1, .prompt_mode = { - N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "), - N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "), - N_("Discard addition from index and worktree [y,n,q,a,d%s,?]? "), - N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "), + N_("Discard mode change from worktree [y,n,q,a,d%s,?]? "), + N_("Discard deletion from worktree [y,n,q,a,d%s,?]? "), + N_("Discard addition from worktree [y,n,q,a,d%s,?]? "), + N_("Discard this hunk from worktree [y,n,q,a,d%s,?]? "), }, .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk " "will immediately be marked for discarding."), @@ -213,10 +219,10 @@ static struct patch_mode patch_mode_worktree_nothead = { .apply_args = { NULL }, .apply_check_args = { NULL }, .prompt_mode = { - N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "), - N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "), - N_("Apply addition to index and worktree [y,n,q,a,d%s,?]? "), - N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "), + N_("Apply mode change to worktree [y,n,q,a,d%s,?]? "), + N_("Apply deletion to worktree [y,n,q,a,d%s,?]? "), + N_("Apply addition to worktree [y,n,q,a,d%s,?]? "), + N_("Apply this hunk to worktree [y,n,q,a,d%s,?]? "), }, .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk " "will immediately be marked for applying."), @@ -238,6 +244,7 @@ struct hunk_header { * include the newline. */ size_t extra_start, extra_end, colored_extra_start, colored_extra_end; + unsigned suppress_colored_line_range:1; }; struct hunk { @@ -266,6 +273,21 @@ struct add_p_state { const char *revision; }; +static void add_p_state_clear(struct add_p_state *s) +{ + size_t i; + + strbuf_release(&s->answer); + strbuf_release(&s->buf); + strbuf_release(&s->plain); + strbuf_release(&s->colored); + for (i = 0; i < s->file_diff_nr; i++) + free(s->file_diff[i].hunk); + free(s->file_diff); + clear_add_i_state(&s->s); +} + +__attribute__((format (printf, 2, 3))) static void err(struct add_p_state *s, const char *fmt, ...) { va_list args; @@ -286,12 +308,12 @@ static void setup_child_process(struct add_p_state *s, va_start(ap, cp); while ((arg = va_arg(ap, const char *))) - argv_array_push(&cp->args, arg); + strvec_push(&cp->args, arg); va_end(ap); cp->git_cmd = 1; - argv_array_pushf(&cp->env_array, - INDEX_ENVIRONMENT "=%s", s->s.r->index_file); + strvec_pushf(&cp->env, + INDEX_ENVIRONMENT "=%s", s->s.r->index_file); } static int parse_range(const char **p, @@ -343,15 +365,14 @@ static int parse_hunk_header(struct add_p_state *s, struct hunk *hunk) if (!eol) eol = s->colored.buf + s->colored.len; p = memmem(line, eol - line, "@@ -", 4); - if (!p) - return error(_("could not parse colored hunk header '%.*s'"), - (int)(eol - line), line); - p = memmem(p + 4, eol - p - 4, " @@", 3); - if (!p) - return error(_("could not parse colored hunk header '%.*s'"), - (int)(eol - line), line); + if (p && (p = memmem(p + 4, eol - p - 4, " @@", 3))) { + header->colored_extra_start = p + 3 - s->colored.buf; + } else { + /* could not parse colored hunk header, leave as-is */ + header->colored_extra_start = hunk->colored_start; + header->suppress_colored_line_range = 1; + } hunk->colored_start = eol - s->colored.buf + (*eol == '\n'); - header->colored_extra_start = p + 3 - s->colored.buf; header->colored_extra_end = hunk->colored_start; return 0; @@ -368,9 +389,20 @@ static int is_octal(const char *p, size_t len) return 1; } +static void complete_file(char marker, struct hunk *hunk) +{ + if (marker == '-' || marker == '+') + /* + * Last hunk ended in non-context line (i.e. it + * appended lines to the file, so there are no + * trailing context lines). + */ + hunk->splittable_into++; +} + static int parse_diff(struct add_p_state *s, const struct pathspec *ps) { - struct argv_array args = ARGV_ARRAY_INIT; + struct strvec args = STRVEC_INIT; const char *diff_algorithm = s->s.interactive_diff_algorithm; struct strbuf *plain = &s->plain, *colored = NULL; struct child_process cp = CHILD_PROCESS_INIT; @@ -380,32 +412,33 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) struct hunk *hunk = NULL; int res; - argv_array_pushv(&args, s->mode->diff_cmd); + strvec_pushv(&args, s->mode->diff_cmd); if (diff_algorithm) - argv_array_pushf(&args, "--diff-algorithm=%s", diff_algorithm); + strvec_pushf(&args, "--diff-algorithm=%s", diff_algorithm); if (s->revision) { struct object_id oid; - argv_array_push(&args, - /* could be on an unborn branch */ - !strcmp("HEAD", s->revision) && - get_oid("HEAD", &oid) ? - empty_tree_oid_hex() : s->revision); + strvec_push(&args, + /* could be on an unborn branch */ + !strcmp("HEAD", s->revision) && + repo_get_oid(the_repository, "HEAD", &oid) ? + empty_tree_oid_hex() : s->revision); } - color_arg_index = args.argc; + color_arg_index = args.nr; /* Use `--no-color` explicitly, just in case `diff.color = always`. */ - argv_array_pushl(&args, "--no-color", "-p", "--", NULL); + strvec_pushl(&args, "--no-color", "--ignore-submodules=dirty", "-p", + "--", NULL); for (i = 0; i < ps->nr; i++) - argv_array_push(&args, ps->items[i].original); + strvec_push(&args, ps->items[i].original); setup_child_process(s, &cp, NULL); - cp.argv = args.argv; + strvec_pushv(&cp.args, args.v); res = capture_command(&cp, plain, 0); if (res) { - argv_array_clear(&args); + strvec_clear(&args); return error(_("could not parse diff")); } if (!plain->len) { - argv_array_clear(&args); + strvec_clear(&args); return 0; } strbuf_complete_line(plain); @@ -415,11 +448,11 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) const char *diff_filter = s->s.interactive_diff_filter; setup_child_process(s, &colored_cp, NULL); - xsnprintf((char *)args.argv[color_arg_index], 8, "--color"); - colored_cp.argv = args.argv; + xsnprintf((char *)args.v[color_arg_index], 8, "--color"); + strvec_pushv(&colored_cp.args, args.v); colored = &s->colored; res = capture_command(&colored_cp, colored, 0); - argv_array_clear(&args); + strvec_clear(&args); if (res) return error(_("could not parse colored diff")); @@ -444,24 +477,24 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) colored_p = colored->buf; colored_pend = colored_p + colored->len; } - argv_array_clear(&args); + strvec_clear(&args); /* parse files and hunks */ p = plain->buf; pend = p + plain->len; while (p != pend) { char *eol = memchr(p, '\n', pend - p); - const char *deleted = NULL, *added = NULL, *mode_change = NULL; + const char *deleted = NULL, *mode_change = NULL; if (!eol) eol = pend; - if (starts_with(p, "diff ")) { - s->file_diff_nr++; - ALLOC_GROW(s->file_diff, s->file_diff_nr, + if (starts_with(p, "diff ") || + starts_with(p, "* Unmerged path ")) { + complete_file(marker, hunk); + ALLOC_GROW_BY(s->file_diff, s->file_diff_nr, 1, file_diff_alloc); file_diff = s->file_diff + s->file_diff_nr - 1; - memset(file_diff, 0, sizeof(*file_diff)); hunk = &file_diff->head; hunk->start = p - plain->buf; if (colored_p) @@ -470,12 +503,11 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) } else if (p == plain->buf) BUG("diff starts with unexpected line:\n" "%.*s\n", (int)(eol - p), p); - else if (file_diff->deleted || file_diff->added) + else if (file_diff->deleted) ; /* keep the rest of the file in a single "hunk" */ else if (starts_with(p, "@@ ") || (hunk == &file_diff->head && - (skip_prefix(p, "deleted file", &deleted) || - skip_prefix(p, "new file", &added)))) { + (skip_prefix(p, "deleted file", &deleted)))) { if (marker == '-' || marker == '+') /* * Should not happen; previous hunk did not end @@ -483,11 +515,9 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) */ hunk->splittable_into++; - file_diff->hunk_nr++; - ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr, + ALLOC_GROW_BY(file_diff->hunk, file_diff->hunk_nr, 1, file_diff->hunk_alloc); hunk = file_diff->hunk + file_diff->hunk_nr - 1; - memset(hunk, 0, sizeof(*hunk)); hunk->start = p - plain->buf; if (colored) @@ -495,8 +525,6 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) if (deleted) file_diff->deleted = 1; - else if (added) - file_diff->added = 1; else if (parse_hunk_header(s, hunk) < 0) return -1; @@ -506,12 +534,15 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) */ marker = *p; } else if (hunk == &file_diff->head && + starts_with(p, "new file")) { + file_diff->added = 1; + } else if (hunk == &file_diff->head && skip_prefix(p, "old mode ", &mode_change) && is_octal(mode_change, eol - mode_change)) { if (file_diff->mode_change) BUG("double mode change?\n\n%.*s", (int)(eol - plain->buf), plain->buf); - if (file_diff->hunk_nr++) + if (file_diff->hunk_nr) BUG("mode change in the middle?\n\n%.*s", (int)(eol - plain->buf), plain->buf); @@ -520,9 +551,8 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) * is _part of_ the header "hunk". */ file_diff->mode_change = 1; - ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr, + ALLOC_GROW_BY(file_diff->hunk, file_diff->hunk_nr, 1, file_diff->hunk_alloc); - memset(file_diff->hunk, 0, sizeof(struct hunk)); file_diff->hunk->start = p - plain->buf; if (colored_p) file_diff->hunk->colored_start = @@ -570,7 +600,10 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) if (colored_eol) colored_p = colored_eol + 1; else if (p != pend) - /* colored shorter than non-colored? */ + /* non-colored has more lines? */ + goto mismatched_output; + else if (colored_p == colored_pend) + /* last line has no matching colored one? */ goto mismatched_output; else colored_p = colored_pend; @@ -588,13 +621,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) file_diff->hunk->colored_end = hunk->colored_end; } } - - if (marker == '-' || marker == '+') - /* - * Last hunk ended in non-context line (i.e. it appended lines - * to the file, so there are no trailing context lines). - */ - hunk->splittable_into++; + complete_file(marker, hunk); /* non-colored shorter than colored? */ if (colored_p != colored_pend) { @@ -640,6 +667,15 @@ static void render_hunk(struct add_p_state *s, struct hunk *hunk, if (!colored) { p = s->plain.buf + header->extra_start; len = header->extra_end - header->extra_start; + } else if (header->suppress_colored_line_range) { + strbuf_add(out, + s->colored.buf + header->colored_extra_start, + header->colored_extra_end - + header->colored_extra_start); + + strbuf_add(out, s->colored.buf + hunk->colored_start, + hunk->colored_end - hunk->colored_start); + return; } else { strbuf_addstr(out, s->s.fraginfo_color); p = s->colored.buf + header->colored_extra_start; @@ -652,13 +688,18 @@ static void render_hunk(struct add_p_state *s, struct hunk *hunk, else new_offset += delta; - strbuf_addf(out, "@@ -%lu,%lu +%lu,%lu @@", - old_offset, header->old_count, - new_offset, header->new_count); + strbuf_addf(out, "@@ -%lu", old_offset); + if (header->old_count != 1) + strbuf_addf(out, ",%lu", header->old_count); + strbuf_addf(out, " +%lu", new_offset); + if (header->new_count != 1) + strbuf_addf(out, ",%lu", header->new_count); + strbuf_addstr(out, " @@"); + if (len) strbuf_add(out, p, len); else if (colored) - strbuf_addf(out, "%s\n", GIT_COLOR_RESET); + strbuf_addf(out, "%s\n", s->s.reset_color); else strbuf_addch(out, '\n'); } @@ -1051,7 +1092,7 @@ static void recolor_hunk(struct add_p_state *s, struct hunk *hunk) s->s.file_new_color : s->s.context_color); strbuf_add(&s->colored, plain + current, eol - current); - strbuf_addstr(&s->colored, GIT_COLOR_RESET); + strbuf_addstr(&s->colored, s->s.reset_color); if (next > eol) strbuf_add(&s->colored, plain + eol, next - eol); current = next; @@ -1064,24 +1105,26 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk) size_t i; strbuf_reset(&s->buf); - strbuf_commented_addf(&s->buf, _("Manual hunk edit mode -- see bottom for " - "a quick guide.\n")); + strbuf_commented_addf(&s->buf, comment_line_str, + _("Manual hunk edit mode -- see bottom for " + "a quick guide.\n")); render_hunk(s, hunk, 0, 0, &s->buf); - strbuf_commented_addf(&s->buf, + strbuf_commented_addf(&s->buf, comment_line_str, _("---\n" "To remove '%c' lines, make them ' ' lines " "(context).\n" "To remove '%c' lines, delete them.\n" - "Lines starting with %c will be removed.\n"), + "Lines starting with %s will be removed.\n"), s->mode->is_reverse ? '+' : '-', s->mode->is_reverse ? '-' : '+', - comment_line_char); - strbuf_commented_addf(&s->buf, "%s", _(s->mode->edit_hunk_hint)); + comment_line_str); + strbuf_commented_addf(&s->buf, comment_line_str, "%s", + _(s->mode->edit_hunk_hint)); /* * TRANSLATORS: 'it' refers to the patch mentioned in the previous * messages. */ - strbuf_commented_addf(&s->buf, + strbuf_commented_addf(&s->buf, comment_line_str, _("If it does not apply cleanly, you will be " "given an opportunity to\n" "edit again. If all lines of the hunk are " @@ -1096,7 +1139,7 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk) for (i = 0; i < s->buf.len; ) { size_t next = find_next_line(&s->buf, i); - if (s->buf.buf[i] != comment_line_char) + if (!starts_with(s->buf.buf + i, comment_line_str)) strbuf_add(&s->plain, s->buf.buf + i, next - i); i = next; } @@ -1158,7 +1201,7 @@ static int run_apply_check(struct add_p_state *s, setup_child_process(s, &cp, "apply", "--check", NULL); - argv_array_pushv(&cp.args, s->mode->apply_check_args); + strvec_pushv(&cp.args, s->mode->apply_check_args); if (pipe_command(&cp, s->buf.buf, s->buf.len, NULL, 0, NULL, 0)) return error(_("'git apply --cached' failed")); @@ -1345,20 +1388,31 @@ N_("j - leave this hunk undecided, see next undecided hunk\n" "/ - search for a hunk matching the given regex\n" "s - split the current hunk into smaller hunks\n" "e - manually edit the current hunk\n" + "p - print the current hunk\n" "? - print help\n"); static int patch_update_file(struct add_p_state *s, struct file_diff *file_diff) { size_t hunk_index = 0; - ssize_t i, undecided_previous, undecided_next; + ssize_t i, undecided_previous, undecided_next, rendered_hunk_index = -1; struct hunk *hunk; char ch; struct child_process cp = CHILD_PROCESS_INIT; int colored = !!s->colored.len, quit = 0; enum prompt_mode_type prompt_mode_type; - - if (!file_diff->hunk_nr) + enum { + ALLOW_GOTO_PREVIOUS_HUNK = 1 << 0, + ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK = 1 << 1, + ALLOW_GOTO_NEXT_HUNK = 1 << 2, + ALLOW_GOTO_NEXT_UNDECIDED_HUNK = 1 << 3, + ALLOW_SEARCH_AND_GOTO = 1 << 4, + ALLOW_SPLIT = 1 << 5, + ALLOW_EDIT = 1 << 6 + } permitted = 0; + + /* Empty added files have no hunks */ + if (!file_diff->hunk_nr && !file_diff->added) return 0; strbuf_reset(&s->buf); @@ -1367,21 +1421,25 @@ static int patch_update_file(struct add_p_state *s, for (;;) { if (hunk_index >= file_diff->hunk_nr) hunk_index = 0; - hunk = file_diff->hunk + hunk_index; - + hunk = file_diff->hunk_nr + ? file_diff->hunk + hunk_index + : &file_diff->head; undecided_previous = -1; - for (i = hunk_index - 1; i >= 0; i--) - if (file_diff->hunk[i].use == UNDECIDED_HUNK) { - undecided_previous = i; - break; - } - undecided_next = -1; - for (i = hunk_index + 1; i < file_diff->hunk_nr; i++) - if (file_diff->hunk[i].use == UNDECIDED_HUNK) { - undecided_next = i; - break; - } + + if (file_diff->hunk_nr) { + for (i = hunk_index - 1; i >= 0; i--) + if (file_diff->hunk[i].use == UNDECIDED_HUNK) { + undecided_previous = i; + break; + } + + for (i = hunk_index + 1; i < file_diff->hunk_nr; i++) + if (file_diff->hunk[i].use == UNDECIDED_HUNK) { + undecided_next = i; + break; + } + } /* Everything decided? */ if (undecided_previous < 0 && undecided_next < 0 && @@ -1389,26 +1447,45 @@ static int patch_update_file(struct add_p_state *s, break; strbuf_reset(&s->buf); - render_hunk(s, hunk, 0, colored, &s->buf); - fputs(s->buf.buf, stdout); - - strbuf_reset(&s->buf); - if (undecided_previous >= 0) - strbuf_addstr(&s->buf, ",k"); - if (hunk_index) - strbuf_addstr(&s->buf, ",K"); - if (undecided_next >= 0) - strbuf_addstr(&s->buf, ",j"); - if (hunk_index + 1 < file_diff->hunk_nr) - strbuf_addstr(&s->buf, ",J"); - if (file_diff->hunk_nr > 1) - strbuf_addstr(&s->buf, ",g,/"); - if (hunk->splittable_into > 1) - strbuf_addstr(&s->buf, ",s"); - if (hunk_index + 1 > file_diff->mode_change && - !file_diff->deleted) - strbuf_addstr(&s->buf, ",e"); + if (file_diff->hunk_nr) { + if (rendered_hunk_index != hunk_index) { + render_hunk(s, hunk, 0, colored, &s->buf); + fputs(s->buf.buf, stdout); + rendered_hunk_index = hunk_index; + } + strbuf_reset(&s->buf); + if (undecided_previous >= 0) { + permitted |= ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK; + strbuf_addstr(&s->buf, ",k"); + } + if (hunk_index) { + permitted |= ALLOW_GOTO_PREVIOUS_HUNK; + strbuf_addstr(&s->buf, ",K"); + } + if (undecided_next >= 0) { + permitted |= ALLOW_GOTO_NEXT_UNDECIDED_HUNK; + strbuf_addstr(&s->buf, ",j"); + } + if (hunk_index + 1 < file_diff->hunk_nr) { + permitted |= ALLOW_GOTO_NEXT_HUNK; + strbuf_addstr(&s->buf, ",J"); + } + if (file_diff->hunk_nr > 1) { + permitted |= ALLOW_SEARCH_AND_GOTO; + strbuf_addstr(&s->buf, ",g,/"); + } + if (hunk->splittable_into > 1) { + permitted |= ALLOW_SPLIT; + strbuf_addstr(&s->buf, ",s"); + } + if (hunk_index + 1 > file_diff->mode_change && + !file_diff->deleted) { + permitted |= ALLOW_EDIT; + strbuf_addstr(&s->buf, ",e"); + } + strbuf_addstr(&s->buf, ",p"); + } if (file_diff->deleted) prompt_mode_type = PROMPT_DELETION; else if (file_diff->added) @@ -1418,13 +1495,15 @@ static int patch_update_file(struct add_p_state *s, else prompt_mode_type = PROMPT_HUNK; - color_fprintf(stdout, s->s.prompt_color, - "(%"PRIuMAX"/%"PRIuMAX") ", + printf("%s(%"PRIuMAX"/%"PRIuMAX") ", s->s.prompt_color, (uintmax_t)hunk_index + 1, - (uintmax_t)file_diff->hunk_nr); - color_fprintf(stdout, s->s.prompt_color, - _(s->mode->prompt_mode[prompt_mode_type]), - s->buf.buf); + (uintmax_t)(file_diff->hunk_nr + ? file_diff->hunk_nr + : 1)); + printf(_(s->mode->prompt_mode[prompt_mode_type]), + s->buf.buf); + if (*s->s.reset_color) + fputs(s->s.reset_color, stdout); fflush(stdout); if (read_single_character(s) == EOF) break; @@ -1441,38 +1520,46 @@ soft_increment: hunk->use = SKIP_HUNK; goto soft_increment; } else if (ch == 'a') { - for (; hunk_index < file_diff->hunk_nr; hunk_index++) { - hunk = file_diff->hunk + hunk_index; - if (hunk->use == UNDECIDED_HUNK) - hunk->use = USE_HUNK; + if (file_diff->hunk_nr) { + for (; hunk_index < file_diff->hunk_nr; hunk_index++) { + hunk = file_diff->hunk + hunk_index; + if (hunk->use == UNDECIDED_HUNK) + hunk->use = USE_HUNK; + } + } else if (hunk->use == UNDECIDED_HUNK) { + hunk->use = USE_HUNK; } } else if (ch == 'd' || ch == 'q') { - for (; hunk_index < file_diff->hunk_nr; hunk_index++) { - hunk = file_diff->hunk + hunk_index; - if (hunk->use == UNDECIDED_HUNK) - hunk->use = SKIP_HUNK; + if (file_diff->hunk_nr) { + for (; hunk_index < file_diff->hunk_nr; hunk_index++) { + hunk = file_diff->hunk + hunk_index; + if (hunk->use == UNDECIDED_HUNK) + hunk->use = SKIP_HUNK; + } + } else if (hunk->use == UNDECIDED_HUNK) { + hunk->use = SKIP_HUNK; } if (ch == 'q') { quit = 1; break; } } else if (s->answer.buf[0] == 'K') { - if (hunk_index) + if (permitted & ALLOW_GOTO_PREVIOUS_HUNK) hunk_index--; else err(s, _("No previous hunk")); } else if (s->answer.buf[0] == 'J') { - if (hunk_index + 1 < file_diff->hunk_nr) + if (permitted & ALLOW_GOTO_NEXT_HUNK) hunk_index++; else err(s, _("No next hunk")); } else if (s->answer.buf[0] == 'k') { - if (undecided_previous >= 0) + if (permitted & ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK) hunk_index = undecided_previous; else err(s, _("No previous hunk")); } else if (s->answer.buf[0] == 'j') { - if (undecided_next >= 0) + if (permitted & ALLOW_GOTO_NEXT_UNDECIDED_HUNK) hunk_index = undecided_next; else err(s, _("No next hunk")); @@ -1480,14 +1567,14 @@ soft_increment: char *pend; unsigned long response; - if (file_diff->hunk_nr < 2) { + if (!(permitted & ALLOW_SEARCH_AND_GOTO)) { err(s, _("No other hunks to goto")); continue; } strbuf_remove(&s->answer, 0, 1); strbuf_trim(&s->answer); i = hunk_index - DISPLAY_HUNKS_LINES / 2; - if (i < file_diff->mode_change) + if (i < (int)file_diff->mode_change) i = file_diff->mode_change; while (s->answer.len == 0) { i = display_hunks(s, file_diff, i); @@ -1517,7 +1604,7 @@ soft_increment: regex_t regex; int ret; - if (file_diff->hunk_nr < 2) { + if (!(permitted & ALLOW_SEARCH_AND_GOTO)) { err(s, _("No other hunks to search")); continue; } @@ -1559,23 +1646,28 @@ soft_increment: err(s, _("No hunk matches the given pattern")); break; } + regfree(®ex); hunk_index = i; } else if (s->answer.buf[0] == 's') { size_t splittable_into = hunk->splittable_into; - if (splittable_into < 2) + if (!(permitted & ALLOW_SPLIT)) { err(s, _("Sorry, cannot split this hunk")); - else if (!split_hunk(s, file_diff, - hunk - file_diff->hunk)) + } else if (!split_hunk(s, file_diff, + hunk - file_diff->hunk)) { color_fprintf_ln(stdout, s->s.header_color, _("Split into %d hunks."), (int)splittable_into); + rendered_hunk_index = -1; + } } else if (s->answer.buf[0] == 'e') { - if (hunk_index + 1 == file_diff->mode_change) + if (!(permitted & ALLOW_EDIT)) err(s, _("Sorry, cannot edit this hunk")); else if (edit_hunk_loop(s, file_diff, hunk) >= 0) { hunk->use = USE_HUNK; goto soft_increment; } + } else if (s->answer.buf[0] == 'p') { + rendered_hunk_index = -1; } else { const char *p = _(help_patch_remainder), *eol = p; @@ -1608,7 +1700,8 @@ soft_increment: if (file_diff->hunk[i].use == USE_HUNK) break; - if (i < file_diff->hunk_nr) { + if (i < file_diff->hunk_nr || + (!file_diff->hunk_nr && file_diff->head.use == USE_HUNK)) { /* At least one hunk selected: apply */ strbuf_reset(&s->buf); reassemble_patch(s, file_diff, 0, &s->buf); @@ -1619,12 +1712,12 @@ soft_increment: s->mode->is_reverse); else { setup_child_process(s, &cp, "apply", NULL); - argv_array_pushv(&cp.args, s->mode->apply_args); + strvec_pushv(&cp.args, s->mode->apply_args); if (pipe_command(&cp, s->buf.buf, s->buf.len, NULL, 0, NULL, 0)) error(_("'git apply' failed")); } - if (!repo_read_index(s->s.r)) + if (repo_read_index(s->s.r) >= 0) repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0, 1, NULL, NULL, NULL); } @@ -1668,14 +1761,13 @@ int run_add_p(struct repository *r, enum add_p_mode mode, s.mode = &patch_mode_add; s.revision = revision; - if (discard_index(r->index) < 0 || repo_read_index(r) < 0 || + discard_index(r->index); + if (repo_read_index(r) < 0 || (!s.mode->index_only && repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1, NULL, NULL, NULL) < 0) || parse_diff(&s, ps) < 0) { - strbuf_release(&s.plain); - strbuf_release(&s.colored); - clear_add_i_state(&s.s); + add_p_state_clear(&s); return -1; } @@ -1690,10 +1782,6 @@ int run_add_p(struct repository *r, enum add_p_mode mode, else if (binary_count == s.file_diff_nr) fprintf(stderr, _("Only binary files changed.\n")); - strbuf_release(&s.answer); - strbuf_release(&s.buf); - strbuf_release(&s.plain); - strbuf_release(&s.colored); - clear_add_i_state(&s.s); + add_p_state_clear(&s); return 0; } |