summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorOkan Demirmen <okan@cvs.openbsd.org>2012-11-07 14:39:45 +0000
committerOkan Demirmen <okan@cvs.openbsd.org>2012-11-07 14:39:45 +0000
commite9a590b3712bd04c3c5ef14960f7d5da4fe7fc54 (patch)
treec2dcc93d5eedb68e1745e4b0c415804807831132 /app
parent09763e3a81ded077d0cac79b0d55d07f24c44a8a (diff)
tab completion support for menus; from Alexander Polakov.
ok sthen@ on an older incarnation
Diffstat (limited to 'app')
-rw-r--r--app/cwm/calmwm.h12
-rw-r--r--app/cwm/kbfunc.c11
-rw-r--r--app/cwm/menu.c78
-rw-r--r--app/cwm/search.c50
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)
{