From 73d2405635469833044e4bebb9ca38c6a41d92be Mon Sep 17 00:00:00 2001 From: bakkeby Date: Wed, 5 Aug 2020 12:27:15 +0200 Subject: [PATCH] Adding dynamic options patch --- README.md | 5 +++- config.def.h | 3 +++ dmenu.c | 31 ++++++++++++++++++++-- patch/dynamicoptions.c | 56 ++++++++++++++++++++++++++++++++++++++++ patch/dynamicoptions.h | 2 ++ patch/include.c | 3 +++ patch/include.h | 3 +++ patch/nonblockingstdin.c | 4 +++ patches.def.h | 7 +++++ 9 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 patch/dynamicoptions.c create mode 100644 patch/dynamicoptions.h diff --git a/README.md b/README.md index fadc83a..0127be0 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Refer to [https://tools.suckless.org/dmenu/](https://tools.suckless.org/dmenu/) ### Changelog: -2020-08-05 - Added the grid patch +2020-08-05 - Added the grid and dynamic options patches 2020-06-13 - Added the pango patch @@ -51,6 +51,9 @@ Refer to [https://tools.suckless.org/dmenu/](https://tools.suckless.org/dmenu/) - enables color emoji in dmenu by removing a workaround for a BadLength error in the Xft library when color glyphs are used - enabling this will crash dmenu on encountering such glyphs unless you also have an updated Xft library that can handle them + - [dynamic_options](https://tools.suckless.org/dmenu/patches/dynamicoptions/) + - adds a flag (`-dy`) which makes dmenu run the command given to it whenever input is changed with the current input as the last argument and update the option list according to the output of that command + - [fuzzyhighlight](https://tools.suckless.org/dmenu/patches/fuzzyhighlight/) - intended to be combined with the fuzzymatch patch, this makes it so that fuzzy matches are highlighted diff --git a/config.def.h b/config.def.h index a7c431e..e736035 100644 --- a/config.def.h +++ b/config.def.h @@ -32,6 +32,9 @@ static const char *fonts[] = }; #endif // PANGO_PATCH static const char *prompt = NULL; /* -p option; prompt to the left of input field */ +#if DYNAMIC_OPTIONS_PATCH +static const char *dynamic = NULL; /* -dy option; dynamic command to run on input change */ +#endif // DYNAMIC_OPTIONS_PATCH #if ALPHA_PATCH static const unsigned int baralpha = 0xd0; diff --git a/dmenu.c b/dmenu.c index 4e909a7..2c7acea 100644 --- a/dmenu.c +++ b/dmenu.c @@ -449,6 +449,11 @@ grabkeyboard(void) static void match(void) { + #if DYNAMIC_OPTIONS_PATCH + if (dynamic && *dynamic) + refreshoptions(); + #endif // DYNAMIC_OPTIONS_PATCH + #if FUZZYMATCH_PATCH if (fuzzy) { fuzzymatch(); @@ -494,8 +499,13 @@ match(void) for (i = 0; i < tokc; i++) if (!fstrstr(item->text, tokv[i])) break; + #if DYNAMIC_OPTIONS_PATCH + if (i != tokc && !(dynamic && *dynamic)) /* not all tokens match */ + continue; + #else if (i != tokc) /* not all tokens match */ continue; + #endif // DYNAMIC_OPTIONS_PATCH /* exact matches go first, then prefixes, then substrings */ if (!tokc || !fstrncmp(text, item->text, textsize)) appenditem(item, &matches, &matchend); @@ -936,7 +946,7 @@ readstdin(void) #endif // PASSWORD_PATCH /* read each line from stdin and add it to the item list */ - for (i = 0; fgets(buf, sizeof buf, stdin); i++) { + for (i = 0; fgets(buf, sizeof buf, stdin); i++) { if (i + 1 >= size / sizeof *items) if (!(items = realloc(items, (size += BUFSIZ)))) die("cannot realloc %u bytes:", size); @@ -1265,9 +1275,12 @@ usage(void) #endif // GRID_PATCH "[-l lines] [-p prompt] [-fn font] [-m monitor]" "\n [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]" - #if ALPHA_PATCH || BORDER_PATCH || INITIALTEXT_PATCH || LINE_HEIGHT_PATCH || NAVHISTORY_PATCH || XYW_PATCH + #if ALPHA_PATCH || BORDER_PATCH || INITIALTEXT_PATCH || LINE_HEIGHT_PATCH || NAVHISTORY_PATCH || XYW_PATCH || DYNAMIC_OPTIONS_PATCH "\n " #endif + #if DYNAMIC_OPTIONS_PATCH + " [ -dy command]" + #endif // DYNAMIC_OPTIONS_PATCH #if ALPHA_PATCH " [ -o opacity]" #endif // ALPHA_PATCH @@ -1418,6 +1431,10 @@ main(int argc, char *argv[]) #endif // FUZZYHIGHLIGHT_PATCH else if (!strcmp(argv[i], "-w")) /* embedding window id */ embed = argv[++i]; + #if DYNAMIC_OPTIONS_PATCH + else if (!strcmp(argv[i], "-dy")) /* dynamic command to run */ + dynamic = argv[++i]; + #endif // DYNAMIC_OPTIONS_PATCH #if BORDER_PATCH else if (!strcmp(argv[i], "-bw")) /* border width around dmenu */ border_width = atoi(argv[++i]); @@ -1486,9 +1503,19 @@ main(int argc, char *argv[]) #else if (fast && !isatty(0)) { grabkeyboard(); + #if DYNAMIC_OPTIONS_PATCH + if (!(dynamic && *dynamic)) + readstdin(); + #else readstdin(); + #endif // DYNAMIC_OPTIONS_PATCH } else { + #if DYNAMIC_OPTIONS_PATCH + if (!(dynamic && *dynamic)) + readstdin(); + #else readstdin(); + #endif // DYNAMIC_OPTIONS_PATCH grabkeyboard(); } #endif // NON_BLOCKING_STDIN_PATCH diff --git a/patch/dynamicoptions.c b/patch/dynamicoptions.c new file mode 100644 index 0000000..71ddd18 --- /dev/null +++ b/patch/dynamicoptions.c @@ -0,0 +1,56 @@ +static void +refreshoptions() +{ + int dynlen = strlen(dynamic); + char* cmd= malloc(dynlen + strlen(text) + 2); + if (cmd == NULL) + die("malloc:"); + sprintf(cmd, "%s %s", dynamic, text); + FILE *stream = popen(cmd, "r"); + if (!stream) + die("popen(%s):", cmd); + readstream(stream); + int pc = pclose(stream); + if (pc == -1) + die("pclose:"); + free(cmd); + curr = sel = items; +} + +static void +readstream(FILE* stream) +{ + char buf[sizeof text], *p; + size_t i, imax = 0, size = 0; + unsigned int tmpmax = 0; + + /* read each line from stdin and add it to the item list */ + for (i = 0; fgets(buf, sizeof buf, stream); i++) { + if (i + 1 >= size / sizeof *items) + if (!(items = realloc(items, (size += BUFSIZ)))) + die("cannot realloc %u bytes:", size); + if ((p = strchr(buf, '\n'))) + *p = '\0'; + if (!(items[i].text = strdup(buf))) + die("cannot strdup %u bytes:", strlen(buf) + 1); + items[i].out = 0; + #if PANGO_PATCH + drw_font_getexts(drw->font, buf, strlen(buf), &tmpmax, NULL, True); + #else + drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL); + #endif // PANGO_PATCH + if (tmpmax > inputw) { + inputw = tmpmax; + imax = i; + } + } + if (items) + items[i].text = NULL; + #if PANGO_PATCH + inputw = items ? TEXTWM(items[imax].text) : 0; + #else + inputw = items ? TEXTW(items[imax].text) : 0; + #endif // PANGO_PATCH + if (!dynamic || !*dynamic) + lines = MIN(lines, i); +} \ No newline at end of file diff --git a/patch/dynamicoptions.h b/patch/dynamicoptions.h new file mode 100644 index 0000000..eba9fb0 --- /dev/null +++ b/patch/dynamicoptions.h @@ -0,0 +1,2 @@ +static void refreshoptions(); +static void readstream(FILE* stream); \ No newline at end of file diff --git a/patch/include.c b/patch/include.c index 2503937..608d71a 100644 --- a/patch/include.c +++ b/patch/include.c @@ -7,6 +7,9 @@ #if FUZZYMATCH_PATCH #include "fuzzymatch.c" #endif +#if DYNAMIC_OPTIONS_PATCH +#include "dynamicoptions.c" +#endif #if MOUSE_SUPPORT_PATCH #include "mousesupport.c" #endif diff --git a/patch/include.h b/patch/include.h index 639773a..311cb1e 100644 --- a/patch/include.h +++ b/patch/include.h @@ -1,3 +1,6 @@ +#if DYNAMIC_OPTIONS_PATCH +#include "dynamicoptions.h" +#endif #if NON_BLOCKING_STDIN_PATCH #include "nonblockingstdin.h" #endif \ No newline at end of file diff --git a/patch/nonblockingstdin.c b/patch/nonblockingstdin.c index a985cdd..eb7013f 100644 --- a/patch/nonblockingstdin.c +++ b/patch/nonblockingstdin.c @@ -28,7 +28,11 @@ readstdin(void) die("cannot strdup %u bytes:", strlen(buf)+1); if (strlen(item->text) > max) { max = strlen(maxstr = item->text); + #if PANGO_PATCH + inputw = maxstr ? TEXTWM(maxstr) : 0; + #else inputw = maxstr ? TEXTW(maxstr) : 0; + #endif // PANGO_PATCH } *end = item; end = &item->next; diff --git a/patches.def.h b/patches.def.h index d0ab33e..25ec59a 100644 --- a/patches.def.h +++ b/patches.def.h @@ -31,6 +31,13 @@ */ #define COLOR_EMOJI_PATCH 0 +/* This patch adds a flag (-dy) which makes dmenu run the command given to it whenever input + * is changed with the current input as the last argument and update the option list according + * to the output of that command. + * https://tools.suckless.org/dmenu/patches/dynamicoptions/ + */ +#define DYNAMIC_OPTIONS_PATCH 0 + /* This patch make it so that fuzzy matches gets highlighted and is therefore meant * to be used together with the fuzzymatch patch. * https://tools.suckless.org/dmenu/patches/fuzzyhighlight/