commit ebfa338f8a3206c92885600229d983f2be4682a2
Author: Philip K <[email protected]>
Date:   Thu Jul 9 10:28:19 2020 +0200

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

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
new file mode 100644
index 00000000..e9c101f3
--- /dev/null
+++ 
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, "
");
++              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] = '++ 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
", 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]
"
+-            "             [-nb color] [-nf color] [-sb color] [-sf color] [-w 
windowid]
", stderr);
++            "             [-nb color] [-nf color] [-sb color] [-sf color] [-w 
windowid]
"
++            "             [-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
new file mode 100644
index 00000000..4acd9970
--- /dev/null
+++ 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, "
");
++              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] = '++ 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
", 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]
"
+-            "             [-nb color] [-nf color] [-sb color] [-sf color] [-w 
windowid]
", stderr);
++            "             [-nb color] [-nf color] [-sb color] [-sf color] [-w 
windowid]
"
++            "             [-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
index d78d00dd..0df5450b 100644
--- 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 <[email protected]>
+* zge <[email protected]>


Reply via email to