I always try to do this and get frustrated when I remember it doesn't
work, but today I actually looked up the man pages and found out how
easy it is to get dmenu to support filename tab-completion.  This patch
adds a small function that completes a filename argument as far as 
possible.  If you'd rather complete to the first match, just comment
or delete the block specified.  With this patch it is now possible to
type 'ooc<tab> ~/big<tab>' and get:
  'oocalc /home/user/big\ filename\ i\ dont\ want\ to\ type.xls'

Hope others find it as useful!

Jeremy


--- dmenu-3.9/dmenu.c   2008-09-09 15:45:00.000000000 -0400
+++ dmenu-4.0/dmenu.c   2009-01-27 16:35:28.000000000 -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);
 static void readstdin(void);
 static void run(void);
 static void setup(Bool topbar);
@@ -470,6 +472,10 @@
                }
                break;
        case XK_Tab:
+               if( strchr(text, ' ')!=NULL ) {
+                       matchfile( strchr(text, ' ')+1 );
+                       break;
+               }
                if(!sel)
                        return;
                strncpy(text, sel->text, sizeof text);
@@ -521,6 +527,35 @@
 }
 
 void
+matchfile(char *filestart) {
+       wordexp_t exp;
+       int i, j, k, p=strlen(filestart);
+       filestart[ p+1 ] = 0;
+       filestart[ p ] = '*';
+
+       wordexp(filestart, &exp, 0);
+       if( exp.we_wordc > 0 ) {
+               for(j=0,i=0; exp.we_wordv[0][i]!=0; i++,j++) {
+                       if( exp.we_wordv[0][i]==' ' ) filestart[j++]='\\';
+                       filestart[j]=exp.we_wordv[0][i];
+               }
+               filestart[j]=0;
+
+               for(k=1; k<exp.we_wordc; k++)  // comment this block for 
first-completion
+                       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;

Reply via email to