From d5ef112748f6b3c7999a6335da2026e4d60f3eb9 Mon Sep 17 00:00:00 2001 From: Lia Lenckowski Date: Thu, 17 Aug 2023 12:17:50 +0200 Subject: swap fuse for a faster fuzzy search backend --- .gitignore | 2 +- frontend/start.ts | 26 +++++++++++++------------- makefile | 9 +++++---- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 9d043c8..1ab3e8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ .stack-work /deploy -frontend/fuse.js +frontend/fuzzysort.js diff --git a/frontend/start.ts b/frontend/start.ts index 71c1923..4b8019d 100644 --- a/frontend/start.ts +++ b/frontend/start.ts @@ -1,7 +1,7 @@ import { e } from "./helper.ts" import { bangs } from "./query.ts" import { status } from "./ui.ts" -import Fuse from "./fuse.js" +import fuzzysort from "./fuzzysort.js" export function section_info_start() { return e("section", { class: "info" }, @@ -59,39 +59,39 @@ export function section_engine_select() { ) } -// TODO fuse is a bit slow; this search function may hinder fast typing -interface FuseItem { bang: string, name: string, url: string } -let bangsSearch: Promise<{ search: (name: string) => { item: FuseItem }[] }> | undefined = undefined; +interface FuzzItem { score: number, obj: E } +let bangsSearch: Promise<(query: string) => FuzzItem<{bang: string, name: string, url: string}>[]> + | undefined = undefined; function setSearchResults(ul: HTMLElement, input: HTMLInputElement, submit: () => void) { if (bangsSearch === undefined) { bangsSearch = bangs.then(bangs => { - const searchSpace = [] + const searchSpace: {bang: string, name: string, url: string}[] = [] for (const k in bangs) { searchSpace.push({ bang: k, - name: bangs[k]!.name, - url: bangs[k]!.url + name: bangs[k]!.name!, + url: bangs[k]!.url! }) } - return new Fuse(searchSpace, { + return q => fuzzysort.go(q, searchSpace, { + threshhold: -5000, + limit: 5, keys: ["bang", "name"], - minMatchCharLength: 3 }) }) } - bangsSearch.then(fuse => { + bangsSearch.then(fs => { ul.innerHTML = "" - const results = fuse.search(input.value).slice(0, 5) + const results = fs(input.value) if (results.length === 0) ul.style.display = "none" else { ul.style.display = "flex" for (const r of results) { - const it = r.item - + const it = r.obj const li = e("li", {}, e("p", { class: "name" }, it.name), e("p", { class: "bang" }, it.bang)) diff --git a/makefile b/makefile index 7bef75e..510c397 100644 --- a/makefile +++ b/makefile @@ -3,7 +3,7 @@ ESFLAGS = --target=esnext --format=esm deploy-dir: deploy deploy/bundle.js deploy/style.css deploy/index.html deploy/fastbangs .PHONY: watch clean deploy-dir -watch-script: frontend/fuse.js +watch-script: frontend/fuzzysort.js esbuild frontend/main.ts --bundle --outfile=deploy/bundle.js $(ESFLAGS) --watch watch-style: while true; do inotifywait -e modify -e move frontend/style.sass; make deploy/style.css; done @@ -12,6 +12,7 @@ clean: stack clean --full rm -f deploy/{bundle.js,index.html,fastbangs,style.css} rm -f deploy.zip + rm -f frontend/fuzzysort.js # This leaves the deploy directory, which is intentional, as it may contain # user data @@ -23,10 +24,10 @@ deploy/index.html: frontend/index.html cp $< $@ deploy/fastbangs: $(shell find src -name '*.hs') stack install --local-bin-path deploy -deploy/bundle.js: $(shell find frontend -name '*.ts') frontend/fuse.js +deploy/bundle.js: $(shell find frontend -name '*.ts') frontend/fuzzysort.js esbuild frontend/main.ts --bundle --outfile=deploy/bundle.js $(ESFLAGS) deploy/style.css: frontend/style.sass sassc $< $@ -frontend/fuse.js: - curl 'https://cdn.jsdelivr.net/npm/fuse.js@6.6.2/dist/fuse.esm.js' -o $@ +frontend/fuzzysort.js: + curl 'https://cdn.jsdelivr.net/npm/fuzzysort@2.0.4/fuzzysort.min.js' -o $@ -- cgit v1.2.3-70-g09d2