/* * Copyright (c) 2010-2013 Stefan Bolte * * 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include "dwb.h" #include "commands.h" #include "util.h" #include "entry.h" #include "completion.h" static GList * completion_update_completion(GtkWidget *box, GList *comps, GList *active, int max, int back); static GList * completion_get_simple_completion(GList *gl); typedef gboolean (*Match_Func)(char*, const char*); static char *s_typed; static int s_last_buf; static gboolean s_leading0 = false; static char *s_current_command; static int s_command_len; /* GUI_FUNCTIONS {{{*/ /* completion_modify_completion_item(Completion *c, GdkColor *fg, GdkColor *bg, PangoFontDescription *fd) {{{*/ static void completion_modify_completion_item(Completion *c, DwbColor *fg, DwbColor *bg, PangoFontDescription *fd) { DWB_WIDGET_OVERRIDE_COLOR(c->llabel, GTK_STATE_NORMAL, fg); DWB_WIDGET_OVERRIDE_COLOR(c->rlabel, GTK_STATE_NORMAL, fg); DWB_WIDGET_OVERRIDE_COLOR(c->mlabel, GTK_STATE_NORMAL, fg); DWB_WIDGET_OVERRIDE_BACKGROUND(c->event, GTK_STATE_NORMAL, bg); DWB_WIDGET_OVERRIDE_FONT(c->llabel, dwb.font.fd_completion); DWB_WIDGET_OVERRIDE_FONT(c->mlabel, dwb.font.fd_completion); DWB_WIDGET_OVERRIDE_FONT(c->rlabel, dwb.font.fd_completion); }/*}}}*/ /* completion_get_completion_item(Navigation *) return: Completion * {{{*/ static Completion * completion_get_completion_item(const char *left, const char *right, const char *middle, void *data) { Completion *c = g_malloc(sizeof(Completion)); c->llabel = gtk_label_new(left); c->rlabel = gtk_label_new(right); c->mlabel = gtk_label_new(middle); c->event = gtk_event_box_new(); c->data = data; gboolean expand = middle != NULL && right != NULL; #if _HAS_GTK3 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_set_homogeneous(GTK_BOX(hbox), expand); #else GtkWidget *hbox = gtk_hbox_new(expand, 0); #endif gtk_box_pack_start(GTK_BOX(hbox), c->llabel, true, true, 5); gtk_box_pack_start(GTK_BOX(hbox), c->mlabel, middle != NULL, true, 5); gtk_box_pack_start(GTK_BOX(hbox), c->rlabel, right != NULL, true, 5); gtk_label_set_ellipsize(GTK_LABEL(c->llabel), PANGO_ELLIPSIZE_MIDDLE); gtk_label_set_ellipsize(GTK_LABEL(c->rlabel), PANGO_ELLIPSIZE_MIDDLE); gtk_misc_set_alignment(GTK_MISC(c->llabel), 0.0, 0.5); gtk_misc_set_alignment(GTK_MISC(c->mlabel), 1.0, 0.5); gtk_misc_set_alignment(GTK_MISC(c->rlabel), 1.0, 0.5); completion_modify_completion_item(c, &dwb.color.normal_c_fg, &dwb.color.normal_c_bg, dwb.font.fd_inactive); int padding = GET_INT("bars-padding"); GtkWidget *alignment = gtk_alignment_new(0.5, 0.5, 1, 1); gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), padding, padding, padding, padding); gtk_container_add(GTK_CONTAINER(alignment), hbox); gtk_container_add(GTK_CONTAINER(c->event), alignment); return c; }/*}}}*/ /* completion_init_completion {{{*/ static GList * completion_init_completion(GList *store, GList *gl, gboolean word_beginnings, void *data, const char *value) { Navigation *n; const char *input = GET_TEXT(); gboolean match; char **token = NULL; s_typed = g_strdup(input); if (dwb.state.mode & COMMAND_MODE) input = strchr(input, ' '); if (input == NULL) input = ""; else token = g_strsplit(input, " ", -1); Match_Func func = word_beginnings ? (Match_Func)g_str_has_prefix : (Match_Func)util_strcasestr; for (GList *l = gl; l; l=l->next) { n = l->data; match = false; if (*input == 0) match = true; else { for (int i=0; token[i]; i++) { if (func(n->first, token[i]) || (!word_beginnings && n->second && func(n->second, token[i]))) match = true; else { match = false; break; } } } if (match) { Completion *c = completion_get_completion_item(n->first, n->second, value, data); gtk_box_pack_start(GTK_BOX(dwb.gui.compbox), c->event, false, false, 0); store = g_list_append(store, c); } } g_strfreev(token); return store; }/*}}}*/ /* dwb_completion_set_text(Completion *) {{{*/ void completion_set_entry_text(Completion *c) { const char *text; int l; CompletionType type = dwb_eval_completion_type(); switch (type) { case COMP_QUICKMARK: text = c->data; break; default: text = gtk_label_get_text(GTK_LABEL(c->llabel)); break; } if (dwb.state.mode & COMMAND_MODE && s_current_command) { gtk_entry_set_text(GTK_ENTRY(dwb.gui.entry), s_current_command); l = strlen(s_current_command); gtk_editable_insert_text(GTK_EDITABLE(dwb.gui.entry), " ", -1, &l); gtk_editable_insert_text(GTK_EDITABLE(dwb.gui.entry), text, -1, &l); } else { char buf[7]; gtk_editable_delete_text(GTK_EDITABLE(dwb.gui.entry), 0, -1); if (dwb.state.nummod > -1) { l = snprintf(buf, sizeof(buf), "%d", dwb.state.nummod); gtk_editable_insert_text(GTK_EDITABLE(dwb.gui.entry), buf, -1, &l); } gtk_editable_insert_text(GTK_EDITABLE(dwb.gui.entry), text, -1, &l); } gtk_editable_set_position(GTK_EDITABLE(dwb.gui.entry), -1); }/*}}}*/ /* completion_update_completion(GtkWidget *box, GList *comps, GList *active, int max, int back) Return *GList (Completions*){{{*/ static GList * completion_update_completion(GtkWidget *box, GList *comps, GList *active, int max, int back) { GList *old, *new; Completion *c; int length = g_list_length(comps); int items = MAX(length, max); int r = (max) % 2; int offset = max / 2 - 1 + r; old = active; int position = g_list_position(comps, active) + 1; if (!back) { if (! (new = old->next) ) new = g_list_first(comps); if (position > offset && position < items - offset - 1 + r) { c = g_list_nth(comps, position - offset - 1)->data; gtk_widget_hide(c->event); c = g_list_nth(comps, position + offset + 1 - r)->data; gtk_widget_show_all(c->event); } else { if (position == items || position == 1) { int i = 0; for (GList *l = g_list_last(comps); l && iprev) { gtk_widget_hide(COMP_EVENT_BOX(l)); } gtk_widget_show(box); i = 0; for (GList *l = g_list_first(comps); l && inext, i++) { gtk_widget_show_all(((Completion*)l->data)->event); } } } } else { if (! (new = old->prev) ) new = g_list_last(comps); if (position -1> offset && position < items - offset + r) { c = g_list_nth(comps, position - offset - 2)->data; gtk_widget_show_all(c->event); c = g_list_nth(comps, position + offset - r)->data; gtk_widget_hide(c->event); } else { if (position == 1) { int i = 0; for (GList *l = g_list_first(comps); l && inext, i++) { gtk_widget_hide(COMP_EVENT_BOX(l)); } gtk_widget_show(box); i = 0; for (GList *l = g_list_last(comps); l && iprev, i++) { c = l->data; gtk_widget_show_all(c->event); } } } } completion_modify_completion_item(old->data, &dwb.color.normal_c_fg, &dwb.color.normal_c_bg, dwb.font.fd_inactive); completion_modify_completion_item(new->data, &dwb.color.active_c_fg, &dwb.color.active_c_bg, dwb.font.fd_active); active = new; completion_set_entry_text(active->data); return active; }/*}}}*/ /*}}}*/ /* STANDARD_COMPLETION {{{*/ /* dwb_clean_completion() {{{*/ void completion_clean_completion(gboolean set_text) { for (GList *l = dwb.comps.completions; l; l=l->next) { g_free(l->data); } g_list_free(dwb.comps.completions); if (dwb.comps.view != NULL) gtk_widget_destroy(dwb.gui.compbox); dwb.comps.view = NULL; dwb.comps.completions = NULL; dwb.comps.active_comp = NULL; if (set_text && s_typed != NULL) entry_set_text(s_typed); FREE0(s_current_command); s_command_len = 0; FREE0(s_typed); if (dwb.state.mode & COMPLETE_BUFFER) { s_last_buf = 0; s_leading0 = false; dwb.state.mode &= ~COMPLETE_BUFFER; dwb_change_mode(NORMAL_MODE, true); } else dwb.state.mode &= ~(COMPLETION_MODE|COMPLETE_PATH); }/*}}}*/ /* completion_show_completion(int back) {{{*/ static void completion_show_completion(int back) { int i=0; if (back) { dwb.comps.active_comp = g_list_last(dwb.comps.completions); for (GList *l = dwb.comps.active_comp; l && iprev, i++) { gtk_widget_show_all(((Completion*)l->data)->event); } } else { dwb.comps.active_comp = g_list_first(dwb.comps.completions); for (GList *l = dwb.comps.active_comp; l && inext, i++) { gtk_widget_show_all(((Completion*)l->data)->event); } } if (dwb.comps.active_comp != NULL) { completion_modify_completion_item(dwb.comps.active_comp->data, &dwb.color.active_c_fg, &dwb.color.active_c_bg, dwb.font.fd_active); completion_set_entry_text(dwb.comps.active_comp->data); gtk_widget_show(dwb.gui.compbox); } }/*}}}*/ /* dwb_completion_get_normal return: GList *Completions{{{*/ static GList * completion_get_normal_completion() { GList *list = NULL; if (!(dwb.state.mode & COMMAND_MODE) ) { if (GET_BOOL("complete-userscripts")) list = completion_init_completion(list, dwb.misc.userscripts, false, NULL, "Userscript"); if (GET_BOOL("complete-searchengines")) list = completion_init_completion(list, dwb.fc.se_completion, false, NULL, "Searchengine"); } if (GET_BOOL("complete-bookmarks")) list = completion_init_completion(list, dwb.fc.bookmarks, false, NULL, "Bookmark"); if (GET_BOOL("complete-history")) list = completion_init_completion(list, dwb.fc.history, false, NULL, "History"); return list; }/*}}}*/ /* completion_get_simple_completion return: GList *Completions{{{*/ static GList * completion_get_simple_completion(GList *gl) { GList *list = NULL; list = completion_init_completion(list, gl, false, NULL, NULL); return list; }/*}}}*/ /* dwb_completion_get_settings return: GList *Completions{{{*/ static GList * completion_get_settings_completion() { GList *l = g_hash_table_get_values(dwb.settings); l = g_list_sort(l, (GCompareFunc)util_web_settings_sort_first); const char *input = GET_TEXT(); GList *list = NULL; for (; l; l=l->next) { WebSettings *s = l->data; Navigation n = s->n; if (g_strrstr(n.first, input)) { char *value = util_arg_to_char(&s->arg, s->type); Completion *c = completion_get_completion_item(s->n.first, s->n.second, value, s); gtk_box_pack_start(GTK_BOX(dwb.gui.compbox), c->event, false, false, 0); list = g_list_append(list, c); } } if (l != NULL) g_list_free(l); return list; }/*}}}*/ /* completion_create_key_completion(GList *l, const char *first, KeyMap *m) {{{*/ static GList * completion_create_key_completion(GList *l, const char *first, KeyMap *m) { char *mod = dwb_modmask_to_string(m->mod); char *value = g_strdup_printf("%s %s", mod, m->key); Completion *c = completion_get_completion_item(first, m->map->n.second, value, m); gtk_box_pack_start(GTK_BOX(dwb.gui.compbox), c->event, false, false, 0); l = g_list_append(l, c); g_free(value); g_free(mod); return l; }/*}}}*/ static GList * completion_complete_scripts() { GList *list = NULL; for (GList *l = dwb.state.script_completion; l; l=l->next) { Completion *c = completion_get_completion_item(((Navigation*)l->data)->first, ((Navigation*)l->data)->second, NULL, NULL); gtk_box_pack_start(GTK_BOX(dwb.gui.compbox), c->event, false, false, 0); list = g_list_append(list, c); } dwb.state.mode = COMPLETE_SCRIPTS; return list; } /*dwb_completion_get_keys() return GList *Completions{{{*/ static GList * completion_get_key_completion(gboolean entry) { GList *list = NULL; const char *input = GET_TEXT(); dwb.keymap = g_list_sort(dwb.keymap, (GCompareFunc)util_keymap_sort_first); input = dwb_parse_nummod(input); /* check for aliases first */ for (GList *l = dwb.keymap; l; l=l->next) { KeyMap *m = l->data; if (!entry && ((m->map->prop & CP_OVERRIDE_ENTRY) || !(m->map->prop & CP_COMMANDLINE))) continue; if (!entry) { for (int i=0; m->map->alias[i] != NULL; i++) { if (g_str_has_prefix(m->map->alias[i], input) || !g_strcmp0(input, m->map->alias[i]) ) { list = completion_create_key_completion(list, m->map->alias[i], m); break; } } } } /* check for long commands */ for (GList *l = dwb.keymap; l; l=l->next) { KeyMap *m = l->data; if (!entry && ((m->map->prop & CP_OVERRIDE_ENTRY) || !(m->map->prop & CP_COMMANDLINE))) continue; Navigation n = m->map->n; if (g_str_has_prefix(n.first, input)) list = completion_create_key_completion(list, n.first, m); } return list; }/*}}}*/ /* completion_path {{{*/ static void completion_path(void) { if (! (dwb.state.mode & DOWNLOAD_GET_PATH) ) dwb.state.mode = COMPLETE_PATH; completion_complete_path(false); }/*}}}*/ /* completion_get_quickmarks {{{*/ static GList * completion_get_quickmarks(int back) { GList *list = NULL; Quickmark *q; char *escaped = NULL; const char *input = GET_TEXT(); s_typed = g_strdup(input); for (GList *l = dwb.fc.quickmarks; l; l=l->next) { q = l->data; if (g_str_has_prefix(q->key, input)) { Completion *c = completion_get_completion_item(NULL, q->nav->first, NULL, q->key); escaped = g_markup_printf_escaped("%s\t\t%s", q->key, q->nav->second); if (escaped != NULL) { gtk_label_set_markup(GTK_LABEL(c->llabel), escaped); g_free(escaped); } else gtk_label_set_text(GTK_LABEL(c->llabel), q->key); gtk_box_pack_start(GTK_BOX(dwb.gui.compbox), c->event, false, false, 0); list = g_list_append(list, c); } } return list; }/*}}}*/ static void completion_buffer_exec(GList *gl) { completion_clean_completion(false); dwb_focus_view(gl, "buffer"); dwb_change_mode(NORMAL_MODE, true); } #define COMPLETION_BUFFER_GET_PRIVATE(c) (((Completion*)((c)->data))->data) void completion_buffer_key_press(GdkEventKey *e) { if (DWB_TAB_KEY(e)) completion_complete(COMP_BUFFER, e->state & GDK_SHIFT_MASK); else if (DIGIT(e)) { int value = e->keyval - GDK_KEY_0; int length = g_list_length(dwb.state.views); if (length < 10) { if (value != 0 && value <= length) completion_buffer_exec(g_list_nth(dwb.state.views, value-1)); } else { s_last_buf = 10*s_last_buf + value; if (s_last_buf > length) { completion_clean_completion(false); dwb_change_mode(NORMAL_MODE, true); return; } if (s_last_buf != 0) { if ((s_last_buf < 10 && s_leading0 == true) || s_last_buf >= 10) completion_buffer_exec(g_list_nth(dwb.state.views, s_last_buf-1)); } else s_leading0 = true; } } } void completion_eval_buffer_completion(void) { /* TODO Wrong View is saved */ GList *l = COMPLETION_BUFFER_GET_PRIVATE(dwb.comps.active_comp); completion_buffer_exec(l); } #undef COMPLETION_BUFFER_GET_PRIVATE /* completion_complete_buffer {{{*/ static GList * completion_complete_buffer() { GList *list = NULL; int i=1; const char *uri, *title, *format; char *text; Completion *c; WebKitWebView *wv; format = g_list_length(dwb.state.views) > 10 ? "%02d : %s" : "%d : %s"; for (GList *l = dwb.state.views;l; l=l->next) { if (VIEW(l)->status->deferred) { text = g_strdup_printf(format, i, VIEW(l)->status->deferred_uri); uri = "deferred"; } else { wv = WEBVIEW(l); title = webkit_web_view_get_title(wv); uri = webkit_web_view_get_uri(wv); text = g_strdup_printf(format, i, title != NULL ? title : uri); } c = completion_get_completion_item(text, uri, NULL, l); gtk_box_pack_start(GTK_BOX(dwb.gui.compbox), c->event, false, false, 0); list = g_list_append(list, c); g_free(text); i++; } if (list != NULL) { dwb.state.mode = COMPLETE_BUFFER; entry_focus(); } return list; }/*}}}*/ static gboolean completion_command_line() { KeyMap *km = NULL; gboolean ret = false; const char *bak, *text; char **token; text = GET_TEXT(); while (g_ascii_isspace(*text)) text++; token = g_strsplit(text, " ", 2); if (dwb.state.mode & COMMAND_MODE) { for (GList *l = dwb.keymap; l; l=l->next) { bak = token[0]; km = l->data; while (bak && (g_ascii_isspace(*bak) || g_ascii_isdigit(*bak))) bak++; if (! g_strcmp0(bak, km->map->n.first) && km->map->entry & EP_COMP_DEFAULT) { ret = true; break; } else { for (int i=0; km->map->alias[i] != NULL; i++) { if (! g_strcmp0(bak, km->map->alias[i]) && km->map->entry & EP_COMP_DEFAULT) { ret = true; break; } } if (ret) break; } } } if (ret) { s_command_len = util_strlen_trailing_space(text); if ((s_command_len > 0 && g_ascii_isspace(text[s_command_len-1])) || token[1] != NULL) { FREE0(s_current_command); s_current_command = g_strdup(token[0]); dwb.state.mode |= COMPLETE_COMMAND_MODE; s_command_len++; } else ret = false; } g_strfreev(token); return ret; } /* completion_complete {{{*/ DwbStatus completion_complete(CompletionType type, int back) { DwbStatus ret = STATUS_OK; if (dwb.state.mode & COMMAND_MODE) { if (completion_command_line()) type = COMP_NONE; } dwb.state.mode &= ~(COMPLETE_PATH | AUTO_COMPLETE | COMPLETE_COMMAND_MODE); if ( !(dwb.state.mode & COMPLETION_MODE) ) { #if _HAS_GTK3 dwb.gui.compbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_set_homogeneous(GTK_BOX(dwb.gui.compbox), true); #else dwb.gui.compbox = gtk_vbox_new(true, 0); #endif gtk_box_pack_start(GTK_BOX(dwb.gui.bottombox), dwb.gui.compbox, false, false, 0); switch (type) { case COMP_SETTINGS: dwb.comps.completions = completion_get_settings_completion(); break; case COMP_KEY: dwb.comps.completions = completion_get_key_completion(true); break; case COMP_COMMAND: dwb.comps.completions = completion_get_key_completion(false); break; case COMP_BOOKMARK: dwb.comps.completions = completion_get_simple_completion(dwb.fc.bookmarks); break; case COMP_HISTORY: dwb.comps.completions = completion_get_simple_completion(dwb.fc.history); break; case COMP_USERSCRIPT: dwb.comps.completions = completion_get_simple_completion(dwb.misc.userscripts); break; case COMP_SEARCH: dwb.comps.completions = completion_get_simple_completion(dwb.fc.se_completion); break; case COMP_QUICKMARK: dwb.comps.completions = completion_get_quickmarks(back); break; case COMP_PATH: completion_path(); return STATUS_OK; case COMP_BUFFER: dwb.comps.completions = completion_complete_buffer(); break; case COMP_SCRIPT: dwb.comps.completions = completion_complete_scripts(); break; default: dwb.comps.completions = completion_get_normal_completion(); break; } if (!dwb.comps.completions) return STATUS_ERROR; dwb.state.mode |= COMPLETION_MODE; completion_show_completion(back); dwb.comps.view = dwb.state.fview; } else if (dwb.comps.completions && dwb.comps.active_comp) dwb.comps.active_comp = completion_update_completion(dwb.gui.compbox, dwb.comps.completions, dwb.comps.active_comp, dwb.misc.max_c_items, back); return ret; }/*}}}*/ /*}}}*/ /* AUTOCOMPLETION {{{*/ /*completion_eval_autocompletion{{{*/ void completion_eval_autocompletion() { Completion *c = dwb.comps.active_auto_c->data; KeyMap *m = c->data; dwb_change_mode(NORMAL_MODE, true); commands_simple_command(m, NULL); }/*}}}*/ /* dwb_set_autcompletion{{{*/ DwbStatus completion_set_autcompletion(GList *l, WebSettings *s) { dwb.comps.autocompletion = s->arg_local.b; return STATUS_OK; }/*}}}*/ /* completion_cleanautocompletion{{{*/ void completion_clean_autocompletion() { for (GList *l = dwb.comps.auto_c; l; l=l->next) g_free(l->data); g_list_free(dwb.comps.auto_c); gtk_widget_destroy(dwb.gui.autocompletion); dwb.comps.auto_c = NULL; dwb.comps.active_auto_c = NULL; dwb.state.mode &= ~AUTO_COMPLETE; gtk_widget_show(dwb.gui.entry); gtk_widget_show(dwb.gui.rstatus); gtk_widget_show(dwb.gui.urilabel); if (! (dwb.state.bar_visible & BAR_VIS_STATUS) ) gtk_widget_hide(dwb.gui.bottombox); }/*}}}*/ /* completion_init_autocompletion (GList *gl) return: GList * (Completion*){{{*/ static GList * completion_init_autocompletion(GList *gl) { GList *ret = NULL; char buffer[128]; KeyMap *m; Completion *c; #if _HAS_GTK3 dwb.gui.autocompletion = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2); gtk_box_set_homogeneous(GTK_BOX(dwb.gui.autocompletion), true); #else dwb.gui.autocompletion = gtk_hbox_new(true, 2); #endif int i=0; for (GList *l=gl; l; l=l->next, i++) { m = l->data; if (! (m->map->prop & CP_OVERRIDE_ENTRY) ) { snprintf(buffer, sizeof(buffer), "%s %s", m->key, m->map->n.second); c = completion_get_completion_item(NULL, NULL, NULL, m); gtk_label_set_use_markup(GTK_LABEL(c->llabel), true); gtk_label_set_markup(GTK_LABEL(c->llabel), buffer); ret = g_list_append(ret, c); if (i<5) { gtk_widget_show_all(c->event); } gtk_box_pack_start(GTK_BOX(dwb.gui.autocompletion), c->event, true, true, 1); } } gtk_box_pack_start(GTK_BOX(dwb.gui.status_hbox), dwb.gui.autocompletion, true, true, 10); entry_hide(); gtk_widget_hide(dwb.gui.rstatus); gtk_widget_hide(dwb.gui.urilabel); gtk_widget_show(dwb.gui.autocompletion); return ret; }/*}}}*/ /* dwb_autocomplete GList *gl(KeyMap*) GdkEventKey *{{{*/ void completion_autocomplete(GList *gl, GdkEventKey *e) { if (!dwb.comps.autocompletion) return; if (! (dwb.state.mode & AUTO_COMPLETE) && gl) { if (! gtk_widget_get_visible(dwb.gui.bottombox)) gtk_widget_show(dwb.gui.bottombox); dwb.state.mode |= AUTO_COMPLETE; dwb.comps.auto_c = completion_init_autocompletion(gl); dwb.comps.active_auto_c = g_list_first(dwb.comps.auto_c); completion_modify_completion_item(dwb.comps.active_auto_c->data, &dwb.color.active_c_fg, &dwb.color.active_c_bg, dwb.font.fd_active); } else if (e) dwb.comps.active_auto_c = completion_update_completion(dwb.gui.autocompletion, dwb.comps.auto_c, dwb.comps.active_auto_c, 5, e->state & GDK_SHIFT_MASK); }/*}}}*/ /*}}}*/ /* PATHCOMPLETION {{{*/ /* completion_clean_path_completion {{{*/ void completion_clean_path_completion() { if (dwb.comps.path_completion) { for (GList *l = g_list_first(dwb.comps.path_completion); l; l=l->next) { char *data = l->data; g_free(data); } g_list_free(dwb.comps.path_completion); dwb.comps.path_completion = NULL; dwb.comps.active_path = NULL; } }/*}}}*/ /* completion_get_binaries(GList *list, char *text) return GList *{{{*/ static GList * completion_get_binaries(GList *list, char *text) { GDir *dir; char **paths = g_strsplit(g_getenv("PATH"), ":", -1); int i=0; char *path; const char *filename; while ( (path = paths[i++]) ) { if ( (dir = g_dir_open(path, 'r', NULL)) ) { while ( (filename = g_dir_read_name(dir))) { if (g_str_has_prefix(filename, text)) list = g_list_prepend(list, g_strdup(filename)); } g_dir_close(dir); } } g_strfreev(paths); return list; }/* }}} */ static GList * completion_get_path(GList *list, char *text) { GDir *dir; char d_tmp[PATH_MAX]; const char *filename; char path[PATH_MAX+1]; char *store; char *newpath; gboolean prefix; if ( ( prefix = g_str_has_prefix(text, "file://")) ) text += 7; g_strlcpy(d_tmp, text, PATH_MAX - 1); char *d_name = dirname(d_tmp); char *b_name = util_basename(text); char *d_current = g_get_current_dir(); if (! *text ) { if (prefix) list = g_list_prepend(list, g_strconcat("file://", d_current, "/", NULL)); else list = g_list_prepend(list, g_strconcat(d_current, "/", NULL)); g_free(d_current); return list; } else g_free(d_current); if (!g_strcmp0(d_name, ".")) { completion_complete(0, 0); return NULL; } if (g_file_test(text, G_FILE_TEST_IS_DIR)) { g_strlcpy(path, text, BUFFER_LENGTH - 1); char path_last = path[strlen(path) - 1]; if (path_last != '/' && path_last != '.') { if (prefix) return g_list_prepend(list, g_strconcat("file://", path, "/", NULL)); else return g_list_prepend(list, g_strconcat(path, "/", NULL)); } } else if (g_file_test(d_name, G_FILE_TEST_IS_DIR)) { g_strlcpy(path, d_name, BUFFER_LENGTH - 1); } if ( (dir = g_dir_open(path, 'r', NULL)) ) { while ( (filename = g_dir_read_name(dir)) ) { if ( ( !b_name && filename[0] != '.') || (b_name && g_str_has_prefix(filename, b_name))) { newpath = g_build_filename(path, filename, NULL); if (prefix) store = g_strconcat("file://", newpath, "/" , NULL); else store = g_strconcat(newpath, "/" , NULL); if (g_file_test(newpath, G_FILE_TEST_IS_DIR)) list = g_list_prepend(list, store); else g_free(store); g_free(newpath); } } g_dir_close(dir); } return list; }/*}}}*/ /* completion_init_path_completion {{{*/ static void completion_init_path_completion(int back) { char *text = gtk_editable_get_chars(GTK_EDITABLE(dwb.gui.entry), 0, -1); char expanded[PATH_MAX]; text = util_expand_home(expanded, text, sizeof(expanded)); dwb.comps.path_completion = dwb.comps.active_path = g_list_append(NULL, g_strdup(text)); if (dwb.state.dl_action == DL_ACTION_EXECUTE) { GList *list = completion_get_binaries(NULL, text); list = g_list_sort(list, (GCompareFunc)g_strcmp0); dwb.comps.path_completion = g_list_concat(dwb.comps.path_completion, list); } else { dwb.comps.path_completion = completion_get_path(dwb.comps.path_completion, text); dwb.comps.path_completion = g_list_sort(dwb.comps.path_completion, (GCompareFunc)g_strcmp0); } if (g_list_length(dwb.comps.path_completion) == 1) { completion_clean_path_completion(); return; } if (dwb.comps.path_completion) { if (back) dwb.comps.active_path = g_list_last(dwb.comps.path_completion); else if (dwb.comps.path_completion->next) dwb.comps.active_path = dwb.comps.path_completion->next; } }/*}}}*/ /* completion_complete_download{{{*/ void completion_complete_path(int back) { if (! dwb.comps.path_completion ) completion_init_path_completion(0); else if (back) { if (dwb.comps.path_completion && dwb.comps.active_path && !(dwb.comps.active_path = dwb.comps.active_path->prev) ) dwb.comps.active_path = g_list_last(dwb.comps.path_completion); } else if (dwb.comps.active_path && !(dwb.comps.active_path = dwb.comps.active_path->next) ) dwb.comps.active_path = g_list_first(dwb.comps.path_completion); if (dwb.comps.active_path && dwb.comps.active_path->data) entry_set_text(dwb.comps.active_path->data); }/*}}}*/ /*}}}*/