From a6cd501a78cdc515168d30586306d9497e2694cf Mon Sep 17 00:00:00 2001 From: Eve <92513238+1320209572@users.noreply.github.com> Date: Tue, 8 Sep 2026 11:51:07 +0800 Subject: [PATCH] fix(elasticsearch): support fuzzy index completion --- .../lib/elasticsearch/elasticsearchCompletion.ts | 14 +++++++++++++- packages/app-tests/elasticsearchCompletion.test.ts | 12 ++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src/lib/elasticsearch/elasticsearchCompletion.ts b/apps/desktop/src/lib/elasticsearch/elasticsearchCompletion.ts index 3d3d2161bb..3ecfec07df 100644 --- a/apps/desktop/src/lib/elasticsearch/elasticsearchCompletion.ts +++ b/apps/desktop/src/lib/elasticsearch/elasticsearchCompletion.ts @@ -242,7 +242,7 @@ function pathItems(context: ElasticsearchCompletionContext, indices: string[]): function indexItems(prefix: string, indices: string[]): ElasticsearchCompletionItem[] { return indices - .filter((index) => matchesFuzzyPrefix(index, prefix)) + .filter((index) => matchesIndexFuzzyPrefix(index, prefix)) .slice(0, 100) .map((index) => ({ label: index, @@ -373,6 +373,18 @@ function matchesPrefix(value: string, prefix: string): boolean { return value.toLowerCase().startsWith(prefix.toLowerCase()); } +function matchesIndexFuzzyPrefix(value: string, prefix: string): boolean { + const normalizedValue = value.toLowerCase(); + const normalizedPrefix = prefix.toLowerCase(); + let from = 0; + for (const char of normalizedPrefix) { + const position = normalizedValue.indexOf(char, from); + if (position < 0) return false; + from = position + char.length; + } + return true; +} + function matchesFuzzyPrefix(value: string, prefix: string): boolean { const normalizedValue = value.toLowerCase(); const normalizedPrefix = prefix.toLowerCase(); diff --git a/packages/app-tests/elasticsearchCompletion.test.ts b/packages/app-tests/elasticsearchCompletion.test.ts index 1455090472..abeb822efb 100644 --- a/packages/app-tests/elasticsearchCompletion.test.ts +++ b/packages/app-tests/elasticsearchCompletion.test.ts @@ -60,6 +60,18 @@ test("suggests Elasticsearch indices by prefix", () => { ); }); +test("suggests Elasticsearch indices by case-insensitive ordered cross-segment match", () => { + const text = "GET /MiM"; + const items = buildElasticsearchCompletionItems(text, text.length, { + indices: ["my_index_misc_20260907", "my_index_logs_20260907"], + }); + + assert.deepEqual( + items.filter((item) => item.detail === "index").map((item) => item.label), + ["my_index_misc_20260907"], + ); +}); + test("index completion preserves endpoint suffix after cursor", () => { const text = "GET /ord/_search"; const cursor = "GET /ord".length;