dmenu-dynamicoptions.diff (4473B)
1 diff --git a/config.def.h b/config.def.h 2 index 1edb647..035b877 100644 3 --- a/config.def.h 4 +++ b/config.def.h 5 @@ -7,6 +7,7 @@ static const char *fonts[] = { 6 "monospace:size=10" 7 }; 8 static const char *prompt = NULL; /* -p option; prompt to the left of input field */ 9 +static const char *dynamic = NULL; /* -dy option; dynamic command to run on input change */ 10 static const char *colors[SchemeLast][2] = { 11 /* fg bg */ 12 [SchemeNorm] = { "#bbbbbb", "#222222" }, 13 diff --git a/dmenu.1 b/dmenu.1 14 index 323f93c..1ae3fe3 100644 15 --- a/dmenu.1 16 +++ b/dmenu.1 17 @@ -22,6 +22,8 @@ dmenu \- dynamic menu 18 .IR color ] 19 .RB [ \-w 20 .IR windowid ] 21 +.RB [ \-dy 22 +.IR command ] 23 .P 24 .BR dmenu_run " ..." 25 .SH DESCRIPTION 26 @@ -80,6 +82,9 @@ prints version information to stdout, then exits. 27 .TP 28 .BI \-w " windowid" 29 embed into windowid. 30 +.TP 31 +.BI \-dy " command" 32 +runs command whenever input changes to update menu items. 33 .SH USAGE 34 dmenu is completely controlled by the keyboard. Items are selected using the 35 arrow keys, page up, page down, home, and end. 36 diff --git a/dmenu.c b/dmenu.c 37 index 7cf253b..e7731ae 100644 38 --- a/dmenu.c 39 +++ b/dmenu.c 40 @@ -44,6 +44,7 @@ static struct item *items = NULL; 41 static struct item *matches, *matchend; 42 static struct item *prev, *curr, *next, *sel; 43 static int mon = -1, screen; 44 +static unsigned int max_lines = 0; 45 46 static Atom clip, utf8; 47 static Display *dpy; 48 @@ -227,6 +228,47 @@ grabkeyboard(void) 49 die("cannot grab keyboard"); 50 } 51 52 +static void readstdin(FILE* stream); 53 + 54 +static void 55 +refreshoptions() 56 +{ 57 + int dynlen = strlen(dynamic); 58 + int cmdlen = dynlen + 4; 59 + char *cmd; 60 + char *c; 61 + char *t = text; 62 + while (*t) 63 + cmdlen += *t++ == '\'' ? 4 : 1; 64 + cmd = malloc(cmdlen); 65 + if (cmd == NULL) 66 + die("cannot malloc %u bytes:", cmdlen); 67 + strcpy(cmd, dynamic); 68 + t = text; 69 + c = cmd + dynlen; 70 + *(c++) = ' '; 71 + *(c++) = '\''; 72 + while (*t) { 73 + // prefix ' with '\' 74 + if (*t == '\'') { 75 + *(c++) = '\''; 76 + *(c++) = '\\'; 77 + *(c++) = '\''; 78 + } 79 + *(c++) = *(t++); 80 + } 81 + *(c++) = '\''; 82 + *(c++) = 0; 83 + FILE *stream = popen(cmd, "r"); 84 + if (!stream) 85 + die("could not popen dynamic command (%s):", cmd); 86 + readstdin(stream); 87 + int r = pclose(stream); 88 + if (r == -1) 89 + die("could not pclose dynamic command"); 90 + free(cmd); 91 +} 92 + 93 static void 94 match(void) 95 { 96 @@ -238,6 +280,16 @@ match(void) 97 size_t len, textsize; 98 struct item *item, *lprefix, *lsubstr, *prefixend, *substrend; 99 100 + if (dynamic) { 101 + refreshoptions(); 102 + matches = matchend = NULL; 103 + for (item = items; item && item->text; item++) 104 + appenditem(item, &matches, &matchend); 105 + curr = sel = matches; 106 + calcoffsets(); 107 + return; 108 + } 109 + 110 strcpy(buf, text); 111 /* separate input text into tokens to be matched individually */ 112 for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " ")) 113 @@ -547,14 +599,14 @@ paste(void) 114 } 115 116 static void 117 -readstdin(void) 118 +readstdin(FILE* stream) 119 { 120 char *line = NULL; 121 size_t i, junk, size = 0; 122 ssize_t len; 123 124 /* read each line from stdin and add it to the item list */ 125 - for (i = 0; (len = getline(&line, &junk, stdin)) != -1; i++, line = NULL) { 126 + for (i = 0; (len = getline(&line, &junk, stream)) != -1; i++, line = NULL) { 127 if (i + 1 >= size / sizeof *items) 128 if (!(items = realloc(items, (size += BUFSIZ)))) 129 die("cannot realloc %zu bytes:", size); 130 @@ -565,7 +617,7 @@ readstdin(void) 131 } 132 if (items) 133 items[i].text = NULL; 134 - lines = MIN(lines, i); 135 + lines = MIN(max_lines, i); 136 } 137 138 static void 139 @@ -711,7 +763,8 @@ static void 140 usage(void) 141 { 142 die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" 143 - " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]"); 144 + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n" 145 + " [-dy command]\n"); 146 } 147 148 int 149 @@ -753,6 +806,8 @@ main(int argc, char *argv[]) 150 colors[SchemeSel][ColFg] = argv[++i]; 151 else if (!strcmp(argv[i], "-w")) /* embedding window id */ 152 embed = argv[++i]; 153 + else if (!strcmp(argv[i], "-dy")) /* dynamic command to run */ 154 + dynamic = argv[++i] && *argv[i] ? argv[i] : NULL; 155 else 156 usage(); 157 158 @@ -777,11 +832,14 @@ main(int argc, char *argv[]) 159 die("pledge"); 160 #endif 161 162 + max_lines = lines; 163 if (fast && !isatty(0)) { 164 grabkeyboard(); 165 - readstdin(); 166 + if (!dynamic) 167 + readstdin(stdin); 168 } else { 169 - readstdin(); 170 + if (!dynamic) 171 + readstdin(stdin); 172 grabkeyboard(); 173 } 174 setup();