Skip to content

Commit ab0301b

Browse files
committed
Merge branch 'add-p-in-c-config-settings'
This is the final leg of the journey to a fully built-in `git add`: the `git add -i` and `git add -p` modes were re-implemented in C, but they lacked support for a couple of config settings. The one that sticks out most is the `interactive.singleKey` setting: it was not only particularly hard to get to work, especially on Windows. It is also the setting that seems to be incomplete already in the Perl version: while the name suggests that it applies to the main loop of `git add --interactive`, or to the file selections in that command, it does not. Only the `git add --patch` mode respects that setting. As it is outside the purpose of the conversion of `git-add--interactive.perl` to C, we will leave that loose end for some future date. Signed-off-by: Johannes Schindelin <[email protected]>
2 parents 8c242f9 + 779d4dd commit ab0301b

File tree

6 files changed

+319
-8
lines changed

6 files changed

+319
-8
lines changed

add-interactive.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,19 @@ int init_add_i_state(struct repository *r, struct add_i_state *s)
5656
strlcpy(s->file_new_color,
5757
diff_get_color(s->use_color, DIFF_FILE_NEW), COLOR_MAXLEN);
5858

59+
free(s->interactive_diff_filter);
60+
if (git_config_get_string("interactive.difffilter",
61+
&s->interactive_diff_filter))
62+
s->interactive_diff_filter = NULL;
63+
64+
free(s->interactive_diff_algorithm);
65+
if (git_config_get_string("diff.algorithm",
66+
&s->interactive_diff_algorithm))
67+
s->interactive_diff_algorithm = NULL;
68+
69+
if (git_config_get_bool("interactive.singlekey",
70+
&s->use_single_key))
71+
s->use_single_key = 0;
5972

6073
return 0;
6174
}

add-interactive.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ struct add_i_state {
1515
char context_color[COLOR_MAXLEN];
1616
char file_old_color[COLOR_MAXLEN];
1717
char file_new_color[COLOR_MAXLEN];
18+
19+
int use_single_key;
20+
char *interactive_diff_filter, *interactive_diff_algorithm;
1821
};
1922

2023
int init_add_i_state(struct repository *r, struct add_i_state *s);
@@ -27,6 +30,9 @@ enum color_add_i {
2730
COLOR_RESET,
2831
};
2932
const char *get_add_i_color(enum color_add_i ix);
33+
const char *get_interactive_diff_filter(void);
34+
const char *get_interactive_diff_algorithm(void);
35+
int get_interactive_use_single_key(void);
3036

3137
struct repository;
3238
struct pathspec;

add-patch.c

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "pathspec.h"
77
#include "color.h"
88
#include "diff.h"
9+
#include "compat/terminal.h"
910

1011
enum prompt_mode_type {
1112
PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK
@@ -309,6 +310,7 @@ static int is_octal(const char *p, size_t len)
309310
static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
310311
{
311312
struct argv_array args = ARGV_ARRAY_INIT;
313+
const char *diff_algorithm = s->s.interactive_diff_algorithm;
312314
struct strbuf *plain = &s->plain, *colored = NULL;
313315
struct child_process cp = CHILD_PROCESS_INIT;
314316
char *p, *pend, *colored_p = NULL, *colored_pend = NULL, marker = '\0';
@@ -318,6 +320,8 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
318320
int res;
319321

320322
argv_array_pushv(&args, s->mode->diff);
323+
if (diff_algorithm)
324+
argv_array_pushf(&args, "--diff-algorithm=%s", diff_algorithm);
321325
if (s->revision) {
322326
struct object_id oid;
323327
argv_array_push(&args,
@@ -347,6 +351,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
347351

348352
if (want_color_fd(1, -1)) {
349353
struct child_process colored_cp = CHILD_PROCESS_INIT;
354+
const char *diff_filter = s->s.interactive_diff_filter;
350355

351356
setup_child_process(&colored_cp, s, NULL);
352357
xsnprintf((char *)args.argv[color_arg_index], 8, "--color");
@@ -356,6 +361,24 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
356361
argv_array_clear(&args);
357362
if (res)
358363
return error(_("could not parse colored diff"));
364+
365+
if (diff_filter) {
366+
struct child_process filter_cp = CHILD_PROCESS_INIT;
367+
368+
setup_child_process(&filter_cp, s,
369+
diff_filter, NULL);
370+
filter_cp.git_cmd = 0;
371+
filter_cp.use_shell = 1;
372+
strbuf_reset(&s->buf);
373+
if (pipe_command(&filter_cp,
374+
colored->buf, colored->len,
375+
&s->buf, colored->len,
376+
NULL, 0) < 0)
377+
return error(_("failed to run '%s'"),
378+
diff_filter);
379+
strbuf_swap(colored, &s->buf);
380+
}
381+
359382
strbuf_complete_line(colored);
360383
colored_p = colored->buf;
361384
colored_pend = colored_p + colored->len;
@@ -457,6 +480,9 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
457480
colored_pend - colored_p);
458481
if (colored_eol)
459482
colored_p = colored_eol + 1;
483+
else if (p != pend)
484+
/* colored shorter than non-colored? */
485+
goto mismatched_output;
460486
else
461487
colored_p = colored_pend;
462488

@@ -478,6 +504,15 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
478504
*/
479505
hunk->splittable_into++;
480506

507+
/* non-colored shorter than colored? */
508+
if (colored_p != colored_pend) {
509+
mismatched_output:
510+
error(_("mismatched output from interactive.diffFilter"));
511+
advise(_("Your filter must maintain a one-to-one correspondence\n"
512+
"between its input and output lines."));
513+
return -1;
514+
}
515+
481516
return 0;
482517
}
483518

@@ -1012,14 +1047,27 @@ static int run_apply_check(struct add_p_state *s,
10121047
return 0;
10131048
}
10141049

1050+
static int read_single_character(struct add_p_state *s)
1051+
{
1052+
if (s->s.use_single_key) {
1053+
int res = read_key_without_echo(&s->answer);
1054+
printf("%s\n", res == EOF ? "" : s->answer.buf);
1055+
return res;
1056+
}
1057+
1058+
if (strbuf_getline(&s->answer, stdin) == EOF)
1059+
return EOF;
1060+
strbuf_trim_trailing_newline(&s->answer);
1061+
return 0;
1062+
}
1063+
10151064
static int prompt_yesno(struct add_p_state *s, const char *prompt)
10161065
{
10171066
for (;;) {
10181067
color_fprintf(stdout, s->s.prompt_color, "%s", _(prompt));
10191068
fflush(stdout);
1020-
if (strbuf_getline(&s->answer, stdin) == EOF)
1069+
if (read_single_character(s) == EOF)
10211070
return -1;
1022-
strbuf_trim_trailing_newline(&s->answer);
10231071
switch (tolower(s->answer.buf[0])) {
10241072
case 'n': return 0;
10251073
case 'y': return 1;
@@ -1255,9 +1303,8 @@ static int patch_update_file(struct add_p_state *s,
12551303
_(s->mode->prompt_mode[prompt_mode_type]),
12561304
s->buf.buf);
12571305
fflush(stdout);
1258-
if (strbuf_getline(&s->answer, stdin) == EOF)
1306+
if (read_single_character(s) == EOF)
12591307
break;
1260-
strbuf_trim_trailing_newline(&s->answer);
12611308

12621309
if (!s->answer.len)
12631310
continue;

ci/run-build-and-tests.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ then
2020
export GIT_TEST_OE_DELTA_SIZE=5
2121
export GIT_TEST_COMMIT_GRAPH=1
2222
export GIT_TEST_MULTI_PACK_INDEX=1
23+
export GIT_TEST_ADD_I_USE_BUILTIN=1
2324
make test
2425
fi
2526

0 commit comments

Comments
 (0)