dmenu

my fork of dmenu
Index Commits Files Refs README LICENSE
patches/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