On Wed 28 Jan 2009 - 12:38PM, bill lam wrote: > It is very useful! > Can it be extended to handle <tab><tab> ?
request granted =) first tab will do longest completion, subsequent tabs will cycle through all choices. I dont know if others tried or not, but my example didnt work... OpenOffice (and a few other apps I noticed) doesn't like the escaped spaces, so I tweaked the dmenu_run script so it'll work now (assuming the filename is the only argument... YMMV) This patch makes the functionality optional through a "-c" command line argument, in the interests of keeping dmenu generic and hoping this will get committed to the main line. So you'll want to add it to your dwm config.h or whatever you call it through. I've also added some info to the man page too. Jeremy
diff -r 13402291bc76 dmenu.1 --- a/dmenu.1 Fri Dec 12 19:58:52 2008 +0000 +++ b/dmenu.1 Wed Jan 28 18:15:59 2009 -0500 @@ -12,6 +12,7 @@ .RB [ \-sb " <color>"] .RB [ \-sf " <color>"] .RB [ \-v ] +.RB [ \-c ] .SH DESCRIPTION .SS Overview dmenu is a generic menu for X, originally designed for @@ -46,6 +47,9 @@ .TP .B \-v prints version information to standard output, then exits. +.TP +.B \-c +enables filename completion for text after a space (useful with the dmenu_run script). .SH USAGE dmenu reads a list of newline-separated items from standard input and creates a menu. When the user selects an item or enters any text and presses Return, his/her @@ -67,7 +71,9 @@ Select the first/last item. .TP .B Tab (Control\-i) -Copy the selected item to the input field. +Copy the selected item to the input field. Also, if the -c option is given and there +is a space in the input, will try to expand and complete text after the space into a +valid filename. (First Tab - Longest Completion, Multiple Tabs - cycle through files) .TP .B Return (Control\-j) Confirm selection and quit (print the selected item to standard output). Returns diff -r 13402291bc76 dmenu.c --- a/dmenu.c Fri Dec 12 19:58:52 2008 +0000 +++ b/dmenu.c Wed Jan 28 18:15:59 2009 -0500 @@ -8,6 +8,7 @@ #include <string.h> #include <strings.h> #include <unistd.h> +#include <wordexp.h> #include <X11/keysym.h> #include <X11/Xlib.h> #include <X11/Xutil.h> @@ -59,6 +60,7 @@ static void initfont(const char *fontstr); static void kpress(XKeyEvent * e); static void match(char *pattern); +static void matchfile(char *filestart, Bool cycling); static void readstdin(void); static void run(void); static void setup(Bool topbar); @@ -77,7 +79,7 @@ static int screen; static unsigned int mw, mh; static unsigned int numlockmask = 0; -static Bool running = True; +static Bool running = True, filecomplete = False; static Display *dpy; static DC dc; static Item *allitems = NULL; /* first of all items */ @@ -311,6 +313,7 @@ void kpress(XKeyEvent * e) { + static KeySym lastkey=0; char buf[32]; int i, num; unsigned int len; @@ -396,7 +399,10 @@ default: if(num && !iscntrl((int) buf[0])) { buf[num] = 0; - strncpy(text + len, buf, sizeof text - len); + if(len > 0) + strncat(text, buf, sizeof text); + else + strncpy(text, buf, sizeof text); match(text); } break; @@ -467,12 +473,17 @@ } break; case XK_Tab: + if( filecomplete && strchr(text, ' ')!=NULL ) { + matchfile( strchr(text, ' ')+1, lastkey==XK_Tab ); + break; + } if(!sel) return; strncpy(text, sel->text, sizeof text); match(text); break; } + lastkey=ksym; drawmenu(); } @@ -518,6 +529,44 @@ } void +matchfile(char *filestart, Bool cycling ) { + static int try=0, p=0; + wordexp_t exp; + int i, j, k; + + if( !cycling ) { + p = strlen(filestart); + try=0; + } + filestart[ p+1 ] = 0; + filestart[ p ] = '*'; + + wordexp(filestart, &exp, 0); + if( exp.we_wordc > 0 ) { + for(j=0,i=0; exp.we_wordv[try][i]!=0; i++,j++) { + if( exp.we_wordv[try][i]==' ' ) filestart[j++]='\\'; + filestart[j]=exp.we_wordv[try][i]; + } + filestart[j]=0; + + if( cycling ) + try = (try+1)%exp.we_wordc; + else + for(k=1; k<exp.we_wordc; k++) + for(j=0, i=0; exp.we_wordv[k][i]; i++,j++) { + if( filestart[j]=='\\' ) j++; + if( filestart[j]!=exp.we_wordv[k][i] ) { + filestart[j]=0; + break; + } + } + } else { + filestart[ p ] = 0; + } + wordfree(&exp); +} + +void readstdin(void) { char *p, buf[1024]; unsigned int len = 0, max = 0; @@ -677,6 +726,8 @@ } else if(!strcmp(argv[i], "-b")) topbar = False; + else if(!strcmp(argv[i], "-c")) + filecomplete = True; else if(!strcmp(argv[i], "-fn")) { if(++i < argc) font = argv[i]; } @@ -699,7 +750,7 @@ eprint("dmenu-"VERSION", ?? 2006-2008 dmenu engineers, see LICENSE for details\n"); else eprint("usage: dmenu [-i] [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n" - " [-p <prompt>] [-sb <color>] [-sf <color>] [-v]\n"); + " [-p <prompt>] [-sb <color>] [-sf <color>] [-v] [-c]\n"); if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) fprintf(stderr, "warning: no locale support\n"); if(!(dpy = XOpenDisplay(0))) diff -r 13402291bc76 dmenu_run --- a/dmenu_run Fri Dec 12 19:58:52 2008 +0000 +++ b/dmenu_run Wed Jan 28 18:15:59 2009 -0500 @@ -1,2 +1,2 @@ -#!/bin/sh -exe=`dmenu_path | dmenu ${1+"$@"}` && exec $exe +#!/bin/zsh +exe=`dmenu_path | dmenu ${1+"$@"}` && exe2=${exe//\\ / } && exec ${exe2%% *} "${exe2#* }"