diff --git a/README.md b/README.md index c0bd7ae..a2dc187 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-08 - Added the symbols, managed, morecolor, multi-selection and preselect patches +2020-08-08 - Added the json, symbols, managed, morecolor, multi-selection and preselect patches 2020-08-05 - Added the grid, highlight, highpriority, dynamic options and numbers patches @@ -81,6 +81,9 @@ Refer to [https://tools.suckless.org/dmenu/](https://tools.suckless.org/dmenu/) - [instant](https://tools.suckless.org/dmenu/patches/instant/) - adds a flag that will cause dmenu to select an item immediately if there is only one matching option left + - [json](https://tools.suckless.org/dmenu/patches/json/) + - adds basic support for json files + - [line-height](http://tools.suckless.org/dmenu/patches/line-height/) - adds a '-h' option which sets the minimum height of a dmenu line - this helps integrate dmenu with other UI elements that require a particular vertical size diff --git a/config.def.h b/config.def.h index 017264b..b6b88f2 100644 --- a/config.def.h +++ b/config.def.h @@ -93,7 +93,7 @@ static int histnodup = 1; /* if 0, record repeated histories */ * Characters not considered part of a word while deleting words * for example: " /?\"&[]" */ -#if PIPEOUT_PATCH && !MULTI_SELECTION_PATCH +#if PIPEOUT_PATCH static const char startpipe[] = "#"; #endif // PIPEOUT_PATCH static const char worddelimiters[] = " "; diff --git a/config.mk b/config.mk index 45b75a0..b860e74 100644 --- a/config.mk +++ b/config.mk @@ -18,6 +18,12 @@ FREETYPEINC = /usr/include/freetype2 # OpenBSD (uncomment) #FREETYPEINC = $(X11INC)/freetype2 +# Uncomment this for the json patch / JSON_PATCH +#JANSSONINC = `pkg-config --cflags jansson` +#JANSSONLIBS = `pkg-config --libs jansson` +# uncomment on RHEL for strcasecmp +#EXTRAFLAGS=-D_GNU_SOURCE + # Uncomment this for the alpha patch / ALPHA_PATCH #XRENDER = -lXrender @@ -26,11 +32,11 @@ FREETYPEINC = /usr/include/freetype2 #PANGOLIB = `pkg-config --libs xft pango pangoxft` # includes and libs -INCS = -I$(X11INC) -I$(FREETYPEINC) ${PANGOINC} -LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lm $(XRENDER) ${PANGOLIB} +INCS = -I$(X11INC) -I$(FREETYPEINC) $(JANSSONINC) ${PANGOINC} +LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) $(JANSSONLIBS) -lm $(XRENDER) ${PANGOLIB} # flags -CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) $(EXTRAFLAGS) CFLAGS = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS) LDFLAGS = $(LIBS) diff --git a/dmenu.c b/dmenu.c index eaa2aca..fe0540a 100644 --- a/dmenu.c +++ b/dmenu.c @@ -17,8 +17,24 @@ #include #include "patches.h" +/* Patch incompatibility overrides */ +#if MULTI_SELECTION_PATCH +#undef NON_BLOCKING_STDIN_PATCH +#undef PIPEOUT_PATCH +#undef JSON_PATCH +#undef PRINTINPUTTEXT_PATCH +#endif // MULTI_SELECTION_PATCH +#if JSON_PATCH +#undef NON_BLOCKING_STDIN_PATCH +#undef PRINTINPUTTEXT_PATCH +#undef PIPEOUT_PATCH +#endif // JSON_PATCH + #include "drw.h" #include "util.h" +#if JSON_PATCH +#include +#endif // JSON_PATCH /* macros */ #define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \ @@ -67,13 +83,16 @@ struct item { #if HIGHPRIORITY_PATCH int hp; #endif // HIGHPRIORITY_PATCH + #if JSON_PATCH + json_t *json; + #endif // JSON_PATCH #if FUZZYMATCH_PATCH double distance; #endif // FUZZYMATCH_PATCH }; static char text[BUFSIZ] = ""; -#if PIPEOUT_PATCH && !MULTI_SELECTION_PATCH +#if PIPEOUT_PATCH static char pipeout[8] = " | dmenu"; #endif // PIPEOUT_PATCH static char *embed; @@ -102,7 +121,7 @@ static int managed = 0; static int *selid = NULL; static unsigned int selidsize = 0; #endif // MULTI_SELECTION_PATCH -#if PRINTINPUTTEXT_PATCH && !MULTI_SELECTION_PATCH +#if PRINTINPUTTEXT_PATCH static int use_text_input = 0; #endif // PRINTINPUTTEXT_PATCH #if PRESELECT_PATCH @@ -536,6 +555,10 @@ match(void) #if NON_BLOCKING_STDIN_PATCH int preserve = 0; #endif // NON_BLOCKING_STDIN_PATCH + #if JSON_PATCH + if (json) + fstrstr = strcasestr; + #endif // JSON_PATCH strcpy(buf, text); /* separate input text into tokens to be matched individually */ @@ -875,7 +898,10 @@ insert: case XK_Return: case XK_KP_Enter: #if !MULTI_SELECTION_PATCH - #if PIPEOUT_PATCH + #if JSON_PATCH + if (!printjsonssel(ev->state)) + break; + #elif PIPEOUT_PATCH #if PRINTINPUTTEXT_PATCH if (sel && ( (use_text_input && (ev->state & ShiftMask)) || @@ -1032,7 +1058,13 @@ static void readstdin(void) { char buf[sizeof text], *p; + #if JSON_PATCH + size_t i; + unsigned int imax = 0; + struct item *item; + #else size_t i, imax = 0, size = 0; + #endif // JSON_PATCH unsigned int tmpmax = 0; #if PASSWORD_PATCH @@ -1044,15 +1076,26 @@ readstdin(void) /* read each line from stdin and add it to the item list */ for (i = 0; fgets(buf, sizeof buf, stdin); i++) { + #if JSON_PATCH + item = itemnew(); + #else if (i + 1 >= size / sizeof *items) if (!(items = realloc(items, (size += BUFSIZ)))) die("cannot realloc %u bytes:", size); + #endif // JSON_PATCH if ((p = strchr(buf, '\n'))) *p = '\0'; + #if JSON_PATCH + if (!(item->text = strdup(buf))) + #else if (!(items[i].text = strdup(buf))) + #endif // JSON_PATCH die("cannot strdup %u bytes:", strlen(buf) + 1); #if MULTI_SELECTION_PATCH items[i].id = i; /* for multiselect */ + #elif JSON_PATCH + item->json = NULL; + item->out = 0; #else items[i].out = 0; #endif // items[i].out = 0; @@ -1066,17 +1109,29 @@ readstdin(void) #endif // PANGO_PATCH if (tmpmax > inputw) { inputw = tmpmax; + #if JSON_PATCH + imax = items_ln - 1; + #else imax = i; + #endif // JSON_PATCH } } if (items) + #if JSON_PATCH + items[items_ln].text = NULL; + #else items[i].text = NULL; + #endif // JSON_PATCH #if PANGO_PATCH inputw = items ? TEXTWM(items[imax].text) : 0; #else inputw = items ? TEXTW(items[imax].text) : 0; #endif // PANGO_PATCH + #if JSON_PATCH + lines = MIN(lines, items_ln); + #else lines = MIN(lines, i); + #endif // JSON_PATCH } #endif // NON_BLOCKING_STDIN_PATCH @@ -1388,7 +1443,7 @@ usage(void) #if INSTANT_PATCH "n" #endif // INSTANT_PATCH - #if PRINTINPUTTEXT_PATCH && !MULTI_SELECTION_PATCH + #if PRINTINPUTTEXT_PATCH "t" #endif // PRINTINPUTTEXT_PATCH #if PREFIXCOMPLETION_PATCH @@ -1412,9 +1467,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 || HIGHPRIORITY_PATCH || INITIALTEXT_PATCH || LINE_HEIGHT_PATCH || NAVHISTORY_PATCH || XYW_PATCH || DYNAMIC_OPTIONS_PATCH + #if ALPHA_PATCH || BORDER_PATCH || HIGHPRIORITY_PATCH || INITIALTEXT_PATCH || LINE_HEIGHT_PATCH || NAVHISTORY_PATCH || XYW_PATCH || DYNAMIC_OPTIONS_PATCH || JSON_PATCH "\n " #endif + #if JSON_PATCH + " [ -j json-file]" + #endif // JSON_PATCH #if DYNAMIC_OPTIONS_PATCH " [ -dy command]" #endif // DYNAMIC_OPTIONS_PATCH @@ -1494,7 +1552,7 @@ main(int argc, char *argv[]) } else if (!strcmp(argv[i], "-n")) { /* instant select only match */ instant = !instant; #endif // INSTANT_PATCH - #if PRINTINPUTTEXT_PATCH && !MULTI_SELECTION_PATCH + #if PRINTINPUTTEXT_PATCH } else if (!strcmp(argv[i], "-t")) { /* favors text input over selection */ use_text_input = 1; #endif // PRINTINPUTTEXT_PATCH @@ -1528,6 +1586,10 @@ main(int argc, char *argv[]) lines = 1; } #endif // GRID_PATCH + #if JSON_PATCH + else if (!strcmp(argv[i], "-j")) + readjson(argv[++i]); + #endif // JSON_PATCH else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */ lines = atoi(argv[++i]); #if XYW_PATCH @@ -1662,19 +1724,39 @@ main(int argc, char *argv[]) #else if (fast && !isatty(0)) { grabkeyboard(); + #if JSON_PATCH + if (json) + listjson(json); #if DYNAMIC_OPTIONS_PATCH + else if (!(dynamic && *dynamic)) + readstdin(); + #else + else + readstdin(); + #endif // DYNAMIC_OPTIONS_PATCH + #elif DYNAMIC_OPTIONS_PATCH if (!(dynamic && *dynamic)) readstdin(); #else readstdin(); - #endif // DYNAMIC_OPTIONS_PATCH + #endif // JSON_PATCH | DYNAMIC_OPTIONS_PATCH } else { + #if JSON_PATCH + if (json) + listjson(json); #if DYNAMIC_OPTIONS_PATCH + else if (!(dynamic && *dynamic)) + readstdin(); + #else + else + readstdin(); + #endif // DYNAMIC_OPTIONS_PATCH + #elif DYNAMIC_OPTIONS_PATCH if (!(dynamic && *dynamic)) readstdin(); #else readstdin(); - #endif // DYNAMIC_OPTIONS_PATCH + #endif // JSON_PATCH | DYNAMIC_OPTIONS_PATCH grabkeyboard(); } #endif // NON_BLOCKING_STDIN_PATCH diff --git a/patch/include.c b/patch/include.c index 80e477d..84f353b 100644 --- a/patch/include.c +++ b/patch/include.c @@ -18,6 +18,9 @@ #if MULTI_SELECTION_PATCH #include "multiselect.c" #endif +#if JSON_PATCH +#include "json.c" +#endif #if MOUSE_SUPPORT_PATCH #include "mousesupport.c" #endif diff --git a/patch/include.h b/patch/include.h index 5928366..1aebc52 100644 --- a/patch/include.h +++ b/patch/include.h @@ -1,6 +1,9 @@ #if DYNAMIC_OPTIONS_PATCH #include "dynamicoptions.h" #endif +#if JSON_PATCH +#include "json.h" +#endif #if NON_BLOCKING_STDIN_PATCH #include "nonblockingstdin.h" #endif diff --git a/patches.def.h b/patches.def.h index 7f590d3..e4b2712 100644 --- a/patches.def.h +++ b/patches.def.h @@ -84,6 +84,19 @@ */ #define INSTANT_PATCH 0 +/* This patch adds basic support for json files. + * This patch depends on the jansson library. Uncomment the relevant line in config.mk when + * enabling this patch. + * + * This patch is not compatible with the multi-selection, printinputtext, pipeout and + * non-blocking stdin patches. + * The multi-selection patch takes precedence over this patch. + * This patch takes precedence over non-blocking stdin, pipeout and printintputtext patches. + * + * https://tools.suckless.org/dmenu/patches/json/ + */ +#define JSON_PATCH 0 + /* This patch adds a '-h' option which sets the minimum height of a dmenu line. This helps * integrate dmenu with other UI elements that require a particular vertical size. * http://tools.suckless.org/dmenu/patches/line-height/ @@ -116,7 +129,8 @@ * deselect any selected item. * Also refer to the dmenu_run replacement on the below URL that supports multiple selections. * - * This patch is not compatible with the printinputtext and pipeout patches. + * This patch is not compatible with, and takes precedence over, the json, printinputtext, + * pipeout and non-blocking stdin patches. * * https://tools.suckless.org/dmenu/patches/multi-selection/ */ @@ -131,6 +145,10 @@ * from stdin and from X. This means that you can continue feeding dmenu while you type. * This patch is meant to be used along with the incremental patch, so that you can use stdout * to feed stdin. + * + * This patch is not compatible with the json and multi-selection patches, both of which takes + * precedence over this patch. + * * https://tools.suckless.org/dmenu/patches/non_blocking_stdin/ */ #define NON_BLOCKING_STDIN_PATCH 0 @@ -173,7 +191,8 @@ * want to display the output of a command on the screen. * Only text starting with the character '#' is piped out by default. * - * This patch is not compatible with the multi-select patch. + * This patch is not compatible with the json and multi-select patches, both of which takes + * precedence over this one. * * https://tools.suckless.org/dmenu/patches/pipeout/ */ @@ -193,7 +212,8 @@ /* This patch adds a flag (-t) which makes Return key to ignore selection and print the input * text to stdout. The flag basically swaps the functions of Return and Shift+Return hotkeys. * - * This patch is not compatible with the multi-select patch. + * This patch is not compatible with the multi-select and json patches, both of which takes + * precedence over this one. * * https://tools.suckless.org/dmenu/patches/printinputtext/ */