about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJames Booth <boothj5@gmail.com>2017-04-06 23:36:50 +0100
committerJames Booth <boothj5@gmail.com>2017-04-06 23:36:50 +0100
commitfd6620a950ebac0794a5eddbc38ce13b6bfc00ae (patch)
tree6679df1f21339c8029e13f1aea8e5b0d8ba9183d
parent6b830277a6e2f90c7f8fde94ccf31dc6a4e4e73e (diff)
downloadprofani-tty-fd6620a950ebac0794a5eddbc38ce13b6bfc00ae.tar.gz
Add basic help search
-rw-r--r--src/command/cmd_ac.c1
-rw-r--r--src/command/cmd_defs.c81
-rw-r--r--src/command/cmd_defs.h2
-rw-r--r--src/command/cmd_funcs.c87
-rw-r--r--src/ui/console.c2
5 files changed, 137 insertions, 36 deletions
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 [<area>|<command>]")
+            "/help [<area>|<command>|search] [<search_term>]")
         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(
             { "<area>",    "Summary help for commands in a certain area of functionality." },
-            { "<command>", "Full help for a specific command, for example '/help connect'." })
+            { "<command>", "Full help for a specific command, for example '/help connect'." },
+            { "search <search_term>",    "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
@@ -1485,6 +1485,41 @@ cmd_win(ProfWin *window, const char *const command, gchar **args)
 }
 
 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)
 {
     cons_show("");
@@ -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);
     }
 }