diff options
author | Okan Demirmen <okan@cvs.openbsd.org> | 2012-11-07 14:39:45 +0000 |
---|---|---|
committer | Okan Demirmen <okan@cvs.openbsd.org> | 2012-11-07 14:39:45 +0000 |
commit | e9a590b3712bd04c3c5ef14960f7d5da4fe7fc54 (patch) | |
tree | c2dcc93d5eedb68e1745e4b0c415804807831132 | |
parent | 09763e3a81ded077d0cac79b0d55d07f24c44a8a (diff) |
tab completion support for menus; from Alexander Polakov.
ok sthen@ on an older incarnation
-rw-r--r-- | app/cwm/calmwm.h | 12 | ||||
-rw-r--r-- | app/cwm/kbfunc.c | 11 | ||||
-rw-r--r-- | app/cwm/menu.c | 78 | ||||
-rw-r--r-- | app/cwm/search.c | 50 |
4 files changed, 139 insertions, 12 deletions
diff --git a/app/cwm/calmwm.h b/app/cwm/calmwm.h index dafc935c1..8dab66a96 100644 --- a/app/cwm/calmwm.h +++ b/app/cwm/calmwm.h @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $OpenBSD: calmwm.h,v 1.155 2012/10/31 22:06:24 okan Exp $ + * $OpenBSD: calmwm.h,v 1.156 2012/11/07 14:39:44 okan Exp $ */ #ifndef _CALMWM_H_ @@ -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; @@ -355,6 +359,10 @@ 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 *); void search_print_client(struct menu *, int); diff --git a/app/cwm/kbfunc.c b/app/cwm/kbfunc.c index 67f7a21ae..90d6aa0e3 100644 --- a/app/cwm/kbfunc.c +++ b/app/cwm/kbfunc.c @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $OpenBSD: kbfunc.c,v 1.64 2012/10/31 19:30:19 okan Exp $ + * $OpenBSD: kbfunc.c,v 1.65 2012/11/07 14:39:44 okan Exp $ */ #include <sys/param.h> @@ -298,8 +298,9 @@ kbfunc_exec(struct client_ctx *cc, union arg *arg) } 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 arg *arg) 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 *cc, union arg *arg) 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) { diff --git a/app/cwm/menu.c b/app/cwm/menu.c index 568727f67..72ae3ebcc 100644 --- a/app/cwm/menu.c +++ b/app/cwm/menu.c @@ -16,7 +16,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $OpenBSD: menu.c,v 1.41 2012/10/31 19:30:19 okan Exp $ + * $OpenBSD: menu.c,v 1.42 2012/11/07 14:39:44 okan Exp $ */ #include <sys/param.h> @@ -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, struct menu_q *menuq, char *prompt, 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, struct menu_q *menuq, char *prompt, } } 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_ctx *mc, struct menu_q *menuq, 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; @@ -484,6 +551,9 @@ menu_keycode(XKeyEvent *ev, enum ctltype *ctl, char *chr) case XK_Return: *ctl = CTL_RETURN; break; + case XK_Tab: + *ctl = CTL_TAB; + break; case XK_Up: *ctl = CTL_UP; break; diff --git a/app/cwm/search.c b/app/cwm/search.c index 9db2f706f..33b4ec64c 100644 --- a/app/cwm/search.c +++ b/app/cwm/search.c @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $OpenBSD: search.c,v 1.24 2011/07/25 15:10:24 okan Exp $ + * $OpenBSD: search.c,v 1.25 2012/11/07 14:39:44 okan Exp $ */ #include <sys/param.h> @@ -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 list) } } +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) { @@ -196,6 +236,14 @@ search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search) } } +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 strsubmatch(char *sub, char *str, int zeroidx) { |