1 #define USE_THE_REPOSITORY_VARIABLE
2 #define DISABLE_SIGN_COMPARE_WARNINGS
4 #include "git-compat-util.h"
5 #include "add-interactive.h"
8 #include "environment.h"
10 #include "object-name.h"
12 #include "read-cache-ll.h"
13 #include "repository.h"
16 #include "run-command.h"
20 #include "compat/terminal.h"
23 enum prompt_mode_type
{
24 PROMPT_MODE_CHANGE
= 0, PROMPT_DELETION
, PROMPT_ADDITION
, PROMPT_HUNK
,
25 PROMPT_MODE_MAX
, /* must be last */
30 * The magic constant 4 is chosen such that all patch modes
31 * provide enough space for three command-line arguments followed by a
34 const char *diff_cmd
[4], *apply_args
[4], *apply_check_args
[4];
35 unsigned is_reverse
:1, index_only
:1, apply_for_checkout
:1;
36 const char *prompt_mode
[PROMPT_MODE_MAX
];
37 const char *edit_hunk_hint
, *help_patch_text
;
40 static struct patch_mode patch_mode_add
= {
41 .diff_cmd
= { "diff-files", NULL
},
42 .apply_args
= { "--cached", NULL
},
43 .apply_check_args
= { "--cached", NULL
},
45 N_("Stage mode change [y,n,q,a,d%s,?]? "),
46 N_("Stage deletion [y,n,q,a,d%s,?]? "),
47 N_("Stage addition [y,n,q,a,d%s,?]? "),
48 N_("Stage this hunk [y,n,q,a,d%s,?]? ")
50 .edit_hunk_hint
= N_("If the patch applies cleanly, the edited hunk "
51 "will immediately be marked for staging."),
53 N_("y - stage this hunk\n"
54 "n - do not stage this hunk\n"
55 "q - quit; do not stage this hunk or any of the remaining "
57 "a - stage this hunk and all later hunks in the file\n"
58 "d - do not stage this hunk or any of the later hunks in "
62 static struct patch_mode patch_mode_stash
= {
63 .diff_cmd
= { "diff-index", "HEAD", NULL
},
64 .apply_args
= { "--cached", NULL
},
65 .apply_check_args
= { "--cached", NULL
},
67 N_("Stash mode change [y,n,q,a,d%s,?]? "),
68 N_("Stash deletion [y,n,q,a,d%s,?]? "),
69 N_("Stash addition [y,n,q,a,d%s,?]? "),
70 N_("Stash this hunk [y,n,q,a,d%s,?]? "),
72 .edit_hunk_hint
= N_("If the patch applies cleanly, the edited hunk "
73 "will immediately be marked for stashing."),
75 N_("y - stash this hunk\n"
76 "n - do not stash this hunk\n"
77 "q - quit; do not stash this hunk or any of the remaining "
79 "a - stash this hunk and all later hunks in the file\n"
80 "d - do not stash this hunk or any of the later hunks in "
84 static struct patch_mode patch_mode_reset_head
= {
85 .diff_cmd
= { "diff-index", "--cached", NULL
},
86 .apply_args
= { "-R", "--cached", NULL
},
87 .apply_check_args
= { "-R", "--cached", NULL
},
91 N_("Unstage mode change [y,n,q,a,d%s,?]? "),
92 N_("Unstage deletion [y,n,q,a,d%s,?]? "),
93 N_("Unstage addition [y,n,q,a,d%s,?]? "),
94 N_("Unstage this hunk [y,n,q,a,d%s,?]? "),
96 .edit_hunk_hint
= N_("If the patch applies cleanly, the edited hunk "
97 "will immediately be marked for unstaging."),
99 N_("y - unstage this hunk\n"
100 "n - do not unstage this hunk\n"
101 "q - quit; do not unstage this hunk or any of the remaining "
103 "a - unstage this hunk and all later hunks in the file\n"
104 "d - do not unstage this hunk or any of the later hunks in "
108 static struct patch_mode patch_mode_reset_nothead
= {
109 .diff_cmd
= { "diff-index", "-R", "--cached", NULL
},
110 .apply_args
= { "--cached", NULL
},
111 .apply_check_args
= { "--cached", NULL
},
114 N_("Apply mode change to index [y,n,q,a,d%s,?]? "),
115 N_("Apply deletion to index [y,n,q,a,d%s,?]? "),
116 N_("Apply addition to index [y,n,q,a,d%s,?]? "),
117 N_("Apply this hunk to index [y,n,q,a,d%s,?]? "),
119 .edit_hunk_hint
= N_("If the patch applies cleanly, the edited hunk "
120 "will immediately be marked for applying."),
122 N_("y - apply this hunk to index\n"
123 "n - do not apply this hunk to index\n"
124 "q - quit; do not apply this hunk or any of the remaining "
126 "a - apply this hunk and all later hunks in the file\n"
127 "d - do not apply this hunk or any of the later hunks in "
131 static struct patch_mode patch_mode_checkout_index
= {
132 .diff_cmd
= { "diff-files", NULL
},
133 .apply_args
= { "-R", NULL
},
134 .apply_check_args
= { "-R", NULL
},
137 N_("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
138 N_("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
139 N_("Discard addition from worktree [y,n,q,a,d%s,?]? "),
140 N_("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
142 .edit_hunk_hint
= N_("If the patch applies cleanly, the edited hunk "
143 "will immediately be marked for discarding."),
145 N_("y - discard this hunk from worktree\n"
146 "n - do not discard this hunk from worktree\n"
147 "q - quit; do not discard this hunk or any of the remaining "
149 "a - discard this hunk and all later hunks in the file\n"
150 "d - do not discard this hunk or any of the later hunks in "
154 static struct patch_mode patch_mode_checkout_head
= {
155 .diff_cmd
= { "diff-index", NULL
},
156 .apply_for_checkout
= 1,
157 .apply_check_args
= { "-R", NULL
},
160 N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
161 N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
162 N_("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
163 N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
165 .edit_hunk_hint
= N_("If the patch applies cleanly, the edited hunk "
166 "will immediately be marked for discarding."),
168 N_("y - discard this hunk from index and worktree\n"
169 "n - do not discard this hunk from index and worktree\n"
170 "q - quit; do not discard this hunk or any of the remaining "
172 "a - discard this hunk and all later hunks in the file\n"
173 "d - do not discard this hunk or any of the later hunks in "
177 static struct patch_mode patch_mode_checkout_nothead
= {
178 .diff_cmd
= { "diff-index", "-R", NULL
},
179 .apply_for_checkout
= 1,
180 .apply_check_args
= { NULL
},
182 N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
183 N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
184 N_("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
185 N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
187 .edit_hunk_hint
= N_("If the patch applies cleanly, the edited hunk "
188 "will immediately be marked for applying."),
190 N_("y - apply this hunk to index and worktree\n"
191 "n - do not apply this hunk to index and worktree\n"
192 "q - quit; do not apply this hunk or any of the remaining "
194 "a - apply this hunk and all later hunks in the file\n"
195 "d - do not apply this hunk or any of the later hunks in "
199 static struct patch_mode patch_mode_worktree_head
= {
200 .diff_cmd
= { "diff-index", NULL
},
201 .apply_args
= { "-R", NULL
},
202 .apply_check_args
= { "-R", NULL
},
205 N_("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
206 N_("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
207 N_("Discard addition from worktree [y,n,q,a,d%s,?]? "),
208 N_("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
210 .edit_hunk_hint
= N_("If the patch applies cleanly, the edited hunk "
211 "will immediately be marked for discarding."),
213 N_("y - discard this hunk from worktree\n"
214 "n - do not discard this hunk from worktree\n"
215 "q - quit; do not discard this hunk or any of the remaining "
217 "a - discard this hunk and all later hunks in the file\n"
218 "d - do not discard this hunk or any of the later hunks in "
222 static struct patch_mode patch_mode_worktree_nothead
= {
223 .diff_cmd
= { "diff-index", "-R", NULL
},
224 .apply_args
= { NULL
},
225 .apply_check_args
= { NULL
},
227 N_("Apply mode change to worktree [y,n,q,a,d%s,?]? "),
228 N_("Apply deletion to worktree [y,n,q,a,d%s,?]? "),
229 N_("Apply addition to worktree [y,n,q,a,d%s,?]? "),
230 N_("Apply this hunk to worktree [y,n,q,a,d%s,?]? "),
232 .edit_hunk_hint
= N_("If the patch applies cleanly, the edited hunk "
233 "will immediately be marked for applying."),
235 N_("y - apply this hunk to worktree\n"
236 "n - do not apply this hunk to worktree\n"
237 "q - quit; do not apply this hunk or any of the remaining "
239 "a - apply this hunk and all later hunks in the file\n"
240 "d - do not apply this hunk or any of the later hunks in "
245 unsigned long old_offset
, old_count
, new_offset
, new_count
;
247 * Start/end offsets to the extra text after the second `@@` in the
248 * hunk header, e.g. the function signature. This is expected to
249 * include the newline.
251 size_t extra_start
, extra_end
, colored_extra_start
, colored_extra_end
;
252 unsigned suppress_colored_line_range
:1;
256 size_t start
, end
, colored_start
, colored_end
, splittable_into
;
258 enum { UNDECIDED_HUNK
= 0, SKIP_HUNK
, USE_HUNK
} use
;
259 struct hunk_header header
;
263 struct add_i_state s
;
264 struct strbuf answer
, buf
;
267 struct strbuf plain
, colored
;
271 size_t hunk_nr
, hunk_alloc
;
272 unsigned deleted
:1, added
:1, mode_change
:1,binary
:1;
277 struct patch_mode
*mode
;
278 const char *revision
;
281 static void add_p_state_clear(struct add_p_state
*s
)
285 strbuf_release(&s
->answer
);
286 strbuf_release(&s
->buf
);
287 strbuf_release(&s
->plain
);
288 strbuf_release(&s
->colored
);
289 for (i
= 0; i
< s
->file_diff_nr
; i
++)
290 free(s
->file_diff
[i
].hunk
);
292 clear_add_i_state(&s
->s
);
295 __attribute__((format (printf
, 2, 3)))
296 static void err(struct add_p_state
*s
, const char *fmt
, ...)
301 fputs(s
->s
.error_color
, stdout
);
303 puts(s
->s
.reset_color
);
307 LAST_ARG_MUST_BE_NULL
308 static void setup_child_process(struct add_p_state
*s
,
309 struct child_process
*cp
, ...)
315 while ((arg
= va_arg(ap
, const char *)))
316 strvec_push(&cp
->args
, arg
);
320 strvec_pushf(&cp
->env
,
321 INDEX_ENVIRONMENT
"=%s", s
->s
.r
->index_file
);
324 static int parse_range(const char **p
,
325 unsigned long *offset
, unsigned long *count
)
329 *offset
= strtoul(*p
, &pend
, 10);
337 *count
= strtoul(pend
+ 1, (char **)p
, 10);
338 return *p
== pend
+ 1 ? -1 : 0;
341 static int parse_hunk_header(struct add_p_state
*s
, struct hunk
*hunk
)
343 struct hunk_header
*header
= &hunk
->header
;
344 const char *line
= s
->plain
.buf
+ hunk
->start
, *p
= line
;
345 char *eol
= memchr(p
, '\n', s
->plain
.len
- hunk
->start
);
348 eol
= s
->plain
.buf
+ s
->plain
.len
;
350 if (!skip_prefix(p
, "@@ -", &p
) ||
351 parse_range(&p
, &header
->old_offset
, &header
->old_count
) < 0 ||
352 !skip_prefix(p
, " +", &p
) ||
353 parse_range(&p
, &header
->new_offset
, &header
->new_count
) < 0 ||
354 !skip_prefix(p
, " @@", &p
))
355 return error(_("could not parse hunk header '%.*s'"),
356 (int)(eol
- line
), line
);
358 hunk
->start
= eol
- s
->plain
.buf
+ (*eol
== '\n');
359 header
->extra_start
= p
- s
->plain
.buf
;
360 header
->extra_end
= hunk
->start
;
362 if (!s
->colored
.len
) {
363 header
->colored_extra_start
= header
->colored_extra_end
= 0;
367 /* Now find the extra text in the colored diff */
368 line
= s
->colored
.buf
+ hunk
->colored_start
;
369 eol
= memchr(line
, '\n', s
->colored
.len
- hunk
->colored_start
);
371 eol
= s
->colored
.buf
+ s
->colored
.len
;
372 p
= memmem(line
, eol
- line
, "@@ -", 4);
373 if (p
&& (p
= memmem(p
+ 4, eol
- p
- 4, " @@", 3))) {
374 header
->colored_extra_start
= p
+ 3 - s
->colored
.buf
;
376 /* could not parse colored hunk header, leave as-is */
377 header
->colored_extra_start
= hunk
->colored_start
;
378 header
->suppress_colored_line_range
= 1;
380 hunk
->colored_start
= eol
- s
->colored
.buf
+ (*eol
== '\n');
381 header
->colored_extra_end
= hunk
->colored_start
;
386 static int is_octal(const char *p
, size_t len
)
392 if (*p
< '0' || *(p
++) > '7')
397 static void complete_file(char marker
, struct hunk
*hunk
)
399 if (marker
== '-' || marker
== '+')
401 * Last hunk ended in non-context line (i.e. it
402 * appended lines to the file, so there are no
403 * trailing context lines).
405 hunk
->splittable_into
++;
408 /* Empty context lines may omit the leading ' ' */
409 static int normalize_marker(const char *p
)
411 return p
[0] == '\n' || (p
[0] == '\r' && p
[1] == '\n') ? ' ' : p
[0];
414 static int parse_diff(struct add_p_state
*s
, const struct pathspec
*ps
)
416 struct strvec args
= STRVEC_INIT
;
417 const char *diff_algorithm
= s
->s
.interactive_diff_algorithm
;
418 struct strbuf
*plain
= &s
->plain
, *colored
= NULL
;
419 struct child_process cp
= CHILD_PROCESS_INIT
;
420 char *p
, *pend
, *colored_p
= NULL
, *colored_pend
= NULL
, marker
= '\0';
421 size_t file_diff_alloc
= 0, i
, color_arg_index
;
422 struct file_diff
*file_diff
= NULL
;
423 struct hunk
*hunk
= NULL
;
426 strvec_pushv(&args
, s
->mode
->diff_cmd
);
428 strvec_pushf(&args
, "--diff-algorithm=%s", diff_algorithm
);
430 struct object_id oid
;
432 /* could be on an unborn branch */
433 !strcmp("HEAD", s
->revision
) &&
434 repo_get_oid(the_repository
, "HEAD", &oid
) ?
435 empty_tree_oid_hex(the_repository
->hash_algo
) : s
->revision
);
437 color_arg_index
= args
.nr
;
438 /* Use `--no-color` explicitly, just in case `diff.color = always`. */
439 strvec_pushl(&args
, "--no-color", "--ignore-submodules=dirty", "-p",
441 for (i
= 0; i
< ps
->nr
; i
++)
442 strvec_push(&args
, ps
->items
[i
].original
);
444 setup_child_process(s
, &cp
, NULL
);
445 strvec_pushv(&cp
.args
, args
.v
);
446 res
= capture_command(&cp
, plain
, 0);
449 return error(_("could not parse diff"));
455 strbuf_complete_line(plain
);
457 if (want_color_fd(1, -1)) {
458 struct child_process colored_cp
= CHILD_PROCESS_INIT
;
459 const char *diff_filter
= s
->s
.interactive_diff_filter
;
461 setup_child_process(s
, &colored_cp
, NULL
);
462 xsnprintf((char *)args
.v
[color_arg_index
], 8, "--color");
463 strvec_pushv(&colored_cp
.args
, args
.v
);
464 colored
= &s
->colored
;
465 res
= capture_command(&colored_cp
, colored
, 0);
468 return error(_("could not parse colored diff"));
471 struct child_process filter_cp
= CHILD_PROCESS_INIT
;
473 setup_child_process(s
, &filter_cp
,
475 filter_cp
.git_cmd
= 0;
476 filter_cp
.use_shell
= 1;
477 strbuf_reset(&s
->buf
);
478 if (pipe_command(&filter_cp
,
479 colored
->buf
, colored
->len
,
480 &s
->buf
, colored
->len
,
482 return error(_("failed to run '%s'"),
484 strbuf_swap(colored
, &s
->buf
);
487 strbuf_complete_line(colored
);
488 colored_p
= colored
->buf
;
489 colored_pend
= colored_p
+ colored
->len
;
493 /* parse files and hunks */
495 pend
= p
+ plain
->len
;
497 char *eol
= memchr(p
, '\n', pend
- p
);
498 const char *deleted
= NULL
, *mode_change
= NULL
;
499 char ch
= normalize_marker(p
);
504 if (starts_with(p
, "diff ") ||
505 starts_with(p
, "* Unmerged path ")) {
506 complete_file(marker
, hunk
);
507 ALLOC_GROW_BY(s
->file_diff
, s
->file_diff_nr
, 1,
509 file_diff
= s
->file_diff
+ s
->file_diff_nr
- 1;
510 hunk
= &file_diff
->head
;
511 hunk
->start
= p
- plain
->buf
;
513 hunk
->colored_start
= colored_p
- colored
->buf
;
515 } else if (p
== plain
->buf
)
516 BUG("diff starts with unexpected line:\n"
517 "%.*s\n", (int)(eol
- p
), p
);
518 else if (file_diff
->deleted
)
519 ; /* keep the rest of the file in a single "hunk" */
520 else if (starts_with(p
, "@@ ") ||
521 (hunk
== &file_diff
->head
&&
522 (skip_prefix(p
, "deleted file", &deleted
)))) {
523 if (marker
== '-' || marker
== '+')
525 * Should not happen; previous hunk did not end
526 * in a context line? Handle it anyway.
528 hunk
->splittable_into
++;
530 ALLOC_GROW_BY(file_diff
->hunk
, file_diff
->hunk_nr
, 1,
531 file_diff
->hunk_alloc
);
532 hunk
= file_diff
->hunk
+ file_diff
->hunk_nr
- 1;
534 hunk
->start
= p
- plain
->buf
;
536 hunk
->colored_start
= colored_p
- colored
->buf
;
539 file_diff
->deleted
= 1;
540 else if (parse_hunk_header(s
, hunk
) < 0)
544 * Start counting into how many hunks this one can be
548 } else if (hunk
== &file_diff
->head
&&
549 starts_with(p
, "new file")) {
550 file_diff
->added
= 1;
551 } else if (hunk
== &file_diff
->head
&&
552 skip_prefix(p
, "old mode ", &mode_change
) &&
553 is_octal(mode_change
, eol
- mode_change
)) {
554 if (file_diff
->mode_change
)
555 BUG("double mode change?\n\n%.*s",
556 (int)(eol
- plain
->buf
), plain
->buf
);
557 if (file_diff
->hunk_nr
)
558 BUG("mode change in the middle?\n\n%.*s",
559 (int)(eol
- plain
->buf
), plain
->buf
);
562 * Do *not* change `hunk`: the mode change pseudo-hunk
563 * is _part of_ the header "hunk".
565 file_diff
->mode_change
= 1;
566 ALLOC_GROW_BY(file_diff
->hunk
, file_diff
->hunk_nr
, 1,
567 file_diff
->hunk_alloc
);
568 file_diff
->hunk
->start
= p
- plain
->buf
;
570 file_diff
->hunk
->colored_start
=
571 colored_p
- colored
->buf
;
572 } else if (hunk
== &file_diff
->head
&&
573 skip_prefix(p
, "new mode ", &mode_change
) &&
574 is_octal(mode_change
, eol
- mode_change
)) {
577 * Extend the "mode change" pseudo-hunk to include also
578 * the "new mode" line.
580 if (!file_diff
->mode_change
)
581 BUG("'new mode' without 'old mode'?\n\n%.*s",
582 (int)(eol
- plain
->buf
), plain
->buf
);
583 if (file_diff
->hunk_nr
!= 1)
584 BUG("mode change in the middle?\n\n%.*s",
585 (int)(eol
- plain
->buf
), plain
->buf
);
586 if (p
- plain
->buf
!= file_diff
->hunk
->end
)
587 BUG("'new mode' does not immediately follow "
588 "'old mode'?\n\n%.*s",
589 (int)(eol
- plain
->buf
), plain
->buf
);
590 } else if (hunk
== &file_diff
->head
&&
591 starts_with(p
, "Binary files "))
592 file_diff
->binary
= 1;
594 if (!!file_diff
->deleted
+ !!file_diff
->added
+
595 !!file_diff
->mode_change
> 1)
596 BUG("diff can only contain delete *or* add *or* a "
597 "mode change?!?\n%.*s",
598 (int)(eol
- (plain
->buf
+ file_diff
->head
.start
)),
599 plain
->buf
+ file_diff
->head
.start
);
601 if ((marker
== '-' || marker
== '+') && ch
== ' ')
602 hunk
->splittable_into
++;
603 if (marker
&& ch
!= '\\')
606 p
= eol
== pend
? pend
: eol
+ 1;
607 hunk
->end
= p
- plain
->buf
;
610 char *colored_eol
= memchr(colored_p
, '\n',
611 colored_pend
- colored_p
);
613 colored_p
= colored_eol
+ 1;
615 /* non-colored has more lines? */
616 goto mismatched_output
;
617 else if (colored_p
== colored_pend
)
618 /* last line has no matching colored one? */
619 goto mismatched_output
;
621 colored_p
= colored_pend
;
623 hunk
->colored_end
= colored_p
- colored
->buf
;
627 if (file_diff
->hunk_nr
!= 1)
628 BUG("mode change in hunk #%d???",
629 (int)file_diff
->hunk_nr
);
630 /* Adjust the end of the "mode change" pseudo-hunk */
631 file_diff
->hunk
->end
= hunk
->end
;
633 file_diff
->hunk
->colored_end
= hunk
->colored_end
;
636 complete_file(marker
, hunk
);
638 /* non-colored shorter than colored? */
639 if (colored_p
!= colored_pend
) {
641 error(_("mismatched output from interactive.diffFilter"));
642 advise(_("Your filter must maintain a one-to-one correspondence\n"
643 "between its input and output lines."));
650 static size_t find_next_line(struct strbuf
*sb
, size_t offset
)
654 if (offset
>= sb
->len
)
655 BUG("looking for next line beyond buffer (%d >= %d)\n%s",
656 (int)offset
, (int)sb
->len
, sb
->buf
);
658 eol
= memchr(sb
->buf
+ offset
, '\n', sb
->len
- offset
);
661 return eol
- sb
->buf
+ 1;
664 static void render_hunk(struct add_p_state
*s
, struct hunk
*hunk
,
665 ssize_t delta
, int colored
, struct strbuf
*out
)
667 struct hunk_header
*header
= &hunk
->header
;
669 if (hunk
->header
.old_offset
!= 0 || hunk
->header
.new_offset
!= 0) {
671 * Generate the hunk header dynamically, except for special
672 * hunks (such as the diff header).
676 unsigned long old_offset
= header
->old_offset
;
677 unsigned long new_offset
= header
->new_offset
;
680 p
= s
->plain
.buf
+ header
->extra_start
;
681 len
= header
->extra_end
- header
->extra_start
;
682 } else if (header
->suppress_colored_line_range
) {
684 s
->colored
.buf
+ header
->colored_extra_start
,
685 header
->colored_extra_end
-
686 header
->colored_extra_start
);
688 strbuf_add(out
, s
->colored
.buf
+ hunk
->colored_start
,
689 hunk
->colored_end
- hunk
->colored_start
);
692 strbuf_addstr(out
, s
->s
.fraginfo_color
);
693 p
= s
->colored
.buf
+ header
->colored_extra_start
;
694 len
= header
->colored_extra_end
695 - header
->colored_extra_start
;
698 if (s
->mode
->is_reverse
)
703 strbuf_addf(out
, "@@ -%lu", old_offset
);
704 if (header
->old_count
!= 1)
705 strbuf_addf(out
, ",%lu", header
->old_count
);
706 strbuf_addf(out
, " +%lu", new_offset
);
707 if (header
->new_count
!= 1)
708 strbuf_addf(out
, ",%lu", header
->new_count
);
709 strbuf_addstr(out
, " @@");
712 strbuf_add(out
, p
, len
);
714 strbuf_addf(out
, "%s\n", s
->s
.reset_color
);
716 strbuf_addch(out
, '\n');
720 strbuf_add(out
, s
->colored
.buf
+ hunk
->colored_start
,
721 hunk
->colored_end
- hunk
->colored_start
);
723 strbuf_add(out
, s
->plain
.buf
+ hunk
->start
,
724 hunk
->end
- hunk
->start
);
727 static void render_diff_header(struct add_p_state
*s
,
728 struct file_diff
*file_diff
, int colored
,
732 * If there was a mode change, the first hunk is a pseudo hunk that
733 * corresponds to the mode line in the header. If the user did not want
734 * to stage that "hunk", we actually have to cut it out from the header.
736 int skip_mode_change
=
737 file_diff
->mode_change
&& file_diff
->hunk
->use
!= USE_HUNK
;
738 struct hunk
*head
= &file_diff
->head
, *first
= file_diff
->hunk
;
740 if (!skip_mode_change
) {
741 render_hunk(s
, head
, 0, colored
, out
);
746 const char *p
= s
->colored
.buf
;
748 strbuf_add(out
, p
+ head
->colored_start
,
749 first
->colored_start
- head
->colored_start
);
750 strbuf_add(out
, p
+ first
->colored_end
,
751 head
->colored_end
- first
->colored_end
);
753 const char *p
= s
->plain
.buf
;
755 strbuf_add(out
, p
+ head
->start
, first
->start
- head
->start
);
756 strbuf_add(out
, p
+ first
->end
, head
->end
- first
->end
);
760 /* Coalesce hunks again that were split */
761 static int merge_hunks(struct add_p_state
*s
, struct file_diff
*file_diff
,
762 size_t *hunk_index
, int use_all
, struct hunk
*merged
)
764 size_t i
= *hunk_index
, delta
;
765 struct hunk
*hunk
= file_diff
->hunk
+ i
;
766 /* `header` corresponds to the merged hunk */
767 struct hunk_header
*header
= &merged
->header
, *next
;
769 if (!use_all
&& hunk
->use
!= USE_HUNK
)
773 /* We simply skip the colored part (if any) when merging hunks */
774 merged
->colored_start
= merged
->colored_end
= 0;
776 for (; i
+ 1 < file_diff
->hunk_nr
; i
++) {
778 next
= &hunk
->header
;
781 * Stop merging hunks when:
783 * - the hunk is not selected for use, or
784 * - the hunk does not overlap with the already-merged hunk(s)
786 if ((!use_all
&& hunk
->use
!= USE_HUNK
) ||
787 header
->new_offset
>= next
->new_offset
+ merged
->delta
||
788 header
->new_offset
+ header
->new_count
789 < next
->new_offset
+ merged
->delta
)
793 * If the hunks were not edited, and overlap, we can simply
794 * extend the line range.
796 if (merged
->start
< hunk
->start
&& merged
->end
> hunk
->start
) {
797 merged
->end
= hunk
->end
;
798 merged
->colored_end
= hunk
->colored_end
;
801 const char *plain
= s
->plain
.buf
;
802 size_t overlapping_line_count
= header
->new_offset
803 + header
->new_count
- merged
->delta
805 size_t overlap_end
= hunk
->start
;
806 size_t overlap_start
= overlap_end
;
807 size_t overlap_next
, len
, j
;
810 * One of the hunks was edited: the modified hunk was
811 * appended to the strbuf `s->plain`.
813 * Let's ensure that at least the last context line of
814 * the first hunk overlaps with the corresponding line
815 * of the second hunk, and then merge.
817 for (j
= 0; j
< overlapping_line_count
; j
++) {
818 overlap_next
= find_next_line(&s
->plain
,
821 if (overlap_next
> hunk
->end
)
822 BUG("failed to find %d context lines "
824 (int)overlapping_line_count
,
825 (int)(hunk
->end
- hunk
->start
),
826 plain
+ hunk
->start
);
828 if (normalize_marker(&plain
[overlap_end
]) != ' ')
829 return error(_("expected context line "
834 plain
+ hunk
->start
);
836 overlap_start
= overlap_end
;
837 overlap_end
= overlap_next
;
839 len
= overlap_end
- overlap_start
;
841 if (len
> merged
->end
- merged
->start
||
842 memcmp(plain
+ merged
->end
- len
,
843 plain
+ overlap_start
, len
))
844 return error(_("hunks do not overlap:\n%.*s\n"
845 "\tdoes not end with:\n%.*s"),
846 (int)(merged
->end
- merged
->start
),
847 plain
+ merged
->start
,
848 (int)len
, plain
+ overlap_start
);
851 * Since the start-end ranges are not adjacent, we
852 * cannot simply take the union of the ranges. To
853 * address that, we temporarily append the union of the
854 * lines to the `plain` strbuf.
856 if (merged
->end
!= s
->plain
.len
) {
857 size_t start
= s
->plain
.len
;
859 strbuf_add(&s
->plain
, plain
+ merged
->start
,
860 merged
->end
- merged
->start
);
861 plain
= s
->plain
.buf
;
862 merged
->start
= start
;
863 merged
->end
= s
->plain
.len
;
866 strbuf_add(&s
->plain
,
868 hunk
->end
- overlap_end
);
869 merged
->end
= s
->plain
.len
;
870 merged
->splittable_into
+= hunk
->splittable_into
;
871 delta
= merged
->delta
;
872 merged
->delta
+= hunk
->delta
;
875 header
->old_count
= next
->old_offset
+ next
->old_count
876 - header
->old_offset
;
877 header
->new_count
= next
->new_offset
+ delta
878 + next
->new_count
- header
->new_offset
;
881 if (i
== *hunk_index
)
888 static void reassemble_patch(struct add_p_state
*s
,
889 struct file_diff
*file_diff
, int use_all
,
893 size_t save_len
= s
->plain
.len
, i
;
896 render_diff_header(s
, file_diff
, 0, out
);
898 for (i
= file_diff
->mode_change
; i
< file_diff
->hunk_nr
; i
++) {
899 struct hunk merged
= { 0 };
901 hunk
= file_diff
->hunk
+ i
;
902 if (!use_all
&& hunk
->use
!= USE_HUNK
)
903 delta
+= hunk
->header
.old_count
904 - hunk
->header
.new_count
;
906 /* merge overlapping hunks into a temporary hunk */
907 if (merge_hunks(s
, file_diff
, &i
, use_all
, &merged
))
910 render_hunk(s
, hunk
, delta
, 0, out
);
913 * In case `merge_hunks()` used `plain` as a scratch
914 * pad (this happens when an edited hunk had to be
915 * coalesced with another hunk).
917 strbuf_setlen(&s
->plain
, save_len
);
919 delta
+= hunk
->delta
;
924 static int split_hunk(struct add_p_state
*s
, struct file_diff
*file_diff
,
927 int colored
= !!s
->colored
.len
, first
= 1;
928 struct hunk
*hunk
= file_diff
->hunk
+ hunk_index
;
929 size_t splittable_into
;
930 size_t end
, colored_end
, current
, colored_current
= 0, context_line_count
;
931 struct hunk_header remaining
, *header
;
934 if (hunk_index
>= file_diff
->hunk_nr
)
935 BUG("invalid hunk index: %d (must be >= 0 and < %d)",
936 (int)hunk_index
, (int)file_diff
->hunk_nr
);
938 if (hunk
->splittable_into
< 2)
940 splittable_into
= hunk
->splittable_into
;
943 colored_end
= hunk
->colored_end
;
945 remaining
= hunk
->header
;
947 file_diff
->hunk_nr
+= splittable_into
- 1;
948 ALLOC_GROW(file_diff
->hunk
, file_diff
->hunk_nr
, file_diff
->hunk_alloc
);
949 if (hunk_index
+ splittable_into
< file_diff
->hunk_nr
)
950 memmove(file_diff
->hunk
+ hunk_index
+ splittable_into
,
951 file_diff
->hunk
+ hunk_index
+ 1,
952 (file_diff
->hunk_nr
- hunk_index
- splittable_into
)
954 hunk
= file_diff
->hunk
+ hunk_index
;
955 hunk
->splittable_into
= 1;
956 memset(hunk
+ 1, 0, (splittable_into
- 1) * sizeof(*hunk
));
958 header
= &hunk
->header
;
959 header
->old_count
= header
->new_count
= 0;
961 current
= hunk
->start
;
963 colored_current
= hunk
->colored_start
;
965 context_line_count
= 0;
967 while (splittable_into
> 1) {
968 ch
= normalize_marker(&s
->plain
.buf
[current
]);
971 BUG("buffer overrun while splitting hunks");
974 * Is this the first context line after a chain of +/- lines?
975 * Then record the start of the next split hunk.
977 if ((marker
== '-' || marker
== '+') && ch
== ' ') {
979 hunk
[1].start
= current
;
981 hunk
[1].colored_start
= colored_current
;
982 context_line_count
= 0;
986 * Was the previous line a +/- one? Alternatively, is this the
987 * first line (and not a +/- one)?
989 * Then just increment the appropriate counter and continue
990 * with the next line.
992 if (marker
!= ' ' || (ch
!= '-' && ch
!= '+')) {
994 /* Comment lines are attached to the previous line */
996 ch
= marker
? marker
: ' ';
998 /* current hunk not done yet */
1000 context_line_count
++;
1002 header
->old_count
++;
1004 header
->new_count
++;
1006 BUG("unhandled diff marker: '%c'", ch
);
1008 current
= find_next_line(&s
->plain
, current
);
1011 find_next_line(&s
->colored
,
1017 * We got us the start of a new hunk!
1019 * This is a context line, so it is shared with the previous
1024 if (header
->old_count
|| header
->new_count
)
1025 BUG("counts are off: %d/%d",
1026 (int)header
->old_count
,
1027 (int)header
->new_count
);
1029 header
->old_count
= context_line_count
;
1030 header
->new_count
= context_line_count
;
1031 context_line_count
= 0;
1033 goto next_hunk_line
;
1036 remaining
.old_offset
+= header
->old_count
;
1037 remaining
.old_count
-= header
->old_count
;
1038 remaining
.new_offset
+= header
->new_count
;
1039 remaining
.new_count
-= header
->new_count
;
1041 /* initialize next hunk header's offsets */
1042 hunk
[1].header
.old_offset
=
1043 header
->old_offset
+ header
->old_count
;
1044 hunk
[1].header
.new_offset
=
1045 header
->new_offset
+ header
->new_count
;
1047 /* add one split hunk */
1048 header
->old_count
+= context_line_count
;
1049 header
->new_count
+= context_line_count
;
1051 hunk
->end
= current
;
1053 hunk
->colored_end
= colored_current
;
1056 hunk
->splittable_into
= 1;
1057 hunk
->use
= hunk
[-1].use
;
1058 header
= &hunk
->header
;
1060 header
->old_count
= header
->new_count
= context_line_count
;
1061 context_line_count
= 0;
1067 /* last hunk simply gets the rest */
1068 if (header
->old_offset
!= remaining
.old_offset
)
1069 BUG("miscounted old_offset: %lu != %lu",
1070 header
->old_offset
, remaining
.old_offset
);
1071 if (header
->new_offset
!= remaining
.new_offset
)
1072 BUG("miscounted new_offset: %lu != %lu",
1073 header
->new_offset
, remaining
.new_offset
);
1074 header
->old_count
= remaining
.old_count
;
1075 header
->new_count
= remaining
.new_count
;
1078 hunk
->colored_end
= colored_end
;
1083 static void recolor_hunk(struct add_p_state
*s
, struct hunk
*hunk
)
1085 const char *plain
= s
->plain
.buf
;
1086 size_t current
, eol
, next
;
1088 if (!s
->colored
.len
)
1091 hunk
->colored_start
= s
->colored
.len
;
1092 for (current
= hunk
->start
; current
< hunk
->end
; ) {
1093 for (eol
= current
; eol
< hunk
->end
; eol
++)
1094 if (plain
[eol
] == '\n')
1096 next
= eol
+ (eol
< hunk
->end
);
1097 if (eol
> current
&& plain
[eol
- 1] == '\r')
1100 strbuf_addstr(&s
->colored
,
1101 plain
[current
] == '-' ?
1102 s
->s
.file_old_color
:
1103 plain
[current
] == '+' ?
1104 s
->s
.file_new_color
:
1105 s
->s
.context_color
);
1106 strbuf_add(&s
->colored
, plain
+ current
, eol
- current
);
1107 strbuf_addstr(&s
->colored
, s
->s
.reset_color
);
1109 strbuf_add(&s
->colored
, plain
+ eol
, next
- eol
);
1112 hunk
->colored_end
= s
->colored
.len
;
1115 static int edit_hunk_manually(struct add_p_state
*s
, struct hunk
*hunk
)
1119 strbuf_reset(&s
->buf
);
1120 strbuf_commented_addf(&s
->buf
, comment_line_str
,
1121 _("Manual hunk edit mode -- see bottom for "
1122 "a quick guide.\n"));
1123 render_hunk(s
, hunk
, 0, 0, &s
->buf
);
1124 strbuf_commented_addf(&s
->buf
, comment_line_str
,
1126 "To remove '%c' lines, make them ' ' lines "
1128 "To remove '%c' lines, delete them.\n"
1129 "Lines starting with %s will be removed.\n"),
1130 s
->mode
->is_reverse
? '+' : '-',
1131 s
->mode
->is_reverse
? '-' : '+',
1133 strbuf_commented_addf(&s
->buf
, comment_line_str
, "%s",
1134 _(s
->mode
->edit_hunk_hint
));
1136 * TRANSLATORS: 'it' refers to the patch mentioned in the previous
1139 strbuf_commented_addf(&s
->buf
, comment_line_str
,
1140 _("If it does not apply cleanly, you will be "
1141 "given an opportunity to\n"
1142 "edit again. If all lines of the hunk are "
1143 "removed, then the edit is\n"
1144 "aborted and the hunk is left unchanged.\n"));
1146 if (strbuf_edit_interactively(the_repository
, &s
->buf
,
1147 "addp-hunk-edit.diff", NULL
) < 0)
1150 /* strip out commented lines */
1151 hunk
->start
= s
->plain
.len
;
1152 for (i
= 0; i
< s
->buf
.len
; ) {
1153 size_t next
= find_next_line(&s
->buf
, i
);
1155 if (!starts_with(s
->buf
.buf
+ i
, comment_line_str
))
1156 strbuf_add(&s
->plain
, s
->buf
.buf
+ i
, next
- i
);
1160 hunk
->end
= s
->plain
.len
;
1161 if (hunk
->end
== hunk
->start
)
1162 /* The user aborted editing by deleting everything */
1165 recolor_hunk(s
, hunk
);
1168 * If the hunk header is intact, parse it, otherwise simply use the
1169 * hunk header prior to editing (which will adjust `hunk->start` to
1170 * skip the hunk header).
1172 if (s
->plain
.buf
[hunk
->start
] == '@' &&
1173 parse_hunk_header(s
, hunk
) < 0)
1174 return error(_("could not parse hunk header"));
1179 static ssize_t
recount_edited_hunk(struct add_p_state
*s
, struct hunk
*hunk
,
1180 size_t orig_old_count
, size_t orig_new_count
)
1182 struct hunk_header
*header
= &hunk
->header
;
1185 header
->old_count
= header
->new_count
= 0;
1186 for (i
= hunk
->start
; i
< hunk
->end
; ) {
1187 switch(normalize_marker(&s
->plain
.buf
[i
])) {
1189 header
->old_count
++;
1192 header
->new_count
++;
1195 header
->old_count
++;
1196 header
->new_count
++;
1200 i
= find_next_line(&s
->plain
, i
);
1203 return orig_old_count
- orig_new_count
1204 - header
->old_count
+ header
->new_count
;
1207 static int run_apply_check(struct add_p_state
*s
,
1208 struct file_diff
*file_diff
)
1210 struct child_process cp
= CHILD_PROCESS_INIT
;
1212 strbuf_reset(&s
->buf
);
1213 reassemble_patch(s
, file_diff
, 1, &s
->buf
);
1215 setup_child_process(s
, &cp
,
1216 "apply", "--check", NULL
);
1217 strvec_pushv(&cp
.args
, s
->mode
->apply_check_args
);
1218 if (pipe_command(&cp
, s
->buf
.buf
, s
->buf
.len
, NULL
, 0, NULL
, 0))
1219 return error(_("'git apply --cached' failed"));
1224 static int read_single_character(struct add_p_state
*s
)
1226 if (s
->s
.use_single_key
) {
1227 int res
= read_key_without_echo(&s
->answer
);
1228 printf("%s\n", res
== EOF
? "" : s
->answer
.buf
);
1232 if (git_read_line_interactively(&s
->answer
) == EOF
)
1237 static int prompt_yesno(struct add_p_state
*s
, const char *prompt
)
1240 color_fprintf(stdout
, s
->s
.prompt_color
, "%s", _(prompt
));
1242 if (read_single_character(s
) == EOF
)
1244 /* do not limit to 1-byte input to allow 'no' etc. */
1245 switch (tolower(s
->answer
.buf
[0])) {
1252 static int edit_hunk_loop(struct add_p_state
*s
,
1253 struct file_diff
*file_diff
, struct hunk
*hunk
)
1255 size_t plain_len
= s
->plain
.len
, colored_len
= s
->colored
.len
;
1261 int res
= edit_hunk_manually(s
, hunk
);
1270 recount_edited_hunk(s
, hunk
,
1271 backup
.header
.old_count
,
1272 backup
.header
.new_count
);
1273 if (!run_apply_check(s
, file_diff
))
1277 /* Drop edits (they were appended to s->plain) */
1278 strbuf_setlen(&s
->plain
, plain_len
);
1279 strbuf_setlen(&s
->colored
, colored_len
);
1283 * TRANSLATORS: do not translate [y/n]
1284 * The program will only accept that input at this point.
1285 * Consider translating (saying "no" discards!) as
1286 * (saying "n" for "no" discards!) if the translation
1287 * of the word "no" does not start with n.
1289 res
= prompt_yesno(s
, _("Your edited hunk does not apply. "
1290 "Edit again (saying \"no\" discards!) "
1297 static int apply_for_checkout(struct add_p_state
*s
, struct strbuf
*diff
,
1300 const char *reverse
= is_reverse
? "-R" : NULL
;
1301 struct child_process check_index
= CHILD_PROCESS_INIT
;
1302 struct child_process check_worktree
= CHILD_PROCESS_INIT
;
1303 struct child_process apply_index
= CHILD_PROCESS_INIT
;
1304 struct child_process apply_worktree
= CHILD_PROCESS_INIT
;
1305 int applies_index
, applies_worktree
;
1307 setup_child_process(s
, &check_index
,
1308 "apply", "--cached", "--check", reverse
, NULL
);
1309 applies_index
= !pipe_command(&check_index
, diff
->buf
, diff
->len
,
1312 setup_child_process(s
, &check_worktree
,
1313 "apply", "--check", reverse
, NULL
);
1314 applies_worktree
= !pipe_command(&check_worktree
, diff
->buf
, diff
->len
,
1317 if (applies_worktree
&& applies_index
) {
1318 setup_child_process(s
, &apply_index
,
1319 "apply", "--cached", reverse
, NULL
);
1320 pipe_command(&apply_index
, diff
->buf
, diff
->len
,
1323 setup_child_process(s
, &apply_worktree
,
1324 "apply", reverse
, NULL
);
1325 pipe_command(&apply_worktree
, diff
->buf
, diff
->len
,
1331 if (!applies_index
) {
1332 err(s
, _("The selected hunks do not apply to the index!"));
1333 if (prompt_yesno(s
, _("Apply them to the worktree "
1335 setup_child_process(s
, &apply_worktree
,
1336 "apply", reverse
, NULL
);
1337 return pipe_command(&apply_worktree
, diff
->buf
,
1338 diff
->len
, NULL
, 0, NULL
, 0);
1340 err(s
, _("Nothing was applied.\n"));
1342 /* As a last resort, show the diff to the user */
1343 fwrite(diff
->buf
, diff
->len
, 1, stdout
);
1348 #define SUMMARY_HEADER_WIDTH 20
1349 #define SUMMARY_LINE_WIDTH 80
1350 static void summarize_hunk(struct add_p_state
*s
, struct hunk
*hunk
,
1353 struct hunk_header
*header
= &hunk
->header
;
1354 struct strbuf
*plain
= &s
->plain
;
1355 size_t len
= out
->len
, i
;
1357 strbuf_addf(out
, " -%lu,%lu +%lu,%lu ",
1358 header
->old_offset
, header
->old_count
,
1359 header
->new_offset
, header
->new_count
);
1360 if (out
->len
- len
< SUMMARY_HEADER_WIDTH
)
1361 strbuf_addchars(out
, ' ',
1362 SUMMARY_HEADER_WIDTH
+ len
- out
->len
);
1363 for (i
= hunk
->start
; i
< hunk
->end
; i
= find_next_line(plain
, i
))
1364 if (plain
->buf
[i
] != ' ')
1367 strbuf_add(out
, plain
->buf
+ i
, find_next_line(plain
, i
) - i
);
1368 if (out
->len
- len
> SUMMARY_LINE_WIDTH
)
1369 strbuf_setlen(out
, len
+ SUMMARY_LINE_WIDTH
);
1370 strbuf_complete_line(out
);
1373 #define DISPLAY_HUNKS_LINES 20
1374 static size_t display_hunks(struct add_p_state
*s
,
1375 struct file_diff
*file_diff
, size_t start_index
)
1377 size_t end_index
= start_index
+ DISPLAY_HUNKS_LINES
;
1379 if (end_index
> file_diff
->hunk_nr
)
1380 end_index
= file_diff
->hunk_nr
;
1382 while (start_index
< end_index
) {
1383 struct hunk
*hunk
= file_diff
->hunk
+ start_index
++;
1385 strbuf_reset(&s
->buf
);
1386 strbuf_addf(&s
->buf
, "%c%2d: ", hunk
->use
== USE_HUNK
? '+'
1387 : hunk
->use
== SKIP_HUNK
? '-' : ' ',
1389 summarize_hunk(s
, hunk
, &s
->buf
);
1390 fputs(s
->buf
.buf
, stdout
);
1396 static const char help_patch_remainder
[] =
1397 N_("j - leave this hunk undecided, see next undecided hunk\n"
1398 "J - leave this hunk undecided, see next hunk\n"
1399 "k - leave this hunk undecided, see previous undecided hunk\n"
1400 "K - leave this hunk undecided, see previous hunk\n"
1401 "g - select a hunk to go to\n"
1402 "/ - search for a hunk matching the given regex\n"
1403 "s - split the current hunk into smaller hunks\n"
1404 "e - manually edit the current hunk\n"
1405 "p - print the current hunk, 'P' to use the pager\n"
1406 "? - print help\n");
1408 static int patch_update_file(struct add_p_state
*s
,
1409 struct file_diff
*file_diff
)
1411 size_t hunk_index
= 0;
1412 ssize_t i
, undecided_previous
, undecided_next
, rendered_hunk_index
= -1;
1415 struct child_process cp
= CHILD_PROCESS_INIT
;
1416 int colored
= !!s
->colored
.len
, quit
= 0, use_pager
= 0;
1417 enum prompt_mode_type prompt_mode_type
;
1419 ALLOW_GOTO_PREVIOUS_HUNK
= 1 << 0,
1420 ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK
= 1 << 1,
1421 ALLOW_GOTO_NEXT_HUNK
= 1 << 2,
1422 ALLOW_GOTO_NEXT_UNDECIDED_HUNK
= 1 << 3,
1423 ALLOW_SEARCH_AND_GOTO
= 1 << 4,
1424 ALLOW_SPLIT
= 1 << 5,
1428 /* Empty added files have no hunks */
1429 if (!file_diff
->hunk_nr
&& !file_diff
->added
)
1432 strbuf_reset(&s
->buf
);
1433 render_diff_header(s
, file_diff
, colored
, &s
->buf
);
1434 fputs(s
->buf
.buf
, stdout
);
1436 if (hunk_index
>= file_diff
->hunk_nr
)
1438 hunk
= file_diff
->hunk_nr
1439 ? file_diff
->hunk
+ hunk_index
1441 undecided_previous
= -1;
1442 undecided_next
= -1;
1444 if (file_diff
->hunk_nr
) {
1445 for (i
= hunk_index
- 1; i
>= 0; i
--)
1446 if (file_diff
->hunk
[i
].use
== UNDECIDED_HUNK
) {
1447 undecided_previous
= i
;
1451 for (i
= hunk_index
+ 1; i
< file_diff
->hunk_nr
; i
++)
1452 if (file_diff
->hunk
[i
].use
== UNDECIDED_HUNK
) {
1458 /* Everything decided? */
1459 if (undecided_previous
< 0 && undecided_next
< 0 &&
1460 hunk
->use
!= UNDECIDED_HUNK
)
1463 strbuf_reset(&s
->buf
);
1464 if (file_diff
->hunk_nr
) {
1465 if (rendered_hunk_index
!= hunk_index
) {
1467 setup_pager(the_repository
);
1468 sigchain_push(SIGPIPE
, SIG_IGN
);
1470 render_hunk(s
, hunk
, 0, colored
, &s
->buf
);
1471 fputs(s
->buf
.buf
, stdout
);
1472 rendered_hunk_index
= hunk_index
;
1474 sigchain_pop(SIGPIPE
);
1480 strbuf_reset(&s
->buf
);
1481 if (undecided_previous
>= 0) {
1482 permitted
|= ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK
;
1483 strbuf_addstr(&s
->buf
, ",k");
1486 permitted
|= ALLOW_GOTO_PREVIOUS_HUNK
;
1487 strbuf_addstr(&s
->buf
, ",K");
1489 if (undecided_next
>= 0) {
1490 permitted
|= ALLOW_GOTO_NEXT_UNDECIDED_HUNK
;
1491 strbuf_addstr(&s
->buf
, ",j");
1493 if (hunk_index
+ 1 < file_diff
->hunk_nr
) {
1494 permitted
|= ALLOW_GOTO_NEXT_HUNK
;
1495 strbuf_addstr(&s
->buf
, ",J");
1497 if (file_diff
->hunk_nr
> 1) {
1498 permitted
|= ALLOW_SEARCH_AND_GOTO
;
1499 strbuf_addstr(&s
->buf
, ",g,/");
1501 if (hunk
->splittable_into
> 1) {
1502 permitted
|= ALLOW_SPLIT
;
1503 strbuf_addstr(&s
->buf
, ",s");
1505 if (hunk_index
+ 1 > file_diff
->mode_change
&&
1506 !file_diff
->deleted
) {
1507 permitted
|= ALLOW_EDIT
;
1508 strbuf_addstr(&s
->buf
, ",e");
1510 strbuf_addstr(&s
->buf
, ",p");
1512 if (file_diff
->deleted
)
1513 prompt_mode_type
= PROMPT_DELETION
;
1514 else if (file_diff
->added
)
1515 prompt_mode_type
= PROMPT_ADDITION
;
1516 else if (file_diff
->mode_change
&& !hunk_index
)
1517 prompt_mode_type
= PROMPT_MODE_CHANGE
;
1519 prompt_mode_type
= PROMPT_HUNK
;
1521 printf("%s(%"PRIuMAX
"/%"PRIuMAX
") ", s
->s
.prompt_color
,
1522 (uintmax_t)hunk_index
+ 1,
1523 (uintmax_t)(file_diff
->hunk_nr
1524 ? file_diff
->hunk_nr
1526 printf(_(s
->mode
->prompt_mode
[prompt_mode_type
]),
1528 if (*s
->s
.reset_color
)
1529 fputs(s
->s
.reset_color
, stdout
);
1531 if (read_single_character(s
) == EOF
)
1536 ch
= tolower(s
->answer
.buf
[0]);
1538 /* 'g' takes a hunk number and '/' takes a regexp */
1539 if (s
->answer
.len
!= 1 && (ch
!= 'g' && ch
!= '/')) {
1540 err(s
, _("Only one letter is expected, got '%s'"), s
->answer
.buf
);
1544 hunk
->use
= USE_HUNK
;
1546 hunk_index
= undecided_next
< 0 ?
1547 file_diff
->hunk_nr
: undecided_next
;
1548 } else if (ch
== 'n') {
1549 hunk
->use
= SKIP_HUNK
;
1550 goto soft_increment
;
1551 } else if (ch
== 'a') {
1552 if (file_diff
->hunk_nr
) {
1553 for (; hunk_index
< file_diff
->hunk_nr
; hunk_index
++) {
1554 hunk
= file_diff
->hunk
+ hunk_index
;
1555 if (hunk
->use
== UNDECIDED_HUNK
)
1556 hunk
->use
= USE_HUNK
;
1558 } else if (hunk
->use
== UNDECIDED_HUNK
) {
1559 hunk
->use
= USE_HUNK
;
1561 } else if (ch
== 'd' || ch
== 'q') {
1562 if (file_diff
->hunk_nr
) {
1563 for (; hunk_index
< file_diff
->hunk_nr
; hunk_index
++) {
1564 hunk
= file_diff
->hunk
+ hunk_index
;
1565 if (hunk
->use
== UNDECIDED_HUNK
)
1566 hunk
->use
= SKIP_HUNK
;
1568 } else if (hunk
->use
== UNDECIDED_HUNK
) {
1569 hunk
->use
= SKIP_HUNK
;
1575 } else if (s
->answer
.buf
[0] == 'K') {
1576 if (permitted
& ALLOW_GOTO_PREVIOUS_HUNK
)
1579 err(s
, _("No previous hunk"));
1580 } else if (s
->answer
.buf
[0] == 'J') {
1581 if (permitted
& ALLOW_GOTO_NEXT_HUNK
)
1584 err(s
, _("No next hunk"));
1585 } else if (s
->answer
.buf
[0] == 'k') {
1586 if (permitted
& ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK
)
1587 hunk_index
= undecided_previous
;
1589 err(s
, _("No previous hunk"));
1590 } else if (s
->answer
.buf
[0] == 'j') {
1591 if (permitted
& ALLOW_GOTO_NEXT_UNDECIDED_HUNK
)
1592 hunk_index
= undecided_next
;
1594 err(s
, _("No next hunk"));
1595 } else if (s
->answer
.buf
[0] == 'g') {
1597 unsigned long response
;
1599 if (!(permitted
& ALLOW_SEARCH_AND_GOTO
)) {
1600 err(s
, _("No other hunks to goto"));
1603 strbuf_remove(&s
->answer
, 0, 1);
1604 strbuf_trim(&s
->answer
);
1605 i
= hunk_index
- DISPLAY_HUNKS_LINES
/ 2;
1606 if (i
< (int)file_diff
->mode_change
)
1607 i
= file_diff
->mode_change
;
1608 while (s
->answer
.len
== 0) {
1609 i
= display_hunks(s
, file_diff
, i
);
1610 printf("%s", i
< file_diff
->hunk_nr
?
1611 _("go to which hunk (<ret> to see "
1612 "more)? ") : _("go to which hunk? "));
1614 if (strbuf_getline(&s
->answer
,
1617 strbuf_trim_trailing_newline(&s
->answer
);
1620 strbuf_trim(&s
->answer
);
1621 response
= strtoul(s
->answer
.buf
, &pend
, 10);
1622 if (*pend
|| pend
== s
->answer
.buf
)
1623 err(s
, _("Invalid number: '%s'"),
1625 else if (0 < response
&& response
<= file_diff
->hunk_nr
)
1626 hunk_index
= response
- 1;
1628 err(s
, Q_("Sorry, only %d hunk available.",
1629 "Sorry, only %d hunks available.",
1630 file_diff
->hunk_nr
),
1631 (int)file_diff
->hunk_nr
);
1632 } else if (s
->answer
.buf
[0] == '/') {
1636 if (!(permitted
& ALLOW_SEARCH_AND_GOTO
)) {
1637 err(s
, _("No other hunks to search"));
1640 strbuf_remove(&s
->answer
, 0, 1);
1641 strbuf_trim_trailing_newline(&s
->answer
);
1642 if (s
->answer
.len
== 0) {
1643 printf("%s", _("search for regex? "));
1645 if (strbuf_getline(&s
->answer
,
1648 strbuf_trim_trailing_newline(&s
->answer
);
1649 if (s
->answer
.len
== 0)
1652 ret
= regcomp(®ex
, s
->answer
.buf
,
1653 REG_EXTENDED
| REG_NOSUB
| REG_NEWLINE
);
1657 regerror(ret
, ®ex
, errbuf
, sizeof(errbuf
));
1658 err(s
, _("Malformed search regexp %s: %s"),
1659 s
->answer
.buf
, errbuf
);
1664 /* render the hunk into a scratch buffer */
1665 render_hunk(s
, file_diff
->hunk
+ i
, 0, 0,
1667 if (regexec(®ex
, s
->buf
.buf
, 0, NULL
, 0)
1671 if (i
== file_diff
->hunk_nr
)
1673 if (i
!= hunk_index
)
1675 err(s
, _("No hunk matches the given pattern"));
1680 } else if (s
->answer
.buf
[0] == 's') {
1681 size_t splittable_into
= hunk
->splittable_into
;
1682 if (!(permitted
& ALLOW_SPLIT
)) {
1683 err(s
, _("Sorry, cannot split this hunk"));
1684 } else if (!split_hunk(s
, file_diff
,
1685 hunk
- file_diff
->hunk
)) {
1686 color_fprintf_ln(stdout
, s
->s
.header_color
,
1687 _("Split into %d hunks."),
1688 (int)splittable_into
);
1689 rendered_hunk_index
= -1;
1691 } else if (s
->answer
.buf
[0] == 'e') {
1692 if (!(permitted
& ALLOW_EDIT
))
1693 err(s
, _("Sorry, cannot edit this hunk"));
1694 else if (edit_hunk_loop(s
, file_diff
, hunk
) >= 0) {
1695 hunk
->use
= USE_HUNK
;
1696 goto soft_increment
;
1698 } else if (ch
== 'p') {
1699 rendered_hunk_index
= -1;
1700 use_pager
= (s
->answer
.buf
[0] == 'P') ? 1 : 0;
1701 } else if (s
->answer
.buf
[0] == '?') {
1702 const char *p
= _(help_patch_remainder
), *eol
= p
;
1704 color_fprintf(stdout
, s
->s
.help_color
, "%s",
1705 _(s
->mode
->help_patch_text
));
1708 * Show only those lines of the remainder that are
1709 * actually applicable with the current hunk.
1711 for (; *p
; p
= eol
+ (*eol
== '\n')) {
1712 eol
= strchrnul(p
, '\n');
1715 * `s->buf` still contains the part of the
1716 * commands shown in the prompt that are not
1719 if (*p
!= '?' && !strchr(s
->buf
.buf
, *p
))
1722 color_fprintf_ln(stdout
, s
->s
.help_color
,
1723 "%.*s", (int)(eol
- p
), p
);
1726 err(s
, _("Unknown command '%s' (use '?' for help)"),
1731 /* Any hunk to be used? */
1732 for (i
= 0; i
< file_diff
->hunk_nr
; i
++)
1733 if (file_diff
->hunk
[i
].use
== USE_HUNK
)
1736 if (i
< file_diff
->hunk_nr
||
1737 (!file_diff
->hunk_nr
&& file_diff
->head
.use
== USE_HUNK
)) {
1738 /* At least one hunk selected: apply */
1739 strbuf_reset(&s
->buf
);
1740 reassemble_patch(s
, file_diff
, 0, &s
->buf
);
1742 discard_index(s
->s
.r
->index
);
1743 if (s
->mode
->apply_for_checkout
)
1744 apply_for_checkout(s
, &s
->buf
,
1745 s
->mode
->is_reverse
);
1747 setup_child_process(s
, &cp
, "apply", NULL
);
1748 strvec_pushv(&cp
.args
, s
->mode
->apply_args
);
1749 if (pipe_command(&cp
, s
->buf
.buf
, s
->buf
.len
,
1751 error(_("'git apply' failed"));
1753 if (repo_read_index(s
->s
.r
) >= 0)
1754 repo_refresh_and_write_index(s
->s
.r
, REFRESH_QUIET
, 0,
1755 1, NULL
, NULL
, NULL
);
1762 int run_add_p(struct repository
*r
, enum add_p_mode mode
,
1763 const char *revision
, const struct pathspec
*ps
)
1765 struct add_p_state s
= {
1766 { r
}, STRBUF_INIT
, STRBUF_INIT
, STRBUF_INIT
, STRBUF_INIT
1768 size_t i
, binary_count
= 0;
1770 init_add_i_state(&s
.s
, r
);
1772 if (mode
== ADD_P_STASH
)
1773 s
.mode
= &patch_mode_stash
;
1774 else if (mode
== ADD_P_RESET
) {
1775 if (!revision
|| !strcmp(revision
, "HEAD"))
1776 s
.mode
= &patch_mode_reset_head
;
1778 s
.mode
= &patch_mode_reset_nothead
;
1779 } else if (mode
== ADD_P_CHECKOUT
) {
1781 s
.mode
= &patch_mode_checkout_index
;
1782 else if (!strcmp(revision
, "HEAD"))
1783 s
.mode
= &patch_mode_checkout_head
;
1785 s
.mode
= &patch_mode_checkout_nothead
;
1786 } else if (mode
== ADD_P_WORKTREE
) {
1788 s
.mode
= &patch_mode_checkout_index
;
1789 else if (!strcmp(revision
, "HEAD"))
1790 s
.mode
= &patch_mode_worktree_head
;
1792 s
.mode
= &patch_mode_worktree_nothead
;
1794 s
.mode
= &patch_mode_add
;
1795 s
.revision
= revision
;
1797 discard_index(r
->index
);
1798 if (repo_read_index(r
) < 0 ||
1799 (!s
.mode
->index_only
&&
1800 repo_refresh_and_write_index(r
, REFRESH_QUIET
, 0, 1,
1801 NULL
, NULL
, NULL
) < 0) ||
1802 parse_diff(&s
, ps
) < 0) {
1803 add_p_state_clear(&s
);
1807 for (i
= 0; i
< s
.file_diff_nr
; i
++)
1808 if (s
.file_diff
[i
].binary
&& !s
.file_diff
[i
].hunk_nr
)
1810 else if (patch_update_file(&s
, s
.file_diff
+ i
))
1813 if (s
.file_diff_nr
== 0)
1814 err(&s
, _("No changes."));
1815 else if (binary_count
== s
.file_diff_nr
)
1816 err(&s
, _("Only binary files changed."));
1818 add_p_state_clear(&s
);