add-patch: remove dependency on "add-interactive" subsystem

With the preceding commit we have split out interactive configuration that is used by both "git add -p" and "git add -i". But we still initialize that configuration in the "add -p" subsystem by calling `init_add_i_state()`, even though we only do so to initialize the interactive configuration as well as a repository pointer. Stop doing so and instead store and initialize the interactive configuration in `struct add_p_state` directly. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Mar 2, 2026 at 13:13 UTC d51b61f5dab9c8e715fa792f31d572bc96fb5687
1 file changed +46 -42
add-patch.c
+46 -42
@@ -2,7 +2,6 @@
2 #define DISABLE_SIGN_COMPARE_WARNINGS
3
4 #include "git-compat-util.h"
5 -#include "add-interactive.h"
5 #include "add-patch.h"
6 #include "advice.h"
7 #include "config.h"
@@ -263,7 +262,8 @@ struct hunk {
262 };
263
264 struct add_p_state {
266 - struct add_i_state s;
265 + struct repository *r;
266 + struct interactive_config cfg;
267 struct strbuf answer, buf;
268
269 /* parsed diff */
@@ -409,7 +409,7 @@ static void add_p_state_clear(struct add_p_state *s)
409 for (i = 0; i < s->file_diff_nr; i++)
410 free(s->file_diff[i].hunk);
411 free(s->file_diff);
412 - clear_add_i_state(&s->s);
412 + interactive_config_clear(&s->cfg);
413 }
414
415 __attribute__((format (printf, 2, 3)))
@@ -418,9 +418,9 @@ static void err(struct add_p_state *s, const char *fmt, ...)
418 va_list args;
419
420 va_start(args, fmt);
421 - fputs(s->s.cfg.error_color, stdout);
421 + fputs(s->cfg.error_color, stdout);
422 vprintf(fmt, args);
423 - puts(s->s.cfg.reset_color_interactive);
423 + puts(s->cfg.reset_color_interactive);
424 va_end(args);
425 }
426
@@ -438,7 +438,7 @@ static void setup_child_process(struct add_p_state *s,
438
439 cp->git_cmd = 1;
440 strvec_pushf(&cp->env,
441 - INDEX_ENVIRONMENT "=%s", s->s.r->index_file);
441 + INDEX_ENVIRONMENT "=%s", s->r->index_file);
442 }
443
444 static int parse_range(const char **p,
@@ -543,12 +543,12 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
543 int res;
544
545 strvec_pushv(&args, s->mode->diff_cmd);
546 - if (s->s.cfg.context != -1)
547 - strvec_pushf(&args, "--unified=%i", s->s.cfg.context);
548 - if (s->s.cfg.interhunkcontext != -1)
549 - strvec_pushf(&args, "--inter-hunk-context=%i", s->s.cfg.interhunkcontext);
550 - if (s->s.cfg.interactive_diff_algorithm)
551 - strvec_pushf(&args, "--diff-algorithm=%s", s->s.cfg.interactive_diff_algorithm);
546 + if (s->cfg.context != -1)
547 + strvec_pushf(&args, "--unified=%i", s->cfg.context);
548 + if (s->cfg.interhunkcontext != -1)
549 + strvec_pushf(&args, "--inter-hunk-context=%i", s->cfg.interhunkcontext);
550 + if (s->cfg.interactive_diff_algorithm)
551 + strvec_pushf(&args, "--diff-algorithm=%s", s->cfg.interactive_diff_algorithm);
552 if (s->revision) {
553 struct object_id oid;
554 strvec_push(&args,
@@ -577,9 +577,9 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
577 }
578 strbuf_complete_line(plain);
579
580 - if (want_color_fd(1, s->s.cfg.use_color_diff)) {
580 + if (want_color_fd(1, s->cfg.use_color_diff)) {
581 struct child_process colored_cp = CHILD_PROCESS_INIT;
582 - const char *diff_filter = s->s.cfg.interactive_diff_filter;
582 + const char *diff_filter = s->cfg.interactive_diff_filter;
583
584 setup_child_process(s, &colored_cp, NULL);
585 xsnprintf((char *)args.v[color_arg_index], 8, "--color");
@@ -812,7 +812,7 @@ static void render_hunk(struct add_p_state *s, struct hunk *hunk,
812 hunk->colored_end - hunk->colored_start);
813 return;
814 } else {
815 - strbuf_addstr(out, s->s.cfg.fraginfo_color);
815 + strbuf_addstr(out, s->cfg.fraginfo_color);
816 p = s->colored.buf + header->colored_extra_start;
817 len = header->colored_extra_end
818 - header->colored_extra_start;
@@ -834,7 +834,7 @@ static void render_hunk(struct add_p_state *s, struct hunk *hunk,
834 if (len)
835 strbuf_add(out, p, len);
836 else if (colored)
837 - strbuf_addf(out, "%s\n", s->s.cfg.reset_color_diff);
837 + strbuf_addf(out, "%s\n", s->cfg.reset_color_diff);
838 else
839 strbuf_addch(out, '\n');
840 }
@@ -1223,12 +1223,12 @@ static void recolor_hunk(struct add_p_state *s, struct hunk *hunk)
1223
1224 strbuf_addstr(&s->colored,
1225 plain[current] == '-' ?
1226 - s->s.cfg.file_old_color :
1226 + s->cfg.file_old_color :
1227 plain[current] == '+' ?
1228 - s->s.cfg.file_new_color :
1229 - s->s.cfg.context_color);
1228 + s->cfg.file_new_color :
1229 + s->cfg.context_color);
1230 strbuf_add(&s->colored, plain + current, eol - current);
1231 - strbuf_addstr(&s->colored, s->s.cfg.reset_color_diff);
1231 + strbuf_addstr(&s->colored, s->cfg.reset_color_diff);
1232 if (next > eol)
1233 strbuf_add(&s->colored, plain + eol, next - eol);
1234 current = next;
@@ -1357,7 +1357,7 @@ static int run_apply_check(struct add_p_state *s,
1357
1358 static int read_single_character(struct add_p_state *s)
1359 {
1360 - if (s->s.cfg.use_single_key) {
1360 + if (s->cfg.use_single_key) {
1361 int res = read_key_without_echo(&s->answer);
1362 printf("%s\n", res == EOF ? "" : s->answer.buf);
1363 return res;
@@ -1371,7 +1371,7 @@ static int read_single_character(struct add_p_state *s)
1371 static int prompt_yesno(struct add_p_state *s, const char *prompt)
1372 {
1373 for (;;) {
1374 - color_fprintf(stdout, s->s.cfg.prompt_color, "%s", _(prompt));
1374 + color_fprintf(stdout, s->cfg.prompt_color, "%s", _(prompt));
1375 fflush(stdout);
1376 if (read_single_character(s) == EOF)
1377 return -1;
@@ -1559,7 +1559,7 @@ static void apply_patch(struct add_p_state *s, struct file_diff *file_diff)
1559 strbuf_reset(&s->buf);
1560 reassemble_patch(s, file_diff, 0, &s->buf);
1561
1562 - discard_index(s->s.r->index);
1562 + discard_index(s->r->index);
1563 if (s->mode->apply_for_checkout)
1564 apply_for_checkout(s, &s->buf,
1565 s->mode->is_reverse);
@@ -1570,9 +1570,9 @@ static void apply_patch(struct add_p_state *s, struct file_diff *file_diff)
1570 NULL, 0, NULL, 0))
1571 error(_("'git apply' failed"));
1572 }
1573 - if (repo_read_index(s->s.r) >= 0)
1574 - repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0,
1575 - 1, NULL, NULL, NULL);
1573 + if (repo_read_index(s->r) >= 0)
1574 + repo_refresh_and_write_index(s->r, REFRESH_QUIET, 0,
1575 + 1, NULL, NULL, NULL);
1576 }
1577
1578 }
@@ -1660,7 +1660,7 @@ static size_t patch_update_file(struct add_p_state *s, size_t idx)
1660 /* Everything decided? */
1661 if (undecided_previous < 0 && undecided_next < 0 &&
1662 hunk->use != UNDECIDED_HUNK) {
1663 - if (!s->s.cfg.auto_advance)
1663 + if (!s->cfg.auto_advance)
1664 all_decided = 1;
1665 else {
1666 patch_update_resp++;
@@ -1714,11 +1714,11 @@ static size_t patch_update_file(struct add_p_state *s, size_t idx)
1714 permitted |= ALLOW_EDIT;
1715 strbuf_addstr(&s->buf, ",e");
1716 }
1717 - if (!s->s.cfg.auto_advance && s->file_diff_nr > 1) {
1717 + if (!s->cfg.auto_advance && s->file_diff_nr > 1) {
1718 permitted |= ALLOW_GOTO_NEXT_FILE;
1719 strbuf_addstr(&s->buf, ",>");
1720 }
1721 - if (!s->s.cfg.auto_advance && s->file_diff_nr > 1) {
1721 + if (!s->cfg.auto_advance && s->file_diff_nr > 1) {
1722 permitted |= ALLOW_GOTO_PREVIOUS_FILE;
1723 strbuf_addstr(&s->buf, ",<");
1724 }
@@ -1733,7 +1733,7 @@ static size_t patch_update_file(struct add_p_state *s, size_t idx)
1733 else
1734 prompt_mode_type = PROMPT_HUNK;
1735
1736 - printf("%s(%"PRIuMAX"/%"PRIuMAX") ", s->s.cfg.prompt_color,
1736 + printf("%s(%"PRIuMAX"/%"PRIuMAX") ", s->cfg.prompt_color,
1737 (uintmax_t)hunk_index + 1,
1738 (uintmax_t)(file_diff->hunk_nr
1739 ? file_diff->hunk_nr
@@ -1746,8 +1746,8 @@ static size_t patch_update_file(struct add_p_state *s, size_t idx)
1746 }
1747 printf(_(s->mode->prompt_mode[prompt_mode_type]),
1748 hunk_use_decision, s->buf.buf);
1749 - if (*s->s.cfg.reset_color_interactive)
1750 - fputs(s->s.cfg.reset_color_interactive, stdout);
1749 + if (*s->cfg.reset_color_interactive)
1750 + fputs(s->cfg.reset_color_interactive, stdout);
1751 fflush(stdout);
1752 if (read_single_character(s) == EOF) {
1753 patch_update_resp = s->file_diff_nr;
@@ -1798,7 +1798,7 @@ soft_increment:
1798 } else if (ch == 'q') {
1799 patch_update_resp = s->file_diff_nr;
1800 break;
1801 - } else if (!s->s.cfg.auto_advance && s->answer.buf[0] == '>') {
1801 + } else if (!s->cfg.auto_advance && s->answer.buf[0] == '>') {
1802 if (permitted & ALLOW_GOTO_NEXT_FILE) {
1803 if (patch_update_resp == s->file_diff_nr - 1)
1804 patch_update_resp = 0;
@@ -1809,7 +1809,7 @@ soft_increment:
1809 err(s, _("No next file"));
1810 continue;
1811 }
1812 - } else if (!s->s.cfg.auto_advance && s->answer.buf[0] == '<') {
1812 + } else if (!s->cfg.auto_advance && s->answer.buf[0] == '<') {
1813 if (permitted & ALLOW_GOTO_PREVIOUS_FILE) {
1814 if (patch_update_resp == 0)
1815 patch_update_resp = s->file_diff_nr - 1;
@@ -1932,7 +1932,7 @@ soft_increment:
1932 err(s, _("Sorry, cannot split this hunk"));
1933 } else if (!split_hunk(s, file_diff,
1934 hunk - file_diff->hunk)) {
1935 - color_fprintf_ln(stdout, s->s.cfg.header_color,
1935 + color_fprintf_ln(stdout, s->cfg.header_color,
1936 _("Split into %d hunks."),
1937 (int)splittable_into);
1938 rendered_hunk_index = -1;
@@ -1950,7 +1950,7 @@ soft_increment:
1950 } else if (s->answer.buf[0] == '?') {
1951 const char *p = _(help_patch_remainder), *eol = p;
1952
1953 - color_fprintf(stdout, s->s.cfg.help_color, "%s",
1953 + color_fprintf(stdout, s->cfg.help_color, "%s",
1954 _(s->mode->help_patch_text));
1955
1956 /*
@@ -1974,13 +1974,13 @@ soft_increment:
1974 if (file_diff->hunk[i].use == SKIP_HUNK)
1975 skipped += 1;
1976 }
1977 - color_fprintf_ln(stdout, s->s.cfg.help_color, _(p),
1977 + color_fprintf_ln(stdout, s->cfg.help_color, _(p),
1978 total, used, skipped);
1979 }
1980 if (*p != '?' && !strchr(s->buf.buf, *p))
1981 continue;
1982
1983 - color_fprintf_ln(stdout, s->s.cfg.help_color,
1983 + color_fprintf_ln(stdout, s->cfg.help_color,
1984 "%.*s", (int)(eol - p), p);
1985 }
1986 } else {
@@ -1989,7 +1989,7 @@ soft_increment:
1989 }
1990 }
1991
1992 - if (s->s.cfg.auto_advance)
1992 + if (s->cfg.auto_advance)
1993 apply_patch(s, file_diff);
1994
1995 putchar('\n');
@@ -2001,11 +2001,15 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
2001 const struct pathspec *ps)
2002 {
2003 struct add_p_state s = {
2004 - { r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
2004 + .r = r,
2005 + .answer = STRBUF_INIT,
2006 + .buf = STRBUF_INIT,
2007 + .plain = STRBUF_INIT,
2008 + .colored = STRBUF_INIT,
2009 };
2010 size_t i, binary_count = 0;
2011
2008 - init_add_i_state(&s.s, r, opts);
2012 + interactive_config_init(&s.cfg, r, opts);
2013
2014 if (mode == ADD_P_STASH)
2015 s.mode = &patch_mode_stash;
@@ -2051,7 +2055,7 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
2055 if ((i = patch_update_file(&s, i)) == s.file_diff_nr)
2056 break;
2057 }
2054 - if (!s.s.cfg.auto_advance)
2058 + if (!s.cfg.auto_advance)
2059 for (i = 0; i < s.file_diff_nr; i++)
2060 apply_patch(&s, s.file_diff + i);
2061