summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjustsaumit <justsaumit@draconyan.xyz>2022-03-02 07:46:02 +0530
committerjustsaumit <justsaumit@draconyan.xyz>2022-03-02 07:46:02 +0530
commit8d1c9ab37821fe51e17ccf34a8e0ec126f97fb47 (patch)
treef9daabb64c10ae4af54d15465147e08d0892c709
parent81ccc187368fcf0c60c3ffdddb257dbe39b00e1d (diff)
new patches
-rw-r--r--patches/3.dmenu-highpriority-4.9.diff (renamed from patches/5.dmenu-highpriority-4.9.diff)0
-rw-r--r--patches/4.dmenu-lineheight-5.0.diff106
-rw-r--r--patches/4.dmenu-numbers-4.9.diff (renamed from patches/3.dmenu-numbers-4.9.diff)0
-rw-r--r--patches/5.dmenu-instant-4.7.diff (renamed from patches/9.dmenu-instant-4.7.diff)0
-rw-r--r--patches/6.dmenu-mousesupport-5.1.diff144
-rw-r--r--patches/7.dmenu-textscroll-20180607-a314412.diff245
-rw-r--r--patches/8.dmenu-navhistory-5.0.diff256
-rw-r--r--patches/9.dmenu-highlight-20201211-fcdc159.diff97
8 files changed, 645 insertions, 203 deletions
diff --git a/patches/5.dmenu-highpriority-4.9.diff b/patches/3.dmenu-highpriority-4.9.diff
index 03e106a..03e106a 100644
--- a/patches/5.dmenu-highpriority-4.9.diff
+++ b/patches/3.dmenu-highpriority-4.9.diff
diff --git a/patches/4.dmenu-lineheight-5.0.diff b/patches/4.dmenu-lineheight-5.0.diff
deleted file mode 100644
index 3b0df3d..0000000
--- a/patches/4.dmenu-lineheight-5.0.diff
+++ /dev/null
@@ -1,106 +0,0 @@
-From ba103e38ea4ab07f9a3ee90627714b9bea17c329 Mon Sep 17 00:00:00 2001
-From: pskry <peter@skrypalle.dk>
-Date: Sun, 8 Nov 2020 22:04:22 +0100
-Subject: [PATCH] Add an option which defines the lineheight
-
-Despite both the panel and dmenu using the same font (a Terminus 12),
-dmenu is shorter and the panel is visible from under the dmenu bar.
-The appearance can be even more distracting when using similar colors
-for background and selections. With the option added by this patch,
-dmenu can be launched with a '-h 24', thus completely covering the panel.
----
- config.def.h | 3 +++
- dmenu.1 | 5 +++++
- dmenu.c | 11 ++++++++---
- 3 files changed, 16 insertions(+), 3 deletions(-)
-
-diff --git a/config.def.h b/config.def.h
-index 1edb647..4394dec 100644
---- a/config.def.h
-+++ b/config.def.h
-@@ -15,6 +15,9 @@ static const char *colors[SchemeLast][2] = {
- };
- /* -l option; if nonzero, dmenu uses vertical list with given number of lines */
- static unsigned int lines = 0;
-+/* -h option; minimum height of a menu line */
-+static unsigned int lineheight = 0;
-+static unsigned int min_lineheight = 8;
-
- /*
- * Characters not considered part of a word while deleting words
-diff --git a/dmenu.1 b/dmenu.1
-index 323f93c..f2a82b4 100644
---- a/dmenu.1
-+++ b/dmenu.1
-@@ -6,6 +6,8 @@ dmenu \- dynamic menu
- .RB [ \-bfiv ]
- .RB [ \-l
- .IR lines ]
-+.RB [ \-h
-+.IR height ]
- .RB [ \-m
- .IR monitor ]
- .RB [ \-p
-@@ -50,6 +52,9 @@ dmenu matches menu items case insensitively.
- .BI \-l " lines"
- dmenu lists items vertically, with the given number of lines.
- .TP
-+.BI \-h " height"
-+dmenu uses a menu line of at least 'height' pixels tall, but no less than 8.
-+.TP
- .BI \-m " monitor"
- dmenu is displayed on the monitor number supplied. Monitor numbers are starting
- from 0.
-diff --git a/dmenu.c b/dmenu.c
-index 65f25ce..f2a4047 100644
---- a/dmenu.c
-+++ b/dmenu.c
-@@ -131,7 +131,7 @@ drawmenu(void)
- {
- unsigned int curpos;
- struct item *item;
-- int x = 0, y = 0, w;
-+ int x = 0, y = 0, fh = drw->fonts->h, w;
-
- drw_setscheme(drw, scheme[SchemeNorm]);
- drw_rect(drw, 0, 0, mw, mh, 1, 1);
-@@ -148,7 +148,7 @@ drawmenu(void)
- curpos = TEXTW(text) - TEXTW(&text[cursor]);
- if ((curpos += lrpad / 2 - 1) < w) {
- drw_setscheme(drw, scheme[SchemeNorm]);
-- drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0);
-+ drw_rect(drw, x + curpos, 2 + (bh - fh) / 2, 2, fh - 4, 1, 0);
- }
-
- if (lines > 0) {
-@@ -609,6 +609,7 @@ setup(void)
-
- /* calculate menu geometry */
- bh = drw->fonts->h + 2;
-+ bh = MAX(bh,lineheight); /* make a menu line AT LEAST 'lineheight' tall */
- lines = MAX(lines, 0);
- mh = (lines + 1) * bh;
- #ifdef XINERAMA
-@@ -689,7 +690,7 @@ setup(void)
- static void
- usage(void)
- {
-- fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
-+ fputs("usage: dmenu [-bfiv] [-l lines] [-h height] [-p prompt] [-fn font] [-m monitor]\n"
- " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr);
- exit(1);
- }
-@@ -717,6 +718,10 @@ main(int argc, char *argv[])
- /* these options take one argument */
- else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */
- lines = atoi(argv[++i]);
-+ else if (!strcmp(argv[i], "-h")) { /* minimum height of one menu line */
-+ lineheight = atoi(argv[++i]);
-+ lineheight = MAX(lineheight, min_lineheight);
-+ }
- else if (!strcmp(argv[i], "-m"))
- mon = atoi(argv[++i]);
- else if (!strcmp(argv[i], "-p")) /* adds prompt to left of input field */
---
-2.29.2
-
diff --git a/patches/3.dmenu-numbers-4.9.diff b/patches/4.dmenu-numbers-4.9.diff
index 113be80..113be80 100644
--- a/patches/3.dmenu-numbers-4.9.diff
+++ b/patches/4.dmenu-numbers-4.9.diff
diff --git a/patches/9.dmenu-instant-4.7.diff b/patches/5.dmenu-instant-4.7.diff
index a78276f..a78276f 100644
--- a/patches/9.dmenu-instant-4.7.diff
+++ b/patches/5.dmenu-instant-4.7.diff
diff --git a/patches/6.dmenu-mousesupport-5.1.diff b/patches/6.dmenu-mousesupport-5.1.diff
new file mode 100644
index 0000000..49824ba
--- /dev/null
+++ b/patches/6.dmenu-mousesupport-5.1.diff
@@ -0,0 +1,144 @@
+diff --git a/dmenu.c b/dmenu.c
+index d95e6c6..75a79d0 100644
+--- a/dmenu.c
++++ b/dmenu.c
+@@ -518,6 +518,119 @@ draw:
+ drawmenu();
+ }
+
++static void
++buttonpress(XEvent *e)
++{
++ struct item *item;
++ XButtonPressedEvent *ev = &e->xbutton;
++ int x = 0, y = 0, h = bh, w;
++
++ if (ev->window != win)
++ return;
++
++ /* right-click: exit */
++ if (ev->button == Button3)
++ exit(1);
++
++ if (prompt && *prompt)
++ x += promptw;
++
++ /* input field */
++ w = (lines > 0 || !matches) ? mw - x : inputw;
++
++ /* left-click on input: clear input,
++ * NOTE: if there is no left-arrow the space for < is reserved so
++ * add that to the input width */
++ if (ev->button == Button1 &&
++ ((lines <= 0 && ev->x >= 0 && ev->x <= x + w +
++ ((!prev || !curr->left) ? TEXTW("<") : 0)) ||
++ (lines > 0 && ev->y >= y && ev->y <= y + h))) {
++ insert(NULL, -cursor);
++ drawmenu();
++ return;
++ }
++ /* middle-mouse click: paste selection */
++ if (ev->button == Button2) {
++ XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
++ utf8, utf8, win, CurrentTime);
++ drawmenu();
++ return;
++ }
++ /* scroll up */
++ if (ev->button == Button4 && prev) {
++ sel = curr = prev;
++ calcoffsets();
++ drawmenu();
++ return;
++ }
++ /* scroll down */
++ if (ev->button == Button5 && next) {
++ sel = curr = next;
++ calcoffsets();
++ drawmenu();
++ return;
++ }
++ if (ev->button != Button1)
++ return;
++ if (ev->state & ~ControlMask)
++ return;
++ if (lines > 0) {
++ /* vertical list: (ctrl)left-click on item */
++ w = mw - x;
++ for (item = curr; item != next; item = item->right) {
++ y += h;
++ if (ev->y >= y && ev->y <= (y + h)) {
++ puts(item->text);
++ if (!(ev->state & ControlMask))
++ exit(0);
++ sel = item;
++ if (sel) {
++ sel->out = 1;
++ drawmenu();
++ }
++ return;
++ }
++ }
++ } else if (matches) {
++ /* left-click on left arrow */
++ x += inputw;
++ w = TEXTW("<");
++ if (prev && curr->left) {
++ if (ev->x >= x && ev->x <= x + w) {
++ sel = curr = prev;
++ calcoffsets();
++ drawmenu();
++ return;
++ }
++ }
++ /* horizontal list: (ctrl)left-click on item */
++ for (item = curr; item != next; item = item->right) {
++ x += w;
++ w = MIN(TEXTW(item->text), mw - x - TEXTW(">"));
++ if (ev->x >= x && ev->x <= x + w) {
++ puts(item->text);
++ if (!(ev->state & ControlMask))
++ exit(0);
++ sel = item;
++ if (sel) {
++ sel->out = 1;
++ drawmenu();
++ }
++ return;
++ }
++ }
++ /* left-click on right arrow */
++ w = TEXTW(">");
++ x = mw - w;
++ if (next && ev->x >= x && ev->x <= x + w) {
++ sel = curr = next;
++ calcoffsets();
++ drawmenu();
++ return;
++ }
++ }
++}
++
+ static void
+ paste(void)
+ {
+@@ -579,6 +692,9 @@ run(void)
+ break;
+ cleanup();
+ exit(1);
++ case ButtonPress:
++ buttonpress(&ev);
++ break;
+ case Expose:
+ if (ev.xexpose.count == 0)
+ drw_map(drw, win, 0, 0, mw, mh);
+@@ -676,7 +792,8 @@ setup(void)
+ /* create menu window */
+ swa.override_redirect = True;
+ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
+- swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
++ swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask |
++ ButtonPressMask;
+ win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
+ CopyFromParent, CopyFromParent, CopyFromParent,
+ CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
diff --git a/patches/7.dmenu-textscroll-20180607-a314412.diff b/patches/7.dmenu-textscroll-20180607-a314412.diff
new file mode 100644
index 0000000..7a7386a
--- /dev/null
+++ b/patches/7.dmenu-textscroll-20180607-a314412.diff
@@ -0,0 +1,245 @@
+diff --git a/dmenu.c b/dmenu.c
+index 5c835dd..71efe52 100644
+--- a/dmenu.c
++++ b/dmenu.c
+@@ -131,9 +131,10 @@ drawitem(struct item *item, int x, int y, int w)
+ static void
+ drawmenu(void)
+ {
+- unsigned int curpos;
++ static int curpos, oldcurlen;
+ struct item *item;
+ int x = 0, y = 0, w;
++ int curlen, rcurlen;
+
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ drw_rect(drw, 0, 0, mw, mh, 1, 1);
+@@ -144,14 +145,21 @@ drawmenu(void)
+ }
+ /* draw input field */
+ w = (lines > 0 || !matches) ? mw - x : inputw;
+- drw_setscheme(drw, scheme[SchemeNorm]);
+- drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0);
++ w -= lrpad / 2;
++ x += lrpad / 2;
+
+- curpos = TEXTW(text) - TEXTW(&text[cursor]);
+- if ((curpos += lrpad / 2 - 1) < w) {
+- drw_setscheme(drw, scheme[SchemeNorm]);
+- drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0);
+- }
++ rcurlen = drw_fontset_getwidth(drw, text + cursor);
++ curlen = drw_fontset_getwidth(drw, text) - rcurlen;
++ curpos += curlen - oldcurlen;
++ curpos = MIN(w, MAX(0, curpos));
++ curpos = MAX(curpos, w - rcurlen);
++ curpos = MIN(curpos, curlen);
++ oldcurlen = curlen;
++
++ drw_setscheme(drw, scheme[SchemeNorm]);
++ drw_text_align(drw, x, 0, curpos, bh, text, cursor, AlignR);
++ drw_text_align(drw, x + curpos, 0, w - curpos, bh, text + cursor, strlen(text) - cursor, AlignL);
++ drw_rect(drw, x + curpos - 1, 2, 2, bh - 4, 1, 0);
+
+ if (lines > 0) {
+ /* draw vertical list */
+diff --git a/drw.c b/drw.c
+index c638323..bfffbc1 100644
+--- a/drw.c
++++ b/drw.c
+@@ -364,6 +364,175 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
+ return x + (render ? w : 0);
+ }
+
++int
++utf8nextchar(const char *str, int len, int i, int inc)
++{
++ int n;
++
++ for (n = i + inc; n + inc >= 0 && n + inc <= len
++ && (str[n] & 0xc0) == 0x80; n += inc)
++ ;
++ return n;
++}
++
++int
++drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align)
++{
++ int ty;
++ unsigned int ew;
++ XftDraw *d = NULL;
++ Fnt *usedfont, *curfont, *nextfont;
++ size_t len;
++ int utf8strlen, utf8charlen, render = x || y || w || h;
++ long utf8codepoint = 0;
++ const char *utf8str;
++ FcCharSet *fccharset;
++ FcPattern *fcpattern;
++ FcPattern *match;
++ XftResult result;
++ int charexists = 0;
++ int i, n;
++
++ if (!drw || (render && !drw->scheme) || !text || !drw->fonts || textlen <= 0
++ || (align != AlignL && align != AlignR))
++ return 0;
++
++ if (!render) {
++ w = ~w;
++ } else {
++ XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel);
++ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
++ d = XftDrawCreate(drw->dpy, drw->drawable,
++ DefaultVisual(drw->dpy, drw->screen),
++ DefaultColormap(drw->dpy, drw->screen));
++ }
++
++ usedfont = drw->fonts;
++ i = align == AlignL ? 0 : textlen;
++ x = align == AlignL ? x : x + w;
++ while (1) {
++ utf8strlen = 0;
++ nextfont = NULL;
++ /* if (align == AlignL) */
++ utf8str = text + i;
++
++ while ((align == AlignL && i < textlen) || (align == AlignR && i > 0)) {
++ if (align == AlignL) {
++ utf8charlen = utf8decode(text + i, &utf8codepoint, MIN(textlen - i, UTF_SIZ));
++ if (!utf8charlen) {
++ textlen = i;
++ break;
++ }
++ } else {
++ n = utf8nextchar(text, textlen, i, -1);
++ utf8charlen = utf8decode(text + n, &utf8codepoint, MIN(textlen - n, UTF_SIZ));
++ if (!utf8charlen) {
++ textlen -= i;
++ text += i;
++ i = 0;
++ break;
++ }
++ }
++ for (curfont = drw->fonts; curfont; curfont = curfont->next) {
++ charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
++ if (charexists) {
++ if (curfont == usedfont) {
++ utf8strlen += utf8charlen;
++ i += align == AlignL ? utf8charlen : -utf8charlen;
++ } else {
++ nextfont = curfont;
++ }
++ break;
++ }
++ }
++
++ if (!charexists || nextfont)
++ break;
++ else
++ charexists = 0;
++ }
++
++ if (align == AlignR)
++ utf8str = text + i;
++
++ if (utf8strlen) {
++ drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
++ /* shorten text if necessary */
++ if (align == AlignL) {
++ for (len = utf8strlen; len && ew > w; ) {
++ len = utf8nextchar(utf8str, len, len, -1);
++ drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
++ }
++ } else {
++ for (len = utf8strlen; len && ew > w; ) {
++ n = utf8nextchar(utf8str, len, 0, +1);
++ utf8str += n;
++ len -= n;
++ drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
++ }
++ }
++
++ if (len) {
++ if (render) {
++ ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
++ XftDrawStringUtf8(d, &drw->scheme[ColFg],
++ usedfont->xfont, align == AlignL ? x : x - ew, ty, (XftChar8 *)utf8str, len);
++ }
++ x += align == AlignL ? ew : -ew;
++ w -= ew;
++ }
++ if (len < utf8strlen)
++ break;
++ }
++
++ if ((align == AlignR && i <= 0) || (align == AlignL && i >= textlen)) {
++ break;
++ } else if (nextfont) {
++ charexists = 0;
++ usedfont = nextfont;
++ } else {
++ /* Regardless of whether or not a fallback font is found, the
++ * character must be drawn. */
++ charexists = 1;
++
++ fccharset = FcCharSetCreate();
++ FcCharSetAddChar(fccharset, utf8codepoint);
++
++ if (!drw->fonts->pattern) {
++ /* Refer to the comment in xfont_create for more information. */
++ die("the first font in the cache must be loaded from a font string.");
++ }
++
++ fcpattern = FcPatternDuplicate(drw->fonts->pattern);
++ FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
++ FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
++
++ FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
++ FcDefaultSubstitute(fcpattern);
++ match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
++
++ FcCharSetDestroy(fccharset);
++ FcPatternDestroy(fcpattern);
++
++ if (match) {
++ usedfont = xfont_create(drw, NULL, match);
++ if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
++ for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
++ ; /* NOP */
++ curfont->next = usedfont;
++ } else {
++ xfont_free(usedfont);
++ usedfont = drw->fonts;
++ }
++ }
++ }
++ }
++ if (d)
++ XftDrawDestroy(d);
++
++ return x;
++}
++
+ void
+ drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
+ {
+diff --git a/drw.h b/drw.h
+index 4c67419..b66a83e 100644
+--- a/drw.h
++++ b/drw.h
+@@ -13,6 +13,7 @@ typedef struct Fnt {
+ } Fnt;
+
+ enum { ColFg, ColBg }; /* Clr scheme index */
++enum { AlignL, AlignR };
+ typedef XftColor Clr;
+
+ typedef struct {
+@@ -52,6 +53,7 @@ void drw_setscheme(Drw *drw, Clr *scm);
+ /* Drawing functions */
+ void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
+ int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert);
++int drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align);
+
+ /* Map functions */
+ void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
diff --git a/patches/8.dmenu-navhistory-5.0.diff b/patches/8.dmenu-navhistory-5.0.diff
new file mode 100644
index 0000000..1f7cf6c
--- /dev/null
+++ b/patches/8.dmenu-navhistory-5.0.diff
@@ -0,0 +1,256 @@
+From a4a08baf35edb6b50ed14f76e99d0c6fe790759d Mon Sep 17 00:00:00 2001
+From: Max Schillinger <maxschillinger@web.de>
+Date: Fri, 9 Jul 2021 17:17:36 +0200
+Subject: [PATCH] Bug fix: Writing first entry to history file was skipped
+
+---
+ config.def.h | 2 +
+ dmenu.1 | 5 ++
+ dmenu.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++-
+ dmenu_run | 2 +-
+ 4 files changed, 151 insertions(+), 2 deletions(-)
+
+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..5023257 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 (histsz == 0 || !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"} &
+--
+2.25.1
+
diff --git a/patches/9.dmenu-highlight-20201211-fcdc159.diff b/patches/9.dmenu-highlight-20201211-fcdc159.diff
deleted file mode 100644
index c3ac5c1..0000000
--- a/patches/9.dmenu-highlight-20201211-fcdc159.diff
+++ /dev/null
@@ -1,97 +0,0 @@
-From fcdc1593ed418166f20b7e691a49b1e6eefc116e Mon Sep 17 00:00:00 2001
-From: Nathaniel Evan <nathanielevan@zohomail.com>
-Date: Fri, 11 Dec 2020 11:08:12 +0700
-Subject: [PATCH] Highlight matched text in a different color scheme
-
----
- config.def.h | 3 +++
- dmenu.c | 44 +++++++++++++++++++++++++++++++++++++++++---
- 2 files changed, 44 insertions(+), 3 deletions(-)
-
-diff --git a/config.def.h b/config.def.h
-index 1edb647..79be73a 100644
---- a/config.def.h
-+++ b/config.def.h
-@@ -11,7 +11,10 @@ static const char *colors[SchemeLast][2] = {
- /* fg bg */
- [SchemeNorm] = { "#bbbbbb", "#222222" },
- [SchemeSel] = { "#eeeeee", "#005577" },
-+ [SchemeSelHighlight] = { "#ffc978", "#005577" },
-+ [SchemeNormHighlight] = { "#ffc978", "#222222" },
- [SchemeOut] = { "#000000", "#00ffff" },
-+ [SchemeOutHighlight] = { "#ffc978", "#00ffff" },
- };
- /* -l option; if nonzero, dmenu uses vertical list with given number of lines */
- static unsigned int lines = 0;
-diff --git a/dmenu.c b/dmenu.c
-index 65f25ce..cce1ad1 100644
---- a/dmenu.c
-+++ b/dmenu.c
-@@ -26,8 +26,7 @@
- #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
-
- /* enums */
--enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */
--
-+enum { SchemeNorm, SchemeSel, SchemeOut, SchemeNormHighlight, SchemeSelHighlight, SchemeOutHighlight, SchemeLast }; /* color schemes */
- struct item {
- char *text;
- struct item *left, *right;
-@@ -113,6 +112,43 @@ cistrstr(const char *s, const char *sub)
- return NULL;
- }
-
-+static void
-+drawhighlights(struct item *item, int x, int y, int maxw)
-+{
-+ char restorechar, tokens[sizeof text], *highlight, *token;
-+ int indentx, highlightlen;
-+
-+ drw_setscheme(drw, scheme[item == sel ? SchemeSelHighlight : item->out ? SchemeOutHighlight : SchemeNormHighlight]);
-+ strcpy(tokens, text);
-+ for (token = strtok(tokens, " "); token; token = strtok(NULL, " ")) {
-+ highlight = fstrstr(item->text, token);
-+ while (highlight) {
-+ // Move item str end, calc width for highlight indent, & restore
-+ highlightlen = highlight - item->text;
-+ restorechar = *highlight;
-+ item->text[highlightlen] = '\0';
-+ indentx = TEXTW(item->text);
-+ item->text[highlightlen] = restorechar;
-+
-+ // Move highlight str end, draw highlight, & restore
-+ restorechar = highlight[strlen(token)];
-+ highlight[strlen(token)] = '\0';
-+ if (indentx - (lrpad / 2) - 1 < maxw)
-+ drw_text(
-+ drw,
-+ x + indentx - (lrpad / 2) - 1,
-+ y,
-+ MIN(maxw - indentx, TEXTW(highlight) - lrpad),
-+ bh, 0, highlight, 0
-+ );
-+ highlight[strlen(token)] = restorechar;
-+
-+ if (strlen(highlight) - strlen(token) < strlen(token)) break;
-+ highlight = fstrstr(highlight + strlen(token), token);
-+ }
-+ }
-+}
-+
- static int
- drawitem(struct item *item, int x, int y, int w)
- {
-@@ -123,7 +159,9 @@ drawitem(struct item *item, int x, int y, int w)
- else
- drw_setscheme(drw, scheme[SchemeNorm]);
-
-- return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0);
-+ int r = drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0);
-+ drawhighlights(item, x, y, w);
-+ return r;
- }
-
- static void
---
-2.29.2
-