Merged url_history and history together.
authorDaniel Carl <danielcarl@gmx.de>
Sun, 24 Mar 2013 14:38:00 +0000 (15:38 +0100)
committerDaniel Carl <danielcarl@gmx.de>
Sun, 24 Mar 2013 14:38:00 +0000 (15:38 +0100)
The history mechanism can now handle different types of history and persist
the items into different files.

doc/vimb.1.txt
src/command.c
src/completion.c
src/config.h
src/history.c
src/history.h
src/main.c
src/main.h
src/setting.c
src/url_history.c [deleted file]
src/url_history.h [deleted file]

index 3f4fac8..39f51bf 100644 (file)
@@ -320,6 +320,11 @@ Holds the URI of the last closed browser window.
 .RS
 This file holds the history of unique opened URIs.
 .RE
+.I $XDG_CONFIG_HOME/PROJECT/command
+.RS
+This file holds the history of commands and search queries performed via input
+box.
+.RE
 .I $XDG_CONFIG_HOME/PROJECT/scripts.js
 .RS
 This file can be used to run user scripts, that are injected into every paged
index a77d2bb..f1368fc 100644 (file)
@@ -527,7 +527,7 @@ gboolean command_history(const Arg* arg)
 {
     const int count = vb.state.count ? vb.state.count : 1;
     const gint step = count * (arg->i == VB_SEARCH_BACKWARD ? -1 : 1);
-    const char* entry = history_get(step);
+    const char* entry = history_get(HISTORY_COMMAND, step);
 
     if (!entry) {
         return FALSE;
index 6d5797e..7835f45 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "completion.h"
 #include "util.h"
-#include "url_history.h"
+#include "history.h"
 
 extern VbCore vb;
 
@@ -77,24 +77,26 @@ gboolean completion_complete(gboolean back)
         vb.comps.completions = completion_init_completion(
             vb.comps.completions, source, (Comp_Func)g_str_has_prefix, &input[5], ":set "
         );
+        g_list_free(source);
     } else if (!strncmp(input, ":open ", 6)) {
-        url_history_get_all(&source);
+        source = history_get_all(HISTORY_URL);
         vb.comps.completions = completion_init_completion(
             vb.comps.completions, source, (Comp_Func)util_strcasestr, &input[6], ":open "
         );
-        g_list_free(source);
+        history_list_free(&source);
     } else if (!strncmp(input, ":tabopen ", 9)) {
-        url_history_get_all(&source);
+        source = history_get_all(HISTORY_URL);
         vb.comps.completions = completion_init_completion(
             vb.comps.completions, source, (Comp_Func)util_strcasestr, &input[9], ":tabopen "
         );
-        g_list_free(source);
+        history_list_free(&source);
     } else {
         source = g_hash_table_get_keys(vb.behave.commands);
         source = g_list_sort(source, (GCompareFunc)g_strcmp0);
         vb.comps.completions = completion_init_completion(
             vb.comps.completions, source, (Comp_Func)g_str_has_prefix, &input[1], ":"
         );
+        g_list_free(source);
     }
 
     if (!vb.comps.completions) {
index 8cc974f..1467e0b 100644 (file)
@@ -30,8 +30,6 @@
 
 const unsigned int MAXIMUM_HINTS = 500;
 
-const unsigned int COMMAND_HISTORY_SIZE = 30;
-
 const struct {
     char* command;
 } default_config[] = {
@@ -144,7 +142,7 @@ const struct {
     {"set ca-bundle=/etc/ssl/certs/ca-certificates.crt"},
     {"set home-page=https://github.com/fanglingsu/vimb"},
     {"set download-path=/tmp/vimb"},
-    {"set history-max-items=500"},
+    {"set history-max-items=2000"},
     {NULL}
 };
 
index e97f30b..4b31317 100644 (file)
 #include "history.h"
 
 extern VbCore vb;
-extern const unsigned int COMMAND_HISTORY_SIZE;
 
+/* map history types to files */
+static const VbFile file_map[HISTORY_LAST] = {
+    FILES_COMMAND,
+    FILES_HISTORY
+};
+
+static const char* history_get_file_by_type(HistoryType type);
+static GList* history_load(const char* file);
+static void history_write_to_file(GList* list, const char* file);
+
+
+/**
+ * Makes all history items unique and force them to fit the maximum history
+ * size and writes all entries of the different history types to file.
+ */
 void history_cleanup(void)
 {
-    g_list_free_full(vb.behave.history, (GDestroyNotify)g_free);
+    for (HistoryType i = HISTORY_FIRST; i < HISTORY_LAST; i++) {
+        const char* file = history_get_file_by_type(i);
+        history_write_to_file(history_load(file), file);
+    }
 }
 
-void history_append(const char* line)
+/**
+ * Write a new history entry to the end of history file.
+ */
+void history_add(HistoryType type, const char* value)
 {
-    if (COMMAND_HISTORY_SIZE <= g_list_length(vb.behave.history)) {
-        /* if list is too long - remove items from beginning */
-        GList* first = g_list_first(vb.behave.history);
-        g_free((char*)first->data);
-        vb.behave.history = g_list_delete_link(vb.behave.history, first);
+    const char* file = history_get_file_by_type(type);
+    FILE* f;
+    if ((f = fopen(file, "a+"))) {
+        file_lock_set(fileno(f), F_WRLCK);
+
+        fprintf(f, "%s\n", value);
+
+        file_lock_set(fileno(f), F_UNLCK);
+        fclose(f);
     }
-    vb.behave.history = g_list_append(vb.behave.history, g_strdup(line));
 }
 
-const char* history_get(const int step)
+/**
+ * Retrieves all history entries for given history type.
+ */
+GList* history_get_all(HistoryType type)
+{
+    return history_load(history_get_file_by_type(type));
+}
+
+const char* history_get(HistoryType type, int step)
 {
     const char* command;
 
@@ -47,11 +78,13 @@ const char* history_get(const int step)
     if (!vb.state.history_active) {
         OVERWRITE_STRING(vb.state.history_prefix, GET_TEXT());
 
+        GList* src = history_load(history_get_file_by_type(type));
+
         /* generate new history list with the matching items */
-        for (GList* l = vb.behave.history; l; l = l->next) {
-            char* entry = g_strdup((char*)l->data);
-            if (g_str_has_prefix(entry, vb.state.history_prefix)) {
-                vb.state.history_active = g_list_prepend(vb.state.history_active, entry);
+        for (GList* l = src; l; l = l->next) {
+            char* value = (char*)l->data;
+            if (g_str_has_prefix(value, vb.state.history_prefix)) {
+                vb.state.history_active = g_list_prepend(vb.state.history_active, g_strdup(value));
             }
         }
 
@@ -71,7 +104,7 @@ const char* history_get(const int step)
     return command;
 }
 
-void history_rewind()
+void history_rewind(void)
 {
     if (vb.state.history_active) {
         OVERWRITE_STRING(vb.state.history_prefix, NULL);
@@ -81,3 +114,88 @@ void history_rewind()
         vb.state.history_active = NULL;
     }
 }
+
+void history_list_free(GList** list)
+{
+    if (*list) {
+        g_list_free_full(*list, (GDestroyNotify)g_free);
+        *list = NULL;
+    }
+}
+
+static const char* history_get_file_by_type(HistoryType type)
+{
+    return vb.files[file_map[type]];
+}
+
+/**
+ * Loads history items form file but elemiate duplicates.
+ */
+static GList* history_load(const char* file)
+{
+    /* read the history items from file */
+    GList* list   = NULL;
+    char buf[512] = {0};
+    FILE* f;
+
+    if (!(f = fopen(file, "r"))) {
+        return list;
+    }
+
+    file_lock_set(fileno(f), F_WRLCK);
+    while (fgets(buf, sizeof(buf), f)) {
+        g_strstrip(buf);
+
+        /* skip empty lines */
+        if (!*buf) {
+            continue;
+        }
+        /* if the value is already in history, remove this entry */
+        for (GList* l = list; l; l = l->next) {
+            if (*buf && !g_strcmp0(buf, (char*)l->data)) {
+                g_free(l->data);
+                list = g_list_delete_link(list, l);
+                break;
+            }
+        }
+
+        list = g_list_prepend(list, g_strdup(buf));
+    }
+    file_lock_set(fileno(f), F_UNLCK);
+    fclose(f);
+
+    /* if list is too long - remove items from end (oldest entries) */
+    if (vb.config.history_max < g_list_length(list)) {
+        /* reverse to not use the slow g_list_last */
+        list = g_list_reverse(list);
+        while (vb.config.history_max < g_list_length(list)) {
+            GList* last = g_list_first(list);
+            g_free(last->data);
+            list = g_list_delete_link(list, last);
+        }
+        list = g_list_reverse(list);
+    }
+
+    return list;
+}
+
+/**
+ * Loads the entries from file, make them unique and write them back to file.
+ */
+static void history_write_to_file(GList* list, const char* file)
+{
+    FILE* f;
+    if ((f = fopen(file, "w"))) {
+        file_lock_set(fileno(f), F_WRLCK);
+
+        /* overwrite the history file with new unique history items */
+        for (GList* link = g_list_reverse(list); link; link = link->next) {
+            fprintf(f, "%s\n", (char*)link->data);
+        }
+
+        file_lock_set(fileno(f), F_UNLCK);
+        fclose(f);
+    }
+
+    history_list_free(&list);
+}
index b968ed2..6e618d4 100644 (file)
 #ifndef _HISTORY_H
 #define _HISTORY_H
 
+typedef enum {
+    HISTORY_FIRST   = 0,
+    HISTORY_COMMAND = 0,
+    HISTORY_URL,
+    HISTORY_LAST
+} HistoryType;
+
 void history_cleanup(void);
-void history_append(const char* line);
-const char* history_get(const int step);
-void history_rewind();
+void history_add(HistoryType type, const char* value);
+GList* history_get_all(HistoryType type);
+const char* history_get(HistoryType type, int step);
+void history_rewind(void);
+void history_list_free(GList** list);
 
 #endif /* end of include guard: _HISTORY_H */
index 938d9c8..7466e5f 100644 (file)
@@ -29,7 +29,6 @@
 #include "hints.h"
 #include "searchengine.h"
 #include "history.h"
-#include "url_history.h"
 
 /* variables */
 static char **args;
@@ -415,7 +414,7 @@ static void vb_webview_load_status_cb(WebKitWebView* view, GParamSpec* pspec)
 
             dom_check_auto_insert();
 
-            url_history_add(uri, webkit_web_view_get_title(vb.gui.webview));
+            history_add(HISTORY_URL, uri);
             break;
 
         case WEBKIT_LOAD_FAILED:
@@ -472,7 +471,7 @@ static void vb_inputbox_activate_cb(GtkEntry *entry)
 
     if (hist_save) {
         /* save the command in history */
-        history_append(command);
+        history_add(HISTORY_COMMAND, command);
     }
     g_free(command);
 }
@@ -837,6 +836,9 @@ static void vb_init_files(void)
     vb.files[FILES_HISTORY] = g_build_filename(path, "history", NULL);
     util_create_file_if_not_exists(vb.files[FILES_HISTORY]);
 
+    vb.files[FILES_COMMAND] = g_build_filename(path, "command", NULL);
+    util_create_file_if_not_exists(vb.files[FILES_COMMAND]);
+
     vb.files[FILES_SCRIPT] = g_build_filename(path, "scripts.js", NULL);
 
     vb.files[FILES_USER_STYLE] = g_build_filename(path, "style.css", NULL);
@@ -1007,7 +1009,7 @@ static void vb_destroy_client()
     setting_cleanup();
     keybind_cleanup();
     searchengine_cleanup();
-    url_history_cleanup();
+    history_cleanup();
 
     for (int i = 0; i < FILES_LAST; i++) {
         g_free(vb.files[i]);
index efb5a78..0fb0211 100644 (file)
@@ -182,9 +182,10 @@ typedef enum {
     FILES_CLOSED,
     FILES_SCRIPT,
     FILES_HISTORY,
+    FILES_COMMAND,
     FILES_USER_STYLE,
     FILES_LAST
-} VpFile;
+} VbFile;
 
 typedef enum {
     TYPE_CHAR,
@@ -256,7 +257,6 @@ typedef struct {
     GSList*     keys;
     GString*    modkeys;
     GSList*     searchengines;
-    GList*      history;
 } Behaviour;
 
 typedef struct {
@@ -265,7 +265,7 @@ typedef struct {
     guint  max_completion_items;
     char*  home_page;
     char*  download_dir;
-    guint  url_history_max;
+    guint  history_max;
 } Config;
 
 typedef struct {
index c1dbfc6..8570c00 100644 (file)
@@ -677,11 +677,11 @@ static gboolean setting_user_style(const Setting* s, const SettingType type)
 static gboolean setting_history_max_items(const Setting* s, const SettingType type)
 {
     if (type == SETTING_GET) {
-        setting_print_value(s, &vb.config.url_history_max);
+        setting_print_value(s, &vb.config.history_max);
 
         return TRUE;
     }
-    vb.config.url_history_max = s->arg.i;
+    vb.config.history_max = s->arg.i;
 
     return TRUE;
 }
diff --git a/src/url_history.c b/src/url_history.c
deleted file mode 100644 (file)
index b5ef10f..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2013 Daniel Carl
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see http://www.gnu.org/licenses/.
- */
-
-#include "main.h"
-#include "url_history.h"
-
-extern VbCore vb;
-static void url_history_add_unique(GList** list, const char* url, const char* title);
-static GList* url_history_load(void);
-static void url_history_write_to_file(GList* list);
-static void url_history_clear(GList** list);
-static void url_history_free(UrlHist* item);
-
-
-void url_history_cleanup(void)
-{
-    url_history_write_to_file(url_history_load());
-}
-
-/**
- * Write a new history entry to the end of history file.
- */
-void url_history_add(const char* uri, const char* title)
-{
-    FILE* file = fopen(vb.files[FILES_HISTORY], "a+");
-    if (file) {
-        file_lock_set(fileno(file), F_WRLCK);
-
-        char* name = g_shell_quote(title ? title : "");
-        char* new  = g_strdup_printf("%s %s\n", uri, name);
-
-        fwrite(new, strlen(new), 1, file);
-
-        g_free(name);
-        g_free(new);
-
-        file_lock_set(fileno(file), F_UNLCK);
-        fclose(file);
-    }
-}
-
-/**
- * Appends all url history entries form history file to given list.
- */
-void url_history_get_all(GList** list)
-{
-    GList* src = url_history_load();
-
-    for (GList* link = src; link; link = link->next) {
-        UrlHist* hi = (UrlHist*)link->data;
-        /* put only the url in the list - do not allocate new memory */
-        *list = g_list_prepend(*list, hi->uri);
-    }
-
-    *list = g_list_reverse(*list);
-}
-
-/**
- * Loads history items form file but elemiate duplicates.
- */
-static GList* url_history_load(void)
-{
-    /* read the history items from file */
-    GList* list   = NULL;
-    char buf[512] = {0};
-    FILE* file;
-    
-    if (!(file = fopen(vb.files[FILES_HISTORY], "r"))) {
-        return list;
-    }
-
-    file_lock_set(fileno(file), F_WRLCK);
-    while (fgets(buf, sizeof(buf), file)) {
-        char** argv = NULL;
-        int    argc = 0;
-        if (g_shell_parse_argv(buf, &argc, &argv, NULL)) {
-            url_history_add_unique(&list, argv[0], argc > 1 ? argv[1] : NULL);
-        }
-        g_strfreev(argv);
-    }
-    file_lock_set(fileno(file), F_UNLCK);
-    fclose(file);
-
-    /* if list is too long - remove items from end (oldest entries) */
-    while (vb.config.url_history_max < g_list_length(list)) {
-        GList* last = g_list_last(list);
-        url_history_free((UrlHist*)last->data);
-        list = g_list_delete_link(list, last);
-    }
-
-    return list;
-}
-
-static void url_history_add_unique(GList** list, const char* url, const char* title)
-{
-    /* if the url is already in history, remove this entry */
-    for (GList* link = *list; link; link = link->next) {
-        UrlHist* hi = (UrlHist*)link->data;
-        if (!g_strcmp0(url, hi->uri)) {
-            url_history_free(hi);
-            *list     = g_list_delete_link(*list, link);
-            break;
-        }
-    }
-
-    UrlHist* item = g_new0(UrlHist, 1);
-    item->uri     = g_strdup(url);
-    item->title   = title ? g_strdup(title) : NULL;
-
-    *list = g_list_prepend(*list, item);
-}
-
-/**
- * Loads the entries from file, make them unique and write them back to file.
- */
-static void url_history_write_to_file(GList* list)
-{
-    FILE* file = fopen(vb.files[FILES_HISTORY], "w");
-    if (file) {
-        file_lock_set(fileno(file), F_WRLCK);
-
-        /* overwrite the history file with new unique history items */
-        for (GList* link = g_list_reverse(list); link; link = link->next) {
-            UrlHist* item = (UrlHist*)link->data;
-
-            char* title = g_shell_quote(item->title ? item->title : "");
-            char* new   = g_strdup_printf("%s %s\n", item->uri, title);
-
-            fwrite(new, strlen(new), 1, file);
-
-            g_free(title);
-            g_free(new);
-        }
-
-        file_lock_set(fileno(file), F_UNLCK);
-        fclose(file);
-    }
-    url_history_clear(&list);
-}
-
-static void url_history_clear(GList** list)
-{
-    if (*list) {
-        g_list_free_full(*list, (GDestroyNotify)url_history_free);
-        *list = NULL;
-    }
-}
-
-static void url_history_free(UrlHist* item)
-{
-    g_free(item->uri);
-    if (item->title) {
-        g_free(item->title);
-    }
-    g_free(item);
-}
diff --git a/src/url_history.h b/src/url_history.h
deleted file mode 100644 (file)
index ee4a159..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * vimb - a webkit based vim like browser.
- *
- * Copyright (C) 2012-2013 Daniel Carl
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see http://www.gnu.org/licenses/.
- */
-
-#ifndef _URL_HISTORY_H
-#define _URL_HISTORY_H
-
-typedef struct {
-    char* uri;
-    char* title;
-} UrlHist;
-
-void url_history_cleanup(void);
-void url_history_add(const char* uri, const char* title);
-void url_history_get_all(GList** list);
-
-#endif /* end of include guard: _URL_HISTORY_H */