sites

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

dmenu-navhistory+search-20250328-52fc8a0.diff (6641B)


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