~pkal/dmenu

ef25aab75c04e8eb76039c6f31002bc0ee583051 — Philip K 1 year, 6 months ago a7d93a5 + f531600
Merge branch 'patch/navhistory' into local
4 files changed, 129 insertions(+), 1 deletions(-)

M config.def.h
M dmenu.1
M dmenu.c
M dmenu_run
M config.def.h => config.def.h +5 -0
@@ 17,9 17,14 @@ 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
 * for example: " /?\"&[]"
 */
static const char worddelimiters[] = " ";

/* Size of the window border */
static const unsigned int border_width = 5;

M dmenu.1 => dmenu.1 +5 -0
@@ 22,6 22,8 @@ dmenu \- dynamic menu
.IR color ]
.RB [ \-w
.IR windowid ]
.RB [ \-H
.IR histfile ]
.P
.BR dmenu_run " ..."
.SH DESCRIPTION


@@ 83,6 85,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.

M dmenu.c => dmenu.c +118 -0
@@ 53,6 53,10 @@ static XIC xic;
static Drw *drw;
static Clr *scheme[SchemeLast];

static char *histfile;
static char *histbuf, *histptr;
static size_t histsz;

#include "config.h"

static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;


@@ 314,6 318,106 @@ movewordedge(int dir)
}

static void
loadhistory(void)
{
	FILE *fp = NULL;
	size_t sz;

	if (!histfile)
		return;
	if (!(fp = fopen(histfile, "r")))
		return;
	fseek(fp, 0, SEEK_END);
	sz = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	if (sz) {
		histsz = sz + 1 + BUFSIZ;
		if (!(histbuf = malloc(histsz))) {
			fprintf(stderr, "warning: cannot malloc %lu "\
				"bytes", histsz);
		} else {
			histptr = histbuf + fread(histbuf, 1, sz, fp);
			if (histptr <= histbuf) { /* fread error */
				free(histbuf);
				histbuf = NULL;
				return;
			}
			if (histptr[-1] != '\n')
				*histptr++ = '\n';
			histptr[BUFSIZ - 1] = '\0';
			*histptr = '\0';
			histsz = histptr - histbuf + BUFSIZ;
		}
	}
	fclose(fp);
}

static void
navhistory(int dir)
{
	char *p;
	size_t len = 0, textlen;

	if (!histbuf)
		return;
	if (dir > 0) {
		if (histptr == histbuf + histsz - BUFSIZ)
			return;
		while (*histptr && *histptr++ != '\n');
		for (p = histptr; *p && *p++ != '\n'; len++);
	} else {
		if (histptr == histbuf)
			return;
		if (histptr == histbuf + histsz - BUFSIZ) {
			textlen = strlen(text);
			textlen = MIN(textlen, BUFSIZ - 1);
			strncpy(histptr, text, textlen);
			histptr[textlen] = '\0';
		}
		for (histptr--; histptr != histbuf && histptr[-1] != '\n';
		     histptr--, len++);
	}
	len = MIN(len, BUFSIZ - 1);
	strncpy(text, histptr, len);
	text[len] = '\0';
	cursor = len;
	match();
}

static void
savehistory(char *str)
{
	unsigned int n, len = 0;
	size_t slen;
	char *p;
	FILE *fp;

	if (!histfile || !maxhist)
		return;
	if (!(slen = strlen(str)))
		return;
	if (histbuf && maxhist > 1) {
		p = histbuf + histsz - BUFSIZ - 1; /* skip the last newline */
		if (histnodup) {
			for (; p != histbuf && p[-1] != '\n'; p--, len++);
			n++;
			if (slen == len && !strncmp(p, str, len)) {
				return;
			}
		}
		for (; p != histbuf; p--, len++)
			if (p[-1] == '\n' && ++n + 1 > maxhist)
				break;
		fp = fopen(histfile, "w");
		fwrite(p, 1, len + 1, fp);	/* plus the last newline */
	} else {
		fp = fopen(histfile, "w");
	}
	fwrite(str, 1, strlen(str), fp);
	fclose(fp);
}

static void
keypress(XKeyEvent *ev)
{
	char buf[32];


@@ 397,6 501,14 @@ keypress(XKeyEvent *ev)
		case XK_j: ksym = XK_Next;  break;
		case XK_k: ksym = XK_Prior; break;
		case XK_l: ksym = XK_Down;  break;
		case XK_p:
			navhistory(-1);
			buf[0]=0;
			break;
		case XK_n:
			navhistory(1);
			buf[0]=0;
			break;
		default:
			return;
		}


@@ 475,6 587,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);
		}


@@ 740,6 854,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"))


@@ 782,6 898,8 @@ main(int argc, char *argv[])
		die("pledge");
#endif

	loadhistory();

	if (fast && !isatty(0)) {
		grabkeyboard();
		readstdin();

M dmenu_run => dmenu_run +1 -1
@@ 1,2 1,2 @@
#!/bin/sh
exec $(dmenu_path | dmenu "$@")
exec $(dmenu_path | dmenu -H "${XDG_CACHE_HOME:-$HOME/.cache/}/dmenu_run.hist" "$@")