sites

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

dmenu-navhistory-20200709.diff (5285B)


      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..9d15f78 100644
     39 --- a/dmenu.c
     40 +++ b/dmenu.c
     41 @@ -53,6 +53,10 @@ static XIC xic;
     42  static Drw *drw;
     43  static Clr *scheme[SchemeLast];
     44 
     45 +static char *histfile;
     46 +static char **history;
     47 +static size_t histsz, histpos;
     48 +
     49  #include "config.h"
     50 
     51  static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
     52 @@ -304,6 +308,129 @@ movewordedge(int dir)
     53  	}
     54  }
     55 
     56 +static void
     57 +loadhistory(void)
     58 +{
     59 +	FILE *fp = NULL;
     60 +	static size_t cap = 0;
     61 +	size_t llen;
     62 +	char *line;
     63 +
     64 +	if (!histfile) {
     65 +		return;
     66 +	}
     67 +
     68 +	fp = fopen(histfile, "r");
     69 +	if (!fp) {
     70 +		return;
     71 +	}
     72 +
     73 +	for (;;) {
     74 +		line = NULL;
     75 +		llen = 0;
     76 +		if (-1 == getline(&line, &llen, fp)) {
     77 +			if (ferror(fp)) {
     78 +				die("failed to read history");
     79 +			}
     80 +			free(line);
     81 +			break;
     82 +		}
     83 +
     84 +		if (cap == histsz) {
     85 +			cap += 64 * sizeof(char*);
     86 +			history = realloc(history, cap);
     87 +			if (!history) {
     88 +				die("failed to realloc memory");
     89 +			}
     90 +		}
     91 +		strtok(line, "\n");
     92 +		history[histsz] = line;
     93 +		histsz++;
     94 +	}
     95 +	histpos = histsz;
     96 +
     97 +	if (fclose(fp)) {
     98 +		die("failed to close file %s", histfile);
     99 +	}
    100 +}
    101 +
    102 +static void
    103 +navhistory(int dir)
    104 +{
    105 +	static char def[BUFSIZ];
    106 +	char *p = NULL;
    107 +	size_t len = 0;
    108 +
    109 +	if (!history || histpos + 1 == 0)
    110 +		return;
    111 +
    112 +	if (histsz == histpos) {
    113 +		strncpy(def, text, sizeof(def));
    114 +	}
    115 +
    116 +	switch(dir) {
    117 +	case 1:
    118 +		if (histpos < histsz - 1) {
    119 +			p = history[++histpos];
    120 +		} else if (histpos == histsz - 1) {
    121 +			p = def;
    122 +			histpos++;
    123 +		}
    124 +		break;
    125 +	case -1:
    126 +		if (histpos > 0) {
    127 +			p = history[--histpos];
    128 +		}
    129 +		break;
    130 +	}
    131 +	if (p == NULL) {
    132 +		return;
    133 +	}
    134 +
    135 +	len = MIN(strlen(p), BUFSIZ - 1);
    136 +	strncpy(text, p, len);
    137 +	text[len] = '\0';
    138 +	cursor = len;
    139 +	match();
    140 +}
    141 +
    142 +static void
    143 +savehistory(char *input)
    144 +{
    145 +	unsigned int i;
    146 +	FILE *fp;
    147 +
    148 +	if (!histfile ||
    149 +	    0 == maxhist ||
    150 +	    0 == strlen(input)) {
    151 +		goto out;
    152 +	}
    153 +
    154 +	fp = fopen(histfile, "w");
    155 +	if (!fp) {
    156 +		die("failed to open %s", histfile);
    157 +	}
    158 +	for (i = histsz < maxhist ? 0 : histsz - maxhist; i < histsz; i++) {
    159 +		if (0 >= fprintf(fp, "%s\n", history[i])) {
    160 +			die("failed to write to %s", histfile);
    161 +		}
    162 +	}
    163 +	if (!histnodup || (histsz > 0 && strcmp(input, history[histsz-1]) != 0)) { /* TODO */
    164 +		if (0 >= fputs(input, fp)) {
    165 +			die("failed to write to %s", histfile);
    166 +		}
    167 +	}
    168 +	if (fclose(fp)) {
    169 +		die("failed to close file %s", histfile);
    170 +	}
    171 +
    172 +out:
    173 +	for (i = 0; i < histsz; i++) {
    174 +		free(history[i]);
    175 +	}
    176 +	free(history);
    177 +}
    178 +
    179  static void
    180  keypress(XKeyEvent *ev)
    181  {
    182 @@ -388,6 +515,14 @@ keypress(XKeyEvent *ev)
    183  		case XK_j: ksym = XK_Next;  break;
    184  		case XK_k: ksym = XK_Prior; break;
    185  		case XK_l: ksym = XK_Down;  break;
    186 +		case XK_p:
    187 +			navhistory(-1);
    188 +			buf[0]=0;
    189 +			break;
    190 +		case XK_n:
    191 +			navhistory(1);
    192 +			buf[0]=0;
    193 +			break;
    194  		default:
    195  			return;
    196  		}
    197 @@ -466,6 +601,8 @@ insert:
    198  	case XK_KP_Enter:
    199  		puts((sel && !(ev->state & ShiftMask)) ? sel->text : text);
    200  		if (!(ev->state & ControlMask)) {
    201 +			savehistory((sel && !(ev->state & ShiftMask))
    202 +				    ? sel->text : text);
    203  			cleanup();
    204  			exit(0);
    205  		}
    206 @@ -690,7 +827,8 @@ static void
    207  usage(void)
    208  {
    209  	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
    210 -	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr);
    211 +	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n"
    212 +	      "             [-H histfile]", stderr);
    213  	exit(1);
    214  }
    215 
    216 @@ -715,6 +853,8 @@ main(int argc, char *argv[])
    217  		} else if (i + 1 == argc)
    218  			usage();
    219  		/* these options take one argument */
    220 +		else if (!strcmp(argv[i], "-H"))
    221 +			histfile = argv[++i];
    222  		else if (!strcmp(argv[i], "-l"))   /* number of lines in vertical list */
    223  			lines = atoi(argv[++i]);
    224  		else if (!strcmp(argv[i], "-m"))
    225 @@ -757,6 +897,8 @@ main(int argc, char *argv[])
    226  		die("pledge");
    227  #endif
    228 
    229 +	loadhistory();
    230 +
    231  	if (fast && !isatty(0)) {
    232  		grabkeyboard();
    233  		readstdin();
    234 diff --git a/dmenu_run b/dmenu_run
    235 index 834ede5..59ec622 100755
    236 --- a/dmenu_run
    237 +++ b/dmenu_run
    238 @@ -1,2 +1,2 @@
    239  #!/bin/sh
    240 -dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &
    241 +dmenu_path | dmenu -H "${XDG_CACHE_HOME:-$HOME/.cache/}/dmenu_run.hist" "$@" | ${SHELL:-"/bin/sh"} &