diff options
| -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 | |||
