From d95b20c27f9eced42521b7ec00e43ebd37d335f9 Mon Sep 17 00:00:00 2001 From: Daniel Carl Date: Fri, 31 May 2013 17:03:31 +0200 Subject: [PATCH] Changed completion of history an bookmarks (#27). Now we distinct between history completion and bookmark completion. 1. Bookmark completion is triggered by ':open !' to complete all bookmarks or by ':open !tag1 tag2' to complete only those bookmarks that have tags with the prefixes tag1 and tag2. 2. History completion is changed to split the search query at the space char and to search for all given words in the history. Only those history items are completed, that match all given words or tags. 3. Search completion works now also tag based like the url and bookmark completions. --- src/bookmark.c | 38 ++++------------------------- src/command.c | 21 ++++++++++++++-- src/command.h | 2 +- src/completion.c | 62 +++++++++++++++--------------------------------- src/history.c | 42 ++++++++++++++++++++++---------- src/history.h | 2 +- src/setting.c | 24 +++++++++++++++++-- src/setting.h | 2 +- src/util.c | 50 ++++++++++++++++++++++++++++++++++++++ src/util.h | 4 ++++ 10 files changed, 151 insertions(+), 96 deletions(-) diff --git a/src/bookmark.c b/src/bookmark.c index 0197c20..0c05b2c 100644 --- a/src/bookmark.c +++ b/src/bookmark.c @@ -19,6 +19,7 @@ #include "main.h" #include "bookmark.h" +#include "util.h" extern VbCore vb; @@ -28,7 +29,6 @@ typedef struct { } Bookmark; static GList *load(const char *file); -static gboolean contains_all_tags(char **src, unsigned int s, char **query, unsigned int q); static void free_bookmark(Bookmark *bm); /** @@ -64,11 +64,10 @@ GList *bookmark_get_by_tags(const char *tags) src = load(vb.files[FILES_BOOKMARK]); if (!tags || *tags == '\0') { + /* without any tags return all bookmarked items */ for (GList *l = src; l; l = l->next) { Bookmark *bm = (Bookmark*)l->data; - if (!bm->tags) { - res = g_list_prepend(res, g_strdup(bm->uri)); - } + res = g_list_prepend(res, g_strdup(bm->uri)); } } else { parts = g_strsplit(tags, " ", 0); @@ -77,7 +76,7 @@ GList *bookmark_get_by_tags(const char *tags) for (GList *l = src; l; l = l->next) { Bookmark *bm = (Bookmark*)l->data; if (bm->tags - && contains_all_tags(bm->tags, g_strv_length(bm->tags), parts, len) + && util_array_contains_all_tags(bm->tags, g_strv_length(bm->tags), parts, len) ) { res = g_list_prepend(res, g_strdup(bm->uri)); } @@ -131,35 +130,6 @@ static GList *load(const char *file) return list; } -/** - * Checks if the given source array of pointer contains all those entries - * given as array of search strings. - */ -static gboolean contains_all_tags(char **src, unsigned int s, char **query, unsigned int q) -{ - unsigned int i, n; - - if (!s || !q) { - return true; - } - - /* iterate over all query parts */ - for (i = 0; i < q; i++) { - gboolean found = false; - for (n = 0; n < s; n++) { - if (!strcmp(query[i], src[n])) { - found = true; - break; - } - } - if (!found) { - return false; - } - } - - return true; -} - static void free_bookmark(Bookmark *bm) { g_free(bm->uri); diff --git a/src/command.c b/src/command.c index b9f405c..115f737 100644 --- a/src/command.c +++ b/src/command.c @@ -153,10 +153,27 @@ void command_init(void) } } -GList *command_get_all(void) +GList *command_get_by_prefix(const char *prefix) { + GList *res = NULL; /* according to vim we return only the long commands here */ - return g_hash_table_get_keys(commands); + GList *src = g_hash_table_get_keys(commands); + + if (!prefix || prefix == '\0') { + for (GList *l = src; l; l = l->next) { + res = g_list_prepend(res, l->data); + } + } else { + for (GList *l = src; l; l = l->next) { + char *value = (char*)l->data; + if (g_str_has_prefix(value, prefix)) { + res = g_list_prepend(res, value); + } + } + } + g_list_free(src); + + return res; } void command_cleanup(void) diff --git a/src/command.h b/src/command.h index b7f49f7..5d234c0 100644 --- a/src/command.h +++ b/src/command.h @@ -21,7 +21,7 @@ #define _COMMAND_H void command_init(void); -GList *command_get_all(void); +GList *command_get_by_prefix(const char *prefix); void command_cleanup(void); gboolean command_exists(const char *name); gboolean command_run(const char *name, const char *param); diff --git a/src/completion.c b/src/completion.c index 7dc3981..8cd037d 100644 --- a/src/completion.c +++ b/src/completion.c @@ -25,9 +25,10 @@ #include "command.h" #include "setting.h" +#define TAG_INDICATOR '!' + extern VbCore vb; -typedef gboolean (*Comp_Func)(char*, const char*); typedef struct { GtkWidget *label; GtkWidget *event; @@ -41,7 +42,6 @@ static struct { char *prefix; } comps; -static GList *filter_list(GList *target, GList *source, Comp_Func func, const char *input); static GList *init_completion(GList *target, GList *source, const char *prefix); static GList *update(GList *completion, GList *active, gboolean back); static void show(gboolean back); @@ -54,7 +54,7 @@ gboolean completion_complete(gboolean back) { VbInputType type; const char *input, *prefix, *suffix; - GList *source = NULL, *tmp = NULL; + GList *source = NULL; input = GET_TEXT(); type = vb_get_input_parts(input, &prefix, &suffix); @@ -91,41 +91,31 @@ gboolean completion_complete(gboolean back) gtk_box_pack_start(GTK_BOX(vb.gui.box), vb.gui.compbox, false, false, 0); if (type == VB_INPUT_SET) { - source = g_list_sort(setting_get_all(), (GCompareFunc)g_strcmp0); - comps.completions = init_completion( - comps.completions, - filter_list(tmp, source, (Comp_Func)g_str_has_prefix, suffix), - prefix - ); + source = g_list_sort(setting_get_by_prefix(suffix), (GCompareFunc)g_strcmp0); + comps.completions = init_completion(comps.completions, source, prefix); g_list_free(source); } else if (type == VB_INPUT_OPEN || type == VB_INPUT_TABOPEN) { - source = history_get_all(HISTORY_URL); - tmp = filter_list(tmp, source, (Comp_Func)util_strcasestr, suffix); - /* prepend the bookmark items */ - tmp = g_list_concat(bookmark_get_by_tags(suffix), tmp); - comps.completions = init_completion(comps.completions, tmp, prefix); - - history_list_free(&source); + /* if search string begins with TAG_INDICATOR lookup the bookmarks */ + if (suffix && *suffix == TAG_INDICATOR) { + source = bookmark_get_by_tags(suffix + 1); + comps.completions = init_completion(comps.completions, source, prefix); + } else { + source = history_get_by_tags(HISTORY_URL, suffix); + comps.completions = init_completion(comps.completions, source, prefix); + } + g_list_free_full(source, (GDestroyNotify)g_free); } else if (type == VB_INPUT_COMMAND) { char *command = NULL; /* remove counts before command and save it to print it later in inputbox */ comps.count = g_ascii_strtoll(suffix, &command, 10); - source = g_list_sort(command_get_all(), (GCompareFunc)g_strcmp0); - comps.completions = init_completion( - comps.completions, - filter_list(tmp, source, (Comp_Func)g_str_has_prefix, command), - prefix - ); + source = g_list_sort(command_get_by_prefix(suffix), (GCompareFunc)g_strcmp0); + comps.completions = init_completion(comps.completions, source, prefix); g_list_free(source); } else if (type == VB_INPUT_SEARCH_FORWARD || type == VB_INPUT_SEARCH_BACKWARD) { - source = g_list_sort(history_get_all(HISTORY_SEARCH), (GCompareFunc)g_strcmp0); - comps.completions = init_completion( - comps.completions, - filter_list(tmp, source, (Comp_Func)g_str_has_prefix, suffix), - prefix - ); - g_list_free(source); + source = g_list_sort(history_get_by_tags(HISTORY_SEARCH, suffix), (GCompareFunc)g_strcmp0); + comps.completions = init_completion(comps.completions, source, prefix); + g_list_free_full(source, (GDestroyNotify)g_free); } if (!comps.completions) { @@ -156,20 +146,6 @@ void completion_clean() vb.state.mode &= ~VB_MODE_COMPLETE; } -static GList *filter_list(GList *target, GList *source, Comp_Func func, const char *input) -{ - for (GList *l = source; l; l = l->next) { - char *data = l->data; - if (func(data, input)) { - target = g_list_prepend(target, data); - } - } - - target = g_list_reverse(target); - - return target; -} - static GList *init_completion(GList *target, GList *source, const char *prefix) { OVERWRITE_STRING(comps.prefix, prefix); diff --git a/src/history.c b/src/history.c index ecbc42f..0eb341d 100644 --- a/src/history.c +++ b/src/history.c @@ -19,6 +19,7 @@ #include "main.h" #include "history.h" +#include "util.h" extern VbCore vb; @@ -73,11 +74,36 @@ void history_add(HistoryType type, const char *value) } /** - * Retrieves all history entries for given history type. + * Retrieves the list of matching history items to given tag string. + * Returned list must be freed. */ -GList *history_get_all(HistoryType type) +GList *history_get_by_tags(HistoryType type, const char *tags) { - return load(get_file_by_type(type)); + GList *res = NULL, *src = NULL; + char **parts; + unsigned int len; + + src = load(get_file_by_type(type)); + if (!tags || *tags == '\0') { + /* without any tags return all items */ + for (GList *l = src; l; l = l->next) { + res = g_list_prepend(res, g_strdup((char*)l->data)); + } + } else { + parts = g_strsplit(tags, " ", 0); + len = g_strv_length(parts); + + for (GList *l = src; l; l = l->next) { + char *value = (char*)l->data; + if (util_string_contains_all_tags(value, parts, len)) { + res = g_list_prepend(res, g_strdup(value)); + } + } + g_strfreev(parts); + } + g_list_free_full(src, (GDestroyNotify)g_free); + + return res; } /** @@ -117,14 +143,6 @@ void history_rewind(void) } } -void history_list_free(GList **list) -{ - if (*list) { - g_list_free_full(*list, (GDestroyNotify)g_free); - *list = NULL; - } -} - /** * Retrieves the list of matching history items. * The list must be freed. @@ -246,5 +264,5 @@ static void write_to_file(GList *list, const char *file) fclose(f); } - history_list_free(&list); + g_list_free_full(list, (GDestroyNotify)g_free); } diff --git a/src/history.h b/src/history.h index e2e711a..739cb0c 100644 --- a/src/history.h +++ b/src/history.h @@ -31,8 +31,8 @@ typedef enum { void history_cleanup(void); void history_add(HistoryType type, const char *value); GList *history_get_all(HistoryType type); +GList *history_get_by_tags(HistoryType type, const char *tags); char *history_get(const char *input, gboolean prev); void history_rewind(void); -void history_list_free(GList **list); #endif /* end of include guard: _HISTORY_H */ diff --git a/src/setting.c b/src/setting.c index 86a42c1..1719b17 100644 --- a/src/setting.c +++ b/src/setting.c @@ -120,9 +120,29 @@ void setting_init(void) } } -GList* setting_get_all(void) +/** + * Retrieves the settings names as list for given prefix. + */ +GList* setting_get_by_prefix(const char *prefix) { - return g_hash_table_get_keys(settings); + GList *res = NULL; + GList *src = g_hash_table_get_keys(settings); + + if (!prefix || prefix == '\0') { + for (GList *l = src; l; l = l->next) { + res = g_list_prepend(res, l->data); + } + } else { + for (GList *l = src; l; l = l->next) { + char *value = (char*)l->data; + if (g_str_has_prefix(value, prefix)) { + res = g_list_prepend(res, value); + } + } + } + g_list_free(src); + + return res; } void setting_cleanup(void) diff --git a/src/setting.h b/src/setting.h index e670d2a..8aa4a36 100644 --- a/src/setting.h +++ b/src/setting.h @@ -40,7 +40,7 @@ struct _Setting { }; void setting_init(void); -GList* setting_get_all(void); +GList* setting_get_by_prefix(const char *prefix); void setting_cleanup(void); gboolean setting_run(char* name, const char* param); diff --git a/src/util.c b/src/util.c index 7ff7b76..6c30c5c 100644 --- a/src/util.c +++ b/src/util.c @@ -120,6 +120,56 @@ next: return NULL; } + +/** + * Checks if the given source array of pointer are prefixes to all those + * entries given as array of search strings. + */ +gboolean util_array_contains_all_tags(char **src, unsigned int s, char **query, unsigned int q) +{ + unsigned int i, n; + + if (!s || !q) { + return true; + } + + /* iterate over all query parts */ + for (i = 0; i < q; i++) { + gboolean found = false; + for (n = 0; n < s; n++) { + if (g_str_has_prefix(src[n], query[i])) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + + return true; +} + +/** + * Checks if the given array of tags are all found in source string. + */ +gboolean util_string_contains_all_tags(char *src, char **query, unsigned int q) +{ + unsigned int i; + if (!q) { + return true; + } + + /* iterate over all query parts */ + for (i = 0; i < q; i++) { + if (!util_strcasestr(src, query[i])) { + return false; + } + } + + return true; +} + /** * Replaces appearances of search in string by given replace. * Returne a new allocated string of search was found. diff --git a/src/util.h b/src/util.h index 804832e..aca552c 100644 --- a/src/util.h +++ b/src/util.h @@ -22,6 +22,8 @@ #include "main.h" +typedef gboolean (*Util_Comp_Func)(const char*, const char*); + char* util_get_config_dir(void); char* util_get_cache_dir(void); const char* util_get_home_dir(void); @@ -30,6 +32,8 @@ void util_create_file_if_not_exists(const char* filename); char* util_get_file_contents(const char* filename, gsize* length); char** util_get_lines(const char* filename); char* util_strcasestr(const char* haystack, const char* needle); +gboolean util_array_contains_all_tags(char **src, unsigned int s, char **query, unsigned int q); +gboolean util_string_contains_all_tags(char *src, char **query, unsigned int q); char *util_str_replace(const char* search, const char* replace, const char* string); gboolean util_create_tmp_file(const char *content, char **file); -- 2.20.1