* Alexander Polakov <p...@sdf.org> [121107 02:20]:
> I think this one is ready for wider testing.
> 
> How to use: hit tab in exec menu to complete the command (start
> with / if you want something not in $PATH).  When you're ready,
> hit tab again.  This will open "file menu", which can be used to
> complete file argument.
> 
> Completion works for other menus as well.

Oops, sorry, I sent the wrong diff (previous revision).

Index: calmwm.h
===================================================================
RCS file: /cvs/xenocara/app/cwm/calmwm.h,v
retrieving revision 1.155
diff -u -p -u -r1.155 calmwm.h
--- calmwm.h    31 Oct 2012 22:06:24 -0000      1.155
+++ calmwm.h    7 Nov 2012 01:06:13 -0000
@@ -73,6 +73,10 @@
 #define CWM_RCYCLE             0x0002
 #define CWM_INGROUP            0x0004
 
+/* menu */
+#define CWM_MENU_DUMMY         0x0001
+#define CWM_MENU_FILE          0x0002
+
 #define KBTOGROUP(X) ((X) - 1)
 
 union arg {
@@ -260,7 +264,7 @@ TAILQ_HEAD(cmd_q, cmd);
 struct menu {
        TAILQ_ENTRY(menu)        entry;
        TAILQ_ENTRY(menu)        resultentry;
-#define MENU_MAXENTRY           50
+#define MENU_MAXENTRY           200
        char                     text[MENU_MAXENTRY + 1];
        char                     print[MENU_MAXENTRY + 1];
        void                    *ctx;
@@ -354,6 +358,10 @@ void                        group_update_names(struct 
screen
 void                    search_match_client(struct menu_q *, struct menu_q *,
                             char *);
 void                    search_match_exec(struct menu_q *, struct menu_q *,
+                            char *);
+void                    search_match_exec_path(struct menu_q *, struct menu_q 
*,
+                            char *);
+void                    search_match_path_any(struct menu_q *, struct menu_q *,
                             char *);
 void                    search_match_text(struct menu_q *, struct menu_q *,
                             char *);
Index: kbfunc.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/kbfunc.c,v
retrieving revision 1.64
diff -u -p -u -r1.64 kbfunc.c
--- kbfunc.c    31 Oct 2012 19:30:19 -0000      1.64
+++ kbfunc.c    7 Nov 2012 01:06:13 -0000
@@ -298,8 +298,9 @@ kbfunc_exec(struct client_ctx *cc, union
        }
        xfree(path);
 
-       if ((mi = menu_filter(sc, &menuq, label, NULL, 1,
-           search_match_exec, NULL)) != NULL) {
+       if ((mi = menu_filter(sc, &menuq, label, NULL,
+           CWM_MENU_DUMMY | CWM_MENU_FILE,
+           search_match_exec_path, NULL)) != NULL) {
                if (mi->text[0] == '\0')
                        goto out;
                switch (cmd) {
@@ -376,7 +377,7 @@ kbfunc_ssh(struct client_ctx *cc, union 
        xfree(lbuf);
        (void)fclose(fp);
 
-       if ((mi = menu_filter(sc, &menuq, "ssh", NULL, 1,
+       if ((mi = menu_filter(sc, &menuq, "ssh", NULL, CWM_MENU_DUMMY,
            search_match_exec, NULL)) != NULL) {
                if (mi->text[0] == '\0')
                        goto out;
@@ -403,7 +404,7 @@ kbfunc_client_label(struct client_ctx *c
        TAILQ_INIT(&menuq);
 
        /* dummy is set, so this will always return */
-       mi = menu_filter(cc->sc, &menuq, "label", cc->label, 1,
+       mi = menu_filter(cc->sc, &menuq, "label", cc->label, CWM_MENU_DUMMY,
            search_match_text, NULL);
 
        if (!mi->abort) {
Index: menu.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/menu.c,v
retrieving revision 1.41
diff -u -p -u -r1.41 menu.c
--- menu.c      31 Oct 2012 19:30:19 -0000      1.41
+++ menu.c      7 Nov 2012 01:06:13 -0000
@@ -28,6 +28,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <ctype.h>
 
 #include "calmwm.h"
 
@@ -37,10 +38,11 @@
 enum ctltype {
        CTL_NONE = -1,
        CTL_ERASEONE = 0, CTL_WIPE, CTL_UP, CTL_DOWN, CTL_RETURN,
-       CTL_ABORT, CTL_ALL
+       CTL_TAB, CTL_ABORT, CTL_ALL
 };
 
 struct menu_ctx {
+       struct screen_ctx       *sc;
        char                     searchstr[MENU_MAXENTRY + 1];
        char                     dispstr[MENU_MAXENTRY*2 + 1];
        char                     promptstr[MENU_MAXENTRY + 1];
@@ -54,6 +56,7 @@ struct menu_ctx {
        int                      height;
        int                      width;
        int                      num;
+       int                      flags;
        int                      x;
        int                      y;
        void (*match)(struct menu_q *, struct menu_q *, char *);
@@ -93,7 +96,7 @@ menu_init(struct screen_ctx *sc)
 
 struct menu *
 menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt,
-    char *initial, int dummy,
+    char *initial, int flags, 
     void (*match)(struct menu_q *, struct menu_q *, char *),
     void (*print)(struct menu *, int))
 {
@@ -114,6 +117,8 @@ menu_filter(struct screen_ctx *sc, struc
        xsave = mc.x;
        ysave = mc.y;
 
+       mc.sc = sc;
+       mc.flags = flags;
        if (prompt == NULL) {
                evmask = MENUMASK;
                mc.promptstr[0] = '\0';
@@ -181,7 +186,8 @@ menu_filter(struct screen_ctx *sc, struc
                }
        }
 out:
-       if (dummy == 0 && mi->dummy) { /* no mouse based match */
+       if ((mc.flags & CWM_MENU_DUMMY) == 0 && mi->dummy) {
+               /* no mouse based match */
                xfree(mi);
                mi = NULL;
        }
@@ -200,6 +206,38 @@ out:
 }
 
 static struct menu *
+menu_complete_path(struct menu_ctx *mc)
+{
+       struct menu             *mi, *mr;
+       struct menu_q            menuq;
+       char *path = NULL;
+
+       path = xcalloc(1, sizeof(mr->text));
+       mr = xcalloc(1, sizeof(*mr));
+
+       TAILQ_INIT(&menuq);
+       if ((mi = menu_filter(mc->sc, &menuq, mc->searchstr, NULL,
+           CWM_MENU_DUMMY, search_match_path_any, NULL)) != NULL) {
+               mr->abort = mi->abort;
+               mr->dummy = mi->dummy;
+               strlcpy(path, mi->text, sizeof(mi->text));
+       }
+       
+       while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
+               TAILQ_REMOVE(&menuq, mi, entry);
+               xfree(mi);
+       }
+
+       if (path[0] != '\0') 
+               snprintf(mr->text, sizeof(mr->text), "%s \"%s\"",
+                       mc->searchstr, path);
+       else if (!mr->abort)
+               strlcpy(mr->text,  mc->searchstr, sizeof(mr->text));
+       xfree(path);
+       return (mr);
+}
+
+static struct menu *
 menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
     struct menu_q *resultq)
 {
@@ -257,6 +295,35 @@ menu_handle_key(XEvent *e, struct menu_c
                mc->searchstr[0] = '\0';
                mc->changed = 1;
                break;
+       case CTL_TAB:
+               if ((mi = TAILQ_FIRST(resultq)) != NULL) {
+                       /* 
+                        * - We are in exec_path menu mode
+                        * - There's only one result
+                        * - It is equal to the input
+                        * We got a command, launch the file menu
+                        */
+                       if ((mc->flags & CWM_MENU_FILE) &&
+                           (TAILQ_NEXT(mi, resultentry) == NULL) &&
+                           (strncmp(mc->searchstr, mi->text,
+                                       strlen(mi->text))) == 0)
+                               return (menu_complete_path(mc));
+
+                       /* 
+                        * Put common prefix of the results into searchstr
+                        */
+                       (void)strlcpy(mc->searchstr,
+                                       mi->text, sizeof(mc->searchstr));
+                       while ((mi = TAILQ_NEXT(mi, resultentry)) != NULL) {
+                               i = 0;
+                               while (tolower(mc->searchstr[i]) ==
+                                              tolower(mi->text[i]))
+                                       i++;
+                               mc->searchstr[i] = '\0';
+                       }
+                       mc->changed = 1;
+               }
+               break;
        case CTL_ALL:
                mc->list = !mc->list;
                break;
@@ -483,6 +550,9 @@ menu_keycode(XKeyEvent *ev, enum ctltype
                break;
        case XK_Return:
                *ctl = CTL_RETURN;
+               break;
+       case XK_Tab:
+               *ctl = CTL_TAB;
                break;
        case XK_Up:
                *ctl = CTL_UP;
Index: search.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/search.c,v
retrieving revision 1.24
diff -u -p -u -r1.24 search.c
--- search.c    25 Jul 2011 15:10:24 -0000      1.24
+++ search.c    7 Nov 2012 01:06:13 -0000
@@ -29,9 +29,12 @@
 #include <string.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <glob.h>
 
 #include "calmwm.h"
 
+#define PATH_EXEC      0x1
+
 static int     strsubmatch(char *, char *, int);
 
 /*
@@ -161,6 +164,43 @@ search_print_client(struct menu *mi, int
        }
 }
 
+static void
+search_match_path(struct menu_q *menuq, struct menu_q *resultq, char *search, 
int flag)
+{
+       struct menu     *mi;
+       char             pattern[MAXPATHLEN];
+       glob_t           g;
+       int              i;
+
+       TAILQ_INIT(resultq);
+
+       (void)strlcpy(pattern, search, sizeof(pattern));
+       (void)strlcat(pattern, "*", sizeof(pattern));
+
+       if (glob(pattern, GLOB_MARK, NULL, &g) != 0)
+               return;
+       for (i = 0; i < g.gl_pathc; i++) {
+               if ((flag & PATH_EXEC) && access(g.gl_pathv[i], X_OK))
+                       continue;
+               mi = xcalloc(1, sizeof(*mi));
+               (void)strlcpy(mi->text, g.gl_pathv[i], sizeof(mi->text));
+               TAILQ_INSERT_TAIL(resultq, mi, resultentry);
+       }
+       globfree(&g);
+}
+
+void 
+search_match_path_exec(struct menu_q *menuq, struct menu_q *resultq, char 
*search)
+{
+       return (search_match_path(menuq, resultq, search, PATH_EXEC));
+}
+
+void 
+search_match_path_any(struct menu_q *menuq, struct menu_q *resultq, char 
*search)
+{
+       return (search_match_path(menuq, resultq, search, 0));
+}
+
 void
 search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
 {
@@ -194,6 +234,14 @@ search_match_exec(struct menu_q *menuq, 
                if (mj == NULL)
                        TAILQ_INSERT_TAIL(resultq, mi, resultentry);
        }
+}
+
+void
+search_match_exec_path(struct menu_q *menuq, struct menu_q *resultq, char 
*search)
+{
+       search_match_exec(menuq, resultq, search);
+       if (TAILQ_EMPTY(resultq))
+               search_match_path_exec(menuq, resultq, search);
 }
 
 static int
-- 
Alexander Polakov | plhk.ru

Reply via email to