autocorrect: provide config resolution API

Add autocorrect_resolve(). This resolves and populates the correct
values for autocorrect config.

Make autocorrect config callback internal. The API is meant to provide
a high-level way to retrieve the config. Allowing access to the config
callback from outside violates that intent.

Additionally, in some cases, without access to the config callback, two
config iterations cannot be merged into one, which can hurt performance.
This is fine, as the code path that calls autocorrect_resolve() is cold.

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-04-23 10:37:56 +09:00
committed by Junio C Hamano
parent 01e68aca69
commit 0df5897d28
3 changed files with 30 additions and 30 deletions

View File

@@ -1,3 +1,5 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "git-compat-util.h"
#include "autocorrect.h"
#include "config.h"
@@ -29,13 +31,13 @@ static enum autocorrect_mode parse_autocorrect(const char *value)
return AUTOCORRECT_DELAY;
}
void autocorrect_resolve_config(const char *var, const char *value,
const struct config_context *ctx, void *data)
static int resolve_autocorrect(const char *var, const char *value,
const struct config_context *ctx, void *data)
{
struct autocorrect *conf = data;
if (strcmp(var, "help.autocorrect"))
return;
return 0;
conf->mode = parse_autocorrect(value);
@@ -53,6 +55,13 @@ void autocorrect_resolve_config(const char *var, const char *value,
else if (conf->delay < 0 || conf->delay == 1)
conf->mode = AUTOCORRECT_IMMEDIATELY;
}
return 0;
}
void autocorrect_resolve(struct autocorrect *conf)
{
read_early_config(the_repository, resolve_autocorrect, conf);
}
void autocorrect_confirm(struct autocorrect *conf, const char *assumed)

View File

@@ -1,8 +1,6 @@
#ifndef AUTOCORRECT_H
#define AUTOCORRECT_H
struct config_context;
enum autocorrect_mode {
AUTOCORRECT_HINT,
AUTOCORRECT_NEVER,
@@ -16,8 +14,7 @@ struct autocorrect {
int delay;
};
void autocorrect_resolve_config(const char *var, const char *value,
const struct config_context *ctx, void *data);
void autocorrect_resolve(struct autocorrect *conf);
void autocorrect_confirm(struct autocorrect *conf, const char *assumed);

40
help.c
View File

@@ -537,32 +537,23 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)
return 0;
}
struct help_unknown_cmd_config {
struct autocorrect autocorrect;
struct cmdnames aliases;
};
static int git_unknown_cmd_config(const char *var, const char *value,
const struct config_context *ctx,
void *cb)
static int resolve_aliases(const char *var, const char *value UNUSED,
const struct config_context *ctx UNUSED, void *data)
{
struct help_unknown_cmd_config *cfg = cb;
struct cmdnames *aliases = data;
const char *subsection, *key;
size_t subsection_len;
autocorrect_resolve_config(var, value, ctx, &cfg->autocorrect);
/* Also use aliases for command lookup */
if (!parse_config_key(var, "alias", &subsection, &subsection_len,
&key)) {
if (subsection) {
/* [alias "name"] command = value */
if (!strcmp(key, "command"))
add_cmdname(&cfg->aliases, subsection,
add_cmdname(aliases, subsection,
subsection_len);
} else {
/* alias.name = value */
add_cmdname(&cfg->aliases, key, strlen(key));
add_cmdname(aliases, key, strlen(key));
}
}
@@ -599,22 +590,26 @@ static const char bad_interpreter_advice[] =
char *help_unknown_cmd(const char *cmd)
{
struct help_unknown_cmd_config cfg = { 0 };
struct cmdnames aliases = { 0 };
struct autocorrect autocorrect = { 0 };
int i, n, best_similarity = 0;
struct cmdnames main_cmds = { 0 };
struct cmdnames other_cmds = { 0 };
struct cmdname_help *common_cmds;
read_early_config(the_repository, git_unknown_cmd_config, &cfg);
autocorrect_resolve(&autocorrect);
if (cfg.autocorrect.mode == AUTOCORRECT_NEVER) {
if (autocorrect.mode == AUTOCORRECT_NEVER) {
fprintf_ln(stderr, _("git: '%s' is not a git command. See 'git --help'."), cmd);
exit(1);
}
load_command_list("git-", &main_cmds, &other_cmds);
add_cmd_list(&main_cmds, &cfg.aliases);
/* Also use aliases for command lookup */
read_early_config(the_repository, resolve_aliases, &aliases);
add_cmd_list(&main_cmds, &aliases);
add_cmd_list(&main_cmds, &other_cmds);
QSORT(main_cmds.names, main_cmds.cnt, cmdname_compare);
uniq(&main_cmds);
@@ -674,18 +669,17 @@ char *help_unknown_cmd(const char *cmd)
; /* still counting */
}
if (cfg.autocorrect.mode != AUTOCORRECT_HINT && n == 1 &&
if (autocorrect.mode != AUTOCORRECT_HINT && n == 1 &&
SIMILAR_ENOUGH(best_similarity)) {
char *assumed = xstrdup(main_cmds.names[0]->name);
fprintf_ln(stderr,
_("WARNING: You called a Git command named '%s', "
"which does not exist."),
_("WARNING: You called a Git command named '%s', which does not exist."),
cmd);
autocorrect_confirm(&cfg.autocorrect, assumed);
autocorrect_confirm(&autocorrect, assumed);
cmdnames_release(&cfg.aliases);
cmdnames_release(&aliases);
cmdnames_release(&main_cmds);
cmdnames_release(&other_cmds);
return assumed;