diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c
index 9d0ee08b..60c2762b 100644
--- a/src/command/cmd_ac.c
+++ b/src/command/cmd_ac.c
@@ -204,6 +204,7 @@ cmd_ac_init(void)
help_ac = autocomplete_new();
autocomplete_add(help_ac, "commands");
autocomplete_add(help_ac, "navigation");
+ autocomplete_add(help_ac, "search");
help_commands_ac = autocomplete_new();
autocomplete_add(help_commands_ac, "chat");
diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c
index d5eba7c8..9c320a4f 100644
--- a/src/command/cmd_defs.c
+++ b/src/command/cmd_defs.c
@@ -113,12 +113,12 @@ static gboolean _cmd_has_tag(Command *pcmd, const char *const tag);
static struct cmd_t command_defs[] =
{
{ "/help",
- parse_args, 0, 2, NULL,
+ parse_args_with_freetext, 0, 2, NULL,
CMD_NOSUBFUNCS
CMD_MAINFUNC(cmd_help)
CMD_NOTAGS
CMD_SYN(
- "/help [|]")
+ "/help [||search] []")
CMD_DESC(
"Help on using Profanity. Passing no arguments list help areas. "
"For command help, optional arguments are shown using square brackets, "
@@ -127,8 +127,10 @@ static struct cmd_t command_defs[] =
"e.g. val1|val2|val3.")
CMD_ARGS(
{ "", "Summary help for commands in a certain area of functionality." },
- { "", "Full help for a specific command, for example '/help connect'." })
+ { "", "Full help for a specific command, for example '/help connect'." },
+ { "search ", "Search commands for search_term." })
CMD_EXAMPLES(
+ "/help search presence show",
"/help commands",
"/help presence",
"/help who")
@@ -2264,9 +2266,75 @@ static struct cmd_t command_defs[] =
CMD_EXAMPLES(
"/export /path/to/output.csv",
"/export ~/contacts.csv")
- },
+ }
};
+static GHashTable *search_index;
+
+char*
+_cmd_index(Command *cmd) {
+ GString *index_source = g_string_new("");
+ index_source = g_string_append(index_source, cmd->cmd);
+ index_source = g_string_append(index_source, " ");
+ index_source = g_string_append(index_source, cmd->help.desc);
+ index_source = g_string_append(index_source, " ");
+
+ int len = g_strv_length(cmd->help.tags);
+ int i = 0;
+ for (i = 0; i < len; i++) {
+ index_source = g_string_append(index_source, cmd->help.tags[i]);
+ index_source = g_string_append(index_source, " ");
+ }
+ len = g_strv_length(cmd->help.synopsis);
+ for (i = 0; i < len; i++) {
+ index_source = g_string_append(index_source, cmd->help.synopsis[i]);
+ index_source = g_string_append(index_source, " ");
+ }
+ for (i = 0; cmd->help.args[i][0] != NULL; i++) {
+ index_source = g_string_append(index_source, cmd->help.args[i][0]);
+ index_source = g_string_append(index_source, " ");
+ index_source = g_string_append(index_source, cmd->help.args[i][1]);
+ index_source = g_string_append(index_source, " ");
+ }
+
+ gchar **tokens = g_str_tokenize_and_fold(index_source->str, NULL, NULL);
+
+ GString *index = g_string_new("");
+ i = 0;
+ for (i = 0; i < g_strv_length(tokens); i++) {
+ index = g_string_append(index, tokens[i]);
+ index = g_string_append(index, " ");
+ }
+
+ char *res = index->str;
+ g_string_free(index, FALSE);
+
+ return res;
+}
+
+GList*
+cmd_search_index(char *term)
+{
+ GList *results = NULL;
+
+ gchar **processed_terms = g_str_tokenize_and_fold(term, NULL, NULL);
+ int terms_len = g_strv_length(processed_terms);
+
+ int i = 0;
+ for (i = 0; i < terms_len; i++) {
+ GList *index_keys = g_hash_table_get_keys(search_index);
+ GList *curr = index_keys;
+ while (curr) {
+ char *index_entry = g_hash_table_lookup(search_index, curr->data);
+ if (g_str_match_string(processed_terms[i], index_entry, FALSE)) {
+ results = g_list_append(results, curr->data);
+ }
+ curr = g_list_next(curr);
+ }
+ }
+
+ return results;
+}
/*
* Initialise command autocompleter and history
@@ -2278,6 +2346,8 @@ cmd_init(void)
cmd_ac_init();
+ search_index = g_hash_table_new_full(g_str_hash, g_str_equal, free, free);
+
// load command defs into hash table
commands = g_hash_table_new(g_str_hash, g_str_equal);
unsigned int i;
@@ -2287,6 +2357,9 @@ cmd_init(void)
// add to hash
g_hash_table_insert(commands, pcmd->cmd, pcmd);
+ // add to search index
+ g_hash_table_insert(search_index, strdup(pcmd->cmd), strdup(_cmd_index(pcmd)));
+
// add to commands and help autocompleters
cmd_ac_add_cmd(pcmd);
}
diff --git a/src/command/cmd_defs.h b/src/command/cmd_defs.h
index 074970c9..286bad0d 100644
--- a/src/command/cmd_defs.h
+++ b/src/command/cmd_defs.h
@@ -49,4 +49,6 @@ gboolean cmd_valid_tag(const char *const str);
void command_docgen(void);
+GList* cmd_search_index(char *term);
+
#endif
diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c
index a2d2571f..fea2d55b 100644
--- a/src/command/cmd_funcs.c
+++ b/src/command/cmd_funcs.c
@@ -1484,6 +1484,41 @@ cmd_win(ProfWin *window, const char *const command, gchar **args)
return TRUE;
}
+static void
+_cmd_list_commands(GList *commands) {
+ int maxlen = 0;
+ GList *curr = commands;
+ while (curr) {
+ gchar *cmd = curr->data;
+ int len = strlen(cmd);
+ if (len > maxlen) maxlen = len;
+ curr = g_list_next(curr);
+ }
+
+ GString *cmds = g_string_new("");
+ curr = commands;
+ int count = 0;
+ while (curr) {
+ gchar *cmd = curr->data;
+ if (count == 5) {
+ cons_show(cmds->str);
+ g_string_free(cmds, TRUE);
+ cmds = g_string_new("");
+ count = 0;
+ }
+ g_string_append_printf(cmds, "%-*s", maxlen + 1, cmd);
+ curr = g_list_next(curr);
+ count++;
+ }
+ cons_show(cmds->str);
+ g_string_free(cmds, TRUE);
+ g_list_free(curr);
+
+ cons_show("");
+ cons_show("Use /help [command] without the leading slash, for help on a specific command");
+ cons_show("");
+}
+
static void
_cmd_help_cmd_list(const char *const tag)
{
@@ -1520,38 +1555,8 @@ _cmd_help_cmd_list(const char *const tag)
}
}
- int maxlen = 0;
- GList *curr = ordered_commands;
- while (curr) {
- gchar *cmd = curr->data;
- int len = strlen(cmd);
- if (len > maxlen) maxlen = len;
- curr = g_list_next(curr);
- }
-
- GString *cmds = g_string_new("");
- curr = ordered_commands;
- int count = 0;
- while (curr) {
- gchar *cmd = curr->data;
- if (count == 5) {
- cons_show(cmds->str);
- g_string_free(cmds, TRUE);
- cmds = g_string_new("");
- count = 0;
- }
- g_string_append_printf(cmds, "%-*s", maxlen + 1, cmd);
- curr = g_list_next(curr);
- count++;
- }
- cons_show(cmds->str);
- g_string_free(cmds, TRUE);
+ _cmd_list_commands(ordered_commands);
g_list_free(ordered_commands);
- g_list_free(curr);
-
- cons_show("");
- cons_show("Use /help [command] without the leading slash, for help on a specific command");
- cons_show("");
}
gboolean
@@ -1560,6 +1565,26 @@ cmd_help(ProfWin *window, const char *const command, gchar **args)
int num_args = g_strv_length(args);
if (num_args == 0) {
cons_help();
+ } else if (strcmp(args[0], "search") == 0) {
+ if (args[1] == NULL) {
+ cons_bad_cmd_usage(command);
+ } else {
+ GList *cmds = cmd_search_index(args[1]);
+ if (cmds == NULL) {
+ cons_show("No commands found.");
+ } else {
+ GList *curr = cmds;
+ GList *results = NULL;
+ while (curr) {
+ results = g_list_insert_sorted(results, curr->data, (GCompareFunc)g_strcmp0);
+ curr = g_list_next(curr);
+ }
+ cons_show("Search results:");
+ _cmd_list_commands(results);
+ g_list_free(results);
+ }
+ g_list_free(cmds);
+ }
} else if (strcmp(args[0], "commands") == 0) {
if (args[1]) {
if (!cmd_valid_tag(args[1])) {
diff --git a/src/ui/console.c b/src/ui/console.c
index 3b904c62..cb5a10b0 100644
--- a/src/ui/console.c
+++ b/src/ui/console.c
@@ -142,7 +142,7 @@ cons_show_help(const char *const cmd, CommandHelp *help)
if (g_strv_length((gchar**)help->examples) > 0) {
cons_show("");
- win_println(console, THEME_HELP_HEADER, '-', "Arguments");
+ win_println(console, THEME_HELP_HEADER, '-', "Examples");
ui_show_lines(console, help->examples);
}
}