diff --git a/src/gui/GenericSuggester/genericSuggester.test.ts b/src/gui/GenericSuggester/genericSuggester.test.ts index 520c6fca..85d28dc2 100644 --- a/src/gui/GenericSuggester/genericSuggester.test.ts +++ b/src/gui/GenericSuggester/genericSuggester.test.ts @@ -18,4 +18,13 @@ describe("GenericSuggester", () => { expect(() => suggester.getSuggestions("1")).not.toThrow(); }); + it("tolerates undefined query input", () => { + const items = ["Alpha", "Beta"]; + const suggester = new GenericSuggester(app, items, items); + + expect(() => + suggester.getSuggestions(undefined as unknown as string), + ).not.toThrow(); + }); + }); diff --git a/src/gui/GenericSuggester/genericSuggester.ts b/src/gui/GenericSuggester/genericSuggester.ts index fb9d9814..1eb0c6bb 100644 --- a/src/gui/GenericSuggester/genericSuggester.ts +++ b/src/gui/GenericSuggester/genericSuggester.ts @@ -1,7 +1,7 @@ import { FuzzySuggestModal } from "obsidian"; import type { FuzzyMatch, App } from "obsidian"; import { log, toError } from "src/logger/logManager"; -import { normalizeDisplayItem } from "../suggesters/utils"; +import { normalizeDisplayItem, normalizeQuery } from "../suggesters/utils"; type SuggestRender = (value: T, el: HTMLElement) => void; @@ -86,6 +86,11 @@ export default class GenericSuggester extends FuzzySuggestModal { return this.items; } + getSuggestions(query: string): FuzzyMatch[] { + const safeQuery = normalizeQuery(query); + return super.getSuggestions(safeQuery); + } + selectSuggestion( value: FuzzyMatch, evt: MouseEvent | KeyboardEvent diff --git a/src/gui/InputSuggester/inputSuggester.test.ts b/src/gui/InputSuggester/inputSuggester.test.ts index 3b34f772..d106b12f 100644 --- a/src/gui/InputSuggester/inputSuggester.test.ts +++ b/src/gui/InputSuggester/inputSuggester.test.ts @@ -42,6 +42,18 @@ describe("InputSuggester", () => { expect(matchingEntries).toHaveLength(1); }); + it("tolerates undefined query input", () => { + const suggester = new InputSuggester( + app, + ["Alpha file", "Beta note"], + ["Alpha file", "Beta note"] + ); + + expect(() => + suggester.getSuggestions(undefined as unknown as string), + ).not.toThrow(); + }); + it("aligns displayItems length with items length", () => { const shortDisplay = ["Alpha"]; const shortItems = ["Alpha", "Beta", "Gamma"]; diff --git a/src/gui/InputSuggester/inputSuggester.ts b/src/gui/InputSuggester/inputSuggester.ts index 6321a9b2..3b703065 100644 --- a/src/gui/InputSuggester/inputSuggester.ts +++ b/src/gui/InputSuggester/inputSuggester.ts @@ -1,7 +1,7 @@ import { FuzzySuggestModal } from "obsidian"; import type { FuzzyMatch, App } from "obsidian"; import { log, toError } from "src/logger/logManager"; -import { normalizeDisplayItem } from "../suggesters/utils"; +import { normalizeDisplayItem, normalizeQuery } from "../suggesters/utils"; type SuggestRender = (value: T, el: HTMLElement) => void; @@ -113,8 +113,9 @@ export default class InputSuggester extends FuzzySuggestModal { } getSuggestions(query: string): FuzzyMatch[] { - const suggestions = super.getSuggestions(query); - const customValue = this.inputEl.value; + const safeQuery = normalizeQuery(query); + const suggestions = super.getSuggestions(safeQuery); + const customValue = normalizeQuery(this.inputEl.value); if (!customValue) return suggestions; diff --git a/src/gui/suggesters/SuggesterInputSuggest.ts b/src/gui/suggesters/SuggesterInputSuggest.ts index 107dac65..945eb7d1 100644 --- a/src/gui/suggesters/SuggesterInputSuggest.ts +++ b/src/gui/suggesters/SuggesterInputSuggest.ts @@ -1,5 +1,6 @@ import type { App } from "obsidian"; import { TextInputSuggest } from "./suggest"; +import { normalizeDisplayItem, normalizeQuery } from "./utils"; export class SuggesterInputSuggest extends TextInputSuggest { private options: string[]; @@ -14,7 +15,7 @@ export class SuggesterInputSuggest extends TextInputSuggest { multiSelect = false, ) { super(app, inputEl); - this.options = options; + this.options = options.map((option) => normalizeDisplayItem(option)); this.caseSensitive = caseSensitive; this.multiSelect = multiSelect; @@ -44,7 +45,8 @@ export class SuggesterInputSuggest extends TextInputSuggest { } getSuggestions(query: string): string[] { - const { alreadySelected, activeTerm } = this.parseMultiSelectInput(query); + const safeQuery = normalizeQuery(query); + const { alreadySelected, activeTerm } = this.parseMultiSelectInput(safeQuery); const searchQuery = this.caseSensitive ? activeTerm : activeTerm.toLowerCase(); const available = this.getRemainingOptions(alreadySelected); diff --git a/src/gui/suggesters/genericTextSuggester.ts b/src/gui/suggesters/genericTextSuggester.ts index eae46d73..d9da868a 100644 --- a/src/gui/suggesters/genericTextSuggester.ts +++ b/src/gui/suggesters/genericTextSuggester.ts @@ -1,5 +1,6 @@ -import { TextInputSuggest } from "./suggest"; import type { App } from "obsidian"; +import { TextInputSuggest } from "./suggest"; +import { normalizeDisplayItem, normalizeQuery } from "./utils"; export class GenericTextSuggester extends TextInputSuggest { constructor( @@ -9,10 +10,11 @@ export class GenericTextSuggester extends TextInputSuggest { private maxSuggestions = Infinity ) { super(app, inputEl); + this.items = items.map((item) => normalizeDisplayItem(item)); } getSuggestions(inputStr: string): string[] { - const inputLowerCase: string = inputStr.toLowerCase(); + const inputLowerCase = normalizeQuery(inputStr).toLowerCase(); const filtered = this.items.filter((item) => { return item.toLowerCase().includes(inputLowerCase); diff --git a/src/gui/suggesters/utils.ts b/src/gui/suggesters/utils.ts index 5dfd63ad..719fb6f7 100644 --- a/src/gui/suggesters/utils.ts +++ b/src/gui/suggesters/utils.ts @@ -8,6 +8,10 @@ export function normalizeDisplayItem(value: unknown): string { return String(value); } +export function normalizeQuery(value: unknown): string { + return normalizeDisplayItem(value); +} + export function normalizeForSearch(value: string): string { return value.normalize("NFC").toLowerCase(); } diff --git a/src/quickAddApi.ts b/src/quickAddApi.ts index a64ee367..4cd584f4 100644 --- a/src/quickAddApi.ts +++ b/src/quickAddApi.ts @@ -17,6 +17,7 @@ import GenericWideInputPrompt from "./gui/GenericWideInputPrompt/GenericWideInpu import GenericYesNoPrompt from "./gui/GenericYesNoPrompt/GenericYesNoPrompt"; import InputSuggester from "./gui/InputSuggester/inputSuggester"; import VDateInputPrompt from "./gui/VDateInputPrompt/VDateInputPrompt"; +import { normalizeDisplayItem } from "./gui/suggesters/utils"; import type { IChoiceExecutor } from "./IChoiceExecutor"; import type QuickAdd from "./main"; import { OnePageInputModal } from "./preflight/OnePageInputModal"; @@ -671,6 +672,7 @@ export class QuickAddApi { } else { displayedItems = displayItems; } + displayedItems = displayedItems.map((item) => normalizeDisplayItem(item)); if (allowCustomInput) { return await InputSuggester.Suggest(