diff --git a/.gitignore b/.gitignore index bef84b4..fb7d745 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ *.rej *.rej.orig *~ +*.swp +.exrc javascript.h xombrero xombrero.cat1 diff --git a/about.c b/about.c index e6d688e..1b882b1 100644 --- a/about.c +++ b/about.c @@ -562,27 +562,15 @@ xtp_handle_dl(struct tab *t, uint8_t cmd, int id, const char *query) void xtp_handle_hl(struct tab *t, uint8_t cmd, int id, const char *query) { - struct history *h, *next, *ht; - int i = 1; + struct pagelist_entry *h, *ht; switch (cmd) { case XT_XTP_HL_REMOVE: - /* walk backwards, as listed in reverse */ - for (h = RB_MAX(history_list, &hl); h != NULL; h = next) { - next = RB_PREV(history_list, &hl, h); - if (id == i) { - RB_REMOVE(history_list, &hl, h); - g_free((gpointer) h->title); - g_free((gpointer) h->uri); - g_free(h); - break; - } - i++; - } + remove_pagelist_entry_by_count(&hl, 1); break; case XT_XTP_HL_REMOVE_ALL: - RB_FOREACH_SAFE(h, history_list, &hl, ht) - RB_REMOVE(history_list, &hl, h); + RB_FOREACH_SAFE(h, pagelist, &hl, ht) + remove_pagelist_entry(&hl, h); break; case XT_XTP_HL_LIST: /* Nothing - just xtp_page_hl() below */ @@ -595,95 +583,32 @@ xtp_handle_hl(struct tab *t, uint8_t cmd, int id, const char *query) xtp_page_hl(t, NULL); } -/* remove a favorite */ void remove_favorite(struct tab *t, int index) { - char file[PATH_MAX], *title, *uri = NULL; - char *new_favs, *tmp; - FILE *f; - int i; - size_t len, lineno; - - /* open favorites */ - snprintf(file, sizeof file, "%s" PS "%s", work_dir, XT_FAVS_FILE); - - if ((f = fopen(file, "r")) == NULL) { - show_oops(t, "%s: can't open favorites: %s", - __func__, strerror(errno)); + /* Load before manipulation in case other processes have changed + the file beneath us */ + if (restore_favorites()) { + show_oops(t, "Error reading favorites file: %s", + strerror(errno)); return; } + + remove_pagelist_entry_by_count(&favs, index); - /* build a string which will become the new favorites file */ - new_favs = g_strdup(""); - - for (i = 1;;) { - if ((title = fparseln(f, &len, &lineno, NULL, 0)) == NULL) - if (feof(f) || ferror(f)) - break; - /* XXX THIS IS NOT THE RIGHT HEURISTIC */ - if (len == 0) { - free(title); - title = NULL; - continue; - } - - if ((uri = fparseln(f, &len, &lineno, NULL, 0)) == NULL) { - if (feof(f) || ferror(f)) { - show_oops(t, "%s: can't parse favorites %s", - __func__, strerror(errno)); - goto clean; - } - } - - /* as long as this isn't the one we are deleting add to file */ - if (i != index) { - tmp = new_favs; - new_favs = g_strdup_printf("%s%s\n%s\n", - new_favs, title, uri); - g_free(tmp); - } - - free(uri); - uri = NULL; - free(title); - title = NULL; - i++; - } - fclose(f); - - /* write back new favorites file */ - if ((f = fopen(file, "w")) == NULL) { - show_oops(t, "%s: can't open favorites: %s", - __func__, strerror(errno)); - goto clean; + if (save_pagelist_to_disk(&favs, XT_FAVS_FILE)) { + update_favorite_tabs(NULL); } - - if (fwrite(new_favs, strlen(new_favs), 1, f) != 1) - show_oops(t, "%s: can't fwrite", __func__); - fclose(f); - -clean: - if (uri) - free(uri); - if (title) - free(title); - - g_free(new_favs); + /* TODO: We should remove the URI from the list of completions here, + too */ } int add_favorite(struct tab *t, struct karg *args) { - char file[PATH_MAX]; - FILE *f; - char *line = NULL; - size_t urilen, linelen; - gchar *argtitle = NULL; const gchar *uri, *title; - - if (t == NULL) - return (1); + gchar *argtitle = NULL; + int retval; /* don't allow adding of xtp pages to favorites */ if (t->xtp_meaning != XT_XTP_TAB_MEANING_NORMAL) { @@ -691,56 +616,112 @@ add_favorite(struct tab *t, struct karg *args) return (1); } - snprintf(file, sizeof file, "%s" PS "%s", work_dir, XT_FAVS_FILE); - if ((f = fopen(file, "r+")) == NULL) { - show_oops(t, "Can't open favorites file: %s", strerror(errno)); - return (1); + /* Load before manipulation in case other processes have changed + the file beneath us */ + if (restore_favorites()) { + show_oops(t, "Error reading favorites file: %s", + strerror(errno)); + return 1; } if (args->s && strlen(g_strstrip(args->s))) argtitle = html_escape(g_strstrip(args->s)); - + title = argtitle ? argtitle : get_title(t, FALSE); uri = get_uri(t); + insert_pagelist_entry(&favs, uri, title, 0); + completion_add_uri(uri); - if (title == NULL || uri == NULL) { - show_oops(t, "can't add page to favorites"); - goto done; + if ((retval = save_pagelist_to_disk(&favs, XT_FAVS_FILE))) { + + update_favorite_tabs(NULL); } + if (argtitle) + g_free(argtitle); + + return (retval); +} + +/* read a legacy favorites from an open FILE* + +(we don't write these any more) +*/ +static int +load_legacy_favorites(FILE *f) +{ + char *uri = NULL, *title = NULL; + size_t len, lineno; + int failed = 0; + const char delim[3] = {'\\', '\\', '\0'}; - urilen = strlen(uri); + for (lineno = 1;;) { + if ((title = fparseln(f, &len, &lineno, delim, 0)) == NULL) + break; + if (strlen(title) == 0) { + free(title); + title = NULL; + continue; + } - for (;;) { - if ((line = fparseln(f, &linelen, NULL, NULL, 0)) == NULL) { - if (feof(f)) + if ((uri = fparseln(f, &len, &lineno, delim, 0)) == NULL) { + if (feof(f) || ferror(f)) { + failed = 1; break; - else { - show_oops(t, "Error reading favorites file: %s", - strerror(errno)); - goto done; } } - if (linelen == urilen && !strcmp(line, uri)) - goto done; + insert_pagelist_entry(&favs, uri, title, 0); + free(title); + free(uri); + lineno += 1; + } + return failed; +} + +/* Pull the list of favorites into memory. + +This supports loading old-style favorite lists (title/url) in addition +to the new standard pagelist format. +*/ +int +restore_favorites(void) +{ + int retval; + char file[PATH_MAX], magic[4]; + FILE *f; + + empty_pagelist(&favs); - free(line); - line = NULL; + /* heuristic: new-style favourites should start with a http url + if our favorites file doesn't, assume it's old style */ + snprintf(file, sizeof file, "%s" PS "%s", work_dir, XT_FAVS_FILE); + if ((f = fopen(file, "r")) == NULL) { + warnx("%s: fopen", __func__); + return (1); } - fprintf(f, "\n%s\n%s", title, uri); -done: - if (argtitle) - g_free(argtitle); - if (line) - free(line); - fclose(f); + if (4==fread(magic, 1, 4, f) + && strncmp(magic, "http", 4)) { + /* doesn't start with http, try old-style favorite parsing */ - update_favorite_tabs(NULL); + warnx("Warning: Suspecting old-style favorites file."); + rewind(f); + retval = load_legacy_favorites(f); + fclose(f); - return (0); + } else { + /* TODO: when we can reasonably assume all favourites files + are updated, remove everything in here but this: */ + + /* file seems to start with URL, use new-style code */ + fclose(f); + retval = load_pagelist_from_disk(&favs, XT_FAVS_FILE); + } + + return retval; } + char * search_engine_add(char *body, const char *name, const char *url, const char *key, int select) @@ -1291,13 +1272,9 @@ xtp_page_ab(struct tab *t, struct karg *args) int xtp_page_fl(struct tab *t, struct karg *args) { - char file[PATH_MAX]; - FILE *f; - char *uri = NULL, *title = NULL; - size_t len, lineno = 0; - int i, failed = 0; + int row = 0, failed = 0; char *body, *tmp, *page = NULL; - const char delim[3] = {'\\', '\\', '\0'}; + struct pagelist_entry *item; DNPRINTF(XT_D_FAVORITE, "%s:", __func__); @@ -1308,13 +1285,6 @@ xtp_page_fl(struct tab *t, struct karg *args) generate_xtp_session_key(&t->session_key); - /* open favorites */ - snprintf(file, sizeof file, "%s" PS "%s", work_dir, XT_FAVS_FILE); - if ((f = fopen(file, "r")) == NULL) { - show_oops(t, "Can't open favorites file: %s", strerror(errno)); - return (1); - } - /* body */ if (args && args->i & XT_DELETE) body = g_strdup_printf("" @@ -1324,22 +1294,7 @@ xtp_page_fl(struct tab *t, struct karg *args) body = g_strdup_printf("
" "\n"); - for (i = 1;;) { - if ((title = fparseln(f, &len, &lineno, delim, 0)) == NULL) - break; - if (strlen(title) == 0) { - free(title); - title = NULL; - continue; - } - - if ((uri = fparseln(f, &len, &lineno, delim, 0)) == NULL) - if (feof(f) || ferror(f)) { - show_oops(t, "favorites file corrupt"); - failed = 1; - break; - } - + RB_FOREACH_REVERSE(item, pagelist, &favs) { tmp = body; if (args && args->i & XT_DELETE) body = g_strdup_printf("%s" @@ -1348,28 +1303,23 @@ xtp_page_fl(struct tab *t, struct karg *args) "" "\n", - body, i, uri, title, + body, row, item->uri, item->title, XT_XTP_STR, XT_XTP_FL, t->session_key ? t->session_key : "", - XT_XTP_FL_REMOVE, i); + XT_XTP_FL_REMOVE, row); else body = g_strdup_printf("%s" "" "" "\n", - body, i, uri, title); + body, row, item->uri, item->title); g_free(tmp); - free(uri); - uri = NULL; - free(title); - title = NULL; - i++; + row++; } - fclose(f); /* if none, say so */ - if (i == 1) { + if (row == 1) { tmp = body; body = g_strdup_printf("%s" "
#Link
" "X
%d%s
" @@ -1382,11 +1332,6 @@ xtp_page_fl(struct tab *t, struct karg *args) body = g_strdup_printf("%s
", body); g_free(tmp); - if (uri) - free(uri); - if (title) - free(title); - /* render */ if (!failed) { page = get_html_page("Favorites", body, "", 1); @@ -1652,7 +1597,7 @@ int xtp_page_hl(struct tab *t, struct karg *args) { char *body, *page, *tmp; - struct history *h; + struct pagelist_entry *h; int i = 1; /* all ids start 1 */ DNPRINTF(XT_D_CMD, "%s", __func__); @@ -1672,7 +1617,7 @@ xtp_page_hl(struct tab *t, struct karg *args) "Rm\n", XT_XTP_STR, XT_XTP_HL, t->session_key, XT_XTP_HL_REMOVE_ALL); - RB_FOREACH_REVERSE(h, history_list, &hl) { + RB_FOREACH_REVERSE(h, pagelist, &hl) { tmp = body; body = g_strdup_printf( "%s\n" diff --git a/history.c b/history.c index dc3e6f8..e3c98b0 100644 --- a/history.c +++ b/history.c @@ -19,6 +19,13 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/* This module contains generic code for lists of web pages, as well +as special handling for history and favorites. + +The page lists are actually managed as red-black trees, but that's +an implementation detail. */ + + #include #define XT_HISTORY_FILE ("history") @@ -28,10 +35,62 @@ * than MAX_HISTORY_AGE. */ #define XT_MAX_HISTORY_AGE (60.0 * 60.0 * 24 * 14) /* 14 days */ +/* remove what's pointed to by item from list. +*/ +void +remove_pagelist_entry(struct pagelist *list, struct pagelist_entry *item) +{ + RB_REMOVE(pagelist, list, item); + g_free((gpointer) item->title); + g_free((gpointer) item->uri); + g_free(item); +} + +/* remove the n-th item from a pagelist, counted from the end. + +Returns 0 on success, 1 if the list is too short. +*/ +int +remove_pagelist_entry_by_count(struct pagelist *list, + int count) +{ + int i = 0; + struct pagelist_entry *item, *next; + + /* walk backwards, as listed in reverse */ + for (item = RB_MAX(pagelist, list); item != NULL; item = next) { + next = RB_PREV(pagelist, list, item); + if (count == i) { + remove_pagelist_entry(list, item); + return 0; + } + i++; + } + return 1; +} + +/* remove the first item with uri from a pagelist. + +It is not an error for no such entry to exist. +*/ +void +remove_pagelist_entry_by_uri(struct pagelist *list, + const gchar *uri) +{ + struct pagelist_entry *item; + + RB_FOREACH(item, pagelist, list) { + if (item->uri==uri) { + remove_pagelist_entry(list, item); + break; + } + } +} + int purge_history(void) { - struct history *h, *next; + struct pagelist_entry *h, *next; double age = 0.0; DNPRINTF(XT_D_HISTORY, "%s: hl_purge_count = %d (%d is max)\n", @@ -40,9 +99,9 @@ purge_history(void) if (hl_purge_count == XT_MAX_HL_PURGE_COUNT) { hl_purge_count = 0; - for (h = RB_MIN(history_list, &hl); h != NULL; h = next) { + for (h = RB_MIN(pagelist, &hl); h != NULL; h = next) { - next = RB_NEXT(history_list, &hl, h); + next = RB_NEXT(pagelist, &hl, h); age = difftime(time(NULL), h->time); @@ -50,7 +109,7 @@ purge_history(void) DNPRINTF(XT_D_HISTORY, "%s: removing %s (age %.1f)\n", __func__, h->uri, age); - RB_REMOVE(history_list, &hl, h); + RB_REMOVE(pagelist, &hl, h); g_free(h->uri); g_free(h->title); g_free(h); @@ -65,32 +124,44 @@ purge_history(void) } int -insert_history_item(const gchar *uri, const gchar *title, time_t time) +insert_pagelist_entry(struct pagelist *list, + const gchar *uri, const gchar *title, time_t time) { - struct history *h; + struct pagelist_entry *h; if (!(uri && strlen(uri) && title && strlen(title))) return (1); - h = g_malloc(sizeof(struct history)); + h = g_malloc(sizeof(struct pagelist_entry)); h->uri = g_strdup(uri); h->title = g_strdup(title); h->time = time; DNPRINTF(XT_D_HISTORY, "%s: adding %s\n", __func__, h->uri); - RB_INSERT(history_list, &hl, h); - completion_add_uri(h->uri); - hl_purge_count++; + RB_INSERT(pagelist, list, h); + + return (0); +} - purge_history(); - update_history_tabs(NULL); +/* delete all items in a pagelist */ +void +empty_pagelist(struct pagelist *list) +{ + struct pagelist_entry *item; - return (0); + RB_FOREACH(item, pagelist, list) { + RB_REMOVE(pagelist, list, item); + g_free(item->uri); + g_free(item->title); + g_free(item); + } } +/* load a list of url/title pairs from disk into memory. +*/ int -restore_global_history(void) +load_pagelist_from_disk(struct pagelist *list, char *file_name) { char file[PATH_MAX]; FILE *f; @@ -99,7 +170,7 @@ restore_global_history(void) struct tm tm; const char delim[3] = {'\\', '\\', '\0'}; - snprintf(file, sizeof file, "%s" PS "%s", work_dir, XT_HISTORY_FILE); + snprintf(file, sizeof file, "%s" PS "%s", work_dir, file_name); if ((f = fopen(file, "r")) == NULL) { warnx("%s: fopen", __func__); @@ -123,14 +194,16 @@ restore_global_history(void) goto done; } - if (strptime(stime, "%a %b %d %H:%M:%S %Y", &tm) == NULL) { + /* TODO: This is locale-dependent and breaks in non-C */ + if (strptime(stime, "%a %b %d %H:%M:%S %Y", &tm) + == NULL) { err = "strptime failed to parse time"; goto done; } time = mktime(&tm); - if (insert_history_item(uri, title, time)) { + if (insert_pagelist_entry(list, uri, title, time)) { err = "failed to insert item"; goto done; } @@ -157,22 +230,22 @@ restore_global_history(void) } int -save_global_history_to_disk(struct tab *t) +save_pagelist_to_disk(struct pagelist *list, char *file_name) { char file[PATH_MAX]; FILE *f; - struct history *h; + struct pagelist_entry *h; - snprintf(file, sizeof file, "%s" PS "%s", work_dir, XT_HISTORY_FILE); + snprintf(file, sizeof file, "%s" PS "%s", work_dir, file_name); if ((f = fopen(file, "w")) == NULL) { - show_oops(t, "%s: global history file: %s", + warnx("%s: global history file: %s", __func__, strerror(errno)); return (1); } - RB_FOREACH_REVERSE(h, history_list, &hl) { - if (h->uri && h->title && h->time) + RB_FOREACH_REVERSE(h, pagelist, list) { + if (h->uri && h->title) fprintf(f, "%s\n%s\n%s", h->uri, h->title, ctime(&h->time)); } @@ -190,9 +263,9 @@ char * color_visited_helper(void) { char *d, *s = NULL, *t; - struct history *h; + struct pagelist_entry *h; - RB_FOREACH_REVERSE(h, history_list, &hl) { + RB_FOREACH_REVERSE(h, pagelist, &hl) { if (s == NULL) s = g_strdup_printf("'%s':'dummy'", h->uri); else { @@ -245,3 +318,37 @@ color_visited(struct tab *t, char *visited) return (0); } + +int +insert_history_item(const gchar *uri, const gchar *title, time_t time) +{ + int retval; + + retval = (insert_pagelist_entry(&hl, uri, title, time)); + + if (retval==0) { + completion_add_uri(uri); + hl_purge_count++; + } + + purge_history(); + update_history_tabs(NULL); + + return (retval); +} + +int +restore_global_history(void) +{ + return (load_pagelist_from_disk( + &hl, XT_HISTORY_FILE)); +} + +int +save_global_history_to_disk(struct tab *t) +{ + /* tab was passed for error messaging; we're now using warnx + in save_pagelist and hence don't need that any more. Do we? */ + return (save_pagelist_to_disk( + &hl, XT_HISTORY_FILE)); +} diff --git a/settings.c b/settings.c index 9267d69..93da775 100644 --- a/settings.c +++ b/settings.c @@ -75,6 +75,7 @@ int show_scrollbars = XT_DS_SHOW_SCROLLBARS; int show_statusbar = XT_DS_SHOW_STATUSBAR; /* vimperator style status bar */ int ctrl_click_focus = XT_DS_CTRL_CLICK_FOCUS; /* ctrl click gets focus */ int cookies_enabled = XT_DS_COOKIES_ENABLED; /* enable cookies */ +int complete_uri_anywhere = XT_DS_COMPLETE_URI_ANYWHERE; /* complete uris by looking for matches anywhere within them */ int read_only_cookies = XT_DS_READ_ONLY_COOKIES; /* enable to not write cookies */ int enable_scripts = XT_DS_ENABLE_SCRIPTS; int enable_plugins = XT_DS_ENABLE_PLUGINS; @@ -159,6 +160,7 @@ int set_cmd_font(char *); int set_color_visited_uris(char *); int set_cookie_policy_rt(char *); int set_cookies_enabled(char *); +int set_complete_uri_anywhere(char *); int set_ctrl_click_focus(char *); int set_fancy_bar(char *); int set_home(char *); @@ -234,6 +236,7 @@ int check_cmd_font(char **); int check_color_visited_uris(char **); int check_cookie_policy(char **); int check_cookies_enabled(char **); +int check_complete_uri_anywhere(char **); int check_ctrl_click_focus(char **); int check_default_script(char **); int check_default_zoom_level(char **); @@ -515,6 +518,7 @@ struct settings rs[] = { { "color_visited_uris", XT_S_BOOL, 0, &color_visited_uris , NULL, NULL, NULL, set_color_visited_uris, check_color_visited_uris, TT_COLOR_VISITED_URIS }, { "cookie_policy", XT_S_STR, 0, NULL, NULL,&s_cookie, NULL, set_cookie_policy_rt, check_cookie_policy, TT_COOKIE_POLICY }, { "cookies_enabled", XT_S_BOOL, 0, &cookies_enabled, NULL, NULL, NULL, set_cookies_enabled, check_cookies_enabled, TT_COOKIES_ENABLED }, + { "complete_uri_anywhere", XT_S_BOOL, 0, &complete_uri_anywhere, NULL, NULL, NULL, set_complete_uri_anywhere, check_complete_uri_anywhere, TT_COMPLETE_URI_ANYWHERE }, { "ctrl_click_focus", XT_S_BOOL, 0, &ctrl_click_focus, NULL, NULL, NULL, set_ctrl_click_focus, check_ctrl_click_focus, TT_CTRL_CLICK_FOCUS }, { "default_script", XT_S_STR, 1, NULL, NULL,&s_default_script, NULL, set_default_script_rt, check_default_script, TT_DEFAULT_SCRIPT }, { "default_zoom_level", XT_S_DOUBLE, 0, NULL, NULL, NULL, &default_zoom_level, set_default_zoom_level, check_default_zoom_level, TT_DEFAULT_ZOOM_LEVEL }, @@ -727,6 +731,31 @@ check_cookies_enabled(char **tt) return (cookies_enabled != XT_DS_COOKIES_ENABLED); } +int +set_complete_uri_anywhere(char *value) +{ + int tmp; + const char *errstr; + + if (value == NULL || strlen(value) == 0) + complete_uri_anywhere = XT_DS_COMPLETE_URI_ANYWHERE; + else { + tmp = strtonum(value, 0, 1, &errstr); + if (errstr) + return (-1); + complete_uri_anywhere = tmp; + } + return (0); +} + +int +check_complete_uri_anywhere(char **tt) +{ + *tt = g_strdup_printf("Default: %s", + XT_DS_COMPLETE_URI_ANYWHERE ? "Enabled" : "Disabled"); + return (complete_uri_anywhere != XT_DS_COMPLETE_URI_ANYWHERE); +} + int set_append_next(char *value) { diff --git a/xombrero.1 b/xombrero.1 index b9b25da..1709226 100644 --- a/xombrero.1 +++ b/xombrero.1 @@ -1162,6 +1162,9 @@ beginning and end of the regex so that, for example, would not match not-moo.com. .It Cm cookies_enabled Enable cookies. +.It Cm complete_uri_anywhere +When completing URIs, match substrings anywhere in the target URI (rather +than just the domain). .It Cm ctrl_click_focus Give focus in newly created tab instead of opening it in the background. .It Cm custom_uri diff --git a/xombrero.c b/xombrero.c index 35d3911..4461fac 100644 --- a/xombrero.c +++ b/xombrero.c @@ -208,8 +208,9 @@ GtkWidget *tab_bar_box; GtkWidget *arrow, *abtn; GdkEvent *fevent = NULL; struct tab_list tabs; -struct history_list hl; +struct pagelist hl; int hl_purge_count = 0; +struct pagelist favs; struct session_list sessions; struct wl_list c_wl; struct wl_list js_wl; @@ -689,11 +690,11 @@ int download_rb_cmp(struct download *, struct download *); gboolean cmd_execute(struct tab *t, char *str); int -history_rb_cmp(struct history *h1, struct history *h2) +pagelist_rb_cmp(struct pagelist_entry *h1, struct pagelist_entry *h2) { return (strcmp(h1->uri, h2->uri)); } -RB_GENERATE(history_list, history, entry, history_rb_cmp); +RB_GENERATE(pagelist, pagelist_entry, entry, pagelist_rb_cmp); int download_rb_cmp(struct download *e1, struct download *e2) @@ -4150,7 +4151,7 @@ void notify_load_status_cb(WebKitWebView* wview, GParamSpec* pspec, struct tab *t) { const gchar *uri = NULL; - struct history *h, find; + struct pagelist_entry *h, find; struct karg a; #if !GTK_CHECK_VERSION(3, 0, 0) gchar *text, *base; @@ -6142,13 +6143,17 @@ match_uri(const gchar *uri, const gchar *key) { if (!strncmp(key, uri, len)) match = TRUE; else { - voffset = strstr(uri, "/") + 2; - if (!strncmp(key, voffset, len)) - match = TRUE; - else if (g_str_has_prefix(voffset, "www.")) { + if (complete_uri_anywhere) { + match = !! strstr(uri, key); + } else { + voffset = strstr(uri, "/") + 2; + if (!strncmp(key, voffset, len)) + match = TRUE; + else if (g_str_has_prefix(voffset, "www.")) { voffset = voffset + strlen("www."); if (!strncmp(key, voffset, len)) match = TRUE; + } } } @@ -6168,7 +6173,7 @@ void cmd_getlist(int id, char *key) { int i, dep, c = 0; - struct history *h; + struct pagelist_entry *h; struct session *s; if (key == NULL) @@ -6176,7 +6181,22 @@ cmd_getlist(int id, char *key) if (id >= 0) { if (cmds[id].type & XT_URLARG) { - RB_FOREACH_REVERSE(h, history_list, &hl) + /* It'd be great if we could use the + completion_model here. Alas, GtkTreeModel apparently + has no API to access the char * in there; it seems + you only can get copies from there, which would + then have to be freed by the calling function. + Hence, we manually to through history and favourites + for now. */ + + RB_FOREACH_REVERSE(h, pagelist, &favs) + if (match_uri(h->uri, key)) { + cmd_status.list[c] = (char *)h->uri; + if (++c > 255) + break; + } + + RB_FOREACH_REVERSE(h, pagelist, &hl) if (match_uri(h->uri, key)) { cmd_status.list[c] = (char *)h->uri; if (++c > 255) @@ -8875,6 +8895,14 @@ main(int argc, char **argv) if (save_global_history) restore_global_history(); + /* pull favorites into memory */ + if (!restore_favorites()) { + struct pagelist_entry *item; + RB_FOREACH(item, pagelist, &favs) { + completion_add_uri(item->uri); + } + } + /* restore session list */ restore_sessions_list(); diff --git a/xombrero.css b/xombrero.css index 5862b10..e2f2ea5 100644 --- a/xombrero.css +++ b/xombrero.css @@ -22,6 +22,7 @@ @define-color ct_inactive #dddddd; @define-color ct_active #bbbb00; @define-color ct_separator #555555; +@define-color text_color #000000; * { border-width: 1px; diff --git a/xombrero.h b/xombrero.h index 303ef1c..1b211af 100644 --- a/xombrero.h +++ b/xombrero.h @@ -325,14 +325,14 @@ struct download { RB_HEAD(download_list, download); RB_PROTOTYPE(download_list, download, entry, download_rb_cmp); -struct history { - RB_ENTRY(history) entry; - gchar *uri; - gchar *title; - time_t time; /* When the item was added. */ +struct pagelist_entry { + RB_ENTRY(pagelist_entry) entry; + gchar *uri; + gchar *title; + time_t time; /* When the item was added. */ }; -RB_HEAD(history_list, history); -RB_PROTOTYPE(history_list, history, entry, history_rb_cmp); +RB_HEAD(pagelist, pagelist_entry); +RB_PROTOTYPE(pagelist, pagelist_entry, entry, pagelist_rb_cmp); #define XT_STS_FLAGS_INCLUDE_SUBDOMAINS (1) #define XT_STS_FLAGS_EXPAND (2) @@ -425,12 +425,22 @@ void setup_cookies(void); void soup_cookie_jar_add_cookie(SoupCookieJar *, SoupCookie *); void soup_cookie_jar_delete_cookie(SoupCookieJar *, SoupCookie *); -/* history */ +/* page lists */ int insert_history_item(const gchar *uri, const gchar *title, time_t time); int save_global_history_to_disk(struct tab *t); int restore_global_history(void); char *color_visited_helper(void); int color_visited(struct tab *t, char *visited); +int remove_pagelist_entry_by_count(struct pagelist *list, int count); +void remove_pagelist_entry_by_uri(struct pagelist *list, const gchar *uri); +void remove_pagelist_entry(struct pagelist *list, struct pagelist_entry *item); +int load_pagelist_from_disk(struct pagelist *list, char *file_name); +int save_pagelist_to_disk(struct pagelist *list, char *file_name); +int insert_pagelist_entry(struct pagelist *list, const gchar *uri, const gchar *title, time_t time); +void empty_pagelist(struct pagelist *list); + + + /* completion */ void completion_add(struct tab *); @@ -518,6 +528,7 @@ int xtp_page_sl(struct tab *, struct karg *); int xtp_page_sv(struct tab *, struct karg *); int parse_xtp_url(struct tab *, const char *); int add_favorite(struct tab *, struct karg *); +int restore_favorites(void); void update_favorite_tabs(struct tab *); void update_history_tabs(struct tab *); void update_download_tabs(struct tab *); @@ -647,6 +658,7 @@ int command_mode(struct tab *, struct karg *); #define XT_DS_SHOW_STATUSBAR (0) #define XT_DS_CTRL_CLICK_FOCUS (0) #define XT_DS_COOKIES_ENABLED (1) +#define XT_DS_COMPLETE_URI_ANYWHERE (0) #define XT_DS_READ_ONLY_COOKIES (0) #define XT_DS_ENABLE_SCRIPTS (1) #define XT_DS_ENABLE_PLUGINS (1) @@ -897,6 +909,7 @@ extern int show_scrollbars; extern int show_statusbar; extern int ctrl_click_focus; extern int cookies_enabled; +extern int complete_uri_anywhere; extern int read_only_cookies; extern int enable_cache; extern int enable_scripts; @@ -988,7 +1001,8 @@ extern void (*_soup_cookie_jar_add_cookie)(SoupCookieJar *, SoupCookie *); extern void (*_soup_cookie_jar_delete_cookie)(SoupCookieJar *, SoupCookie *); -extern struct history_list hl; +extern struct pagelist hl; +extern struct pagelist favs; extern int hl_purge_count; extern struct download_list downloads; extern struct tab_list tabs;