2 #include "../builtin.h"
10 struct cmdname *
ent =
malloc(
sizeof(*ent) + len + 1);
13 memcpy(ent->name, name, len);
24 for (i = 0; i < cmds->
cnt; ++
i)
31 static int cmdname_compare(
const void *a_,
const void *b_)
33 struct cmdname *
a = *(
struct cmdname **)a_;
34 struct cmdname *
b = *(
struct cmdname **)b_;
35 return strcmp(a->name, b->name);
45 for (i = j = 1; i < cmds->
cnt; i++)
58 while (ci < cmds->
cnt && ei < excludes->
cnt) {
68 while (ci < cmds->cnt)
74 static void pretty_print_string_list(
struct cmdnames *cmds,
int longest)
77 int space = longest + 1;
83 max_cols =
win.ws_col - 1;
86 cols = max_cols / space;
87 rows = (cmds->
cnt + cols - 1) / cols;
89 for (i = 0; i <
rows; i++) {
92 for (j = 0; j <
cols; j++) {
93 unsigned int n = j * rows +
i;
94 unsigned int size = space;
98 if (j == cols-1 || n + rows >= cmds->
cnt)
106 static int is_executable(
const char *
name)
117 static void list_commands_in_dir(
struct cmdnames *cmds,
131 prefix_len =
strlen(prefix);
136 while ((de = readdir(dir)) !=
NULL) {
142 strbuf_setlen(&buf, len);
143 strbuf_addstr(&buf, de->d_name);
144 if (!is_executable(buf.
buf))
147 entlen =
strlen(de->d_name) - prefix_len;
148 if (has_extension(de->d_name,
".exe"))
151 add_cmdname(cmds, de->d_name + prefix_len, entlen);
161 const char *env_path = getenv(
"PATH");
165 list_commands_in_dir(main_cmds, exec_path, prefix);
166 qsort(main_cmds->
names, main_cmds->
cnt,
167 sizeof(*main_cmds->
names), cmdname_compare);
172 char *paths, *
path, *colon;
173 path = paths = strdup(env_path);
177 if (!exec_path ||
strcmp(path, exec_path))
178 list_commands_in_dir(other_cmds, path, prefix);
186 qsort(other_cmds->
names, other_cmds->
cnt,
187 sizeof(*other_cmds->
names), cmdname_compare);
196 unsigned int i, longest = 0;
198 for (i = 0; i < main_cmds->
cnt; i++)
199 if (longest < main_cmds->names[i]->len)
200 longest = main_cmds->
names[
i]->len;
201 for (i = 0; i < other_cmds->
cnt; i++)
202 if (longest < other_cmds->names[i]->len)
203 longest = other_cmds->
names[
i]->len;
205 if (main_cmds->
cnt) {
207 printf(
"available %s in '%s'\n", title, exec_path);
208 printf(
"----------------");
211 pretty_print_string_list(main_cmds, longest);
215 if (other_cmds->
cnt) {
216 printf(
"%s available from elsewhere on your $PATH\n", title);
217 printf(
"---------------------------------------");
218 mput_char(
'-',
strlen(title));
220 pretty_print_string_list(other_cmds, longest);
229 for (i = 0; i < c->
cnt; i++)
235 static int autocorrect;
238 static int perf_unknown_cmd_config(
const char *var,
const char *
value,
void *
cb)
240 if (!
strcmp(var,
"help.autocorrect"))
249 static int levenshtein_compare(
const void *
p1,
const void *p2)
251 const struct cmdname *
const *c1 =
p1, *
const *c2 = p2;
252 const char *
s1 = (*c1)->name, *
s2 = (*c2)->name;
255 return l1 != l2 ? l1 - l2 :
strcmp(s1,
s2);
264 for (i = 0; i < old->
cnt; i++)
273 unsigned int i,
n = 0, best_similarity = 0;
274 struct cmdnames main_cmds, other_cmds;
276 memset(&main_cmds, 0,
sizeof(main_cmds));
277 memset(&other_cmds, 0,
sizeof(main_cmds));
284 add_cmd_list(&main_cmds, &
aliases);
285 add_cmd_list(&main_cmds, &other_cmds);
286 qsort(main_cmds.
names, main_cmds.
cnt,
287 sizeof(main_cmds.
names), cmdname_compare);
292 for (i = 0; i < main_cmds.
cnt; ++
i)
293 main_cmds.
names[i]->len =
296 qsort(main_cmds.
names, main_cmds.
cnt,
297 sizeof(*main_cmds.
names), levenshtein_compare);
299 best_similarity = main_cmds.
names[0]->len;
301 while (n < main_cmds.
cnt && best_similarity == main_cmds.
names[n]->len)
305 if (autocorrect && n == 1) {
306 const char *assumed = main_cmds.
names[0]->name;
309 clean_cmdnames(&main_cmds);
310 fprintf(stderr,
"WARNING: You called a perf program named '%s', "
311 "which does not exist.\n"
312 "Continuing under the assumption that you meant '%s'\n",
314 if (autocorrect > 0) {
315 fprintf(stderr,
"in %0.1f seconds automatically...\n",
316 (
float)autocorrect/10.0);
322 fprintf(stderr,
"perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
324 if (main_cmds.
cnt && best_similarity < 6) {
325 fprintf(stderr,
"\nDid you mean %s?\n",
326 n < 2 ?
"this":
"one of these");
328 for (i = 0; i <
n; i++)
336 const char *prefix __maybe_unused)