diff options
| author | auric <104602845+ihateamongus@users.noreply.github.com> | 2025-09-11 10:32:34 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-11 10:32:34 -0500 |
| commit | 089761fb4a6216ba64acbe52c0b72d87a1d9e0ae (patch) | |
| tree | 65c378c58eb1efe6c8bacc0f50ce987e6ae7995e | |
| parent | e58f13a6d7db7d046933d72ccafebbb0fb58202d (diff) | |
| parent | 71e912f02f5cd6af784dcda4f706989db61175b4 (diff) | |
Merge pull request #26 from ihateamongus/codex/create-universal-launcher-with-dmenu
feat: add universal dmenu launcher
| -rw-r--r-- | core/dmenu/dmenu.c | 226 |
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 */ |
