help: make autocorrect handling reusable

Move config parsing and prompt/delay handling into autocorrect.c and
expose them in autocorrect.h. This makes autocorrect reusable regardless
of which target links against it.

Signed-off-by: Jiamu Sun <39@barroit.sh>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jiamu Sun
2026-03-10 20:41:01 +09:00
committed by Junio C Hamano
parent 38ed9faa1d
commit db8b01619c
4 changed files with 93 additions and 60 deletions

View File

@@ -1098,6 +1098,7 @@ LIB_OBJS += archive-tar.o
LIB_OBJS += archive-zip.o
LIB_OBJS += archive.o
LIB_OBJS += attr.o
LIB_OBJS += autocorrect.o
LIB_OBJS += base85.o
LIB_OBJS += bisect.o
LIB_OBJS += blame.o

72
autocorrect.c Normal file
View File

@@ -0,0 +1,72 @@
#include "git-compat-util.h"
#include "autocorrect.h"
#include "config.h"
#include "parse.h"
#include "strbuf.h"
#include "prompt.h"
#include "gettext.h"
static int parse_autocorrect(const char *value)
{
switch (git_parse_maybe_bool_text(value)) {
case 1:
return AUTOCORRECT_IMMEDIATELY;
case 0:
return AUTOCORRECT_SHOW;
default: /* other random text */
break;
}
if (!strcmp(value, "prompt"))
return AUTOCORRECT_PROMPT;
if (!strcmp(value, "never"))
return AUTOCORRECT_NEVER;
if (!strcmp(value, "immediate"))
return AUTOCORRECT_IMMEDIATELY;
if (!strcmp(value, "show"))
return AUTOCORRECT_SHOW;
return 0;
}
void autocorr_resolve_config(const char *var, const char *value,
const struct config_context *ctx, void *data)
{
int *out = data;
if (!strcmp(var, "help.autocorrect")) {
int v = parse_autocorrect(value);
if (!v) {
v = git_config_int(var, value, ctx->kvi);
if (v < 0 || v == 1)
v = AUTOCORRECT_IMMEDIATELY;
}
*out = v;
}
}
void autocorr_confirm(int autocorrect, const char *assumed)
{
if (autocorrect == AUTOCORRECT_IMMEDIATELY) {
fprintf_ln(stderr,
_("Continuing under the assumption that you meant '%s'."),
assumed);
} else if (autocorrect == AUTOCORRECT_PROMPT) {
char *answer;
struct strbuf msg = STRBUF_INIT;
strbuf_addf(&msg, _("Run '%s' instead [y/N]? "), assumed);
answer = git_prompt(msg.buf, PROMPT_ECHO);
strbuf_release(&msg);
if (!(starts_with(answer, "y") || starts_with(answer, "Y")))
exit(1);
} else {
fprintf_ln(stderr,
_("Continuing in %0.1f seconds, assuming that you meant '%s'."),
(float)autocorrect / 10.0, assumed);
sleep_millisec(autocorrect * 100);
}
}

16
autocorrect.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef AUTOCORRECT_H
#define AUTOCORRECT_H
#define AUTOCORRECT_SHOW (-4)
#define AUTOCORRECT_PROMPT (-3)
#define AUTOCORRECT_NEVER (-2)
#define AUTOCORRECT_IMMEDIATELY (-1)
struct config_context;
void autocorr_resolve_config(const char *var, const char *value,
const struct config_context *ctx, void *data);
void autocorr_confirm(int autocorr, const char *assumed);
#endif /* AUTOCORRECT_H */

64
help.c
View File

@@ -22,6 +22,7 @@
#include "repository.h"
#include "alias.h"
#include "utf8.h"
#include "autocorrect.h"
#ifndef NO_CURL
#include "git-curl-compat.h" /* For LIBCURL_VERSION only */
@@ -541,34 +542,6 @@ struct help_unknown_cmd_config {
struct cmdnames aliases;
};
#define AUTOCORRECT_SHOW (-4)
#define AUTOCORRECT_PROMPT (-3)
#define AUTOCORRECT_NEVER (-2)
#define AUTOCORRECT_IMMEDIATELY (-1)
static int parse_autocorrect(const char *value)
{
switch (git_parse_maybe_bool_text(value)) {
case 1:
return AUTOCORRECT_IMMEDIATELY;
case 0:
return AUTOCORRECT_SHOW;
default: /* other random text */
break;
}
if (!strcmp(value, "prompt"))
return AUTOCORRECT_PROMPT;
if (!strcmp(value, "never"))
return AUTOCORRECT_NEVER;
if (!strcmp(value, "immediate"))
return AUTOCORRECT_IMMEDIATELY;
if (!strcmp(value, "show"))
return AUTOCORRECT_SHOW;
return 0;
}
static int git_unknown_cmd_config(const char *var, const char *value,
const struct config_context *ctx,
void *cb)
@@ -577,17 +550,7 @@ static int git_unknown_cmd_config(const char *var, const char *value,
const char *subsection, *key;
size_t subsection_len;
if (!strcmp(var, "help.autocorrect")) {
int v = parse_autocorrect(value);
if (!v) {
v = git_config_int(var, value, ctx->kvi);
if (v < 0 || v == 1)
v = AUTOCORRECT_IMMEDIATELY;
}
cfg->autocorrect = v;
}
autocorr_resolve_config(var, value, ctx, &cfg->autocorrect);
/* Also use aliases for command lookup */
if (!parse_config_key(var, "alias", &subsection, &subsection_len,
@@ -724,27 +687,8 @@ char *help_unknown_cmd(const char *cmd)
_("WARNING: You called a Git command named '%s', "
"which does not exist."),
cmd);
if (cfg.autocorrect == AUTOCORRECT_IMMEDIATELY)
fprintf_ln(stderr,
_("Continuing under the assumption that "
"you meant '%s'."),
assumed);
else if (cfg.autocorrect == AUTOCORRECT_PROMPT) {
char *answer;
struct strbuf msg = STRBUF_INIT;
strbuf_addf(&msg, _("Run '%s' instead [y/N]? "), assumed);
answer = git_prompt(msg.buf, PROMPT_ECHO);
strbuf_release(&msg);
if (!(starts_with(answer, "y") ||
starts_with(answer, "Y")))
exit(1);
} else {
fprintf_ln(stderr,
_("Continuing in %0.1f seconds, "
"assuming that you meant '%s'."),
(float)cfg.autocorrect/10.0, assumed);
sleep_millisec(cfg.autocorrect * 100);
}
autocorr_confirm(cfg.autocorrect, assumed);
cmdnames_release(&cfg.aliases);
cmdnames_release(&main_cmds);