From 6af26c335bd24d54e4cb5b7ad61984d7c2570780 Mon Sep 17 00:00:00 2001
From: Andrea Brancaleoni <miwaxe@gmail.com>
Date: Tue, 10 Nov 2015 19:50:35 +0100
Subject: [PATCH] dmenu: add fuzzymatch optional support

---
 srcpkgs/dmenu/files/fuzzymatch.patch | 147 +++++++++++++++++++++++++++
 srcpkgs/dmenu/template               |  11 ++
 2 files changed, 158 insertions(+)
 create mode 100644 srcpkgs/dmenu/files/fuzzymatch.patch

diff --git a/srcpkgs/dmenu/files/fuzzymatch.patch b/srcpkgs/dmenu/files/fuzzymatch.patch
new file mode 100644
index 00000000000..5216f8a2d7e
--- /dev/null
+++ b/srcpkgs/dmenu/files/fuzzymatch.patch
@@ -0,0 +1,147 @@
+From 34e4ada60c7ca73cfdd83a02c7416af39dfc0dc0 Mon Sep 17 00:00:00 2001
+From: Andrea Brancaleoni <miwaxe@gmail.com>
+Date: Tue, 10 Nov 2015 19:29:45 +0100
+Subject: [PATCH] fuzzymatch-4.6
+
+---
+ dmenu.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 85 insertions(+), 4 deletions(-)
+
+diff --git a/dmenu.c b/dmenu.c
+index a07f8e3..c26ecfc 100644
+--- a/dmenu.c
++++ b/dmenu.c
+@@ -32,6 +32,7 @@ struct item {
+ 	char *text;
+ 	struct item *left, *right;
+ 	int out;
++	int distance;
+ };
+ 
+ static char text[BUFSIZ] = "";
+@@ -253,6 +254,86 @@ match(void)
+ 	calcoffsets();
+ }
+ 
++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;
++}
++
++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;
++			sidx = eidx = -1;
++			/* walk through item text */
++			for (i = 0; i < itext_len && (c = it->text[i]); i++) {
++				/* fuzzy match pattern */
++				if (text[pidx] == c) {
++					if(sidx == -1)
++						sidx = i;
++					pidx++;
++					if (pidx == text_len) {
++						eidx = i;
++						break;
++					}
++				}
++			}
++			/* build list of matches */
++			if (eidx != -1) {
++				/* compute distance */
++				/* factor in 30% of sidx and distance between eidx and total
++				 * text length .. let's see how it works */
++				it->distance = eidx - sidx + (itext_len - eidx + sidx) / 3;
++				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
+ insert(const char *str, ssize_t n)
+ {
+@@ -263,7 +344,7 @@ insert(const char *str, ssize_t n)
+ 	if (n > 0)
+ 		memcpy(&text[cursor], str, n);
+ 	cursor += n;
+-	match();
++	fuzzymatch();
+ }
+ 
+ static size_t
+@@ -308,7 +389,7 @@ keypress(XKeyEvent *ev)
+ 
+ 		case XK_k: /* delete right */
+ 			text[cursor] = '\0';
+-			match();
++			fuzzymatch();
+ 			break;
+ 		case XK_u: /* delete left */
+ 			insert(NULL, 0 - cursor);
+@@ -442,7 +523,7 @@ keypress(XKeyEvent *ev)
+ 		strncpy(text, sel->text, sizeof text - 1);
+ 		text[sizeof text - 1] = '\0';
+ 		cursor = strlen(text);
+-		match();
++		fuzzymatch();
+ 		break;
+ 	}
+ 	drawmenu();
+@@ -584,7 +665,7 @@ setup(void)
+ 	}
+ 	promptw = (prompt && *prompt) ? TEXTW(prompt) : 0;
+ 	inputw = MIN(inputw, mw/3);
+-	match();
++	fuzzymatch();
+ 
+ 	/* create menu window */
+ 	swa.override_redirect = True;
+-- 
+2.6.3
+
diff --git a/srcpkgs/dmenu/template b/srcpkgs/dmenu/template
index a83567382b9..4b9b8ef369f 100644
--- a/srcpkgs/dmenu/template
+++ b/srcpkgs/dmenu/template
@@ -10,6 +10,17 @@ homepage="http://tools.suckless.org/dmenu/"
 distfiles="http://dl.suckless.org/tools/${pkgname}-${version}.tar.gz"
 checksum=4a7a24008a621c3cd656155ad91ab8136db8f0d3b9ec56dafeec518cabda96b3
 
+build_options="fuzzymatch"
+desc_option_fuzzymatch="Enable Fuzzymatch support"
+
+pre_build() {
+	local srcdir="${XBPS_SRCDISTDIR}/${pkgname}-${version}/"
+	if [ "$build_option_fuzzymatch" ]; then
+		msg_normal "Applying fuzzymatch patches"
+		patch -p1 < "${FILESDIR}/fuzzymatch.patch"
+	fi
+}
+
 do_build() {
 	cp ${FILESDIR}/config.h config.h
 	sed -i -e "s|^FREETYPEINC|#FREETYPEINC|g" \