dmenu-dynamicoptions-5.0.diff (5263B)
1 From f70735c476c25da46f9e44b835ac967e0dfa4d85 Mon Sep 17 00:00:00 2001 2 From: Ziad EL KHOURY HANNA <me@ziadkh.ovh> 3 Date: Mon, 29 Nov 2021 17:36:35 +0100 4 Subject: [PATCH] add `-dy` flag for dynamic menu updating 5 6 `-dy` flag makes dmenu run the command given to it whenever input is 7 changed with the current input as the last argument and update the 8 option list according to the output of that command. 9 10 Based on dynamic options patch by ttmx <tiago.sequeira.teles@gmail.com>. 11 Adds proper quoting of the given command. 12 Adds option to man file documentation. 13 --- 14 config.def.h | 1 + 15 dmenu.1 | 5 ++++ 16 dmenu.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++----- 17 3 files changed, 70 insertions(+), 6 deletions(-) 18 19 diff --git a/config.def.h b/config.def.h 20 index 1edb647..035b877 100644 21 --- a/config.def.h 22 +++ b/config.def.h 23 @@ -7,6 +7,7 @@ static const char *fonts[] = { 24 "monospace:size=10" 25 }; 26 static const char *prompt = NULL; /* -p option; prompt to the left of input field */ 27 +static const char *dynamic = NULL; /* -dy option; dynamic command to run on input change */ 28 static const char *colors[SchemeLast][2] = { 29 /* fg bg */ 30 [SchemeNorm] = { "#bbbbbb", "#222222" }, 31 diff --git a/dmenu.1 b/dmenu.1 32 index 323f93c..1ae3fe3 100644 33 --- a/dmenu.1 34 +++ b/dmenu.1 35 @@ -22,6 +22,8 @@ dmenu \- dynamic menu 36 .IR color ] 37 .RB [ \-w 38 .IR windowid ] 39 +.RB [ \-dy 40 +.IR command ] 41 .P 42 .BR dmenu_run " ..." 43 .SH DESCRIPTION 44 @@ -80,6 +82,9 @@ prints version information to stdout, then exits. 45 .TP 46 .BI \-w " windowid" 47 embed into windowid. 48 +.TP 49 +.BI \-dy " command" 50 +runs command whenever input changes to update menu items. 51 .SH USAGE 52 dmenu is completely controlled by the keyboard. Items are selected using the 53 arrow keys, page up, page down, home, and end. 54 diff --git a/dmenu.c b/dmenu.c 55 index 65f25ce..6780122 100644 56 --- a/dmenu.c 57 +++ b/dmenu.c 58 @@ -44,6 +44,7 @@ static struct item *items = NULL; 59 static struct item *matches, *matchend; 60 static struct item *prev, *curr, *next, *sel; 61 static int mon = -1, screen; 62 +static unsigned int max_lines = 0; 63 64 static Atom clip, utf8; 65 static Display *dpy; 66 @@ -210,6 +211,47 @@ grabkeyboard(void) 67 die("cannot grab keyboard"); 68 } 69 70 +static void readstdin(FILE* stream); 71 + 72 +static void 73 +refreshoptions() 74 +{ 75 + int dynlen = strlen(dynamic); 76 + int cmdlen = dynlen + 4; 77 + char *cmd; 78 + char *c; 79 + char *t = text; 80 + while (*t) 81 + cmdlen += *t++ == '\'' ? 4 : 1; 82 + cmd = malloc(cmdlen); 83 + if (cmd == NULL) 84 + die("cannot malloc %u bytes:", cmdlen); 85 + strcpy(cmd, dynamic); 86 + t = text; 87 + c = cmd + dynlen; 88 + *(c++) = ' '; 89 + *(c++) = '\''; 90 + while (*t) { 91 + // prefix ' with '\' 92 + if (*t == '\'') { 93 + *(c++) = '\''; 94 + *(c++) = '\\'; 95 + *(c++) = '\''; 96 + } 97 + *(c++) = *(t++); 98 + } 99 + *(c++) = '\''; 100 + *(c++) = 0; 101 + FILE *stream = popen(cmd, "r"); 102 + if (!stream) 103 + die("could not popen dynamic command (%s):", cmd); 104 + readstdin(stream); 105 + int r = pclose(stream); 106 + if (r == -1) 107 + die("could not pclose dynamic command"); 108 + free(cmd); 109 +} 110 + 111 static void 112 match(void) 113 { 114 @@ -221,6 +263,16 @@ match(void) 115 size_t len, textsize; 116 struct item *item, *lprefix, *lsubstr, *prefixend, *substrend; 117 118 + if (dynamic) { 119 + refreshoptions(); 120 + matches = matchend = NULL; 121 + for (item = items; item && item->text; item++) 122 + appenditem(item, &matches, &matchend); 123 + curr = sel = matches; 124 + calcoffsets(); 125 + return; 126 + } 127 + 128 strcpy(buf, text); 129 /* separate input text into tokens to be matched individually */ 130 for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " ")) 131 @@ -519,14 +571,14 @@ paste(void) 132 } 133 134 static void 135 -readstdin(void) 136 +readstdin(FILE* stream) 137 { 138 char buf[sizeof text], *p; 139 size_t i, imax = 0, size = 0; 140 unsigned int tmpmax = 0; 141 142 /* read each line from stdin and add it to the item list */ 143 - for (i = 0; fgets(buf, sizeof buf, stdin); i++) { 144 + for (i = 0; fgets(buf, sizeof buf, stream); i++) { 145 if (i + 1 >= size / sizeof *items) 146 if (!(items = realloc(items, (size += BUFSIZ)))) 147 die("cannot realloc %u bytes:", size); 148 @@ -544,7 +596,7 @@ readstdin(void) 149 if (items) 150 items[i].text = NULL; 151 inputw = items ? TEXTW(items[imax].text) : 0; 152 - lines = MIN(lines, i); 153 + lines = MIN(max_lines, i); 154 } 155 156 static void 157 @@ -690,7 +742,8 @@ static void 158 usage(void) 159 { 160 fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" 161 - " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); 162 + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n" 163 + " [-dy command]\n", stderr); 164 exit(1); 165 } 166 167 @@ -733,6 +786,8 @@ main(int argc, char *argv[]) 168 colors[SchemeSel][ColFg] = argv[++i]; 169 else if (!strcmp(argv[i], "-w")) /* embedding window id */ 170 embed = argv[++i]; 171 + else if (!strcmp(argv[i], "-dy")) /* dynamic command to run */ 172 + dynamic = argv[++i] && *argv[i] ? argv[i] : NULL; 173 else 174 usage(); 175 176 @@ -757,11 +812,14 @@ main(int argc, char *argv[]) 177 die("pledge"); 178 #endif 179 180 + max_lines = lines; 181 if (fast && !isatty(0)) { 182 grabkeyboard(); 183 - readstdin(); 184 + if (!dynamic) 185 + readstdin(stdin); 186 } else { 187 - readstdin(); 188 + if (!dynamic) 189 + readstdin(stdin); 190 grabkeyboard(); 191 } 192 setup(); 193 -- 194 2.34.1 195