sites

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

commit ebfa338f8a3206c92885600229d983f2be4682a2
parent 04350def97572383730cfa37dcba05eef62eac82
Author: Philip K <philip@warpmail.net>
Date:   Thu,  9 Jul 2020 10:28:19 +0200

[dmenu][patch] navhist: update and add search patch

Diffstat:
Atools.suckless.org/dmenu/patches/navhistory/dmenu-navhistory+search-20200709.diff | 283+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/dmenu/patches/navhistory/dmenu-navhistory-20200709.diff | 241+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtools.suckless.org/dmenu/patches/navhistory/index.md | 10++++++++++
3 files changed, 534 insertions(+), 0 deletions(-)

diff --git a/tools.suckless.org/dmenu/patches/navhistory/dmenu-navhistory+search-20200709.diff b/tools.suckless.org/dmenu/patches/navhistory/dmenu-navhistory+search-20200709.diff @@ -0,0 +1,283 @@ +diff --git a/config.def.h b/config.def.h +index 1edb647..e3e1b53 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,6 +15,8 @@ static const char *colors[SchemeLast][2] = { + }; + /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ + static unsigned int lines = 0; ++static unsigned int maxhist = 64; ++static int histnodup = 1; /* if 0, record repeated histories */ + + /* + * Characters not considered part of a word while deleting words +diff --git a/dmenu.1 b/dmenu.1 +index 323f93c..ff496dd 100644 +--- a/dmenu.1 ++++ b/dmenu.1 +@@ -22,6 +22,8 @@ dmenu \- dynamic menu + .IR color ] + .RB [ \-w + .IR windowid ] ++.RB [ \-H ++.IR histfile ] + .P + .BR dmenu_run " ..." + .SH DESCRIPTION +@@ -80,6 +82,9 @@ prints version information to stdout, then exits. + .TP + .BI \-w " windowid" + embed into windowid. ++.TP ++.BI \-H " histfile" ++save input in histfile and use it for history navigation. + .SH USAGE + dmenu is completely controlled by the keyboard. Items are selected using the + arrow keys, page up, page down, home, and end. +diff --git a/dmenu.c b/dmenu.c +index 65f25ce..4242eb4 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -40,7 +40,7 @@ static int bh, mw, mh; + static int inputw = 0, promptw; + static int lrpad; /* sum of left and right padding */ + static size_t cursor; +-static struct item *items = NULL; ++static struct item *items = NULL, *backup_items; + static struct item *matches, *matchend; + static struct item *prev, *curr, *next, *sel; + static int mon = -1, screen; +@@ -53,6 +53,10 @@ static XIC xic; + static Drw *drw; + static Clr *scheme[SchemeLast]; + ++static char *histfile; ++static char **history; ++static size_t histsz, histpos; ++ + #include "config.h" + + static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; +@@ -304,11 +308,134 @@ movewordedge(int dir) + } + } + ++static void ++loadhistory(void) ++{ ++ FILE *fp = NULL; ++ static size_t cap = 0; ++ size_t llen; ++ char *line; ++ ++ if (!histfile) { ++ return; ++ } ++ ++ fp = fopen(histfile, "r"); ++ if (!fp) { ++ return; ++ } ++ ++ for (;;) { ++ line = NULL; ++ llen = 0; ++ if (-1 == getline(&line, &llen, fp)) { ++ if (ferror(fp)) { ++ die("failed to read history"); ++ } ++ free(line); ++ break; ++ } ++ ++ if (cap == histsz) { ++ cap += 64 * sizeof(char*); ++ history = realloc(history, cap); ++ if (!history) { ++ die("failed to realloc memory"); ++ } ++ } ++ strtok(line, "\n"); ++ history[histsz] = line; ++ histsz++; ++ } ++ histpos = histsz; ++ ++ if (fclose(fp)) { ++ die("failed to close file %s", histfile); ++ } ++} ++ ++static void ++navhistory(int dir) ++{ ++ static char def[BUFSIZ]; ++ char *p = NULL; ++ size_t len = 0; ++ ++ if (!history || histpos + 1 == 0) ++ return; ++ ++ if (histsz == histpos) { ++ strncpy(def, text, sizeof(def)); ++ } ++ ++ switch(dir) { ++ case 1: ++ if (histpos < histsz - 1) { ++ p = history[++histpos]; ++ } else if (histpos == histsz - 1) { ++ p = def; ++ histpos++; ++ } ++ break; ++ case -1: ++ if (histpos > 0) { ++ p = history[--histpos]; ++ } ++ break; ++ } ++ if (p == NULL) { ++ return; ++ } ++ ++ len = MIN(strlen(p), BUFSIZ - 1); ++ strncpy(text, p, len); ++ text[len] = '\0'; ++ cursor = len; ++ match(); ++} ++ ++static void ++savehistory(char *input) ++{ ++ unsigned int i; ++ FILE *fp; ++ ++ if (!histfile || ++ 0 == maxhist || ++ 0 == strlen(input)) { ++ goto out; ++ } ++ ++ fp = fopen(histfile, "w"); ++ if (!fp) { ++ die("failed to open %s", histfile); ++ } ++ for (i = histsz < maxhist ? 0 : histsz - maxhist; i < histsz; i++) { ++ if (0 >= fprintf(fp, "%s\n", history[i])) { ++ die("failed to write to %s", histfile); ++ } ++ } ++ if (!histnodup || (histsz > 0 && strcmp(input, history[histsz-1]) != 0)) { /* TODO */ ++ if (0 >= fputs(input, fp)) { ++ die("failed to write to %s", histfile); ++ } ++ } ++ if (fclose(fp)) { ++ die("failed to close file %s", histfile); ++ } ++ ++out: ++ for (i = 0; i < histsz; i++) { ++ free(history[i]); ++ } ++ free(history); ++} ++ + static void + keypress(XKeyEvent *ev) + { + char buf[32]; +- int len; ++ int len, i; + KeySym ksym; + Status status; + +@@ -359,6 +486,26 @@ keypress(XKeyEvent *ev) + XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, + utf8, utf8, win, CurrentTime); + return; ++ case XK_r: ++ if (histfile) { ++ if (!backup_items) { ++ backup_items = items; ++ items = calloc(histsz + 1, sizeof(struct item)); ++ if (!items) { ++ die("cannot allocate memory"); ++ } ++ ++ for (i = 0; i < histsz; i++) { ++ items[i].text = history[i]; ++ } ++ } else { ++ free(items); ++ items = backup_items; ++ backup_items = NULL; ++ } ++ } ++ match(); ++ goto draw; + case XK_Left: + movewordedge(-1); + goto draw; +@@ -388,6 +535,14 @@ keypress(XKeyEvent *ev) + case XK_j: ksym = XK_Next; break; + case XK_k: ksym = XK_Prior; break; + case XK_l: ksym = XK_Down; break; ++ case XK_p: ++ navhistory(-1); ++ buf[0]=0; ++ break; ++ case XK_n: ++ navhistory(1); ++ buf[0]=0; ++ break; + default: + return; + } +@@ -466,6 +621,8 @@ insert: + case XK_KP_Enter: + puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); + if (!(ev->state & ControlMask)) { ++ savehistory((sel && !(ev->state & ShiftMask)) ++ ? sel->text : text); + cleanup(); + exit(0); + } +@@ -690,7 +847,8 @@ static void + usage(void) + { + fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" +- " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); ++ " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n" ++ " [-H histfile]", stderr); + exit(1); + } + +@@ -715,6 +873,8 @@ main(int argc, char *argv[]) + } else if (i + 1 == argc) + usage(); + /* these options take one argument */ ++ else if (!strcmp(argv[i], "-H")) ++ histfile = argv[++i]; + else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */ + lines = atoi(argv[++i]); + else if (!strcmp(argv[i], "-m")) +@@ -757,6 +917,8 @@ main(int argc, char *argv[]) + die("pledge"); + #endif + ++ loadhistory(); ++ + if (fast && !isatty(0)) { + grabkeyboard(); + readstdin(); +diff --git a/dmenu_run b/dmenu_run +index 834ede5..59ec622 100755 +--- a/dmenu_run ++++ b/dmenu_run +@@ -1,2 +1,2 @@ + #!/bin/sh +-dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} & ++dmenu_path | dmenu -H "${XDG_CACHE_HOME:-$HOME/.cache/}/dmenu_run.hist" "$@" | ${SHELL:-"/bin/sh"} & diff --git a/tools.suckless.org/dmenu/patches/navhistory/dmenu-navhistory-20200709.diff b/tools.suckless.org/dmenu/patches/navhistory/dmenu-navhistory-20200709.diff @@ -0,0 +1,241 @@ +diff --git a/config.def.h b/config.def.h +index 1edb647..e3e1b53 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,6 +15,8 @@ static const char *colors[SchemeLast][2] = { + }; + /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ + static unsigned int lines = 0; ++static unsigned int maxhist = 64; ++static int histnodup = 1; /* if 0, record repeated histories */ + + /* + * Characters not considered part of a word while deleting words +diff --git a/dmenu.1 b/dmenu.1 +index 323f93c..ff496dd 100644 +--- a/dmenu.1 ++++ b/dmenu.1 +@@ -22,6 +22,8 @@ dmenu \- dynamic menu + .IR color ] + .RB [ \-w + .IR windowid ] ++.RB [ \-H ++.IR histfile ] + .P + .BR dmenu_run " ..." + .SH DESCRIPTION +@@ -80,6 +82,9 @@ prints version information to stdout, then exits. + .TP + .BI \-w " windowid" + embed into windowid. ++.TP ++.BI \-H " histfile" ++save input in histfile and use it for history navigation. + .SH USAGE + dmenu is completely controlled by the keyboard. Items are selected using the + arrow keys, page up, page down, home, and end. +diff --git a/dmenu.c b/dmenu.c +index 65f25ce..9d15f78 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -53,6 +53,10 @@ static XIC xic; + static Drw *drw; + static Clr *scheme[SchemeLast]; + ++static char *histfile; ++static char **history; ++static size_t histsz, histpos; ++ + #include "config.h" + + static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; +@@ -304,6 +308,129 @@ movewordedge(int dir) + } + } + ++static void ++loadhistory(void) ++{ ++ FILE *fp = NULL; ++ static size_t cap = 0; ++ size_t llen; ++ char *line; ++ ++ if (!histfile) { ++ return; ++ } ++ ++ fp = fopen(histfile, "r"); ++ if (!fp) { ++ return; ++ } ++ ++ for (;;) { ++ line = NULL; ++ llen = 0; ++ if (-1 == getline(&line, &llen, fp)) { ++ if (ferror(fp)) { ++ die("failed to read history"); ++ } ++ free(line); ++ break; ++ } ++ ++ if (cap == histsz) { ++ cap += 64 * sizeof(char*); ++ history = realloc(history, cap); ++ if (!history) { ++ die("failed to realloc memory"); ++ } ++ } ++ strtok(line, "\n"); ++ history[histsz] = line; ++ histsz++; ++ } ++ histpos = histsz; ++ ++ if (fclose(fp)) { ++ die("failed to close file %s", histfile); ++ } ++} ++ ++static void ++navhistory(int dir) ++{ ++ static char def[BUFSIZ]; ++ char *p = NULL; ++ size_t len = 0; ++ ++ if (!history || histpos + 1 == 0) ++ return; ++ ++ if (histsz == histpos) { ++ strncpy(def, text, sizeof(def)); ++ } ++ ++ switch(dir) { ++ case 1: ++ if (histpos < histsz - 1) { ++ p = history[++histpos]; ++ } else if (histpos == histsz - 1) { ++ p = def; ++ histpos++; ++ } ++ break; ++ case -1: ++ if (histpos > 0) { ++ p = history[--histpos]; ++ } ++ break; ++ } ++ if (p == NULL) { ++ return; ++ } ++ ++ len = MIN(strlen(p), BUFSIZ - 1); ++ strncpy(text, p, len); ++ text[len] = '\0'; ++ cursor = len; ++ match(); ++} ++ ++static void ++savehistory(char *input) ++{ ++ unsigned int i; ++ FILE *fp; ++ ++ if (!histfile || ++ 0 == maxhist || ++ 0 == strlen(input)) { ++ goto out; ++ } ++ ++ fp = fopen(histfile, "w"); ++ if (!fp) { ++ die("failed to open %s", histfile); ++ } ++ for (i = histsz < maxhist ? 0 : histsz - maxhist; i < histsz; i++) { ++ if (0 >= fprintf(fp, "%s\n", history[i])) { ++ die("failed to write to %s", histfile); ++ } ++ } ++ if (!histnodup || (histsz > 0 && strcmp(input, history[histsz-1]) != 0)) { /* TODO */ ++ if (0 >= fputs(input, fp)) { ++ die("failed to write to %s", histfile); ++ } ++ } ++ if (fclose(fp)) { ++ die("failed to close file %s", histfile); ++ } ++ ++out: ++ for (i = 0; i < histsz; i++) { ++ free(history[i]); ++ } ++ free(history); ++} ++ + static void + keypress(XKeyEvent *ev) + { +@@ -388,6 +515,14 @@ keypress(XKeyEvent *ev) + case XK_j: ksym = XK_Next; break; + case XK_k: ksym = XK_Prior; break; + case XK_l: ksym = XK_Down; break; ++ case XK_p: ++ navhistory(-1); ++ buf[0]=0; ++ break; ++ case XK_n: ++ navhistory(1); ++ buf[0]=0; ++ break; + default: + return; + } +@@ -466,6 +601,8 @@ insert: + case XK_KP_Enter: + puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); + if (!(ev->state & ControlMask)) { ++ savehistory((sel && !(ev->state & ShiftMask)) ++ ? sel->text : text); + cleanup(); + exit(0); + } +@@ -690,7 +827,8 @@ static void + usage(void) + { + fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" +- " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); ++ " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n" ++ " [-H histfile]", stderr); + exit(1); + } + +@@ -715,6 +853,8 @@ main(int argc, char *argv[]) + } else if (i + 1 == argc) + usage(); + /* these options take one argument */ ++ else if (!strcmp(argv[i], "-H")) ++ histfile = argv[++i]; + else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */ + lines = atoi(argv[++i]); + else if (!strcmp(argv[i], "-m")) +@@ -757,6 +897,8 @@ main(int argc, char *argv[]) + die("pledge"); + #endif + ++ loadhistory(); ++ + if (fast && !isatty(0)) { + grabkeyboard(); + readstdin(); +diff --git a/dmenu_run b/dmenu_run +index 834ede5..59ec622 100755 +--- a/dmenu_run ++++ b/dmenu_run +@@ -1,2 +1,2 @@ + #!/bin/sh +-dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} & ++dmenu_path | dmenu -H "${XDG_CACHE_HOME:-$HOME/.cache/}/dmenu_run.hist" "$@" | ${SHELL:-"/bin/sh"} & diff --git a/tools.suckless.org/dmenu/patches/navhistory/index.md b/tools.suckless.org/dmenu/patches/navhistory/index.md @@ -15,7 +15,17 @@ To change this behaviour, set 'histnodup' to 0 in config.h. Download -------- * [dmenu-navhistory-4.6.diff](dmenu-navhistory-4.6.diff) +* [dmenu-navhistory-20200709.diff](dmenu-navhistory-20200709.diff) + +### With Search +This patch extends navhist with history-search functionality. Press +ctrl-r, like in bash or ksh, and the suggestions will be replaced with +the history. Press ctrl-r again to revert. + +* [dmenu-navhistory+search-20200709.diff](dmenu-navhistory+search-20200709.diff) + Author ------ * phi <crispyfrog@163.com> +* zge <philip@warpmail.net>