sites

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

dmenu-navhistory-5.0.diff (5744B)


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