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