XFCE 4.2 mini-commandline plugin bask-like auto completion patch
Submitted to the Xfce-Goodies development group patch tracker: here.
This patch brings bash-like autocompletion to the commandline plugin for the XFCE4 panel. In other words, instead of remembering and completing only the last 10 program you've run, it's capable of suggesting you the name of all the executables it finds in the PATH environment variable (just like bash does when you press the TAB key).
The patch is released under GPL, just as the plugin.
Update: Thanks to Stelian (fe[nl]ix) for the suggestion 'bout moving from <sys/dir.h> (BSD) to <dirent.h> (POSIX). Now it should be more compatible with unixes other than Linux.
Disclaimer: Use this patch at your own risk. I won't guarantee that it works, and I won't be held liable for any damage caused by it!
--- xfce4-minicmd-plugin-0.3.0/panel-plugin/command.c 2004-11-01 16:01:04.000000000 +0100 +++ xfce4-minicmd-plugin-0.3.0.new/panel-plugin/command.c 2005-02-10 21:57:57.000000000 +0100 @@ -1,4 +1,7 @@ -/* +/* + * xfce4-minicmd-plugin - bash-like completion patch + * Copyright (C) 2005 Federico Quagliata (quaqo@users.sf.net) + * * xfce4-minicmd-plugin * Copyright (C) 2003 Biju Philip Chacko (botsie@users.sf.net) * Copyright (C) 2003 Eduard Roccatello (master@spine-group.org) @@ -75,6 +78,9 @@ #include <panel/plugins.h> #include <panel/xfce.h> +// Needed for bash-like completion +#include <dirent.h> + #ifndef PATH_MAX #define DEFAULT_LENGTH 1024 #else @@ -111,25 +117,39 @@ * Globals */ static GList *History = NULL; /* Command Entry History */ +static GList *Execlist = NULL; /* Execlist */ static char *Fileman = NULL; /* Default File Manager */ static GList *Curr = NULL; /* Current History Item Being Displayed */ GCompletion *complete; /* Command Completion Structure */ gint nComplete; /* Number of iteration done */ -/* Load history items in *complete item for autocompletion */ +/* Load history items and executables from path in + * *complete item for autocompletion */ GCompletion *load_completion (void) { - GList *hitem, *hstrings; + GList *hitem, *hstrings, *bstrings; XFCommand *current; for (hitem = History, hstrings = NULL; hitem != NULL; hitem = hitem->next) { current = hitem->data; hstrings = g_list_append(hstrings,current->command); } + + // Executables list from PATH + for (hitem = Execlist, bstrings = NULL; hitem != NULL; hitem = hitem->next) { + bstrings = g_list_append(bstrings, hitem->data); + } + complete = g_completion_new(NULL); + + // Append executables list after history if (hstrings != NULL) { g_completion_add_items(complete, hstrings); } + if (bstrings != NULL) { + g_completion_add_items(complete, bstrings); + } + return complete; } @@ -175,6 +195,58 @@ return g_strdup("xffm"); } +/* filter directories and hidden files (used by scandir) */ +int file_filter (struct dirent *file_entry) +{ + if (strcmp(file_entry->d_name, ".") == 0 || + strcmp(file_entry->d_name, "..") == 0 || + file_entry->d_name[0] == '.') + return FALSE; + else + return TRUE; +} + +/* Bash-like autocompletion */ +GList *get_execlist(void) +{ + GList *cbtemp = NULL; + gchar **env_path = g_strsplit(g_getenv("PATH"), ":", 0); + gchar *pathname, *filepath; + struct dirent **file_list, **list; + int i, j, k, file_filter(); + + cbtemp = g_list_append(cbtemp, g_strdup("")); + + for (i = 0; env_path[i] != NULL; i++) { + + k = scandir(env_path[i], &file_list, file_filter, alphasort); + + if (k > 0) { + // Check if the path has the final slash (nedded // + // later to pass full path to access()) // + if (env_path[i][strlen(env_path[i]) - 1] != '/') + pathname = g_strconcat(env_path[i], "/", NULL); + else + pathname = g_strdup(env_path[i]); + + for (j=0, list=file_list; j<k; j++) { + filepath = g_strconcat(pathname, (*list)->d_name, NULL); + if (access(filepath, X_OK) == 0) + cbtemp = g_list_append(cbtemp, g_strdup((*list)->d_name)); + g_free(filepath); + g_free(*list); + list++; + } + + g_free(pathname); + g_free(file_list); + } + + } + g_strfreev(env_path); + return cbtemp; +} + GList *get_history(void) { FILE *fp; @@ -264,6 +336,20 @@ g_free(hfile); } +// Execlist +static void free_execlist(GList *execlist) +{ + GList *tmp; + tmp = Execlist; + while(tmp) { + g_free(tmp->data); + tmp->data = NULL; + tmp = g_list_next(tmp); + } + g_list_free(execlist); + return; +} + static void free_hitem(XFCommand * hitem) { DBG("Freeing command line"); @@ -389,8 +475,10 @@ if (do_run(cmd, terminal)) { put_history(cmd, terminal, History); /* save this cmdline to history */ free_history(History); /* Delete current history */ + free_execlist(Execlist); /* Delete executables list */ g_completion_free(complete); /* Free completion items */ History = get_history(); /* reload modified history */ + Execlist = get_execlist(); /* reload executables list */ complete = load_completion(); /* Reload completion items */ Curr = NULL; /* reset current history item pointer */ terminal = FALSE; /* Reset run in term flag */ @@ -474,6 +562,7 @@ command = command_new(); History = get_history(); + Execlist = get_execlist(); complete = load_completion(); Fileman = get_fileman();