sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

dmenu-navhistory+search-20200709.diff (6371B)


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