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#* }"

Reply via email to