* Alexander Polakov <[email protected]> [120120 01:11]:
> Sometimes I want to type something like "xterm -e top" in "exec" menu,
> and feel the need for tab completion.
And now a bigger thing on top of that. One can tab-complete command with
the first menu entry, once ready, just hit tab again and start typing
file path. It uses glob(3), so asterisks are allowed.
I think diff needs more work, posting now to get comments and check if
there's any interest in this.
Index: calmwm.h
===================================================================
RCS file: /cvs/xenocara/app/cwm/calmwm.h,v
retrieving revision 1.142
diff -u -p -r1.142 calmwm.h
--- calmwm.h 13 Sep 2011 08:41:57 -0000 1.142
+++ calmwm.h 22 Jan 2012 10:26:55 -0000
@@ -257,7 +257,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 +354,8 @@ void search_match_exec(struct
menu_q
char *);
void search_match_text(struct menu_q *, struct menu_q *,
char *);
+void search_match_path(struct menu_q *, struct menu_q *,
+ char *);
void search_print_client(struct menu *, int);
XineramaScreenInfo *screen_find_xinerama(struct screen_ctx *, int, int);
@@ -410,7 +412,7 @@ void mousefunc_window_raise(struct
cl
void mousefunc_window_resize(struct client_ctx *, void *);
struct menu *menu_filter(struct screen_ctx *, struct menu_q *,
- char *, char *, int,
+ char *, char *, int, int,
void (*)(struct menu_q *, struct menu_q *, char *),
void (*)(struct menu *, int));
void menu_init(struct screen_ctx *);
Index: group.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/group.c,v
retrieving revision 1.55
diff -u -p -r1.55 group.c
--- group.c 29 Dec 2011 20:48:38 -0000 1.55
+++ group.c 22 Jan 2012 10:26:55 -0000
@@ -395,7 +395,7 @@ group_menu(XButtonEvent *e)
if (TAILQ_EMPTY(&menuq))
return;
- mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
+ mi = menu_filter(sc, &menuq, NULL, NULL, 0, 0, NULL, NULL);
if (mi == NULL || mi->ctx == NULL)
goto cleanup;
Index: kbfunc.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/kbfunc.c,v
retrieving revision 1.58
diff -u -p -r1.58 kbfunc.c
--- kbfunc.c 29 Aug 2011 09:09:45 -0000 1.58
+++ kbfunc.c 22 Jan 2012 10:26:55 -0000
@@ -157,7 +157,7 @@ kbfunc_client_search(struct client_ctx *
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
- if ((mi = menu_filter(sc, &menuq, "window", NULL, 0,
+ if ((mi = menu_filter(sc, &menuq, "window", NULL, 0, 0,
search_match_client, search_print_client)) != NULL) {
cc = (struct client_ctx *)mi->ctx;
if (cc->flags & CLIENT_HIDDEN)
@@ -192,7 +192,7 @@ kbfunc_menu_search(struct client_ctx *cc
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
- if ((mi = menu_filter(sc, &menuq, "application", NULL, 0,
+ if ((mi = menu_filter(sc, &menuq, "application", NULL, 0, 0,
search_match_text, NULL)) != NULL)
u_spawn(((struct cmd *)mi->ctx)->image);
@@ -303,7 +303,7 @@ kbfunc_exec(struct client_ctx *cc, union
}
xfree(path);
- if ((mi = menu_filter(sc, &menuq, label, NULL, 1,
+ if ((mi = menu_filter(sc, &menuq, label, NULL, 1, 1,
search_match_exec, NULL)) != NULL) {
if (mi->text[0] == '\0')
goto out;
@@ -383,7 +383,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, 1, 0,
search_match_exec, NULL)) != NULL) {
if (mi->text[0] == '\0')
goto out;
@@ -410,7 +410,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, 1, 0,
search_match_text, NULL);
if (!mi->abort) {
Index: menu.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/menu.c,v
retrieving revision 1.33
diff -u -p -r1.33 menu.c
--- menu.c 8 Sep 2011 12:00:50 -0000 1.33
+++ menu.c 22 Jan 2012 10:26:55 -0000
@@ -37,10 +37,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];
@@ -53,6 +54,7 @@ struct menu_ctx {
int entry;
int width;
int num;
+ int filecomplete;
int x;
int y;
void (*match)(struct menu_q *, struct menu_q *, char *);
@@ -96,7 +98,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 dummy, int filecomplete,
void (*match)(struct menu_q *, struct menu_q *, char *),
void (*print)(struct menu *, int))
{
@@ -117,6 +119,8 @@ menu_filter(struct screen_ctx *sc, struc
xsave = mc.x;
ysave = mc.y;
+ mc.sc = sc;
+ mc.filecomplete = filecomplete;
if (prompt == NULL) {
evmask = MENUMASK;
mc.promptstr[0] = '\0';
@@ -202,13 +206,40 @@ out:
return (mi);
}
+static char *
+menu_complete_path(struct screen_ctx *sc, char *label, char *space)
+{
+ struct menu *mi;
+ struct menu_q menuq;
+ char *path = NULL;
+
+ TAILQ_INIT(&menuq);
+ if ((mi = menu_filter(sc, &menuq, label, space, 1, 0,
+ search_match_path, NULL)) != NULL) {
+ if (mi->text[0] == '\0')
+ goto out;
+ path = xcalloc(1, MAXPATHLEN);
+ path[0] = '"';
+ strlcpy(path+1, mi->text, MAXPATHLEN);
+ strlcat(path, "\"", MAXPATHLEN);
+ }
+out:
+ if (mi != NULL && mi->dummy)
+ xfree(mi);
+ while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
+ TAILQ_REMOVE(&menuq, mi, entry);
+ xfree(mi);
+ }
+ return path;
+}
+
static struct menu *
menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
struct menu_q *resultq)
{
struct menu *mi;
enum ctltype ctl;
- char chr;
+ char chr, *fcp, *sp;
size_t len;
if (menu_keycode(e->xkey.keycode, e->xkey.state, &ctl, &chr) < 0)
@@ -254,6 +285,40 @@ 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) {
+ if (strncmp(mc->searchstr, mi->text,
+ strlen(mi->text)) == 0) {
+ goto filecomplete;
+ }
+ (void)strlcpy(mc->searchstr,
+ mi->text, sizeof(mc->searchstr));
+ mc->changed = 1;
+ break;
+ }
+filecomplete:
+ if (mc->filecomplete && mc->searchstr[0] != '\0') {
+ mi = xcalloc(1, sizeof *mi);
+ sp = strrchr(mc->searchstr, ' ');
+ if (sp != NULL) {
+ strlcpy(mi->text, mc->searchstr, sp -
mc->searchstr + 1);
+ if (sp + 1 < mc->searchstr +
strlen(mc->searchstr)-1)
+ sp++;
+ else
+ sp = NULL;
+ } else
+ strlcpy(mi->text, mc->searchstr,
sizeof(mi->text));
+ fcp = menu_complete_path(mc->sc, mi->text, sp);
+ if (fcp) {
+ strlcat(mi->text, " ", sizeof(mi->text));
+ strlcat(mi->text, fcp, sizeof(mi->text));
+ xfree(fcp);
+ }
+ mi->dummy = 1;
+ return (mi);
+ }
+ mc->changed = 1;
+ /* FALLTHROUGH */
case CTL_ALL:
mc->list = !mc->list;
break;
@@ -475,6 +540,9 @@ menu_keycode(KeyCode kc, u_int state, en
break;
case XK_Return:
*ctl = CTL_RETURN;
+ break;
+ case XK_Tab:
+ *ctl = CTL_TAB;
break;
case XK_Up:
*ctl = CTL_UP;
Index: mousefunc.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/mousefunc.c,v
retrieving revision 1.34
diff -u -p -r1.34 mousefunc.c
--- mousefunc.c 17 Oct 2011 18:18:38 -0000 1.34
+++ mousefunc.c 22 Jan 2012 10:26:55 -0000
@@ -242,7 +242,7 @@ mousefunc_menu_unhide(struct client_ctx
if (TAILQ_EMPTY(&menuq))
return;
- mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
+ mi = menu_filter(sc, &menuq, NULL, NULL, 0, 0, NULL, NULL);
if (mi != NULL) {
cc = (struct client_ctx *)mi->ctx;
client_unhide(cc);
@@ -278,7 +278,7 @@ mousefunc_menu_cmd(struct client_ctx *cc
if (TAILQ_EMPTY(&menuq))
return;
- mi = menu_filter(sc, &menuq, NULL, NULL, 0, NULL, NULL);
+ mi = menu_filter(sc, &menuq, NULL, NULL, 0, 0, NULL, NULL);
if (mi != NULL)
u_spawn(((struct cmd *)mi->ctx)->image);
else
Index: search.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/search.c,v
retrieving revision 1.24
diff -u -p -r1.24 search.c
--- search.c 25 Jul 2011 15:10:24 -0000 1.24
+++ search.c 22 Jan 2012 10:26:55 -0000
@@ -29,6 +29,7 @@
#include <string.h>
#include <stdio.h>
#include <unistd.h>
+#include <glob.h>
#include "calmwm.h"
@@ -159,6 +160,31 @@ search_print_client(struct menu *mi, int
(void)snprintf(mi->print, sizeof(mi->print),
"%s:%.*s%s", buf, diff, cc->name, marker);
}
+}
+
+void
+search_match_path(struct menu_q *menuq, struct menu_q *resultq, char *search)
+{
+ struct menu *mi;
+ char pattern[MAXPATHLEN] = "*";
+ glob_t g;
+ int i;
+
+ TAILQ_INIT(resultq);
+
+ strlcpy(pattern, search, sizeof(pattern));
+ strlcat(pattern, "*", sizeof(pattern));
+
+ if (glob(pattern, GLOB_MARK, NULL, &g) != 0)
+ return;
+ for (i = 0; i < g.gl_matchc; i++) {
+ mi = xcalloc(1, sizeof(*mi));
+ (void)strlcpy(mi->text, g.gl_pathv[i],
+ sizeof(mi->text));
+ TAILQ_INSERT_TAIL(resultq, mi, resultentry);
+ TAILQ_INSERT_TAIL(menuq, mi, entry);
+ }
+ globfree(&g);
}
void
--
Alexander Polakov | plhk.ru