Return to repo list

suckless-gf-dmenu

Gentoo-friendly patches for Suckless's dmenu.
Return to HMagellan.com

navhistorysearch.patch (5971B)


      1 diff --git a/dmenu.1 b/dmenu.1
      2 index 323f93c..ff496dd 100644
      3 --- a/dmenu.1
      4 +++ b/dmenu.1
      5 @@ -22,6 +22,8 @@ dmenu \- dynamic menu
      6  .IR color ]
      7  .RB [ \-w
      8  .IR windowid ]
      9 +.RB [ \-H
     10 +.IR histfile ]
     11  .P
     12  .BR dmenu_run " ..."
     13  .SH DESCRIPTION
     14 @@ -80,6 +82,9 @@ prints version information to stdout, then exits.
     15  .TP
     16  .BI \-w " windowid"
     17  embed into windowid.
     18 +.TP
     19 +.BI \-H " histfile"
     20 +save input in histfile and use it for history navigation.
     21  .SH USAGE
     22  dmenu is completely controlled by the keyboard.  Items are selected using the
     23  arrow keys, page up, page down, home, and end.
     24 diff --git a/dmenu.c b/dmenu.c
     25 index 65f25ce..4242eb4 100644
     26 --- a/dmenu.c
     27 +++ b/dmenu.c
     28 @@ -40,7 +40,7 @@ static int bh, mw, mh;
     29  static int inputw = 0, promptw;
     30  static int lrpad; /* sum of left and right padding */
     31  static size_t cursor;
     32 -static struct item *items = NULL;
     33 +static struct item *items = NULL, *backup_items;
     34  static struct item *matches, *matchend;
     35  static struct item *prev, *curr, *next, *sel;
     36  static int mon = -1, screen;
     37 @@ -53,6 +53,10 @@ static XIC xic;
     38  static Drw *drw;
     39  static Clr *scheme[SchemeLast];
     40 
     41 +static char *histfile;
     42 +static char **history;
     43 +static size_t histsz, histpos;
     44 +
     45  #include "config.h"
     46 
     47  static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
     48 @@ -304,11 +308,134 @@ movewordedge(int dir)
     49  	}
     50  }
     51 
     52 +static void
     53 +loadhistory(void)
     54 +{
     55 +	FILE *fp = NULL;
     56 +	static size_t cap = 0;
     57 +	size_t llen;
     58 +	char *line;
     59 +
     60 +	if (!histfile) {
     61 +		return;
     62 +	}
     63 +
     64 +	fp = fopen(histfile, "r");
     65 +	if (!fp) {
     66 +		return;
     67 +	}
     68 +
     69 +	for (;;) {
     70 +		line = NULL;
     71 +		llen = 0;
     72 +		if (-1 == getline(&line, &llen, fp)) {
     73 +			if (ferror(fp)) {
     74 +				die("failed to read history");
     75 +			}
     76 +			free(line);
     77 +			break;
     78 +		}
     79 +
     80 +		if (cap == histsz) {
     81 +			cap += 64 * sizeof(char*);
     82 +			history = realloc(history, cap);
     83 +			if (!history) {
     84 +				die("failed to realloc memory");
     85 +			}
     86 +		}
     87 +		strtok(line, "\n");
     88 +		history[histsz] = line;
     89 +		histsz++;
     90 +	}
     91 +	histpos = histsz;
     92 +
     93 +	if (fclose(fp)) {
     94 +		die("failed to close file %s", histfile);
     95 +	}
     96 +}
     97 +
     98 +static void
     99 +navhistory(int dir)
    100 +{
    101 +	static char def[BUFSIZ];
    102 +	char *p = NULL;
    103 +	size_t len = 0;
    104 +
    105 +	if (!history || histpos + 1 == 0)
    106 +		return;
    107 +
    108 +	if (histsz == histpos) {
    109 +		strncpy(def, text, sizeof(def));
    110 +	}
    111 +
    112 +	switch(dir) {
    113 +	case 1:
    114 +		if (histpos < histsz - 1) {
    115 +			p = history[++histpos];
    116 +		} else if (histpos == histsz - 1) {
    117 +			p = def;
    118 +			histpos++;
    119 +		}
    120 +		break;
    121 +	case -1:
    122 +		if (histpos > 0) {
    123 +			p = history[--histpos];
    124 +		}
    125 +		break;
    126 +	}
    127 +	if (p == NULL) {
    128 +		return;
    129 +	}
    130 +
    131 +	len = MIN(strlen(p), BUFSIZ - 1);
    132 +	strncpy(text, p, len);
    133 +	text[len] = '\0';
    134 +	cursor = len;
    135 +	match();
    136 +}
    137 +
    138 +static void
    139 +savehistory(char *input)
    140 +{
    141 +	unsigned int i;
    142 +	FILE *fp;
    143 +
    144 +	if (!histfile ||
    145 +	    0 == maxhist ||
    146 +	    0 == strlen(input)) {
    147 +		goto out;
    148 +	}
    149 +
    150 +	fp = fopen(histfile, "w");
    151 +	if (!fp) {
    152 +		die("failed to open %s", histfile);
    153 +	}
    154 +	for (i = histsz < maxhist ? 0 : histsz - maxhist; i < histsz; i++) {
    155 +		if (0 >= fprintf(fp, "%s\n", history[i])) {
    156 +			die("failed to write to %s", histfile);
    157 +		}
    158 +	}
    159 +	if (!histnodup || (histsz > 0 && strcmp(input, history[histsz-1]) != 0)) { /* TODO */
    160 +		if (0 >= fputs(input, fp)) {
    161 +			die("failed to write to %s", histfile);
    162 +		}
    163 +	}
    164 +	if (fclose(fp)) {
    165 +		die("failed to close file %s", histfile);
    166 +	}
    167 +
    168 +out:
    169 +	for (i = 0; i < histsz; i++) {
    170 +		free(history[i]);
    171 +	}
    172 +	free(history);
    173 +}
    174 +
    175  static void
    176  keypress(XKeyEvent *ev)
    177  {
    178  	char buf[32];
    179 -	int len;
    180 +	int len, i;
    181  	KeySym ksym = NoSymbol;
    182  	Status status;
    183 
    184 @@ -359,6 +486,27 @@ keypress(XKeyEvent *ev)
    185  			XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
    186  			                  utf8, utf8, win, CurrentTime);
    187  			return;
    188 +		case XK_r:
    189 +			if (histfile) {
    190 +				if (!backup_items) {
    191 +					backup_items = items;
    192 +					items = calloc(histsz + 1, sizeof(struct item));
    193 +					if (!items) {
    194 +						die("cannot allocate memory");
    195 +					}
    196 +
    197 +					for (i = 0; i < histsz; i++) {
    198 +						items[i].text = history[i];
    199 +					}
    200 +				} else {
    201 +					free(items);
    202 +					items = backup_items;
    203 +					backup_items = NULL;
    204 +				}
    205 +			}
    206 +			match();
    207 +			ksym = NoSymbol;
    208 +           break;
    209  		case XK_Left:
    210  			movewordedge(-1);
    211             ksym = NoSymbol;
    212 @@ -388,6 +535,14 @@ keypress(XKeyEvent *ev)
    213  		case XK_j: ksym = XK_Next;  break;
    214  		case XK_k: ksym = XK_Prior; break;
    215  		case XK_l: ksym = XK_Down;  break;
    216 +		case XK_p:
    217 +			navhistory(-1);
    218 +			buf[0]=0;
    219 +			break;
    220 +		case XK_n:
    221 +			navhistory(1);
    222 +			buf[0]=0;
    223 +			break;
    224  		default:
    225  			return;
    226  		}
    227 @@ -466,6 +621,8 @@ insert:
    228  	case XK_KP_Enter:
    229  		puts((sel && !(ev->state & ShiftMask)) ? sel->text : text);
    230  		if (!(ev->state & ControlMask)) {
    231 +			savehistory((sel && !(ev->state & ShiftMask))
    232 +				    ? sel->text : text);
    233  			cleanup();
    234  			exit(0);
    235  		}
    236 @@ -690,7 +847,8 @@ static void
    237  usage(void)
    238  {
    239  	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
    240 -	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr);
    241 +	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n"
    242 +	      "             [-H histfile]", stderr);
    243  	exit(1);
    244  }
    245 
    246 @@ -715,6 +873,8 @@ main(int argc, char *argv[])
    247  		} else if (i + 1 == argc)
    248  			usage();
    249  		/* these options take one argument */
    250 +		else if (!strcmp(argv[i], "-H"))
    251 +			histfile = argv[++i];
    252  		else if (!strcmp(argv[i], "-l"))   /* number of lines in vertical list */
    253  			lines = atoi(argv[++i]);
    254  		else if (!strcmp(argv[i], "-m"))
    255 @@ -757,6 +897,8 @@ main(int argc, char *argv[])
    256         die("no fonts could be loaded.");
    257     lrpad = drw->fonts->h;
    258 
    259 +	loadhistory();
    260 +
    261  	if (fast) {
    262  		grabkeyboard();
    263  		readstdin();
    264 diff --git a/dmenu_run b/dmenu_run
    265 index 834ede5..59ec622 100755
    266 --- a/dmenu_run
    267 +++ b/dmenu_run
    268 @@ -1,2 +1,2 @@
    269  #!/bin/sh
    270 -dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &
    271 +dmenu_path | dmenu -H "${XDG_CACHE_HOME:-$HOME/.cache/}/dmenu_run.hist" "$@" | ${SHELL:-"/bin/sh"} &