]> git.ipfire.org Git - thirdparty/git.git/blobdiff - add-patch.c
Merge branch 'master' of github.com:Softcatala/git-po into git-po-master
[thirdparty/git.git] / add-patch.c
index fdbb1e3e2276f827ba187b7e86f7e2f394ec0c7d..2c46fe5b3332bf844007ea0d17dee250f0ba5756 100644 (file)
@@ -12,9 +12,9 @@ enum prompt_mode_type {
 };
 
 static const char *prompt_mode[] = {
-       N_("Stage mode change [y,n,a,d%s,?]? "),
-       N_("Stage deletion [y,n,a,d%s,?]? "),
-       N_("Stage this hunk [y,n,a,d%s,?]? ")
+       N_("Stage mode change [y,n,a,q,d%s,?]? "),
+       N_("Stage deletion [y,n,a,q,d%s,?]? "),
+       N_("Stage this hunk [y,n,a,q,d%s,?]? ")
 };
 
 struct hunk_header {
@@ -44,7 +44,7 @@ struct add_p_state {
                struct hunk head;
                struct hunk *hunk;
                size_t hunk_nr, hunk_alloc;
-               unsigned deleted:1, mode_change:1;
+               unsigned deleted:1, mode_change:1,binary:1;
        } *file_diff;
        size_t file_diff_nr;
 };
@@ -294,7 +294,9 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
                                BUG("'new mode' does not immediately follow "
                                    "'old mode'?\n\n%.*s",
                                    (int)(eol - plain->buf), plain->buf);
-               }
+               } else if (hunk == &file_diff->head &&
+                          starts_with(p, "Binary files "))
+                       file_diff->binary = 1;
 
                if (file_diff->deleted && file_diff->mode_change)
                        BUG("diff contains delete *and* a mode change?!?\n%.*s",
@@ -1006,13 +1008,17 @@ static size_t display_hunks(struct add_p_state *s,
 static const char help_patch_text[] =
 N_("y - stage this hunk\n"
    "n - do not stage this hunk\n"
+   "q - quit; do not stage this hunk or any of the remaining ones\n"
    "a - stage this and all the remaining hunks\n"
-   "d - do not stage this hunk nor any of the remaining hunks\n"
-   "j - leave this hunk undecided, see next undecided hunk\n"
+   "d - do not stage this hunk nor any of the remaining hunks\n");
+
+static const char help_patch_remainder[] =
+N_("j - leave this hunk undecided, see next undecided hunk\n"
    "J - leave this hunk undecided, see next hunk\n"
    "k - leave this hunk undecided, see previous undecided hunk\n"
    "K - leave this hunk undecided, see previous hunk\n"
    "g - select a hunk to go to\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"
    "? - print help\n");
@@ -1025,7 +1031,7 @@ static int patch_update_file(struct add_p_state *s,
        struct hunk *hunk;
        char ch;
        struct child_process cp = CHILD_PROCESS_INIT;
-       int colored = !!s->colored.len;
+       int colored = !!s->colored.len, quit = 0;
        enum prompt_mode_type prompt_mode_type;
 
        if (!file_diff->hunk_nr)
@@ -1072,7 +1078,7 @@ static int patch_update_file(struct add_p_state *s,
                if (hunk_index + 1 < file_diff->hunk_nr)
                        strbuf_addstr(&s->buf, ",J");
                if (file_diff->hunk_nr > 1)
-                       strbuf_addstr(&s->buf, ",g");
+                       strbuf_addstr(&s->buf, ",g,/");
                if (hunk->splittable_into > 1)
                        strbuf_addstr(&s->buf, ",s");
                if (hunk_index + 1 > file_diff->mode_change &&
@@ -1114,12 +1120,16 @@ soft_increment:
                                if (hunk->use == UNDECIDED_HUNK)
                                        hunk->use = USE_HUNK;
                        }
-               } else if (ch == 'd') {
+               } 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 (ch == 'q') {
+                               quit = 1;
+                               break;
+                       }
                } else if (s->answer.buf[0] == 'K') {
                        if (hunk_index)
                                hunk_index--;
@@ -1177,6 +1187,53 @@ soft_increment:
                                          "Sorry, only %d hunks available.",
                                          file_diff->hunk_nr),
                                    (int)file_diff->hunk_nr);
+               } else if (s->answer.buf[0] == '/') {
+                       regex_t regex;
+                       int ret;
+
+                       if (file_diff->hunk_nr < 2) {
+                               err(s, _("No other hunks to search"));
+                               continue;
+                       }
+                       strbuf_remove(&s->answer, 0, 1);
+                       strbuf_trim_trailing_newline(&s->answer);
+                       if (s->answer.len == 0) {
+                               printf("%s", _("search for regex? "));
+                               fflush(stdout);
+                               if (strbuf_getline(&s->answer,
+                                                  stdin) == EOF)
+                                       break;
+                               strbuf_trim_trailing_newline(&s->answer);
+                               if (s->answer.len == 0)
+                                       continue;
+                       }
+                       ret = regcomp(&regex, s->answer.buf,
+                                     REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+                       if (ret) {
+                               char errbuf[1024];
+
+                               regerror(ret, &regex, errbuf, sizeof(errbuf));
+                               err(s, _("Malformed search regexp %s: %s"),
+                                   s->answer.buf, errbuf);
+                               continue;
+                       }
+                       i = hunk_index;
+                       for (;;) {
+                               /* render the hunk into a scratch buffer */
+                               render_hunk(s, file_diff->hunk + i, 0, 0,
+                                           &s->buf);
+                               if (regexec(&regex, s->buf.buf, 0, NULL, 0)
+                                   != REG_NOMATCH)
+                                       break;
+                               i++;
+                               if (i == file_diff->hunk_nr)
+                                       i = 0;
+                               if (i != hunk_index)
+                                       continue;
+                               err(s, _("No hunk matches the given pattern"));
+                               break;
+                       }
+                       hunk_index = i;
                } else if (s->answer.buf[0] == 's') {
                        size_t splittable_into = hunk->splittable_into;
                        if (splittable_into < 2)
@@ -1193,9 +1250,31 @@ soft_increment:
                                hunk->use = USE_HUNK;
                                goto soft_increment;
                        }
-               } else
-                       color_fprintf(stdout, s->s.help_color,
+               } else {
+                       const char *p = _(help_patch_remainder), *eol = p;
+
+                       color_fprintf(stdout, s->s.help_color, "%s",
                                      _(help_patch_text));
+
+                       /*
+                        * Show only those lines of the remainder that are
+                        * actually applicable with the current hunk.
+                        */
+                       for (; *p; p = eol + (*eol == '\n')) {
+                               eol = strchrnul(p, '\n');
+
+                               /*
+                                * `s->buf` still contains the part of the
+                                * commands shown in the prompt that are not
+                                * always available.
+                                */
+                               if (*p != '?' && !strchr(s->buf.buf, *p))
+                                       continue;
+
+                               color_fprintf_ln(stdout, s->s.help_color,
+                                                "%.*s", (int)(eol - p), p);
+                       }
+               }
        }
 
        /* Any hunk to be used? */
@@ -1219,7 +1298,7 @@ soft_increment:
        }
 
        putchar('\n');
-       return 0;
+       return quit;
 }
 
 int run_add_p(struct repository *r, const struct pathspec *ps)
@@ -1227,7 +1306,7 @@ int run_add_p(struct repository *r, const struct pathspec *ps)
        struct add_p_state s = {
                { r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
        };
-       size_t i;
+       size_t i, binary_count = 0;
 
        init_add_i_state(&s.s, r);
 
@@ -1241,9 +1320,16 @@ int run_add_p(struct repository *r, const struct pathspec *ps)
        }
 
        for (i = 0; i < s.file_diff_nr; i++)
-               if (patch_update_file(&s, s.file_diff + i))
+               if (s.file_diff[i].binary && !s.file_diff[i].hunk_nr)
+                       binary_count++;
+               else if (patch_update_file(&s, s.file_diff + i))
                        break;
 
+       if (s.file_diff_nr == 0)
+               fprintf(stderr, _("No changes.\n"));
+       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);