From a32e316cd1e1150d21a4e218c3d883e9af3d1e32 Mon Sep 17 00:00:00 2001 From: Hieu Le Date: Sun, 1 Nov 2026 23:43:40 +0100 Subject: [PATCH] perf(shared): stop single-token message search at the best hit --- packages/shared/src/paletteSearch.test.ts | 29 +++++++++++++++++++++++ packages/shared/src/paletteSearch.ts | 13 +++++++--- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/packages/shared/src/paletteSearch.test.ts b/packages/shared/src/paletteSearch.test.ts index 644a40912640a..d30b3189ee42c 100644 --- a/packages/shared/src/paletteSearch.test.ts +++ b/packages/shared/src/paletteSearch.test.ts @@ -661,6 +661,26 @@ describe("scoreMessageMatch", () => { expect(scoreMessageMatch("We trust the build", "rust")).toEqual({ quality: 0.3, offset: 4 }); expect(scoreMessageMatch("Rust and trust", "rust")).toEqual({ quality: 1, offset: 0 }); expect(scoreMessageMatch("Use the sidebar", '"sidebar"')).toEqual({ quality: 1, offset: 8 }); + for (const [text, query, expected] of [ + ["model mode mode", "mode", { quality: 1, offset: 6 }], + ["xmode model models", "mode", { quality: 0.8, offset: 6 }], + ["model models", "mode", { quality: 0.8, offset: 0 }], + ["xmode ymode", "mode", { quality: 0.3, offset: 1 }], + ["mode mode", "mode", { quality: 1, offset: 0 }], + ["fts fts", "fts", { quality: 1, offset: 0 }], + ["the theme", "he", null], + ["he theme", "he", { quality: 1, offset: 0 }], + ["notes", "", { quality: 1, offset: 0 }], + ["", "notes", null], + ["same same same", "same same", { quality: 1.25, offset: 0 }], + ["7cafe52bb8 cafe cafe", "cafe", { quality: 1, offset: 11 }], + ["7cafe52bb8 7cafe52bb8", "7cafe52", { quality: 1, offset: 0 }], + ["明天部署部署到生产环境", "部署", { quality: 1, offset: 2 }], + ["gannet’s gannet's", "gannet's", { quality: 1, offset: 9 }], + ["gannet's gannet’s", "gannet’s", { quality: 1, offset: 0 }], + ] as const) { + expect(scoreMessageMatch(text, query), `${query} in ${text}`).toEqual(expected); + } // Words written together as typed rank above the same words apart, and // the snippet starts where they are together. const together = "Run the tests, then vp run dev to check"; @@ -736,5 +756,14 @@ describe("scoreMessageMatch", () => { expect(scoreMessageMatch("İ Enable fts and model", "fts")).toMatchObject({ offset: 9 }); expect(scoreMessageMatch("İ Enable fts and model", "model")?.quality).toBe(1); expect(scoreMessageMatch("Trip to İstanbul", "İstanbul")).toEqual({ quality: 1, offset: 8 }); + for (const [text, query, expected] of [ + ["İ cafeteria Café CAFÉ", "cafe", { quality: 1, offset: 12 }], + ["Café cafe", "cafe", { quality: 1, offset: 5 }], + ["İ Café Café", "café", { quality: 1, offset: 2 }], + ["İ Résumé Résumé", "resume", { quality: 1, offset: 2 }], + ["İ résuméprefix résumé", "resume", { quality: 1, offset: 15 }], + ] as const) { + expect(scoreMessageMatch(text, query), `${query} in ${text}`).toEqual(expected); + } }); }); diff --git a/packages/shared/src/paletteSearch.ts b/packages/shared/src/paletteSearch.ts index 8594100a27e70..af7d4ca48a0cf 100644 --- a/packages/shared/src/paletteSearch.ts +++ b/packages/shared/src/paletteSearch.ts @@ -535,6 +535,7 @@ function findMessageToken( text: string, folded: string, token: string, + firstOnly: boolean, ): { readonly at: ReadonlyArray; readonly quality: number } | null { let quality = 0; let at: number[] = []; @@ -559,7 +560,8 @@ function findMessageToken( if (found > quality) { quality = found; at = [index]; - } else if (found === quality) { + if (firstOnly && quality === 1) return { at, quality }; + } else if (!firstOnly && found === quality) { at.push(index); } } @@ -611,10 +613,15 @@ export function messageMatcher(query: string): (text: string) => MessageMatch | let quality = 1; const positions: Array> = []; for (const { token, folded: foldedToken, nonAscii, mustStartWord, grades } of tokens) { - let found = findMessageToken(text, plain, token); + let found = findMessageToken(text, plain, token, tokens.length === 1); // Accents typed or left out: "cafe" finds "Café", also after "cafeteria". if (found?.quality !== 1 && foldedToken.length > 0 && (nonAscii || NON_ASCII.test(text))) { - found = findMessageToken(text, (folded ??= foldInPlace(text)), foldedToken); + found = findMessageToken( + text, + (folded ??= foldInPlace(text)), + foldedToken, + tokens.length === 1, + ); } if (found === null) return null; if (found.quality === MID_WORD && mustStartWord) return null;