diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index a27467f06..c3caa5bd5 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -12,6 +12,7 @@ ### Fixed +- Fixed spaces in `/settings` searches toggling the highlighted setting while typing multi-word queries such as **UI mode** or **Quiet startup**. - Fixed custom editors not inheriting the default editor's autocomplete dropdown item limit ([#7333](https://github.com/earendil-works/pi/issues/7333)). - Fixed malformed resource arrays in package manifests crashing session startup ([#7187](https://github.com/earendil-works/pi/issues/7187)). - Fixed the DOOM overlay example downloading its shareware WAD from a dead URL. diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index 39982a6f5..8d8232561 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -6,6 +6,7 @@ - Fixed terminal width accounting for Indic conjunct grapheme clusters ([#6124](https://github.com/earendil-works/pi/issues/6124) by [@petrroll](https://github.com/petrroll)). - Fixed phantom alternate-screen text selection from unmatched mouse events when changing terminal pane focus. +- Fixed spaces in searchable settings queries changing the selected value instead of filtering multi-word labels. ### Added diff --git a/packages/tui/src/components/settings-list.ts b/packages/tui/src/components/settings-list.ts index 88e9433f7..7dce91b87 100644 --- a/packages/tui/src/components/settings-list.ts +++ b/packages/tui/src/components/settings-list.ts @@ -182,16 +182,15 @@ export class SettingsList implements Component { } else if (kb.matches(data, "tui.select.down")) { if (displayItems.length === 0) return; this.selectedIndex = this.selectedIndex === displayItems.length - 1 ? 0 : this.selectedIndex + 1; - } else if (kb.matches(data, "tui.select.confirm") || data === " ") { + } else if ( + kb.matches(data, "tui.select.confirm") || + (data === " " && (!this.searchEnabled || this.searchInput?.getValue().length === 0)) + ) { this.activateItem(); } else if (kb.matches(data, "tui.select.cancel")) { this.onCancel(); } else if (this.searchEnabled && this.searchInput) { - const sanitized = data.replace(/ /g, ""); - if (!sanitized) { - return; - } - this.searchInput.handleInput(sanitized); + this.searchInput.handleInput(data); this.applyFilter(this.searchInput.getValue()); } } diff --git a/packages/tui/test/settings-list.test.ts b/packages/tui/test/settings-list.test.ts new file mode 100644 index 000000000..b39eddce8 --- /dev/null +++ b/packages/tui/test/settings-list.test.ts @@ -0,0 +1,58 @@ +import assert from "node:assert"; +import { describe, it } from "node:test"; +import { SettingsList, type SettingsListTheme } from "../src/components/settings-list.ts"; + +const testTheme: SettingsListTheme = { + label: (text) => text, + value: (text) => text, + description: (text) => text, + cursor: "> ", + hint: (text) => text, +}; + +const items = [ + { + id: "ui-mode", + label: "UI mode", + currentValue: "regular", + values: ["regular", "fullscreen"], + }, +]; + +describe("SettingsList", () => { + it("includes spaces in an active search instead of changing the selected setting", () => { + const changes: Array<{ id: string; value: string }> = []; + const list = new SettingsList( + items.map((item) => ({ ...item })), + 10, + testTheme, + (id, value) => changes.push({ id, value }), + () => {}, + { enableSearch: true }, + ); + + for (const character of "UI mode") list.handleInput(character); + + assert.deepStrictEqual(changes, []); + assert.match(list.render(80)[0] ?? "", /UI mode/); + + list.handleInput("\r"); + assert.deepStrictEqual(changes, [{ id: "ui-mode", value: "fullscreen" }]); + }); + + it("keeps Space as a change shortcut before a search query is entered", () => { + const changes: Array<{ id: string; value: string }> = []; + const list = new SettingsList( + items.map((item) => ({ ...item })), + 10, + testTheme, + (id, value) => changes.push({ id, value }), + () => {}, + { enableSearch: true }, + ); + + list.handleInput(" "); + + assert.deepStrictEqual(changes, [{ id: "ui-mode", value: "fullscreen" }]); + }); +});