sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

dmenu-fuzzymatch-4.9.diff (4683B)


      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
      5 
      6 ---
      7  config.def.h |  1 +
      8  config.mk    |  2 +-
      9  dmenu.c      | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++
     10  3 files changed, 91 insertions(+), 1 deletion(-)
     11 
     12 diff --git a/config.def.h b/config.def.h
     13 index 1edb647..51612b9 100644
     14 --- a/config.def.h
     15 +++ b/config.def.h
     16 @@ -2,6 +2,7 @@
     17  /* Default settings; can be overriden by command line. */
     18  
     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[] = {
     23  	"monospace:size=10"
     24 diff --git a/config.mk b/config.mk
     25 index 0929b4a..d14309a 100644
     26 --- a/config.mk
     27 +++ b/config.mk
     28 @@ -20,7 +20,7 @@ FREETYPEINC = /usr/include/freetype2
     29  
     30  # includes and libs
     31  INCS = -I$(X11INC) -I$(FREETYPEINC)
     32 -LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS)
     33 +LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lm
     34  
     35  # flags
     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
     39 --- a/dmenu.c
     40 +++ b/dmenu.c
     41 @@ -1,6 +1,7 @@
     42  /* See LICENSE file for copyright and license details. */
     43  #include <ctype.h>
     44  #include <locale.h>
     45 +#include <math.h>
     46  #include <stdio.h>
     47  #include <stdlib.h>
     48  #include <string.h>
     49 @@ -32,6 +33,7 @@ struct item {
     50  	char *text;
     51  	struct item *left, *right;
     52  	int out;
     53 +	double distance;
     54  };
     55  
     56  static char text[BUFSIZ] = "";
     57 @@ -210,9 +212,94 @@ grabkeyboard(void)
     58  	die("cannot grab keyboard");
     59  }
     60  
     61 +int
     62 +compare_distance(const void *a, const void *b)
     63 +{
     64 +	struct item *da = *(struct item **) a;
     65 +	struct item *db = *(struct item **) b;
     66 +
     67 +	if (!db)
     68 +		return 1;
     69 +	if (!da)
     70 +		return -1;
     71 +
     72 +	return da->distance == db->distance ? 0 : da->distance < db->distance ? -1 : 1;
     73 +}
     74 +
     75 +void
     76 +fuzzymatch(void)
     77 +{
     78 +	/* bang - we have so much memory */
     79 +	struct item *it;
     80 +	struct item **fuzzymatches = NULL;
     81 +	char c;
     82 +	int number_of_matches = 0, i, pidx, sidx, eidx;
     83 +	int text_len = strlen(text), itext_len;
     84 +
     85 +	matches = matchend = NULL;
     86 +
     87 +	/* walk through all items */
     88 +	for (it = items; it && it->text; it++) {
     89 +		if (text_len) {
     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)) {
     97 +					if(sidx == -1)
     98 +						sidx = i;
     99 +					pidx++;
    100 +					if (pidx == text_len) {
    101 +						eidx = i;
    102 +						break;
    103 +					}
    104 +				}
    105 +			}
    106 +			/* build list of matches */
    107 +			if (eidx != -1) {
    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++;
    115 +			}
    116 +		} else {
    117 +			appenditem(it, &matches, &matchend);
    118 +		}
    119 +	}
    120 +
    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;
    127 +		}
    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);
    135 +		}
    136 +		free(fuzzymatches);
    137 +	}
    138 +	curr = sel = matches;
    139 +	calcoffsets();
    140 +}
    141 +
    142  static void
    143  match(void)
    144  {
    145 +	if (fuzzy) {
    146 +		fuzzymatch();
    147 +		return;
    148 +	}
    149  	static char **tokv = NULL;
    150  	static int tokn = 0;
    151  
    152 @@ -702,6 +789,8 @@ main(int argc, char *argv[])
    153  			topbar = 0;
    154  		else if (!strcmp(argv[i], "-f"))   /* grabs keyboard before reading stdin */
    155  			fast = 1;
    156 +		else if (!strcmp(argv[i], "-F"))   /* grabs keyboard before reading stdin */
    157 +			fuzzy = 0;
    158  		else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
    159  			fstrncmp = strncasecmp;
    160  			fstrstr = cistrstr;
    161 -- 
    162 2.22.0
    163