summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/dmenu/dmenu.c226
1 files changed, 82 insertions, 144 deletions
diff --git a/core/dmenu/dmenu.c b/core/dmenu/dmenu.c
index 28a0658..b009179 100644
--- a/core/dmenu/dmenu.c
+++ b/core/dmenu/dmenu.c
@@ -41,7 +41,7 @@ struct item {
static char text[BUFSIZ] = "";
static char *embed;
static int bh, mw, mh;
-static int inputw = 0, promptw;
+static int promptw;
static int lrpad; /* sum of left and right padding */
static size_t cursor;
static struct item *items = NULL;
@@ -70,14 +70,18 @@ static void setopacity(Window w, double opacity);
#include "config.h"
-static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
-static char *(*fstrstr)(const char *, const char *) = strstr;
-
-static unsigned int
-textw_clamp(const char *str, unsigned int n)
+static int
+fuzzy(const char *text, const char *pattern)
{
- unsigned int w = drw_fontset_getwidth_clamp(drw, str, n) + lrpad;
- return MIN(w, n);
+ for (; *pattern; pattern++) {
+ while (*text && tolower((unsigned char)*text) !=
+ tolower((unsigned char)*pattern))
+ text++;
+ if (!*text)
+ return 0;
+ text++;
+ }
+ return 1;
}
static void
@@ -96,19 +100,15 @@ appenditem(struct item *item, struct item **list, struct item **last)
static void
calcoffsets(void)
{
- int i, n;
-
- if (lines > 0)
- n = lines * bh;
- else
- n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
- /* calculate which items will begin the next page and previous page */
- for (i = 0, next = curr; next; next = next->right)
- if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)) > n)
- break;
- for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
- if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n)
- break;
+ int i, n;
+
+ n = lines * bh;
+ for (i = 0, next = curr; next; next = next->right)
+ if ((i += bh) > n)
+ break;
+ for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
+ if ((i += bh) > n)
+ break;
}
static void
@@ -144,24 +144,6 @@ initaccent(void)
{
updateaccent();
}
-static char *
-cistrstr(const char *h, const char *n)
-{
- size_t i;
-
- if (!n[0])
- return (char *)h;
-
- for (; *h; ++h) {
- for (i = 0; n[i] && tolower((unsigned char)n[i]) ==
- tolower((unsigned char)h[i]); ++i)
- ;
- if (n[i] == '\0')
- return (char *)h;
- }
- return NULL;
-}
-
static int
drawitem(struct item *item, int x, int y, int w)
{
@@ -178,54 +160,36 @@ drawitem(struct item *item, int x, int y, int w)
static void
drawmenu(void)
{
- unsigned int curpos;
- struct item *item;
- int x = 0, y = 0, w;
+ unsigned int curpos;
+ struct item *item;
+ int x = 0, y = 0, w;
- drw_setscheme(drw, scheme[SchemeNorm]);
- drw_rect(drw, 0, 0, mw, mh, 1, 1);
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ drw_rect(drw, 0, 0, mw, mh, 1, 1);
- if (prompt && *prompt) {
- drw_setscheme(drw, scheme[SchemeSel]);
- x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0);
- }
- /* draw input field */
- w = (lines > 0 || !matches) ? mw - x : inputw;
- drw_setscheme(drw, scheme[SchemeNorm]);
- drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0);
+ if (prompt && *prompt) {
+ drw_setscheme(drw, scheme[SchemeSel]);
+ x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0);
+ }
+ /* draw input field */
+ w = mw - x;
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0);
+
+ curpos = TEXTW(text) - TEXTW(&text[cursor]);
+ if ((curpos += lrpad / 2 - 1) < w) {
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0);
+ }
- curpos = TEXTW(text) - TEXTW(&text[cursor]);
- if ((curpos += lrpad / 2 - 1) < w) {
- drw_setscheme(drw, scheme[SchemeNorm]);
- drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0);
- }
+ for (item = curr; item != next; item = item->right) {
+ y += bh;
+ drawitem(item, x, y, mw - x);
+ drw_setscheme(drw, accent);
+ drw_rect(drw, x, y + bh - 1, mw - x, 1, 1, 1);
+ }
- if (lines > 0) {
- /* draw vertical list */
- for (item = curr; item != next; item = item->right) {
- y += bh;
- drawitem(item, x, y, mw - x);
- drw_setscheme(drw, accent);
- drw_rect(drw, x, y + bh - 1, mw - x, 1, 1, 1);
- }
- } else if (matches) {
- /* draw horizontal list */
- x += inputw;
- w = TEXTW("<");
- if (curr->left) {
- drw_setscheme(drw, scheme[SchemeNorm]);
- drw_text(drw, x, 0, w, bh, lrpad / 2, "<", 0);
- }
- x += w;
- for (item = curr; item != next; item = item->right)
- x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">")));
- if (next) {
- w = TEXTW(">");
- drw_setscheme(drw, scheme[SchemeNorm]);
- drw_text(drw, mw - w, 0, w, bh, lrpad / 2, ">", 0);
- }
- }
- drw_map(drw, win, 0, 0, mw, mh);
+ drw_map(drw, win, 0, 0, mw, mh);
}
static void
@@ -275,55 +239,32 @@ grabkeyboard(void)
static void
match(void)
{
- static char **tokv = NULL;
- static int tokn = 0;
-
- char buf[sizeof text], *s;
- int i, tokc = 0;
- size_t len, textsize;
- struct item *item, *lprefix, *lsubstr, *prefixend, *substrend;
-
- strcpy(buf, text);
- /* separate input text into tokens to be matched individually */
- for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " "))
- if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv)))
- die("cannot realloc %zu bytes:", tokn * sizeof *tokv);
- len = tokc ? strlen(tokv[0]) : 0;
-
- matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
- textsize = strlen(text) + 1;
- for (item = items; item && item->text; item++) {
- for (i = 0; i < tokc; i++)
- if (!fstrstr(item->text, tokv[i]))
- break;
- if (i != tokc) /* not all tokens match */
- continue;
- /* exact matches go first, then prefixes, then substrings */
- if (!tokc || !fstrncmp(text, item->text, textsize))
- appenditem(item, &matches, &matchend);
- else if (!fstrncmp(tokv[0], item->text, len))
- appenditem(item, &lprefix, &prefixend);
- else
- appenditem(item, &lsubstr, &substrend);
- }
- if (lprefix) {
- if (matches) {
- matchend->right = lprefix;
- lprefix->left = matchend;
- } else
- matches = lprefix;
- matchend = prefixend;
- }
- if (lsubstr) {
- if (matches) {
- matchend->right = lsubstr;
- lsubstr->left = matchend;
- } else
- matches = lsubstr;
- matchend = substrend;
- }
- curr = sel = matches;
- calcoffsets();
+ static char **tokv = NULL;
+ static int tokn = 0;
+
+ char buf[sizeof text], *s;
+ int i, tokc = 0;
+ struct item *item;
+
+ strcpy(buf, text);
+ /* separate input text into tokens to be matched individually */
+ for (s = strtok(buf, " "); s; s = strtok(NULL, " ")) {
+ if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv)))
+ die("cannot realloc %zu bytes:", tokn * sizeof *tokv);
+ tokv[tokc - 1] = s;
+ }
+
+ matches = matchend = NULL;
+ for (item = items; item && item->text; item++) {
+ for (i = 0; i < tokc; i++)
+ if (!fuzzy(item->text, tokv[i]))
+ break;
+ if (i != tokc)
+ continue;
+ appenditem(item, &matches, &matchend);
+ }
+ curr = sel = matches;
+ calcoffsets();
}
static void
@@ -696,7 +637,6 @@ setup(void)
/* calculate menu geometry */
bh = drw->fonts->h + 2;
- lines = MAX(lines, 0);
#ifdef XINERAMA
i = 0;
if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
@@ -721,8 +661,8 @@ setup(void)
break;
mw = info[i].width / 2;
- if (lines > info[i].height / bh - 1)
- lines = info[i].height / bh - 1;
+ int max_lines = info[i].height / bh - 1;
+ lines = lines ? MIN(lines, max_lines) : MIN(20, max_lines);
mh = (lines + 1) * bh;
x = info[i].x_org + (info[i].width - mw) / 2;
y = info[i].y_org + (info[i].height - mh) / 2;
@@ -734,14 +674,13 @@ setup(void)
die("could not get embedding window attributes: 0x%lx",
parentwin);
mw = wa.width / 2;
- if (lines > wa.height / bh - 1)
- lines = wa.height / bh - 1;
+ int max_lines = wa.height / bh - 1;
+ lines = lines ? MIN(lines, max_lines) : MIN(20, max_lines);
mh = (lines + 1) * bh;
x = (wa.width - mw) / 2;
y = (wa.height - mh) / 2;
}
promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
- inputw = mw - promptw;
match();
/* create menu window */
@@ -798,12 +737,11 @@ main(int argc, char *argv[])
exit(0);
} else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */
topbar = 0;
- else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */
- fast = 1;
- else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
- fstrncmp = strncasecmp;
- fstrstr = cistrstr;
- } else if (i + 1 == argc)
+ else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */
+ fast = 1;
+ else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
+ /* no-op: matching is case-insensitive */
+ } else if (i + 1 == argc)
usage();
/* these options take one argument */
else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */