8
#include "diff.h"
9
10
enum prompt_mode_type {
11
- PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK
11
+ PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK,
12
+ PROMPT_MODE_MAX, /* must be last */
13
};
14
14
-static const char *prompt_mode[] = {
15
- N_("Stage mode change [y,n,a,q,d%s,?]? "),
16
- N_("Stage deletion [y,n,a,q,d%s,?]? "),
17
- N_("Stage this hunk [y,n,a,q,d%s,?]? ")
15
+struct patch_mode {
16
+ /*
17
+ * The magic constant 4 is chosen such that all patch modes
18
+ * provide enough space for three command-line arguments followed by a
19
+ * trailing `NULL`.
20
+ */
21
+ const char *diff_cmd[4], *apply_args[4], *apply_check_args[4];
22
+ unsigned is_reverse:1, apply_for_checkout:1;
23
+ const char *prompt_mode[PROMPT_MODE_MAX];
24
+ const char *edit_hunk_hint, *help_patch_text;
25
+};
26
+
27
+static struct patch_mode patch_mode_add = {
28
+ .diff_cmd = { "diff-files", NULL },
29
+ .apply_args = { "--cached", NULL },
30
+ .apply_check_args = { "--cached", NULL },
31
+ .prompt_mode = {
32
+ N_("Stage mode change [y,n,q,a,d%s,?]? "),
33
+ N_("Stage deletion [y,n,q,a,d%s,?]? "),
34
+ N_("Stage this hunk [y,n,q,a,d%s,?]? ")
35
+ },
36
+ .edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
37
+ "will immediately be marked for staging."),
38
+ .help_patch_text =
39
+ N_("y - stage this hunk\n"
40
+ "n - do not stage this hunk\n"
41
+ "q - quit; do not stage this hunk or any of the remaining "
42
+ "ones\n"
43
+ "a - stage this hunk and all later hunks in the file\n"
44
+ "d - do not stage this hunk or any of the later hunks in "
45
+ "the file\n")
46
};
47
48
struct hunk_header {
75
unsigned deleted:1, mode_change:1,binary:1;
76
} *file_diff;
77
size_t file_diff_nr;
78
+
79
+ /* patch mode */
80
+ struct patch_mode *mode;
81
+ const char *revision;
82
};
83
84
static void err(struct add_p_state *s, const char *fmt, ...)
194
struct hunk *hunk = NULL;
195
int res;
196
197
+ argv_array_pushv(&args, s->mode->diff_cmd);
198
+ if (s->revision) {
199
+ struct object_id oid;
200
+ argv_array_push(&args,
201
+ /* could be on an unborn branch */
202
+ !strcmp("HEAD", s->revision) &&
203
+ get_oid("HEAD", &oid) ?
204
+ empty_tree_oid_hex() : s->revision);
205
+ }
206
+ color_arg_index = args.argc;
207
/* Use `--no-color` explicitly, just in case `diff.color = always`. */
166
- argv_array_pushl(&args, "diff-files", "-p", "--no-color", "--", NULL);
167
- color_arg_index = args.argc - 2;
208
+ argv_array_pushl(&args, "--no-color", "-p", "--", NULL);
209
for (i = 0; i < ps->nr; i++)
210
argv_array_push(&args, ps->items[i].original);
211
423
- header->colored_extra_start;
424
}
425
385
- new_offset += delta;
426
+ if (s->mode->is_reverse)
427
+ old_offset -= delta;
428
+ else
429
+ new_offset += delta;
430
431
strbuf_addf(out, "@@ -%lu,%lu +%lu,%lu @@",
432
old_offset, header->old_count,
849
"(context).\n"
850
"To remove '%c' lines, delete them.\n"
851
"Lines starting with %c will be removed.\n"),
808
- '-', '+', comment_line_char);
809
- strbuf_commented_addf(&s->buf,
810
- _("If the patch applies cleanly, the edited hunk "
811
- "will immediately be\n"
812
- "marked for staging.\n"));
852
+ s->mode->is_reverse ? '+' : '-',
853
+ s->mode->is_reverse ? '-' : '+',
854
+ comment_line_char);
855
+ strbuf_commented_addf(&s->buf, "%s", _(s->mode->edit_hunk_hint));
856
/*
857
* TRANSLATORS: 'it' refers to the patch mentioned in the previous
858
* messages.
933
reassemble_patch(s, file_diff, 1, &s->buf);
934
935
setup_child_process(s, &cp,
893
- "apply", "--cached", "--check", NULL);
936
+ "apply", "--check", NULL);
937
+ argv_array_pushv(&cp.args, s->mode->apply_check_args);
938
if (pipe_command(&cp, s->buf.buf, s->buf.len, NULL, 0, NULL, 0))
939
return error(_("'git apply --cached' failed"));
940
1049
return end_index;
1050
}
1051
1008
-static const char help_patch_text[] =
1009
-N_("y - stage this hunk\n"
1010
- "n - do not stage this hunk\n"
1011
- "q - quit; do not stage this hunk or any of the remaining ones\n"
1012
- "a - stage this and all the remaining hunks\n"
1013
- "d - do not stage this hunk nor any of the remaining hunks\n");
1014
-
1052
static const char help_patch_remainder[] =
1053
N_("j - leave this hunk undecided, see next undecided hunk\n"
1054
"J - leave this hunk undecided, see next hunk\n"
1134
(uintmax_t)hunk_index + 1,
1135
(uintmax_t)file_diff->hunk_nr);
1136
color_fprintf(stdout, s->s.prompt_color,
1100
- _(prompt_mode[prompt_mode_type]), s->buf.buf);
1137
+ _(s->mode->prompt_mode[prompt_mode_type]),
1138
+ s->buf.buf);
1139
fflush(stdout);
1140
if (strbuf_getline(&s->answer, stdin) == EOF)
1141
break;
1292
const char *p = _(help_patch_remainder), *eol = p;
1293
1294
color_fprintf(stdout, s->s.help_color, "%s",
1257
- _(help_patch_text));
1295
+ _(s->mode->help_patch_text));
1296
1297
/*
1298
* Show only those lines of the remainder that are
1326
reassemble_patch(s, file_diff, 0, &s->buf);
1327
1328
discard_index(s->s.r->index);
1291
- setup_child_process(s, &cp, "apply", "--cached", NULL);
1329
+ setup_child_process(s, &cp, "apply", NULL);
1330
+ argv_array_pushv(&cp.args, s->mode->apply_args);
1331
if (pipe_command(&cp, s->buf.buf, s->buf.len,
1332
NULL, 0, NULL, 0))
1294
- error(_("'git apply --cached' failed"));
1333
+ error(_("'git apply' failed"));
1334
if (!repo_read_index(s->s.r))
1335
repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0,
1336
1, NULL, NULL, NULL);
1340
return quit;
1341
}
1342
1304
-int run_add_p(struct repository *r, const struct pathspec *ps)
1343
+int run_add_p(struct repository *r, enum add_p_mode mode,
1344
+ const char *revision, const struct pathspec *ps)
1345
{
1346
struct add_p_state s = {
1347
{ r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
1350
1351
init_add_i_state(&s.s, r);
1352
1353
+ s.mode = &patch_mode_add;
1354
+ s.revision = revision;
1355
+
1356
if (discard_index(r->index) < 0 || repo_read_index(r) < 0 ||
1357
repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
1358
NULL, NULL, NULL) < 0 ||