diff options
author | Sam Chudnick <sam@chudnick.com> | 2023-02-25 22:04:40 -0500 |
---|---|---|
committer | Sam Chudnick <sam@chudnick.com> | 2023-02-25 22:04:40 -0500 |
commit | 66d02ca70f0d58bce2f7f4da72e3fc090d4cba6d (patch) | |
tree | b44f2d9e6bf4c6c5dc0f7ad16e0af2583ce6ba61 | |
parent | ae8e8b68270205defacecdc88d8eba591e462b9d (diff) |
Apply fuzzymatch patch
-rw-r--r-- | config.h | 1 | ||||
-rw-r--r-- | config.mk | 2 | ||||
-rwxr-xr-x | dmenu | bin | 0 -> 44432 bytes | |||
-rw-r--r-- | dmenu.c | 91 | ||||
-rwxr-xr-x | stest | bin | 0 -> 17680 bytes |
5 files changed, 92 insertions, 2 deletions
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ | 4 | static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ |
5 | static const unsigned int alpha = 0xf0; | 5 | static const unsigned int alpha = 0xf0; |
6 | static int fuzzy = 1; /* -F option; if 0, dmenu doesn't use fuzzy matching */ | ||
6 | /* -fn option overrides fonts[0]; default X11 font or font set */ | 7 | /* -fn option overrides fonts[0]; default X11 font or font set */ |
7 | static const char *fonts[] = { | 8 | static const char *fonts[] = { |
8 | "monospace:size=10" | 9 | "monospace:size=10" |
@@ -21,7 +21,7 @@ FREETYPEINC = /usr/include/freetype2 | |||
21 | 21 | ||
22 | # includes and libs | 22 | # includes and libs |
23 | INCS = -I$(X11INC) -I$(FREETYPEINC) | 23 | INCS = -I$(X11INC) -I$(FREETYPEINC) |
24 | LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) | 24 | LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lm -lXrender |
25 | 25 | ||
26 | # flags | 26 | # flags |
27 | CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) | 27 | CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) |
Binary files differ | |||
@@ -1,6 +1,7 @@ | |||
1 | /* See LICENSE file for copyright and license details. */ | 1 | /* See LICENSE file for copyright and license details. */ |
2 | #include <ctype.h> | 2 | #include <ctype.h> |
3 | #include <locale.h> | 3 | #include <locale.h> |
4 | #include <math.h> | ||
4 | #include <stdio.h> | 5 | #include <stdio.h> |
5 | #include <stdlib.h> | 6 | #include <stdlib.h> |
6 | #include <string.h> | 7 | #include <string.h> |
@@ -35,6 +36,7 @@ struct item { | |||
35 | char *text; | 36 | char *text; |
36 | struct item *left, *right; | 37 | struct item *left, *right; |
37 | int out; | 38 | int out; |
39 | double distance; | ||
38 | }; | 40 | }; |
39 | 41 | ||
40 | static char text[BUFSIZ] = ""; | 42 | static char text[BUFSIZ] = ""; |
@@ -236,9 +238,94 @@ grabkeyboard(void) | |||
236 | die("cannot grab keyboard"); | 238 | die("cannot grab keyboard"); |
237 | } | 239 | } |
238 | 240 | ||
241 | int | ||
242 | compare_distance(const void *a, const void *b) | ||
243 | { | ||
244 | struct item *da = *(struct item **) a; | ||
245 | struct item *db = *(struct item **) b; | ||
246 | |||
247 | if (!db) | ||
248 | return 1; | ||
249 | if (!da) | ||
250 | return -1; | ||
251 | |||
252 | return da->distance == db->distance ? 0 : da->distance < db->distance ? -1 : 1; | ||
253 | } | ||
254 | |||
255 | void | ||
256 | fuzzymatch(void) | ||
257 | { | ||
258 | /* bang - we have so much memory */ | ||
259 | struct item *it; | ||
260 | struct item **fuzzymatches = NULL; | ||
261 | char c; | ||
262 | int number_of_matches = 0, i, pidx, sidx, eidx; | ||
263 | int text_len = strlen(text), itext_len; | ||
264 | |||
265 | matches = matchend = NULL; | ||
266 | |||
267 | /* walk through all items */ | ||
268 | for (it = items; it && it->text; it++) { | ||
269 | if (text_len) { | ||
270 | itext_len = strlen(it->text); | ||
271 | pidx = 0; /* pointer */ | ||
272 | sidx = eidx = -1; /* start of match, end of match */ | ||
273 | /* walk through item text */ | ||
274 | for (i = 0; i < itext_len && (c = it->text[i]); i++) { | ||
275 | /* fuzzy match pattern */ | ||
276 | if (!fstrncmp(&text[pidx], &c, 1)) { | ||
277 | if(sidx == -1) | ||
278 | sidx = i; | ||
279 | pidx++; | ||
280 | if (pidx == text_len) { | ||
281 | eidx = i; | ||
282 | break; | ||
283 | } | ||
284 | } | ||
285 | } | ||
286 | /* build list of matches */ | ||
287 | if (eidx != -1) { | ||
288 | /* compute distance */ | ||
289 | /* add penalty if match starts late (log(sidx+2)) | ||
290 | * add penalty for long a match without many matching characters */ | ||
291 | it->distance = log(sidx + 2) + (double)(eidx - sidx - text_len); | ||
292 | /* fprintf(stderr, "distance %s %f\n", it->text, it->distance); */ | ||
293 | appenditem(it, &matches, &matchend); | ||
294 | number_of_matches++; | ||
295 | } | ||
296 | } else { | ||
297 | appenditem(it, &matches, &matchend); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | if (number_of_matches) { | ||
302 | /* initialize array with matches */ | ||
303 | if (!(fuzzymatches = realloc(fuzzymatches, number_of_matches * sizeof(struct item*)))) | ||
304 | die("cannot realloc %u bytes:", number_of_matches * sizeof(struct item*)); | ||
305 | for (i = 0, it = matches; it && i < number_of_matches; i++, it = it->right) { | ||
306 | fuzzymatches[i] = it; | ||
307 | } | ||
308 | /* sort matches according to distance */ | ||
309 | qsort(fuzzymatches, number_of_matches, sizeof(struct item*), compare_distance); | ||
310 | /* rebuild list of matches */ | ||
311 | matches = matchend = NULL; | ||
312 | for (i = 0, it = fuzzymatches[i]; i < number_of_matches && it && \ | ||
313 | it->text; i++, it = fuzzymatches[i]) { | ||
314 | appenditem(it, &matches, &matchend); | ||
315 | } | ||
316 | free(fuzzymatches); | ||
317 | } | ||
318 | curr = sel = matches; | ||
319 | calcoffsets(); | ||
320 | } | ||
321 | |||
239 | static void | 322 | static void |
240 | match(void) | 323 | match(void) |
241 | { | 324 | { |
325 | if (fuzzy) { | ||
326 | fuzzymatch(); | ||
327 | return; | ||
328 | } | ||
242 | static char **tokv = NULL; | 329 | static char **tokv = NULL; |
243 | static int tokn = 0; | 330 | static int tokn = 0; |
244 | 331 | ||
@@ -692,7 +779,7 @@ setup(void) | |||
692 | swa.border_pixel = 0; | 779 | swa.border_pixel = 0; |
693 | swa.colormap = cmap; | 780 | swa.colormap = cmap; |
694 | swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; | 781 | swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; |
695 | win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width, | 782 | win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0, |
696 | depth, CopyFromParent, visual, | 783 | depth, CopyFromParent, visual, |
697 | CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &swa); | 784 | CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &swa); |
698 | XSetClassHint(dpy, win, &ch); | 785 | XSetClassHint(dpy, win, &ch); |
@@ -741,6 +828,8 @@ main(int argc, char *argv[]) | |||
741 | topbar = 0; | 828 | topbar = 0; |
742 | else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ | 829 | else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ |
743 | fast = 1; | 830 | fast = 1; |
831 | else if (!strcmp(argv[i], "-F")) /* grabs keyboard before reading stdin */ | ||
832 | fuzzy = 0; | ||
744 | else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ | 833 | else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ |
745 | fstrncmp = strncasecmp; | 834 | fstrncmp = strncasecmp; |
746 | fstrstr = cistrstr; | 835 | fstrstr = cistrstr; |
Binary files differ | |||