aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dmenu.115
-rw-r--r--dmenu.c61
2 files changed, 42 insertions, 34 deletions
diff --git a/dmenu.1 b/dmenu.1
index 616a2a5..7243a36 100644
--- a/dmenu.1
+++ b/dmenu.1
@@ -25,13 +25,10 @@ dmenu \- dynamic menu
25.BR dmenu_run " ..." 25.BR dmenu_run " ..."
26.SH DESCRIPTION 26.SH DESCRIPTION
27.B dmenu 27.B dmenu
28is a dynamic menu for X, originally designed for 28is a dynamic menu for X, which reads a list of newline\-separated items from
29.IR dwm (1). 29stdin. When the user selects an item and presses Return, their choice is printed
30It manages huge numbers of user\-defined menu items efficiently. 30to stdout and dmenu terminates. Entering text will narrow the items to those
31.P 31matching the tokens in the input.
32dmenu reads a list of newline\-separated items from stdin and creates a menu.
33When the user selects an item or enters any text and presses Return, their
34choice is printed to stdout and dmenu terminates.
35.P 32.P
36.B dmenu_run 33.B dmenu_run
37is a dmenu script used by dwm which lists programs in the user's $PATH and 34is a dmenu script used by dwm which lists programs in the user's $PATH and
@@ -42,8 +39,8 @@ executes the selected item.
42dmenu appears at the bottom of the screen. 39dmenu appears at the bottom of the screen.
43.TP 40.TP
44.B \-f 41.B \-f
45dmenu grabs the keyboard before reading stdin. This is faster, but may lock up 42dmenu grabs the keyboard before reading stdin. This is faster, but will lock up
46X if stdin is from a terminal. 43X until stdin reaches end\-of\-file.
47.TP 44.TP
48.B \-i 45.B \-i
49dmenu matches menu items case insensitively. 46dmenu matches menu items case insensitively.
diff --git a/dmenu.c b/dmenu.c
index 6c1407d..9d479f9 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -30,7 +30,7 @@ static void drawmenu(void);
30static void grabkeyboard(void); 30static void grabkeyboard(void);
31static void insert(const char *str, ssize_t n); 31static void insert(const char *str, ssize_t n);
32static void keypress(XKeyEvent *ev); 32static void keypress(XKeyEvent *ev);
33static void match(Bool sub); 33static void match(void);
34static size_t nextrune(int inc); 34static size_t nextrune(int inc);
35static void paste(void); 35static void paste(void);
36static void readstdin(void); 36static void readstdin(void);
@@ -120,10 +120,10 @@ main(int argc, char *argv[]) {
120 120
121void 121void
122appenditem(Item *item, Item **list, Item **last) { 122appenditem(Item *item, Item **list, Item **last) {
123 if(!*last) 123 if(*last)
124 *list = item;
125 else
126 (*last)->right = item; 124 (*last)->right = item;
125 else
126 *list = item;
127 127
128 item->left = *last; 128 item->left = *last;
129 item->right = NULL; 129 item->right = NULL;
@@ -223,7 +223,7 @@ insert(const char *str, ssize_t n) {
223 if(n > 0) 223 if(n > 0)
224 memcpy(&text[cursor], str, n); 224 memcpy(&text[cursor], str, n);
225 cursor += n; 225 cursor += n;
226 match(n > 0 && text[cursor] == '\0'); 226 match();
227} 227}
228 228
229void 229void
@@ -252,7 +252,7 @@ keypress(XKeyEvent *ev) {
252 252
253 case XK_k: /* delete right */ 253 case XK_k: /* delete right */
254 text[cursor] = '\0'; 254 text[cursor] = '\0';
255 match(False); 255 match();
256 break; 256 break;
257 case XK_u: /* delete left */ 257 case XK_u: /* delete left */
258 insert(NULL, 0 - cursor); 258 insert(NULL, 0 - cursor);
@@ -355,33 +355,44 @@ keypress(XKeyEvent *ev) {
355 return; 355 return;
356 strncpy(text, sel->text, sizeof text); 356 strncpy(text, sel->text, sizeof text);
357 cursor = strlen(text); 357 cursor = strlen(text);
358 match(True); 358 match();
359 break; 359 break;
360 } 360 }
361 drawmenu(); 361 drawmenu();
362} 362}
363 363
364void 364void
365match(Bool sub) { 365match(void) {
366 size_t len = strlen(text); 366 static char **tokv = NULL;
367 Item *lexact, *lprefix, *lsubstr, *exactend, *prefixend, *substrend; 367 static int tokn = 0;
368 Item *item, *lnext; 368
369 369 char buf[sizeof text], *s;
370 lexact = lprefix = lsubstr = exactend = prefixend = substrend = NULL; 370 int i, tokc = 0;
371 for(item = sub ? matches : items; item && item->text; item = lnext) { 371 size_t len;
372 lnext = sub ? item->right : item + 1; 372 Item *item, *lprefix, *lsubstr, *prefixend, *substrend;
373 if(!fstrncmp(text, item->text, len + 1)) 373
374 appenditem(item, &lexact, &exactend); 374 strcpy(buf, text);
375 else if(!fstrncmp(text, item->text, len)) 375 for(s = strtok(buf, " "); s; tokv[tokc-1] = s, s = strtok(NULL, " "))
376 if(++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv)))
377 eprintf("cannot realloc %u bytes\n", tokn * sizeof *tokv);
378 len = tokc ? strlen(tokv[0]) : 0;
379
380 matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
381 for(item = items; item && item->text; item++) {
382 for(i = 0; i < tokc; i++)
383 if(!fstrstr(item->text, tokv[i]))
384 break;
385 if(i != tokc)
386 continue;
387 if(!tokc || !fstrncmp(tokv[0], item->text, len+1))
388 appenditem(item, &matches, &matchend);
389 else if(!fstrncmp(tokv[0], item->text, len))
376 appenditem(item, &lprefix, &prefixend); 390 appenditem(item, &lprefix, &prefixend);
377 else if(fstrstr(item->text, text)) 391 else
378 appenditem(item, &lsubstr, &substrend); 392 appenditem(item, &lsubstr, &substrend);
379 } 393 }
380 matches = lexact;
381 matchend = exactend;
382
383 if(lprefix) { 394 if(lprefix) {
384 if(matchend) { 395 if(matches) {
385 matchend->right = lprefix; 396 matchend->right = lprefix;
386 lprefix->left = matchend; 397 lprefix->left = matchend;
387 } 398 }
@@ -390,7 +401,7 @@ match(Bool sub) {
390 matchend = prefixend; 401 matchend = prefixend;
391 } 402 }
392 if(lsubstr) { 403 if(lsubstr) {
393 if(matchend) { 404 if(matches) {
394 matchend->right = lsubstr; 405 matchend->right = lsubstr;
395 lsubstr->left = matchend; 406 lsubstr->left = matchend;
396 } 407 }
@@ -519,7 +530,7 @@ setup(void) {
519 } 530 }
520 promptw = prompt ? textw(dc, prompt) : 0; 531 promptw = prompt ? textw(dc, prompt) : 0;
521 inputw = MIN(inputw, mw/3); 532 inputw = MIN(inputw, mw/3);
522 match(False); 533 match();
523 534
524 /* menu window */ 535 /* menu window */
525 swa.override_redirect = True; 536 swa.override_redirect = True;