]> git.ipfire.org Git - thirdparty/git.git/blobdiff - add-patch.c
Merge branch 'jk/add-i-fixes'
[thirdparty/git.git] / add-patch.c
index e6fa10715d44b09d5c0c0154762d2934c43a835c..cd5cfc93fad5a04643718edd56b65326b51ff7ee 100644 (file)
@@ -2,7 +2,7 @@
 #include "add-interactive.h"
 #include "strbuf.h"
 #include "run-command.h"
-#include "argv-array.h"
+#include "strvec.h"
 #include "pathspec.h"
 #include "color.h"
 #include "diff.h"
@@ -266,6 +266,20 @@ 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);
+}
+
 static void err(struct add_p_state *s, const char *fmt, ...)
 {
        va_list args;
@@ -286,12 +300,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_array,
+                    INDEX_ENVIRONMENT "=%s", s->s.r->index_file);
 }
 
 static int parse_range(const char **p,
@@ -370,7 +384,7 @@ static int is_octal(const char *p, size_t len)
 
 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 +394,32 @@ 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) &&
+                           get_oid("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", "-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;
+       cp.argv = 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 +429,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");
+               colored_cp.argv = 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,7 +458,7 @@ 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;
@@ -457,11 +471,9 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
                        eol = pend;
 
                if (starts_with(p, "diff ")) {
-                       s->file_diff_nr++;
-                       ALLOC_GROW(s->file_diff, s->file_diff_nr,
+                       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)
@@ -483,11 +495,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)
@@ -511,7 +521,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
                        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 +530,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 =
@@ -1158,7 +1167,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"));
 
@@ -1203,7 +1212,7 @@ static int edit_hunk_loop(struct add_p_state *s,
        for (;;) {
                int res = edit_hunk_manually(s, hunk);
                if (res == 0) {
-                       /* abandonded */
+                       /* abandoned */
                        *hunk = backup;
                        return -1;
                }
@@ -1357,6 +1366,15 @@ static int patch_update_file(struct add_p_state *s,
        struct child_process cp = CHILD_PROCESS_INIT;
        int colored = !!s->colored.len, quit = 0;
        enum prompt_mode_type prompt_mode_type;
+       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;
 
        if (!file_diff->hunk_nr)
                return 0;
@@ -1393,22 +1411,35 @@ static int patch_update_file(struct add_p_state *s,
                fputs(s->buf.buf, stdout);
 
                strbuf_reset(&s->buf);
-               if (undecided_previous >= 0)
+               if (undecided_previous >= 0) {
+                       permitted |= ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK;
                        strbuf_addstr(&s->buf, ",k");
-               if (hunk_index)
+               }
+               if (hunk_index) {
+                       permitted |= ALLOW_GOTO_PREVIOUS_HUNK;
                        strbuf_addstr(&s->buf, ",K");
-               if (undecided_next >= 0)
+               }
+               if (undecided_next >= 0) {
+                       permitted |= ALLOW_GOTO_NEXT_UNDECIDED_HUNK;
                        strbuf_addstr(&s->buf, ",j");
-               if (hunk_index + 1 < file_diff->hunk_nr)
+               }
+               if (hunk_index + 1 < file_diff->hunk_nr) {
+                       permitted |= ALLOW_GOTO_NEXT_HUNK;
                        strbuf_addstr(&s->buf, ",J");
-               if (file_diff->hunk_nr > 1)
+               }
+               if (file_diff->hunk_nr > 1) {
+                       permitted |= ALLOW_SEARCH_AND_GOTO;
                        strbuf_addstr(&s->buf, ",g,/");
-               if (hunk->splittable_into > 1)
+               }
+               if (hunk->splittable_into > 1) {
+                       permitted |= ALLOW_SPLIT;
                        strbuf_addstr(&s->buf, ",s");
+               }
                if (hunk_index + 1 > file_diff->mode_change &&
-                   !file_diff->deleted)
+                   !file_diff->deleted) {
+                       permitted |= ALLOW_EDIT;
                        strbuf_addstr(&s->buf, ",e");
-
+               }
                if (file_diff->deleted)
                        prompt_mode_type = PROMPT_DELETION;
                else if (file_diff->added)
@@ -1457,22 +1488,22 @@ soft_increment:
                                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,7 +1511,7 @@ 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;
                        }
@@ -1517,7 +1548,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;
                        }
@@ -1562,7 +1593,7 @@ soft_increment:
                        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))
@@ -1570,7 +1601,7 @@ soft_increment:
                                                 _("Split into %d hunks."),
                                                 (int)splittable_into);
                } 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;
@@ -1619,7 +1650,7 @@ 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"));
@@ -1673,9 +1704,7 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
             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 +1719,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;
 }