From: Daniel Carl Date: Sat, 6 Apr 2013 17:38:29 +0000 (+0200) Subject: Show bookmarked uri also in completion list (#4). X-Git-Url: https://git.owens.tech///git?a=commitdiff_plain;h=38bbeda20321dfd684207ced54034302ca5068a3;p=vimb.git Show bookmarked uri also in completion list (#4). --- diff --git a/doc/vimb.1.txt b/doc/vimb.1.txt index 1f6af08..5583aa3 100644 --- a/doc/vimb.1.txt +++ b/doc/vimb.1.txt @@ -217,7 +217,23 @@ Remove a Search Mode keybinding. .TP .B complete Start a completion according to the current first chars in the inputbox. If -complation is already started, switch to the next completion item. +completion is already started, switch to the next completion item. + +Following completions are available: +.RS +.nr step 1 1 +.IP \n[step] 3 +Commands `:' +.IP \n+[step] +Settings `:set ' +.IP \n+[step] +Url-History and Bookmarks `:open \fIQUERY\fP' or `:tabopen \fIQUERY\fP'. +If \fIQUERY\fP is given, this will be used to fetch matching urls from history +file, or to find bookmarks from bookmark file. The urls from history will only +be matched by their url, the bookmarks only by their tags. If multiple tags +are given to get the bookmarks, only those bookmarks will be returned, that +matches all the given tags or that don't have any tag set. +.RE .TP .B complete-back If complation is already started, switch to the previous completion item. diff --git a/src/bookmark.c b/src/bookmark.c index 793ce57..59b86f5 100644 --- a/src/bookmark.c +++ b/src/bookmark.c @@ -22,6 +22,16 @@ extern VbCore vb; +typedef struct { + char *uri; + char **argv; + int argc; +} Bookmark; + +static GList *load(const char *file); +static gboolean contains_all_args(char **argv_src, unsigned int s, char **argv_query, unsigned int q); +static void free_bookmark(Bookmark *bm); + /** * Write a new bookmark entry to the end of bookmark file. */ @@ -55,3 +65,115 @@ void bookmark_add(const char *uri, const char *tags) g_string_free(string, true); } } + +/** + * Retrieves all bookmark uri matching the given space separated tags string. + * Don't forget to free the returned list. + */ +GList *bookmark_get_by_tags(const char *tags) +{ + GList *res = NULL; + GList *src = load(vb.files[FILES_BOOKMARK]); + char **parts; + unsigned int len; + + parts = g_strsplit(tags, " ", 0); + len = g_strv_length(parts); + + for (GList *l = src; l; l = l->next) { + Bookmark *bm = (Bookmark*)l->data; + if (contains_all_args(bm->argv, bm->argc, parts, len)) { + res = g_list_prepend(res, g_strdup(bm->uri)); + } + } + + g_list_free_full(src, (GDestroyNotify)free_bookmark); + g_strfreev(parts); + + return res; +} + +static GList *load(const char *file) +{ + /* read the items from file */ + GList *list = NULL; + char buf[512] = {0}, **argv = NULL; + int argc = 0; + FILE *f; + + if (!(f = fopen(file, "r"))) { + return list; + } + + file_lock_set(fileno(f), F_RDLCK); + while (fgets(buf, sizeof(buf), f)) { + char *p; + Bookmark *bm; + + g_strstrip(buf); + /* skip empty lines */ + if (!*buf) { + continue; + } + + /* create bookmark */ + bm = g_new(Bookmark, 1); + if ((p = strchr(buf, ' '))) { + *p = '\0'; + /* parse tags */ + if (g_shell_parse_argv(p + 1, &argc, &argv, NULL)) { + bm->uri = g_strdup(buf); + bm->argv = argv; + bm->argc = argc; + } else { + continue; + } + } else { + bm->uri = g_strdup(buf); + bm->argv = NULL; + bm->argc = 0; + } + + list = g_list_prepend(list, bm); + } + file_lock_set(fileno(f), F_UNLCK); + fclose(f); + + return list; +} + +/** + * Checks if the given source array of pointer contains all those entries + * given as array of search strings. + */ +static gboolean contains_all_args(char **argv_src, unsigned int s, char **argv_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(argv_query[i], argv_src[n])) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + + return true; +} + +static void free_bookmark(Bookmark *bm) +{ + g_free(bm->uri); + g_strfreev(bm->argv); + g_free(bm); +} diff --git a/src/bookmark.h b/src/bookmark.h index 6dac270..20f1538 100644 --- a/src/bookmark.h +++ b/src/bookmark.h @@ -21,5 +21,6 @@ #define _BOOKMARK_H void bookmark_add(const char *uri, const char *tags); +GList *bookmark_get_by_tags(const char *tags); #endif /* end of include guard: _BOOKMARK_H */ diff --git a/src/completion.c b/src/completion.c index d106c58..ad2b7e3 100644 --- a/src/completion.c +++ b/src/completion.c @@ -20,6 +20,7 @@ #include "completion.h" #include "util.h" #include "history.h" +#include "bookmark.h" extern VbCore vb; @@ -32,6 +33,8 @@ typedef struct { static GList *init_completion(GList *target, GList *source, Comp_Func func, const char *input, const char *prefix); +static GList *prepend_bookmark_completion(GList *target, GList *source, const char *prefix); +static void pack_boxes(GList *list); static GList *update(GList *completion, GList *active, gboolean back); static void show(gboolean back); static void set_entry_text(Completion *completion); @@ -71,6 +74,8 @@ gboolean completion_complete(gboolean back) gtk_box_pack_start(GTK_BOX(vb.gui.box), vb.gui.compbox, false, false, 0); /* TODO move these decision to a more generic place */ + /* TODO simplify this logic - seperate the list preparation, filtering and + * gtk box creation from another */ if (!strncmp(input, ":set ", 5)) { source = g_hash_table_get_keys(vb.settings); source = g_list_sort(source, (GCompareFunc)g_strcmp0); @@ -84,12 +89,26 @@ gboolean completion_complete(gboolean back) vb.comps.completions, source, (Comp_Func)util_strcasestr, &input[6], ":open " ); history_list_free(&source); + + /* prepend the bookmark items */ + source = bookmark_get_by_tags(&input[6]); + vb.comps.completions = prepend_bookmark_completion( + vb.comps.completions, source, ":open " + ); + history_list_free(&source); } else if (!strncmp(input, ":tabopen ", 9)) { source = history_get_all(HISTORY_URL); vb.comps.completions = init_completion( vb.comps.completions, source, (Comp_Func)util_strcasestr, &input[9], ":tabopen " ); history_list_free(&source); + + /* prepend the bookmark items */ + source = bookmark_get_by_tags(&input[9]); + vb.comps.completions = prepend_bookmark_completion( + vb.comps.completions, source, ":tabopen " + ); + history_list_free(&source); } else { source = g_hash_table_get_keys(vb.behave.commands); source = g_list_sort(source, (GCompareFunc)g_strcmp0); @@ -102,6 +121,7 @@ gboolean completion_complete(gboolean back) if (!vb.comps.completions) { return false; } + pack_boxes(vb.comps.completions); show(back); return TRUE; @@ -152,10 +172,8 @@ static GList *init_completion(GList *target, GList *source, } } if (match) { - Completion *completion = get_new(data, prefix); - gtk_box_pack_start(GTK_BOX(vb.gui.compbox), completion->event, TRUE, TRUE, 0); /* use prepend because that faster */ - target = g_list_prepend(target, completion); + target = g_list_prepend(target, get_new(data, prefix)); } } @@ -165,6 +183,23 @@ static GList *init_completion(GList *target, GList *source, return target; } +static GList *prepend_bookmark_completion(GList *target, GList *source, const char *prefix) +{ + for (GList *l = source; l; l = l->next) { + target = g_list_prepend(target, get_new(l->data, prefix)); + } + + return target; +} + +static void pack_boxes(GList *list) +{ + for (GList *l = list; l; l = l->next) { + Completion *c = (Completion*)l->data; + gtk_box_pack_start(GTK_BOX(vb.gui.compbox), c->event, TRUE, TRUE, 0); + } +} + static GList *update(GList *completion, GList *active, gboolean back) { GList *old, *new;