diff --git a/libs/argv.c b/libs/argv.c index 786761d..ab367f0 100644 --- a/libs/argv.c +++ b/libs/argv.c @@ -142,7 +142,7 @@ readargs(int argc, char *argv[]) } else if (!strcmp(argv[i], "-hp")) { menupaddingh = atoi(argv[++i]); } else if (!strcmp(argv[i], "-pri")) { - parse_hpitems(argv[++i]); + hpitems = tokenize(argv[++i], ",", &hplength); } else if (!strcmp(argv[i], "-ig")) { imagegaps = atoi(argv[++i]); } else if (!strcmp(argv[i], "-la")) { diff --git a/libs/sort.c b/libs/sort.c index 683c976..128309d 100644 --- a/libs/sort.c +++ b/libs/sort.c @@ -1,22 +1,35 @@ -int -str_compar(const void *s0_in, const void *s1_in) +char ** +tokenize(char *source, const char *delim, int *llen) { - const char *s0 = *(const char **)s0_in; - const char *s1 = *(const char **)s1_in; - return fstrncmp == strncasecmp ? strcasecmp(s0, s1) : strcmp(s0, s1); -} + int listlength = 0, list_size = 0; + char **list = NULL, *token; -void -parse_hpitems(char *src) -{ - int n = 0; - char *t; - - for (t = strtok(src, ","); t; t = strtok(NULL, ",")) { - if (hplength + 1 >= n) { - if (!(hpitems = realloc(hpitems, (n += 8) * sizeof *hpitems))) - die("Unable to realloc %zu bytes\n", n * sizeof *hpitems); + token = strtok(source, delim); + while (token) { + if (listlength + 1 >= list_size) { + if (!(list = realloc(list, (list_size += 8) * sizeof(*list)))) + die("Unable to realloc %zu bytes\n", list_size * sizeof(*list)); } - hpitems[hplength++] = t; + if (!(list[listlength] = strdup(token))) + die("Unable to strdup %zu bytes\n", strlen(token) + 1); + token = strtok(NULL, delim); + listlength++; } + + *llen = listlength; + return list; +} + +int +arrayhas(char **list, int length, char *item) +{ + int i; + + for (i = 0; i < length; i++) { + size_t len1 = strlen(list[i]); + size_t len2 = strlen(item); + if (!fstrncmp(list[i], item, len1 > len2 ? len2 : len1)) + return 1; + } + return 0; } diff --git a/libs/sort.h b/libs/sort.h index d450e32..e83c7b2 100644 --- a/libs/sort.h +++ b/libs/sort.h @@ -1,2 +1,2 @@ -static int str_compar(const void *s0_in, const void *s1_in); -static void parse_hpitems(char *src); +static char **tokenize(char *source, const char *delim, int *llen); +static int arrayhas(char **list, int length, char *item); diff --git a/options.h b/options.h index 4a9eab4..669dbf3 100644 --- a/options.h +++ b/options.h @@ -48,7 +48,6 @@ static int casesensitive = 0; /* Case-sensitive by default? (0/1) static int preselected = 0; /* Which line should spmenu preselect? */ static int accuratewidth = 1; /* Enable accurate width. May have a performance hit if you are matching a lot of items at once */ static int fuzzy = 1; /* Whether or not to enable fuzzy matching by default */ -static char **hpitems = NULL; /* High priority items */ /* Line options */ static int lineheight = 5; /* Line height (0: Calculate automatically) */ diff --git a/spmenu.c b/spmenu.c index 79e5df6..f8e50b5 100644 --- a/spmenu.c +++ b/spmenu.c @@ -135,6 +135,7 @@ typedef struct { static char numbers[NUMBERSBUFSIZE] = ""; static int hplength = 0; +static char **hpitems = NULL; static char *embed; static int numlockmask = 0; static int bh, mw, mh; @@ -320,8 +321,13 @@ cleanup(void) #endif XUngrabKey(dpy, AnyKey, AnyModifier, root); + for (i = 0; i < SchemeLast; i++) free(scheme[i]); + + for (i = 0; i < hplength; ++i) + free(hpitems[i]); + drw_free(drw); XSync(dpy, False); XCloseDisplay(dpy); @@ -410,6 +416,8 @@ fuzzymatch(void) /* bang - we have so much memory */ struct item *it; struct item **fuzzymatches = NULL; + struct item *lhpprefix, *hpprefixend; + lhpprefix = hpprefixend = NULL; char c; int number_of_matches = 0, i, pidx, sidx, eidx; int text_len = strlen(text), itext_len; @@ -458,16 +466,26 @@ fuzzymatch(void) fuzzymatches[i] = it; } /* sort matches according to distance */ - qsort(fuzzymatches, number_of_matches, sizeof(struct item*), compare_distance); + if (sortmatches) qsort(fuzzymatches, number_of_matches, sizeof(struct item*), compare_distance); + /* rebuild list of matches */ matches = matchend = NULL; for (i = 0, it = fuzzymatches[i]; i < number_of_matches && it && \ it->text; i++, it = fuzzymatches[i]) { - appenditem(it, &matches, &matchend); + + if (sortmatches && it->hp) + appenditem(it, &lhpprefix, &hpprefixend); + + appenditem(it, &matches, &matchend); } free(fuzzymatches); } + if (lhpprefix) { + hpprefixend->right = matches; + matches = lhpprefix; + } + curr = sel = matches; for (i = 0; i < preselected; i++) { @@ -515,10 +533,10 @@ match(void) appenditem(item, &matches, &matchend); else { /* exact matches go first, then prefixes with high priority, then prefixes, then substrings */ - if (!tokc || !fstrncmp(text, item->text, textsize)) - appenditem(item, &matches, &matchend); - else if (item->hp && !fstrncmp(tokv[0], item->text, len)) + if (item->hp && !fstrncmp(tokv[0], item->text, len)) appenditem(item, &lhpprefix, &hpprefixend); + else if (!tokc || !fstrncmp(text, item->text, textsize)) + appenditem(item, &matches, &matchend); else if (!fstrncmp(tokv[0], item->text, len)) appenditem(item, &lprefix, &prefixend); else @@ -749,9 +767,6 @@ readstdin(void) return; } - if (hpitems && hplength > 0) - qsort(hpitems, hplength, sizeof *hpitems, str_compar); - /* read each line from stdin and add it to the item list */ for (i = 0; fgets(buf, sizeof buf, stdin); i++) { if (i + 1 >= itemsiz) { @@ -763,11 +778,7 @@ readstdin(void) *p = '\0'; if (!(items[i].text = strdup(buf))) die("cannot strdup %u bytes:", strlen(buf) + 1); - p = hpitems == NULL ? NULL : bsearch( - &items[i].text, hpitems, hplength, sizeof *hpitems, - str_compar - ); - items[i].hp = p != NULL; + items[i].hp = arrayhas(hpitems, hplength, items[i].text); drw_font_getexts(drw->font, buf, strlen(buf), &tmpmax, NULL, True); if (tmpmax > inputw) { inputw = tmpmax;