diff options
Diffstat (limited to 'dmenu.c')
-rw-r--r-- | dmenu.c | 157 |
1 files changed, 154 insertions, 3 deletions
@@ -60,6 +60,10 @@ static Clr *scheme[SchemeLast]; static char *colortemp[4]; static char *tempfonts; +static char *histfile; +static char **history; +static size_t histsz, histpos; + #include "config.h" static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; @@ -374,6 +378,129 @@ movewordedge(int dir) } static void +loadhistory(void) +{ + FILE *fp = NULL; + static size_t cap = 0; + size_t llen; + char *line; + + if (!histfile) { + return; + } + + fp = fopen(histfile, "r"); + if (!fp) { + return; + } + + for (;;) { + line = NULL; + llen = 0; + if (-1 == getline(&line, &llen, fp)) { + if (ferror(fp)) { + die("failed to read history"); + } + free(line); + break; + } + + if (cap == histsz) { + cap += 64 * sizeof(char*); + history = realloc(history, cap); + if (!history) { + die("failed to realloc memory"); + } + } + strtok(line, "\n"); + history[histsz] = line; + histsz++; + } + histpos = histsz; + + if (fclose(fp)) { + die("failed to close file %s", histfile); + } +} + +static void +navhistory(int dir) +{ + static char def[BUFSIZ]; + char *p = NULL; + size_t len = 0; + + if (!history || histpos + 1 == 0) + return; + + if (histsz == histpos) { + strncpy(def, text, sizeof(def)); + } + + switch(dir) { + case 1: + if (histpos < histsz - 1) { + p = history[++histpos]; + } else if (histpos == histsz - 1) { + p = def; + histpos++; + } + break; + case -1: + if (histpos > 0) { + p = history[--histpos]; + } + break; + } + if (p == NULL) { + return; + } + + len = MIN(strlen(p), BUFSIZ - 1); + strncpy(text, p, len); + text[len] = '\0'; + cursor = len; + match(); +} + +static void +savehistory(char *input) +{ + unsigned int i; + FILE *fp; + + if (!histfile || + 0 == maxhist || + 0 == strlen(input)) { + goto out; + } + + fp = fopen(histfile, "w"); + if (!fp) { + die("failed to open %s", histfile); + } + for (i = histsz < maxhist ? 0 : histsz - maxhist; i < histsz; i++) { + if (0 >= fprintf(fp, "%s\n", history[i])) { + die("failed to write to %s", histfile); + } + } + if (histsz == 0 || !histnodup || (histsz > 0 && strcmp(input, history[histsz-1]) != 0)) { /* TODO */ + if (0 >= fputs(input, fp)) { + die("failed to write to %s", histfile); + } + } + if (fclose(fp)) { + die("failed to close file %s", histfile); + } + +out: + for (i = 0; i < histsz; i++) { + free(history[i]); + } + free(history); +} + +static void keypress(XKeyEvent *ev) { char buf[32]; @@ -456,9 +583,26 @@ keypress(XKeyEvent *ev) case XK_g: ksym = XK_Home; break; case XK_G: ksym = XK_End; break; case XK_h: ksym = XK_Up; break; - case XK_j: ksym = XK_Next; break; - case XK_k: ksym = XK_Prior; break; + //case XK_j: ksym = XK_Next; break; + //case XK_k: ksym = XK_Prior; break; case XK_l: ksym = XK_Down; break; + + case XK_j: + navhistory(-1); + buf[0]=0; + break; + case XK_k: + navhistory(1); + buf[0]=0; + break; + case XK_p: + navhistory(-1); + buf[0]=0; + break; + case XK_n: + navhistory(1); + buf[0]=0; + break; default: return; } @@ -544,6 +688,8 @@ insert: case XK_KP_Enter: puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); if (!(ev->state & ControlMask)) { + savehistory((sel && !(ev->state & ShiftMask)) + ? sel->text : text); cleanup(); exit(0); } @@ -899,7 +1045,8 @@ usage(void) { fputs("usage: dmenu [-bfinvP] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n" - " [-hb color] [-hf color] [-hp items]\n", stderr); + " [-hb color] [-hf color] [-hp items]\n" + " [-H histfile]", stderr); exit(1); } @@ -965,6 +1112,8 @@ main(int argc, char *argv[]) else if (i + 1 == argc) usage(); /* these options take one argument */ + else if (!strcmp(argv[i], "-H")) + histfile = argv[++i]; else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */ lines = atoi(argv[++i]); else if (!strcmp(argv[i], "-m")) @@ -1028,6 +1177,8 @@ main(int argc, char *argv[]) die("pledge"); #endif + loadhistory(); + if (fast && !isatty(0)) { grabkeyboard(); readstdin(); |