diff -up ../dmenu-4.5/dmenu.1 ./dmenu.1 --- ../dmenu-4.5/dmenu.1 2012-01-08 07:18:43.000000000 -0500 +++ ./dmenu.1 2013-03-11 15:57:11.812706207 -0400 @@ -20,6 +20,8 @@ dmenu \- dynamic menu .IR color ] .RB [ \-sf .IR color ] +.RB [ \-hist +.IR "" ] .RB [ \-v ] .P .BR dmenu_run " ..." @@ -70,6 +72,9 @@ defines the selected background color. .BI \-sf " color" defines the selected foreground color. .TP +.BI \-hist " " +the file to use for history +.TP .B \-v prints version information to stdout, then exits. .SH USAGE diff -up ../dmenu-4.5/dmenu.c ./dmenu.c --- ../dmenu-4.5/dmenu.c 2012-01-08 07:18:43.000000000 -0500 +++ ./dmenu.c 2013-03-11 16:07:40.556683999 -0400 @@ -34,7 +34,7 @@ static void keypress(XKeyEvent *ev); static void match(void); static size_t nextrune(int inc); static void paste(void); -static void readstdin(void); +static void readitems(void); static void run(void); static void setup(void); static void usage(void); @@ -61,6 +61,9 @@ static Item *prev, *curr, *next, *sel; static Window win; static XIC xic; +static char *histfile = NULL; +static Item *histitems, *histend; + static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; static char *(*fstrstr)(const char *, const char *) = strstr; @@ -100,6 +103,8 @@ main(int argc, char *argv[]) { selbgcolor = argv[++i]; else if(!strcmp(argv[i], "-sf")) /* selected foreground color */ selfgcolor = argv[++i]; + else if(!strcmp(argv[i], "-hist")) + histfile = argv[++i]; else usage(); @@ -108,10 +113,10 @@ main(int argc, char *argv[]) { if(fast) { grabkeyboard(); - readstdin(); + readitems(); } else { - readstdin(); + readitems(); grabkeyboard(); } setup(); @@ -120,6 +125,59 @@ main(int argc, char *argv[]) { return 1; /* unreachable */ } +static int +writehistory(char *command) { + FILE *f; + Item *histitem; + char *histline; + char *histcmd; + int currcnt = 1; + int histcnt; + + if(!histfile || strlen(command) <= 0) + return 0; + + if((f = fopen(histfile, "w"))) { + /* get the current count of previous runs for this command */ + for(histitem = histitems; histitem && histitem->text; histitem=histitem->right) { + histline = strdup(histitem->text); + histcmd = strsep(&histline, "\t"); + if(strcmp(command, histcmd) == 0) { + currcnt = atoi(strsep(&histline, "\t")) + 1; + } + } + + /* loop through history printing those with more runs */ + for(histitem = histitems; histitem && histitem->text; histitem=histitem->right) { + histline = strdup(histitem->text); + histcmd = strsep(&histline, "\t"); + histcnt = atoi(strsep(&histline, "\t")); + if(histcnt > currcnt) { + fprintf(f, "%s", histitem->text); + } else { + break; + } + } + + /* print this command now so it's the first in line with this run count */ + /* reducing the count by 1 here to keep the next comparison loop simple */ + fprintf(f, "%s\t%d\n", command, currcnt--); + + /* print all the rest except this command's old line */ + for(; histitem && histitem->text; histitem=histitem->right) { + histline = strdup(histitem->text); + histcmd = strsep(&histline, "\t"); + histcnt = atoi(strsep(&histline, "\t")); + if(histcnt < currcnt || strcmp(command, histcmd) != 0) + fprintf(f, "%s", histitem->text); + } + fclose(f); + return 1; + } + + return 0; +} + void appenditem(Item *item, Item **list, Item **last) { if(*last) @@ -359,6 +417,7 @@ keypress(XKeyEvent *ev) { case XK_Return: case XK_KP_Enter: puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); + writehistory( (sel == NULL) ? text : sel->text); exit(EXIT_SUCCESS); case XK_Right: if(text[cursor] != '\0') { @@ -464,26 +523,60 @@ paste(void) { } void -readstdin(void) { - char buf[sizeof text], *p, *maxstr = NULL; - size_t i, max = 0, size = 0; +readitems(void) { + char buf[sizeof text], *p, *maxstr = NULL, *histline, *histcmd; + size_t i = 0, j = 0, k = 0, max = 0, size = 0; + FILE *f; + Bool listed; + Item *histitem; + histitems = histend = NULL; + + if(histfile && (f = fopen(histfile, "r"))) { + for(; fgets(buf, sizeof buf, f); i++) { + histitem = malloc(sizeof *histitem); + histitem->text = strdup(buf); + appenditem(histitem, &histitems, &histend); + if(i+1 >= size / sizeof *items) + if(!(items = realloc(items, (size += BUFSIZ)))) + eprintf("cannot realloc %u bytes:", size); + if((p = strchr(buf, '\n'))) + *p = '\0'; + histline = strdup(buf); + histcmd = strsep(&histline, "\t"); + if(!(items[i].text = strdup(histcmd))) + eprintf("cannot strdup %u bytes:", strlen(histcmd)+1); + if(strlen(items[i].text) > max) + max = strlen(maxstr = items[i].text); + } + fclose(f); + } /* 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)))) - eprintf("cannot realloc %u bytes:", size); + for(j = i; fgets(buf, sizeof buf, stdin); j++) { if((p = strchr(buf, '\n'))) *p = '\0'; - if(!(items[i].text = strdup(buf))) - eprintf("cannot strdup %u bytes:", strlen(buf)+1); - if(strlen(items[i].text) > max) - max = strlen(maxstr = items[i].text); + listed = False; + for(k = 0; k < i; k++) { + if(strcmp(buf, items[k].text) == 0) { + listed = True; + j--; + break; + } + } + if(!listed) { + if(j+1 >= size / sizeof *items) + if(!(items = realloc(items, (size += BUFSIZ)))) + eprintf("cannot realloc %u bytes:", size); + if(!(items[j].text = strdup(buf))) + eprintf("cannot strdup %u bytes:", strlen(buf)+1); + if(strlen(items[j].text) > max) + max = strlen(maxstr = items[j].text); + } } if(items) - items[i].text = NULL; + items[j].text = NULL; inputw = maxstr ? textw(dc, maxstr) : 0; - lines = MIN(lines, i); + lines = MIN(lines, j); } void @@ -602,6 +695,6 @@ setup(void) { void usage(void) { fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font]\n" - " [-nb color] [-nf color] [-sb color] [-sf color] [-v]\n", stderr); + " [-nb color] [-nf color] [-sb color] [-sf color] [-hist histfile] [-v]\n", stderr); exit(EXIT_FAILURE); }