Recently Written · git

sbm-extension

sbm bookmarks for Firefox and Chrome: fuzzy search, add the page, sync with bm and the sbm app

git clone https://github.com/equwal/sbm-extension

Log | Files | Refs


lib/fuzzy.js (1753 bytes)

1 // Search as in fzf. Each word of the query must occur in the text, with its
2 // letters in order but not always together. Case does not matter.
3 "use strict";
4 
5 const Fuzzy = (() => {
6   const letterOrDigit = /[\p{L}\p{N}]/u;
7 
8   function startsWord(hay, i) {
9     return i === 0 || !letterOrDigit.test(hay[i - 1]);
10   }
11 
12   function scoreWord(word, hay) {
13     // The whole word in one place scores highest, most at the start of a word.
14     const at = hay.indexOf(word);
15     if (at >= 0) return 100 + word.length + (startsWord(hay, at) ? 20 : 0);
16     let score = 0;
17     let previous = -2;
18     let from = 0;
19     for (const c of word) {
20       const i = hay.indexOf(c, from);
21       if (i < 0) return null;
22       score += 1;
23       if (i === previous + 1) score += 5;
24       if (startsWord(hay, i)) score += 3;
25       previous = i;
26       from = i + c.length;
27     }
28     return score;
29   }
30 
31   return {
32     /** The score of query in text, or null when a word does not occur. Higher is better. */
33     score(query, text) {
34       const hay = text.toLowerCase();
35       let total = 0;
36       for (const word of query.toLowerCase().split(/[ \t]/)) {
37         if (word === "") continue;
38         const s = scoreWord(word, hay);
39         if (s === null) return null;
40         total += s;
41       }
42       return total;
43     },
44 
45     /** The items that match query, best first. Items with the same score keep their order. */
46     filter(items, query, text) {
47       if (query.trim() === "") return items;
48       return items
49         .map((item, i) => ({ item, i, s: Fuzzy.score(query, text(item)) }))
50         .filter((x) => x.s !== null)
51         .sort((a, b) => b.s - a.s || a.i - b.i)
52         .map((x) => x.item);
53     },
54   };
55 })();
56 
57 if (typeof module !== "undefined") module.exports = Fuzzy;