mirror of
https://github.com/leahneukirchen/cwm.git
synced 2023-08-10 21:13:12 +03:00
modify "exec" dialog so that it auto-completes based on executables in
_PATH_DEFPATH add an "ssh-to" dialog which auto-completes based on contents of ~/.ssh/known_hosts (M-.) testing and eyeballing by Simon Kuhnle <simonkuhnle at web.de>, todd@, pedro@ mk@ and David Cathcart <david at cathcart.cx> ok todd@
This commit is contained in:
parent
80d08270b8
commit
a1d4169eb3
5
calmwm.h
5
calmwm.h
|
@ -257,6 +257,7 @@ struct menu {
|
|||
char print[MENU_MAXENTRY + 1];
|
||||
void *ctx;
|
||||
short lasthit;
|
||||
short dummy;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(menu_q, menu);
|
||||
|
@ -427,6 +428,7 @@ void kbfunc_client_maximize(struct client_ctx *, void *);
|
|||
void kbfunc_client_vmaximize(struct client_ctx *, void *);
|
||||
void kbfunc_menu_search(struct client_ctx *, void *);
|
||||
void kbfunc_exec(struct client_ctx *, void *);
|
||||
void kbfunc_ssh(struct client_ctx *, void *);
|
||||
void kbfunc_term(struct client_ctx *cc, void *arg);
|
||||
void kbfunc_lock(struct client_ctx *cc, void *arg);
|
||||
|
||||
|
@ -437,10 +439,11 @@ struct menu *search_start(struct menu_q *menuq,
|
|||
void (*match)(struct menu_q *, struct menu_q *, char *),
|
||||
void (*rank)(struct menu_q *, char *),
|
||||
void (*print)(struct menu *mi, int),
|
||||
char *);
|
||||
char *, int);
|
||||
void search_match_client(struct menu_q *, struct menu_q *, char *);
|
||||
void search_print_client(struct menu *mi, int list);
|
||||
void search_match_text(struct menu_q *, struct menu_q *, char *);
|
||||
void search_match_exec(struct menu_q *, struct menu_q *, char *);
|
||||
void search_rank_text(struct menu_q *, char *);
|
||||
|
||||
void group_init(void);
|
||||
|
|
1
conf.c
1
conf.c
|
@ -189,6 +189,7 @@ conf_setup(struct conf *c)
|
|||
conf_bindkey(c, kbfunc_lock,
|
||||
XK_Delete, ControlMask|Mod1Mask, 0, NULL);
|
||||
conf_bindkey(c, kbfunc_exec, XK_question, Mod1Mask, 0, NULL);
|
||||
conf_bindkey(c, kbfunc_ssh, XK_period, Mod1Mask, 0, NULL);
|
||||
conf_bindkey(c, kbfunc_client_hide,
|
||||
XK_Return, Mod1Mask, KBFLAG_NEEDCLIENT, 0);
|
||||
conf_bindkey(c, kbfunc_client_lower,
|
||||
|
|
4
cwm.1
4
cwm.1
|
@ -87,6 +87,10 @@ Toggle full-screen size of window.
|
|||
Toggle vertical maximization of window.
|
||||
.It Fa M-?
|
||||
Spawn \&"Exec program\&" dialog.
|
||||
.It Fa M-.
|
||||
Spawn \&"Ssh to\&" dialog.
|
||||
This parses your $HOME/.ssh/known_hosts file to provide host auto-completion.
|
||||
Ssh will be executed via the configured terminal emulator.
|
||||
.El
|
||||
.Pp
|
||||
The mouse bindings are also important, they are:
|
||||
|
|
154
kbfunc.c
154
kbfunc.c
|
@ -7,9 +7,14 @@
|
|||
* $Id$
|
||||
*/
|
||||
|
||||
#include <paths.h>
|
||||
|
||||
#include "headers.h"
|
||||
#include "calmwm.h"
|
||||
|
||||
#define KNOWN_HOSTS ".ssh/known_hosts"
|
||||
#define HASH_MARKER "|1|"
|
||||
|
||||
void
|
||||
kbfunc_client_lower(struct client_ctx *cc, void *arg)
|
||||
{
|
||||
|
@ -41,7 +46,7 @@ kbfunc_client_search(struct client_ctx *scratch, void *arg)
|
|||
|
||||
if ((mi = search_start(&menuq,
|
||||
search_match_client, NULL,
|
||||
search_print_client, "window")) != NULL) {
|
||||
search_print_client, "window", 0)) != NULL) {
|
||||
cc = (struct client_ctx *)mi->ctx;
|
||||
if (cc->flags & CLIENT_HIDDEN)
|
||||
client_unhide(cc);
|
||||
|
@ -75,7 +80,7 @@ kbfunc_menu_search(struct client_ctx *scratch, void *arg)
|
|||
}
|
||||
|
||||
if ((mi = search_start(&menuq,
|
||||
search_match_text, NULL, NULL, "application")) != NULL)
|
||||
search_match_text, NULL, NULL, "application", 0)) != NULL)
|
||||
u_spawn(((struct cmd *)mi->ctx)->image);
|
||||
|
||||
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
|
||||
|
@ -125,7 +130,150 @@ kbfunc_lock(struct client_ctx *cc, void *arg)
|
|||
void
|
||||
kbfunc_exec(struct client_ctx *scratch, void *arg)
|
||||
{
|
||||
grab_exec();
|
||||
char **ap, *paths[256], *path, tpath[MAXPATHLEN];
|
||||
int l, i, j, ngroups;
|
||||
gid_t mygroups[NGROUPS_MAX];
|
||||
uid_t ruid, euid, suid;
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
struct stat sb;
|
||||
struct menu_q menuq;
|
||||
struct menu *mi;
|
||||
|
||||
if (getgroups(0, mygroups) == -1)
|
||||
err(1, "getgroups failure");
|
||||
if ((ngroups = getresuid(&ruid, &euid, &suid)) == -1)
|
||||
err(1, "getresuid failure");
|
||||
|
||||
TAILQ_INIT(&menuq);
|
||||
/* just use default path until we have config to set this */
|
||||
path = xstrdup(_PATH_DEFPATH);
|
||||
for (ap = paths; ap < &paths[sizeof(paths) - 1] &&
|
||||
(*ap = strsep(&path, ":")) != NULL;) {
|
||||
if (**ap != '\0')
|
||||
ap++;
|
||||
}
|
||||
*ap = NULL;
|
||||
for (i = 0; i < sizeof(paths) && paths[i] != NULL; i++) {
|
||||
if ((dirp = opendir(paths[i])) == NULL)
|
||||
continue;
|
||||
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
/* skip everything but regular files and symlinks */
|
||||
if (dp->d_type != DT_REG && dp->d_type != DT_LNK)
|
||||
continue;
|
||||
memset(tpath, '\0', sizeof(tpath));
|
||||
l = snprintf(tpath, sizeof(tpath), "%s/%s", paths[i],
|
||||
dp->d_name);
|
||||
/* check for truncation etc */
|
||||
if (l == -1 || l >= (int)sizeof(tpath))
|
||||
continue;
|
||||
/* just ignore on stat failure */
|
||||
if (stat(tpath, &sb) == -1)
|
||||
continue;
|
||||
/* may we execute this file? */
|
||||
if (euid == sb.st_uid)
|
||||
if (sb.st_mode & S_IXUSR)
|
||||
goto executable;
|
||||
else
|
||||
continue;
|
||||
for (j = 0; j < ngroups; j++)
|
||||
if (mygroups[j] == sb.st_gid)
|
||||
if (sb.st_mode & S_IXGRP)
|
||||
goto executable;
|
||||
else
|
||||
continue;
|
||||
if (sb.st_mode & S_IXOTH)
|
||||
goto executable;
|
||||
continue;
|
||||
executable:
|
||||
/* the thing in tpath, we may execute */
|
||||
XCALLOC(mi, struct menu);
|
||||
strlcpy(mi->text, dp->d_name, sizeof(mi->text));
|
||||
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
||||
}
|
||||
(void) closedir(dirp);
|
||||
}
|
||||
|
||||
if ((mi = search_start(&menuq,
|
||||
search_match_exec, NULL, NULL, "exec", 1)) != NULL)
|
||||
u_spawn(mi->text);
|
||||
|
||||
if (mi != NULL && mi->dummy)
|
||||
xfree(mi);
|
||||
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
|
||||
TAILQ_REMOVE(&menuq, mi, entry);
|
||||
xfree(mi);
|
||||
}
|
||||
xfree(path);
|
||||
}
|
||||
|
||||
void
|
||||
kbfunc_ssh(struct client_ctx *scratch, void *arg)
|
||||
{
|
||||
struct menu_q menuq;
|
||||
struct menu *mi;
|
||||
FILE *fp;
|
||||
size_t len;
|
||||
char *buf, *lbuf, *p, *home;
|
||||
char hostbuf[MAXHOSTNAMELEN], filename[MAXPATHLEN], cmd[256];
|
||||
int l;
|
||||
|
||||
if ((home = getenv("HOME")) == NULL)
|
||||
return;
|
||||
|
||||
l = snprintf(filename, sizeof(filename), "%s/%s", home, KNOWN_HOSTS);
|
||||
if (l == -1 || l >= sizeof(filename))
|
||||
return;
|
||||
|
||||
if ((fp = fopen(filename, "r")) == NULL)
|
||||
return;
|
||||
|
||||
TAILQ_INIT(&menuq);
|
||||
lbuf = NULL;
|
||||
while ((buf = fgetln(fp, &len))) {
|
||||
if (buf[len - 1] == '\n')
|
||||
buf[len - 1] = '\0';
|
||||
else {
|
||||
/* EOF without EOL, copy and add the NUL */
|
||||
lbuf = xmalloc(len + 1);
|
||||
memcpy(lbuf, buf, len);
|
||||
lbuf[len] = '\0';
|
||||
buf = lbuf;
|
||||
}
|
||||
/* skip hashed hosts */
|
||||
if (strncmp(buf, HASH_MARKER, strlen(HASH_MARKER)) == 0)
|
||||
continue;
|
||||
for (p = buf; *p != ',' && *p != ' ' && p != buf + len; p++) {
|
||||
/* do nothing */
|
||||
}
|
||||
/* ignore badness */
|
||||
if (p - buf + 1 > sizeof(hostbuf))
|
||||
continue;
|
||||
(void) strlcpy(hostbuf, buf, p - buf + 1);
|
||||
XCALLOC(mi, struct menu);
|
||||
(void) strlcpy(mi->text, hostbuf, sizeof(mi->text));
|
||||
TAILQ_INSERT_TAIL(&menuq, mi, entry);
|
||||
}
|
||||
xfree(lbuf);
|
||||
fclose(fp);
|
||||
|
||||
|
||||
if ((mi = search_start(&menuq,
|
||||
search_match_exec, NULL, NULL, "ssh", 1)) != NULL) {
|
||||
conf_cmd_refresh(&Conf);
|
||||
l = snprintf(cmd, sizeof(cmd), "%s -e ssh %s", Conf.termpath,
|
||||
mi->text);
|
||||
if (l != -1 && l < sizeof(cmd))
|
||||
u_spawn(cmd);
|
||||
}
|
||||
|
||||
if (mi != NULL && mi->dummy)
|
||||
xfree(mi);
|
||||
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
|
||||
TAILQ_REMOVE(&menuq, mi, entry);
|
||||
xfree(mi);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
49
search.c
49
search.c
|
@ -12,7 +12,7 @@
|
|||
|
||||
#define SearchMask (KeyPressMask|ExposureMask)
|
||||
|
||||
static int _strsubmatch(char *, char *);
|
||||
static int _strsubmatch(char *, char *, int);
|
||||
|
||||
void
|
||||
search_init(struct screen_ctx *sc)
|
||||
|
@ -37,7 +37,7 @@ search_start(struct menu_q *menuq,
|
|||
void (*match)(struct menu_q *, struct menu_q *, char *),
|
||||
void (*rank)(struct menu_q *resultq, char *search),
|
||||
void (*print)(struct menu *mi, int print),
|
||||
char *prompt)
|
||||
char *prompt, int dummy)
|
||||
{
|
||||
struct screen_ctx *sc = screen_current();
|
||||
int x, y, dx, dy, fontheight,
|
||||
|
@ -47,7 +47,7 @@ search_start(struct menu_q *menuq,
|
|||
char dispstr[MENU_MAXENTRY*2 + 1];
|
||||
char promptstr[MENU_MAXENTRY + 1];
|
||||
Window focuswin;
|
||||
struct menu *mi = NULL;
|
||||
struct menu *mi = NULL, *dummy_mi = NULL;
|
||||
struct menu_q resultq;
|
||||
char chr;
|
||||
enum ctltype ctl;
|
||||
|
@ -133,9 +133,15 @@ search_start(struct menu_q *menuq,
|
|||
case CTL_RETURN:
|
||||
/* This is just picking the match the
|
||||
* cursor is over. */
|
||||
if ((mi = TAILQ_FIRST(&resultq)) != NULL)
|
||||
if ((mi = TAILQ_FIRST(&resultq)) != NULL) {
|
||||
goto found;
|
||||
else
|
||||
} else if (dummy) {
|
||||
dummy_mi = xmalloc(sizeof *dummy_mi);
|
||||
(void) strlcpy(dummy_mi->text,
|
||||
searchstr, sizeof(dummy_mi->text));
|
||||
dummy_mi->dummy = 1;
|
||||
goto found;
|
||||
}
|
||||
goto out;
|
||||
case CTL_WIPE:
|
||||
searchstr[0] = '\0';
|
||||
|
@ -273,9 +279,12 @@ out:
|
|||
/* (if no match) */
|
||||
xu_ptr_ungrab();
|
||||
XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
|
||||
|
||||
found:
|
||||
XUnmapWindow(X_Dpy, sc->searchwin);
|
||||
|
||||
if (dummy && dummy_mi != NULL)
|
||||
return (dummy_mi);
|
||||
return (mi);
|
||||
}
|
||||
|
||||
|
@ -307,7 +316,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
|||
struct client_ctx *cc = mi->ctx;
|
||||
|
||||
/* First, try to match on labels. */
|
||||
if (cc->label != NULL && _strsubmatch(search, cc->label)) {
|
||||
if (cc->label != NULL && _strsubmatch(search, cc->label, 0)) {
|
||||
cc->matchname = cc->label;
|
||||
tier = 0;
|
||||
}
|
||||
|
@ -315,7 +324,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
|||
/* Then, on window names. */
|
||||
if (tier < 0) {
|
||||
TAILQ_FOREACH_REVERSE(wn, &cc->nameq, winname_q, entry)
|
||||
if (_strsubmatch(search, wn->name)) {
|
||||
if (_strsubmatch(search, wn->name, 0)) {
|
||||
cc->matchname = wn->name;
|
||||
tier = 2;
|
||||
break;
|
||||
|
@ -327,7 +336,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
|||
* name.
|
||||
*/
|
||||
|
||||
if (tier < 0 && _strsubmatch(search, cc->app_class)) {
|
||||
if (tier < 0 && _strsubmatch(search, cc->app_class, 0)) {
|
||||
cc->matchname = cc->app_class;
|
||||
tier = 3;
|
||||
}
|
||||
|
@ -417,7 +426,19 @@ search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
|||
TAILQ_INIT(resultq);
|
||||
|
||||
TAILQ_FOREACH(mi, menuq, entry)
|
||||
if (_strsubmatch(search, mi->text))
|
||||
if (_strsubmatch(search, mi->text, 0))
|
||||
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
|
||||
}
|
||||
|
||||
void
|
||||
search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
|
||||
{
|
||||
struct menu *mi;
|
||||
|
||||
TAILQ_INIT(resultq);
|
||||
|
||||
TAILQ_FOREACH(mi, menuq, entry)
|
||||
if (_strsubmatch(search, mi->text, 1))
|
||||
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
|
||||
}
|
||||
|
||||
|
@ -428,10 +449,10 @@ search_rank_text(struct menu_q *resultq, char *search)
|
|||
}
|
||||
|
||||
static int
|
||||
_strsubmatch(char *sub, char *str)
|
||||
_strsubmatch(char *sub, char *str, int zeroidx)
|
||||
{
|
||||
size_t len, sublen;
|
||||
u_int n;
|
||||
u_int n, flen;
|
||||
|
||||
if (sub == NULL || str == NULL)
|
||||
return (0);
|
||||
|
@ -442,7 +463,11 @@ _strsubmatch(char *sub, char *str)
|
|||
if (sublen > len)
|
||||
return (0);
|
||||
|
||||
for (n = 0; n <= len - sublen; n++)
|
||||
if (!zeroidx)
|
||||
flen = len - sublen;
|
||||
else
|
||||
flen = 0;
|
||||
for (n = 0; n <= flen; n++)
|
||||
if (strncasecmp(sub, str + n, sublen) == 0)
|
||||
return (1);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user