summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.h2
-rwxr-xr-xdmenubin43736 -> 44160 bytes
-rw-r--r--dmenu.15
-rw-r--r--dmenu.c157
-rw-r--r--dmenu.obin41056 -> 44704 bytes
-rwxr-xr-xdmenu_run2
6 files changed, 162 insertions, 4 deletions
diff --git a/config.h b/config.h
index 4962f01..eedb917 100644
--- a/config.h
+++ b/config.h
@@ -17,6 +17,8 @@ static const char *colors[SchemeLast][2] = {
};
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
static unsigned int lines = 0;
+static unsigned int maxhist = 64;
+static int histnodup = 1; /* if 0, record repeated histories */
/*
* Characters not considered part of a word while deleting words
diff --git a/dmenu b/dmenu
index 8dbe25b..da6be5e 100755
--- a/dmenu
+++ b/dmenu
Binary files differ
diff --git a/dmenu.1 b/dmenu.1
index aac82c0..a54abdf 100644
--- a/dmenu.1
+++ b/dmenu.1
@@ -22,6 +22,8 @@ dmenu \- dynamic menu
.IR color ]
.RB [ \-w
.IR windowid ]
+.RB [ \-H
+.IR histfile ]
.P
.BR dmenu_run " ..."
.SH DESCRIPTION
@@ -86,6 +88,9 @@ prints version information to stdout, then exits.
.TP
.BI \-w " windowid"
embed into windowid.
+.TP
+.BI \-H " histfile"
+save input in histfile and use it for history navigation.
.SH USAGE
dmenu is completely controlled by the keyboard. Items are selected using the
arrow keys, page up, page down, home, and end.
diff --git a/dmenu.c b/dmenu.c
index f2542a4..61f6af6 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -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();
diff --git a/dmenu.o b/dmenu.o
index e75ed6b..3533401 100644
--- a/dmenu.o
+++ b/dmenu.o
Binary files differ
diff --git a/dmenu_run b/dmenu_run
index 834ede5..59ec622 100755
--- a/dmenu_run
+++ b/dmenu_run
@@ -1,2 +1,2 @@
#!/bin/sh
-dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &
+dmenu_path | dmenu -H "${XDG_CACHE_HOME:-$HOME/.cache/}/dmenu_run.hist" "$@" | ${SHELL:-"/bin/sh"} &