about summary refs log tree commit diff
path: root/patches/dmenu-fuzzymatch-4.9.diff
diff options
context:
space:
mode:
Diffstat (limited to 'patches/dmenu-fuzzymatch-4.9.diff')
-rw-r--r--patches/dmenu-fuzzymatch-4.9.diff167
1 files changed, 167 insertions, 0 deletions
diff --git a/patches/dmenu-fuzzymatch-4.9.diff b/patches/dmenu-fuzzymatch-4.9.diff
new file mode 100644
index 0000000..97712fa
--- /dev/null
+++ b/patches/dmenu-fuzzymatch-4.9.diff
@@ -0,0 +1,167 @@
+diff --git a/config.h b/config.h
+index 704fb6f..625b1a4 100644
+--- a/config.h
++++ b/config.h
+@@ -2,6 +2,7 @@
+ /* Default settings; can be overriden by command line. */
+ 
+ static int topbar = 1;                      /* -b  option; if 0, dmenu appears at bottom     */
++static int fuzzy = 1;                      /* -F  option; if 0, dmenu doesn't use fuzzy matching     */
+ /* -fn option overrides fonts[0]; default X11 font or font set */
+ static const char *fonts[] = {
+ 	"Noto Sans Display Nerd Font:size=10"
+diff --git a/config.mk b/config.mk
+index 260eeae..74396bc 100644
+--- a/config.mk
++++ b/config.mk
+@@ -20,7 +20,7 @@ FREETYPEINC = /usr/include/freetype2
+ 
+ # includes and libs
+ INCS = -I$(X11INC) -I$(FREETYPEINC)
+-LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lXrender
++LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lXrender -lm
+ 
+ # flags
+ CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS)
+diff --git a/dmenu.1 b/dmenu.1
+index fe988bc..35e164e 100644
+--- a/dmenu.1
++++ b/dmenu.1
+@@ -47,6 +47,9 @@ dmenu appears at the bottom of the screen.
+ dmenu grabs the keyboard before reading stdin if not reading from a tty. This
+ is faster, but will lock up X until stdin reaches end\-of\-file.
+ .TP
++.B \-F
++dmenu sorts items using fuzzymatch
++.TP
+ .B \-i
+ dmenu matches menu items case insensitively.
+ .TP
+diff --git a/dmenu.c b/dmenu.c
+index 95bcace..0f7d5dd 100644
+--- a/dmenu.c
++++ b/dmenu.c
+@@ -1,6 +1,7 @@
+ /* See LICENSE file for copyright and license details. */
+ #include <ctype.h>
+ #include <locale.h>
++#include <math.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -34,6 +35,7 @@ struct item {
+ 	char *text;
+ 	struct item *left, *right;
+ 	int out;
++  double distance;
+ };
+ static void xinitvisual();
+ static char text[BUFSIZ] = "";
+@@ -199,6 +201,87 @@ grabfocus(void)
+ 	die("cannot grab focus");
+ }
+ 
++int
++compare_distance(const void *a, const void *b)
++{
++	struct item *da = *(struct item **) a;
++	struct item *db = *(struct item **) b;
++
++	if (!db)
++		return 1;
++	if (!da)
++		return -1;
++
++	return da->distance == db->distance ? 0 : da->distance < db->distance ? -1 : 1;
++}
++
++void
++fuzzymatch(void)
++{
++	/* bang - we have so much memory */
++	struct item *it;
++	struct item **fuzzymatches = NULL;
++	char c;
++	int number_of_matches = 0, i, pidx, sidx, eidx;
++	int text_len = strlen(text), itext_len;
++
++	matches = matchend = NULL;
++
++	/* walk through all items */
++	for (it = items; it && it->text; it++) {
++		if (text_len) {
++			itext_len = strlen(it->text);
++			pidx = 0; /* pointer */
++			sidx = eidx = -1; /* start of match, end of match */
++			/* walk through item text */
++			for (i = 0; i < itext_len && (c = it->text[i]); i++) {
++				/* fuzzy match pattern */
++				if (!fstrncmp(&text[pidx], &c, 1)) {
++					if(sidx == -1)
++						sidx = i;
++					pidx++;
++					if (pidx == text_len) {
++						eidx = i;
++						break;
++					}
++				}
++			}
++			/* build list of matches */
++			if (eidx != -1) {
++				/* compute distance */
++				/* add penalty if match starts late (log(sidx+2))
++				 * add penalty for long a match without many matching characters */
++				it->distance = log(sidx + 2) + (double)(eidx - sidx - text_len);
++				/* fprintf(stderr, "distance %s %f\n", it->text, it->distance); */
++				appenditem(it, &matches, &matchend);
++				number_of_matches++;
++			}
++		} else {
++			appenditem(it, &matches, &matchend);
++		}
++	}
++
++	if (number_of_matches) {
++		/* initialize array with matches */
++		if (!(fuzzymatches = realloc(fuzzymatches, number_of_matches * sizeof(struct item*))))
++			die("cannot realloc %u bytes:", number_of_matches * sizeof(struct item*));
++		for (i = 0, it = matches; it && i < number_of_matches; i++, it = it->right) {
++			fuzzymatches[i] = it;
++		}
++		/* sort matches according to distance */
++		qsort(fuzzymatches, number_of_matches, sizeof(struct item*), compare_distance);
++		/* rebuild list of matches */
++		matches = matchend = NULL;
++		for (i = 0, it = fuzzymatches[i];  i < number_of_matches && it && \
++				it->text; i++, it = fuzzymatches[i]) {
++			appenditem(it, &matches, &matchend);
++		}
++		free(fuzzymatches);
++	}
++	curr = sel = matches;
++	calcoffsets();
++}
++
+ static void
+ grabkeyboard(void)
+ {
+@@ -220,6 +303,10 @@ grabkeyboard(void)
+ static void
+ match(void)
+ {
++  if (fuzzy) {
++  	fuzzymatch();
++  	return;
++  }
+ 	static char **tokv = NULL;
+ 	static int tokn = 0;
+ 
+@@ -887,6 +974,8 @@ main(int argc, char *argv[])
+ 			topbar = 0;
+ 		else if (!strcmp(argv[i], "-f"))   /* grabs keyboard before reading stdin */
+ 			fast = 1;
++    else if (!strcmp(argv[i], "-F"))   /* grabs keyboard before reading stdin */
++      fuzzy = 0;
+ 		else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
+ 			fstrncmp = strncasecmp;
+ 			fstrstr = cistrstr;