diff --git a/dmenu/dmenu.1 b/dmenu/dmenu.1 index 2279835..4e669a2 100644 --- a/dmenu/dmenu.1 +++ b/dmenu/dmenu.1 @@ -14,6 +14,7 @@ dmenu \- dynamic menu .RB [ \-sf " "] .RB [ \-xs ] .RB [ \-v ] +.RB [ \-c ] .SH DESCRIPTION .SS Overview dmenu is a generic menu for X, originally designed for @@ -55,6 +56,9 @@ xmms-like pattern matching. .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 @@ -76,7 +80,9 @@ Select the first item of the previous/next 'page' of items. 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 --git a/dmenu/dmenu.c b/dmenu/dmenu.c index b30b92a..8d1f33c 100644 --- a/dmenu/dmenu.c +++ b/dmenu/dmenu.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +62,7 @@ static Bool grabkeyboard(void); 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); @@ -81,7 +83,7 @@ static int cursor = 0; static int screen; static unsigned int mw, mh; static unsigned int numlockmask = 0; -static Bool running = True; +static Bool running = True, filecomplete = False; static Bool xmms = False; static Display *dpy; static DC dc; @@ -384,6 +386,7 @@ initfont(const char *fontstr) { void kpress(XKeyEvent * e) { + static KeySym lastkey=0; char buf[32]; int i, num; unsigned int len; @@ -498,7 +501,11 @@ kpress(XKeyEvent * e) { if(num && !iscntrl((int) buf[0])) { buf[num] = 0; memmove(text + cursor + num, text + cursor, sizeof text - cursor); - strncpy(text + cursor, buf, sizeof text - cursor); + //strncpy(text + cursor, buf, sizeof text - cursor); + if (len > 0) + strncat(text, buf, sizeof text); + else + strncpy(text, buf, sizeof text); cursor+=num; match(text); } @@ -581,6 +588,11 @@ kpress(XKeyEvent * e) { return; break; case XK_Tab: + if( filecomplete && strchr(text, ' ')!=NULL ) { + matchfile( strchr(text, ' ')+1, lastkey==XK_Tab ); + cursor = strlen(text); + break; + } if(!sel) return; strncpy(text, sel->text, sizeof text); @@ -591,6 +603,7 @@ kpress(XKeyEvent * e) { len = strlen(text); cursor = MIN(cursor, len); cursor = MAX(cursor, 0); + lastkey=ksym; drawmenu(); } @@ -669,6 +682,44 @@ match(char *pattern) { } 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] [-fn ] [-nb ] [-nf ]\n" - " [-p ] [-sb ] [-sf ] [-xs] [-v]\n"); + " [-p ] [-sb ] [-sf ] [-xs] [-v] [-c]\n"); if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) fprintf(stderr, "warning: no locale support\n"); if(!(dpy = XOpenDisplay(NULL))) diff --git a/dmenu/dmenu_run b/dmenu/dmenu_run index 3e1e6e4..a4c09e5 100755 --- a/dmenu/dmenu_run +++ b/dmenu/dmenu_run @@ -1,2 +1,2 @@ #!/bin/sh -exe=`dmenu_path | dmenu ${1+"$@"}` && exec $exe +exe=`dmenu_path | dmenu ${1+"$@"}` && exe2=${exe//\\ / } && exec ${exe2%% *} "${exe2#* }" diff --git a/dmenu/filecompletion2.diff b/dmenu/filecompletion2.diff new file mode 100644 index 0000000..080bc80 --- /dev/null +++ b/dmenu/filecompletion2.diff @@ -0,0 +1,170 @@ +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 " "] + .RB [ \-sf " "] + .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 + #include + #include ++#include + #include + #include + #include +@@ -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] [-nb ] [-nf ]\n" +- " [-p ] [-sb ] [-sf ] [-v]\n"); ++ " [-p ] [-sb ] [-sf ] [-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#* }" +