1 From 94353eb52055927d9079f3d9e33da1c954abf386 Mon Sep 17 00:00:00 2001
2 From: aleks <aleks.stier@icloud.com>
3 Date: Wed, 26 Jun 2019 13:25:10 +0200
4 Subject: [PATCH] Add support for fuzzy-matching
9 dmenu.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++
10 3 files changed, 91 insertions(+), 1 deletion(-)
12 diff --git a/config.def.h b/config.def.h
13 index 1edb647..51612b9 100644
17 /* Default settings; can be overriden by command line. */
19 static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
20 +static int fuzzy = 1; /* -F option; if 0, dmenu doesn't use fuzzy matching */
21 /* -fn option overrides fonts[0]; default X11 font or font set */
22 static const char *fonts[] = {
24 diff --git a/config.mk b/config.mk
25 index 0929b4a..d14309a 100644
28 @@ -20,7 +20,7 @@ FREETYPEINC = /usr/include/freetype2
31 INCS = -I$(X11INC) -I$(FREETYPEINC)
32 -LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS)
33 +LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lm
36 CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS)
37 diff --git a/dmenu.c b/dmenu.c
38 index 6b8f51b..96ddc98 100644
42 /* See LICENSE file for copyright and license details. */
49 @@ -32,6 +33,7 @@ struct item {
51 struct item *left, *right;
56 static char text[BUFSIZ] = "";
57 @@ -210,9 +212,94 @@ grabkeyboard(void)
58 die("cannot grab keyboard");
62 +compare_distance(const void *a, const void *b)
64 + struct item *da = *(struct item **) a;
65 + struct item *db = *(struct item **) b;
72 + return da->distance == db->distance ? 0 : da->distance < db->distance ? -1 : 1;
78 + /* bang - we have so much memory */
80 + struct item **fuzzymatches = NULL;
82 + int number_of_matches = 0, i, pidx, sidx, eidx;
83 + int text_len = strlen(text), itext_len;
85 + matches = matchend = NULL;
87 + /* walk through all items */
88 + for (it = items; it && it->text; it++) {
90 + itext_len = strlen(it->text);
91 + pidx = 0; /* pointer */
92 + sidx = eidx = -1; /* start of match, end of match */
93 + /* walk through item text */
94 + for (i = 0; i < itext_len && (c = it->text[i]); i++) {
95 + /* fuzzy match pattern */
96 + if (!fstrncmp(&text[pidx], &c, 1)) {
100 + if (pidx == text_len) {
106 + /* build list of matches */
108 + /* compute distance */
109 + /* add penalty if match starts late (log(sidx+2))
110 + * add penalty for long a match without many matching characters */
111 + it->distance = log(sidx + 2) + (double)(eidx - sidx - text_len);
112 + /* fprintf(stderr, "distance %s %f\n", it->text, it->distance); */
113 + appenditem(it, &matches, &matchend);
114 + number_of_matches++;
117 + appenditem(it, &matches, &matchend);
121 + if (number_of_matches) {
122 + /* initialize array with matches */
123 + if (!(fuzzymatches = realloc(fuzzymatches, number_of_matches * sizeof(struct item*))))
124 + die("cannot realloc %u bytes:", number_of_matches * sizeof(struct item*));
125 + for (i = 0, it = matches; it && i < number_of_matches; i++, it = it->right) {
126 + fuzzymatches[i] = it;
128 + /* sort matches according to distance */
129 + qsort(fuzzymatches, number_of_matches, sizeof(struct item*), compare_distance);
130 + /* rebuild list of matches */
131 + matches = matchend = NULL;
132 + for (i = 0, it = fuzzymatches[i]; i < number_of_matches && it && \
133 + it->text; i++, it = fuzzymatches[i]) {
134 + appenditem(it, &matches, &matchend);
136 + free(fuzzymatches);
138 + curr = sel = matches;
149 static char **tokv = NULL;
152 @@ -702,6 +789,8 @@ main(int argc, char *argv[])
154 else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */
156 + else if (!strcmp(argv[i], "-F")) /* grabs keyboard before reading stdin */
158 else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
159 fstrncmp = strncasecmp;