mirror of
https://github.com/leahneukirchen/cwm.git
synced 2023-08-10 21:13:12 +03:00
tab completion support for menus; from Alexander Polakov.
ok sthen@ on an older incarnation
This commit is contained in:
parent
dabc05034f
commit
4b84287d19
10
calmwm.h
10
calmwm.h
@ -73,6 +73,10 @@
|
|||||||
#define CWM_RCYCLE 0x0002
|
#define CWM_RCYCLE 0x0002
|
||||||
#define CWM_INGROUP 0x0004
|
#define CWM_INGROUP 0x0004
|
||||||
|
|
||||||
|
/* menu */
|
||||||
|
#define CWM_MENU_DUMMY 0x0001
|
||||||
|
#define CWM_MENU_FILE 0x0002
|
||||||
|
|
||||||
#define KBTOGROUP(X) ((X) - 1)
|
#define KBTOGROUP(X) ((X) - 1)
|
||||||
|
|
||||||
union arg {
|
union arg {
|
||||||
@ -260,7 +264,7 @@ TAILQ_HEAD(cmd_q, cmd);
|
|||||||
struct menu {
|
struct menu {
|
||||||
TAILQ_ENTRY(menu) entry;
|
TAILQ_ENTRY(menu) entry;
|
||||||
TAILQ_ENTRY(menu) resultentry;
|
TAILQ_ENTRY(menu) resultentry;
|
||||||
#define MENU_MAXENTRY 50
|
#define MENU_MAXENTRY 200
|
||||||
char text[MENU_MAXENTRY + 1];
|
char text[MENU_MAXENTRY + 1];
|
||||||
char print[MENU_MAXENTRY + 1];
|
char print[MENU_MAXENTRY + 1];
|
||||||
void *ctx;
|
void *ctx;
|
||||||
@ -355,6 +359,10 @@ void search_match_client(struct menu_q *, struct menu_q *,
|
|||||||
char *);
|
char *);
|
||||||
void search_match_exec(struct menu_q *, struct menu_q *,
|
void search_match_exec(struct menu_q *, struct menu_q *,
|
||||||
char *);
|
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 *,
|
void search_match_text(struct menu_q *, struct menu_q *,
|
||||||
char *);
|
char *);
|
||||||
void search_print_client(struct menu *, int);
|
void search_print_client(struct menu *, int);
|
||||||
|
9
kbfunc.c
9
kbfunc.c
@ -298,8 +298,9 @@ kbfunc_exec(struct client_ctx *cc, union arg *arg)
|
|||||||
}
|
}
|
||||||
xfree(path);
|
xfree(path);
|
||||||
|
|
||||||
if ((mi = menu_filter(sc, &menuq, label, NULL, 1,
|
if ((mi = menu_filter(sc, &menuq, label, NULL,
|
||||||
search_match_exec, NULL)) != NULL) {
|
CWM_MENU_DUMMY | CWM_MENU_FILE,
|
||||||
|
search_match_exec_path, NULL)) != NULL) {
|
||||||
if (mi->text[0] == '\0')
|
if (mi->text[0] == '\0')
|
||||||
goto out;
|
goto out;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
@ -376,7 +377,7 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg)
|
|||||||
xfree(lbuf);
|
xfree(lbuf);
|
||||||
(void)fclose(fp);
|
(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) {
|
search_match_exec, NULL)) != NULL) {
|
||||||
if (mi->text[0] == '\0')
|
if (mi->text[0] == '\0')
|
||||||
goto out;
|
goto out;
|
||||||
@ -403,7 +404,7 @@ kbfunc_client_label(struct client_ctx *cc, union arg *arg)
|
|||||||
TAILQ_INIT(&menuq);
|
TAILQ_INIT(&menuq);
|
||||||
|
|
||||||
/* dummy is set, so this will always return */
|
/* 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);
|
search_match_text, NULL);
|
||||||
|
|
||||||
if (!mi->abort) {
|
if (!mi->abort) {
|
||||||
|
76
menu.c
76
menu.c
@ -28,6 +28,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "calmwm.h"
|
#include "calmwm.h"
|
||||||
|
|
||||||
@ -37,10 +38,11 @@
|
|||||||
enum ctltype {
|
enum ctltype {
|
||||||
CTL_NONE = -1,
|
CTL_NONE = -1,
|
||||||
CTL_ERASEONE = 0, CTL_WIPE, CTL_UP, CTL_DOWN, CTL_RETURN,
|
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 menu_ctx {
|
||||||
|
struct screen_ctx *sc;
|
||||||
char searchstr[MENU_MAXENTRY + 1];
|
char searchstr[MENU_MAXENTRY + 1];
|
||||||
char dispstr[MENU_MAXENTRY*2 + 1];
|
char dispstr[MENU_MAXENTRY*2 + 1];
|
||||||
char promptstr[MENU_MAXENTRY + 1];
|
char promptstr[MENU_MAXENTRY + 1];
|
||||||
@ -54,6 +56,7 @@ struct menu_ctx {
|
|||||||
int height;
|
int height;
|
||||||
int width;
|
int width;
|
||||||
int num;
|
int num;
|
||||||
|
int flags;
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
void (*match)(struct menu_q *, struct menu_q *, char *);
|
void (*match)(struct menu_q *, struct menu_q *, char *);
|
||||||
@ -93,7 +96,7 @@ menu_init(struct screen_ctx *sc)
|
|||||||
|
|
||||||
struct menu *
|
struct menu *
|
||||||
menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt,
|
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 (*match)(struct menu_q *, struct menu_q *, char *),
|
||||||
void (*print)(struct menu *, int))
|
void (*print)(struct menu *, int))
|
||||||
{
|
{
|
||||||
@ -114,6 +117,8 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt,
|
|||||||
xsave = mc.x;
|
xsave = mc.x;
|
||||||
ysave = mc.y;
|
ysave = mc.y;
|
||||||
|
|
||||||
|
mc.sc = sc;
|
||||||
|
mc.flags = flags;
|
||||||
if (prompt == NULL) {
|
if (prompt == NULL) {
|
||||||
evmask = MENUMASK;
|
evmask = MENUMASK;
|
||||||
mc.promptstr[0] = '\0';
|
mc.promptstr[0] = '\0';
|
||||||
@ -181,7 +186,8 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
out:
|
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);
|
xfree(mi);
|
||||||
mi = NULL;
|
mi = NULL;
|
||||||
}
|
}
|
||||||
@ -199,6 +205,38 @@ out:
|
|||||||
return (mi);
|
return (mi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 *
|
static struct menu *
|
||||||
menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
|
menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
|
||||||
struct menu_q *resultq)
|
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->searchstr[0] = '\0';
|
||||||
mc->changed = 1;
|
mc->changed = 1;
|
||||||
break;
|
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:
|
case CTL_ALL:
|
||||||
mc->list = !mc->list;
|
mc->list = !mc->list;
|
||||||
break;
|
break;
|
||||||
@ -484,6 +551,9 @@ menu_keycode(XKeyEvent *ev, enum ctltype *ctl, char *chr)
|
|||||||
case XK_Return:
|
case XK_Return:
|
||||||
*ctl = CTL_RETURN;
|
*ctl = CTL_RETURN;
|
||||||
break;
|
break;
|
||||||
|
case XK_Tab:
|
||||||
|
*ctl = CTL_TAB;
|
||||||
|
break;
|
||||||
case XK_Up:
|
case XK_Up:
|
||||||
*ctl = CTL_UP;
|
*ctl = CTL_UP;
|
||||||
break;
|
break;
|
||||||
|
48
search.c
48
search.c
@ -29,9 +29,12 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <glob.h>
|
||||||
|
|
||||||
#include "calmwm.h"
|
#include "calmwm.h"
|
||||||
|
|
||||||
|
#define PATH_EXEC 0x1
|
||||||
|
|
||||||
static int strsubmatch(char *, char *, int);
|
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
|
void
|
||||||
search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
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
|
static int
|
||||||
strsubmatch(char *sub, char *str, int zeroidx)
|
strsubmatch(char *sub, char *str, int zeroidx)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user