| dmenu-navhistory-5.0.diff - 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 <[email protected]> | |
| 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… | |
| 20 static unsigned int lines = 0; | |
| 21 +static unsigned int maxhist = 64; | |
| 22 +static int histnodup = 1; /* if 0, record repeated his… | |
| 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 usi… | |
| 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, h… | |
| 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 : te… | |
| 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] [… | |
| 222 - " [-nb color] [-nf color] [-sb color] [-sf co… | |
| 223 + " [-nb color] [-nf color] [-sb color] [-sf co… | |
| 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 i… | |
| 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"… | |
| 254 -- | |
| 255 2.25.1 | |
| 256 |