From b513fafe8354b85d1ba4609733b7f33c7b46b7d5 Mon Sep 17 00:00:00 2001 From: Daniel Polito Date: Tue, 21 Jul 2026 12:08:23 -0300 Subject: [PATCH] fix(app): support nested slash command autocomplete (#38097) --- .../src/v2/components/prompt-input/machine.test.ts | 13 +++++++++++++ .../src/v2/components/prompt-input/machine.ts | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/session-ui/src/v2/components/prompt-input/machine.test.ts b/packages/session-ui/src/v2/components/prompt-input/machine.test.ts index 231fca61a7a..e36982666e4 100644 --- a/packages/session-ui/src/v2/components/prompt-input/machine.test.ts +++ b/packages/session-ui/src/v2/components/prompt-input/machine.test.ts @@ -26,6 +26,19 @@ describe("prompt input v2 interaction machine", () => { expect(closed.state.popover).toEqual({ type: "closed" }) }) + test("completes nested slash command names", () => { + const open = transitionPromptInputV2( + createPromptInputV2InteractionState(), + { type: "input.changed", value: "/review/" }, + persisted(), + ) + const item = { ...command, label: "/review/nested" } + const selected = transitionPromptInputV2(open.state, { type: "popover.select", item }, persisted("/review/")) + + expect(open.state.popover).toEqual({ type: "command-inline", query: "review/" }) + expect(selected.commands).toContainEqual({ type: "draft.setText", value: "/review/nested " }) + }) + test("opens context completion at the cursor", () => { const value = "alpha @sr omega" const input = persisted(value) diff --git a/packages/session-ui/src/v2/components/prompt-input/machine.ts b/packages/session-ui/src/v2/components/prompt-input/machine.ts index fcf5131a170..d2508e249c5 100644 --- a/packages/session-ui/src/v2/components/prompt-input/machine.ts +++ b/packages/session-ui/src/v2/components/prompt-input/machine.ts @@ -102,7 +102,7 @@ function inputChanged( ]) } - const command = value.match(/^\/([^\s/]*)$/) + const command = value.match(/^\/(\S*)$/) if (command) { const query = command[1] ?? "" return changed({ ...state, popover: { type: "command-inline", query }, focus: "editor" }, [ @@ -240,7 +240,7 @@ function populated(persisted: PromptInputV2PersistedState) { } function replaceTrigger(value: string, trigger: "@" | "/", replacement: string) { - const index = value.lastIndexOf(trigger) + const index = trigger === "/" ? value.indexOf(trigger) : value.lastIndexOf(trigger) return index < 0 ? replacement : value.slice(0, index) + replacement }