cwm/search.c

267 lines
6.2 KiB
C
Raw Normal View History

2007-04-27 21:58:48 +04:00
/*
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
2011-05-11 17:53:51 +04:00
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2007-04-27 21:58:48 +04:00
*
2011-05-11 17:53:51 +04:00
* $OpenBSD$
2007-04-27 21:58:48 +04:00
*/
#include <sys/types.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <fnmatch.h>
2012-11-09 07:52:02 +04:00
#include <glob.h>
#include <limits.h>
2012-11-09 07:52:02 +04:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
2007-04-27 21:58:48 +04:00
#include "calmwm.h"
#define PATH_ANY 0x0001
#define PATH_EXEC 0x0002
static void search_match_path(struct menu_q *, struct menu_q *,
char *, int);
2013-05-01 01:11:07 +04:00
static void search_match_path_exec(struct menu_q *, struct menu_q *,
char *);
static int strsubmatch(char *, char *, int);
2007-04-27 21:58:48 +04:00
void
search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct winname *wn;
struct menu *mi, *tierp[4], *before = NULL;
2007-04-27 21:58:48 +04:00
TAILQ_INIT(resultq);
(void)memset(tierp, 0, sizeof(tierp));
2007-04-27 21:58:48 +04:00
/*
* In order of rank:
*
* 1. Look through labels.
* 2. Look at title history, from present to past.
* 3. Look at window class name.
*/
TAILQ_FOREACH(mi, menuq, entry) {
int tier = -1, t;
2015-06-30 21:42:50 +03:00
struct client_ctx *cc = (struct client_ctx *)mi->ctx;
2007-04-27 21:58:48 +04:00
/* First, try to match on labels. */
if (cc->label != NULL && strsubmatch(search, cc->label, 0)) {
2007-04-27 21:58:48 +04:00
cc->matchname = cc->label;
tier = 0;
2008-04-16 00:24:41 +04:00
}
2007-04-27 21:58:48 +04:00
/* Then, on window names. */
if (tier < 0) {
TAILQ_FOREACH_REVERSE(wn, &cc->nameq, winname_q, entry)
if (strsubmatch(search, wn->name, 0)) {
2008-04-16 00:24:41 +04:00
cc->matchname = wn->name;
tier = 2;
break;
}
2007-04-27 21:58:48 +04:00
}
2010-09-26 00:01:27 +04:00
/* Then if there is a match on the window class name. */
2013-12-11 18:09:21 +04:00
if (tier < 0 && strsubmatch(search, cc->ch.res_class, 0)) {
cc->matchname = cc->ch.res_class;
2007-04-27 21:58:48 +04:00
tier = 3;
}
if (tier < 0)
continue;
/*
* De-rank a client one tier if it's the current
* window. Furthermore, this is denoted by a "!" when
* printing the window name in the search menu.
*/
if (cc == client_current() && tier < nitems(tierp) - 1)
2007-04-27 21:58:48 +04:00
tier++;
2010-09-26 00:01:27 +04:00
/* Clients that are hidden get ranked one up. */
2014-09-15 17:00:49 +04:00
if ((cc->flags & CLIENT_HIDDEN) && (tier > 0))
2007-04-27 21:58:48 +04:00
tier--;
2015-06-28 22:50:46 +03:00
if (tier >= nitems(tierp))
errx(1, "search_match_client: invalid tier");
2007-04-27 21:58:48 +04:00
/*
* If you have a tierp, insert after it, and make it
* the new tierp. If you don't have a tierp, find the
* first nonzero tierp above you, insert after it.
* Always make your current tierp the newly inserted
* entry.
*/
for (t = tier; t >= 0 && ((before = tierp[t]) == NULL); t--)
;
if (before == NULL)
TAILQ_INSERT_HEAD(resultq, mi, resultentry);
else
TAILQ_INSERT_AFTER(resultq, before, mi, resultentry);
tierp[tier] = mi;
}
}
void
search_print_cmd(struct menu *mi, int i)
{
struct cmd *cmd = (struct cmd *)mi->ctx;
(void)snprintf(mi->print, sizeof(mi->print), "%s", cmd->name);
}
void
search_print_group(struct menu *mi, int i)
{
struct group_ctx *gc = (struct group_ctx *)mi->ctx;
(void)snprintf(mi->print, sizeof(mi->print),
(group_holds_only_hidden(gc)) ? "%d: [%s]" : "%d: %s",
gc->num, gc->name);
}
2007-04-27 21:58:48 +04:00
void
search_print_client(struct menu *mi, int list)
{
2015-06-30 21:42:50 +03:00
struct client_ctx *cc = (struct client_ctx *)mi->ctx;
char flag = ' ';
2007-04-27 21:58:48 +04:00
if (cc == client_current())
flag = '!';
else if (cc->flags & CLIENT_HIDDEN)
flag = '&';
2015-07-01 17:36:42 +03:00
if ((list) || (cc->matchname == cc->label))
cc->matchname = cc->name;
2007-04-27 21:58:48 +04:00
2015-06-08 18:34:03 +03:00
(void)snprintf(mi->print, sizeof(mi->print), "(%d) %c[%s] %s",
2015-08-27 21:53:14 +03:00
(cc->gc) ? cc->gc->num : 0, flag,
2015-07-01 17:36:42 +03:00
(cc->label) ? cc->label : "", cc->matchname);
2007-04-27 21:58:48 +04:00
}
static void
search_match_path(struct menu_q *menuq, struct menu_q *resultq, char *search, int flag)
{
char pattern[PATH_MAX];
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;
menuq_add(resultq, NULL, "%s", g.gl_pathv[i]);
}
globfree(&g);
}
2013-05-01 01:11:07 +04:00
static void
search_match_path_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
2014-09-07 23:27:30 +04:00
return(search_match_path(menuq, resultq, search, PATH_EXEC));
}
2013-04-05 21:07:25 +04:00
void
search_match_path_any(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
2014-09-07 23:27:30 +04:00
return(search_match_path(menuq, resultq, search, PATH_ANY));
}
2007-04-27 21:58:48 +04:00
void
search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct menu *mi;
2007-04-27 21:58:48 +04:00
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry)
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, *mj;
int r;
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry) {
if (strsubmatch(search, mi->text, 1) == 0 &&
fnmatch(search, mi->text, 0) == FNM_NOMATCH)
continue;
TAILQ_FOREACH(mj, resultq, resultentry) {
r = strcasecmp(mi->text, mj->text);
if (r < 0)
TAILQ_INSERT_BEFORE(mj, mi, resultentry);
if (r <= 0)
break;
}
if (mj == NULL)
2007-04-27 21:58:48 +04:00
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
2007-04-27 21:58:48 +04:00
}
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);
}
2007-04-27 21:58:48 +04:00
static int
strsubmatch(char *sub, char *str, int zeroidx)
2007-04-27 21:58:48 +04:00
{
2014-01-03 19:29:06 +04:00
size_t len, sublen;
unsigned int n, flen;
2007-04-27 21:58:48 +04:00
if (sub == NULL || str == NULL)
2014-09-07 23:27:30 +04:00
return(0);
2007-04-27 21:58:48 +04:00
len = strlen(str);
sublen = strlen(sub);
if (sublen > len)
2014-09-07 23:27:30 +04:00
return(0);
2007-04-27 21:58:48 +04:00
if (!zeroidx)
flen = len - sublen;
else
flen = 0;
for (n = 0; n <= flen; n++)
2007-04-27 21:58:48 +04:00
if (strncasecmp(sub, str + n, sublen) == 0)
2014-09-07 23:27:30 +04:00
return(1);
2007-04-27 21:58:48 +04:00
2014-09-07 23:27:30 +04:00
return(0);
2007-04-27 21:58:48 +04:00
}