diff --git a/config.mk b/config.mk index 0929b4a..4627988 100644 --- a/config.mk +++ b/config.mk @@ -18,13 +18,19 @@ FREETYPEINC = /usr/include/freetype2 # OpenBSD (uncomment) #FREETYPEINC = $(X11INC)/freetype2 +# jansson +JANSSONINC = `pkg-config --cflags jansson` +JANSSONLIBS = `pkg-config --libs jansson` +# uncomment on RHEL for strcasecmp +#EXTRAFLAGS=-D_GNU_SOURCE + # includes and libs -INCS = -I$(X11INC) -I$(FREETYPEINC) -LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) +INCS = -I$(X11INC) -I$(FREETYPEINC) $(JANSSONINC) +LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) $(JANSSONLIBS) # flags -CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) -CFLAGS = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS) +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) # compiler and linker diff --git a/dmenu.c b/dmenu.c index 65f25ce..58c1e23 100644 --- a/dmenu.c +++ b/dmenu.c @@ -15,6 +15,7 @@ #include #endif #include +#include #include "drw.h" #include "util.h" @@ -32,6 +33,7 @@ struct item { char *text; struct item *left, *right; int out; + json_t *json; }; static char text[BUFSIZ] = ""; @@ -40,6 +42,8 @@ static int bh, mw, mh; static int inputw = 0, promptw; static int lrpad; /* sum of left and right padding */ static size_t cursor; +static size_t items_sz = 0; +static size_t items_ln = 0; static struct item *items = NULL; static struct item *matches, *matchend; static struct item *prev, *curr, *next, *sel; @@ -58,6 +62,18 @@ static Clr *scheme[SchemeLast]; static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; static char *(*fstrstr)(const char *, const char *) = strstr; +static void listjson(json_t *obj); +static json_t *json = NULL; + +static struct item * +itemnew(void) +{ + if (items_ln + 1 >= (items_sz / sizeof *items)) + if (!(items = realloc(items, (items_sz += BUFSIZ)))) + die("cannot realloc %u bytes:", items_sz); + return &items[items_ln++]; +} + static void appenditem(struct item *item, struct item **list, struct item **last) { @@ -221,6 +237,8 @@ match(void) size_t len, textsize; struct item *item, *lprefix, *lsubstr, *prefixend, *substrend; + if (json) + fstrstr = strcasestr; strcpy(buf, text); /* separate input text into tokens to be matched individually */ for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " ")) @@ -464,7 +482,19 @@ insert: break; case XK_Return: case XK_KP_Enter: - puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); + if (sel && sel->json) { + if (json_is_object(sel->json)) { + listjson(sel->json); + text[0] = '\0'; + match(); + drawmenu(); + break; + } else { + puts(json_string_value(sel->json)); + } + } else { + puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); + } if (!(ev->state & ControlMask)) { cleanup(); exit(0); @@ -519,32 +549,71 @@ paste(void) } static void +readjson(const char *path) +{ + json_error_t jerr; + + if (!(json = json_load_file(path, 0, &jerr))) + die("%s @ line: %i - %s", jerr.text, jerr.line, path); +} + +static void +listjson(json_t *obj) +{ + void *iter; + unsigned imax = 0; + unsigned tmpmax = 0; + struct item *item; + + items_ln = 0; + iter = json_object_iter(obj); + while (iter) { + item = itemnew(); + item->text = (char*) json_object_iter_key(iter); + item->json = json_object_iter_value(iter); + item->out = 0; + drw_font_getexts(drw->fonts, item->text, strlen(item->text), + &tmpmax, NULL); + if (tmpmax > inputw) { + inputw = tmpmax; + imax = items_ln - 1; + } + iter = json_object_iter_next(obj, iter); + } + if (items) + items[items_ln].text = NULL; + inputw = items ? TEXTW(items[imax].text) : 0; + lines = MIN(lines, items_ln - 1); +} + +static void readstdin(void) { char buf[sizeof text], *p; - size_t i, imax = 0, size = 0; + size_t i; + unsigned int imax = 0; unsigned int tmpmax = 0; + struct item *item; /* read each line from stdin and add it to the item list */ 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); + item = itemnew(); if ((p = strchr(buf, '\n'))) *p = '\0'; - if (!(items[i].text = strdup(buf))) + if (!(item->text = strdup(buf))) die("cannot strdup %u bytes:", strlen(buf) + 1); - items[i].out = 0; + item->json = NULL; + item->out = 0; drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL); if (tmpmax > inputw) { inputw = tmpmax; - imax = i; + imax = items_ln - 1; } } if (items) - items[i].text = NULL; + items[items_ln].text = NULL; inputw = items ? TEXTW(items[imax].text) : 0; - lines = MIN(lines, i); + lines = MIN(lines, items_ln); } static void @@ -689,8 +758,9 @@ setup(void) static void usage(void) { - fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" - " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); + fputs("usage: dmenu [-bfiv] [-j json-file] [-l lines] [-p prompt]\n" + " [-fn font] [-m monitor] [-nb color] [-nf color]\n" + " [-sb color] [-sf color] [-w windowid]\n", stderr); exit(1); } @@ -715,6 +785,8 @@ main(int argc, char *argv[]) } else if (i + 1 == argc) usage(); /* these options take one argument */ + else if (!strcmp(argv[i], "-j")) + readjson(argv[++i]); else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */ lines = atoi(argv[++i]); else if (!strcmp(argv[i], "-m")) @@ -759,9 +831,15 @@ main(int argc, char *argv[]) if (fast && !isatty(0)) { grabkeyboard(); - readstdin(); + if (json) + listjson(json); + else + readstdin(); } else { - readstdin(); + if (json) + listjson(json); + else + readstdin(); grabkeyboard(); } setup();