Skip to content

feat: slash-command dropdown with a themed panel - #3

Merged
wowi42 merged 3 commits into
mainfrom
feat/slash-command-dropdown
Sep 8, 2026
Merged

feat: slash-command dropdown with a themed panel#3
wowi42 merged 3 commits into
mainfrom
feat/slash-command-dropdown

Conversation

@Mouhand-Kaddo

Copy link
Copy Markdown
Contributor

What

Typing / at the start of the input opens a dropdown listing every registered command (built-ins + skill commands), prefix-filtered case-insensitively and in alphabetical order. /mod narrows to mode, model, model-subagent, models, models-subagent; /MOD matches the same as /mod.

Behavior

  • Open: / at input start (only there — not mid-message). Editing the command prefix reopens; a space after the command name closes it.
  • Navigate: Up/Down move through matches and wrap at both ends.
  • Select: Enter or Tab fills /name into the input without executing; a second Enter submits. Existing arguments are preserved.
  • Dismiss: Escape closes the menu and restores the typed text. The inert No matching commands row (shown when nothing matches) stays dismissed until the prefix changes or Tab reopens it; Enter still submits normally there.
  • Scope: @ files/agents, . personas, and path completion keep working. /-tokens at buffer start belong to the slash picker; mid-message absolute paths (read /etc/ho) still complete as paths.

Look

Themed in-flow panel below the input (no cursor-following float): dark purple background, thin muted border, lavender command names, muted descriptions, violet selection with a > marker, commands heading with a live match count, and a key-hints footer. Rows size to the number of matches, capped at eight, with scrolling. Colors come from the fixed theme (themes.py), not inline hex.

Implementation notes

  • Slash candidates switched from fuzzy to case-insensitive prefix matching (prefix_matches); candidate list extracted to command_candidates (shared by the completer and the no-match row).
  • The themed panel renders from the buffer's completion state; the stock CompletionsMenu float keeps serving the @/./path pickers, with a dynamically reserved spacer so it is not clipped (the app renders at natural height, full_screen=False).
  • Approval Escape keeps precedence (completion Escape is filtered on ~approval_pending).

Tests

  • Picker filter (case-insensitive, alphabetical, no fuzzy gaps) and path-token guard (buffer-start / vs mid-message absolute paths).
  • Keyboard: menu opens on /, filtering, Enter fills then second Enter submits, arrows wrap, Tab accepts, Escape restores and reopens, space closes, no-match row dismissal/reopen, mid-message no trigger.
  • Real-terminal (pty) coverage: panel rendering, colors, alignment, compact sizing, eight-row cap, scrolling, and Enter submitting normally on zero matches.

Full suite green locally (1098 passed); only pre-existing telemetry failures remain (missing optional opentelemetry/sentry_sdk extras). ruff check and ruff format --check clean.

Typing '/' at input start opens a dropdown of every registered command
(built-ins + skills), prefix-filtered case-insensitively and alphabetical.
Up/Down navigate with wrap, Enter/Tab fill '/name ' without submitting, a
second Enter submits, Escape dismisses (restoring typed text; the inert
no-match row stays dismissed until the prefix changes or Tab reopens it).
A space after the command closes the menu; editing the prefix reopens it.

The panel is in-flow below the input, styled from the fixed theme: dark
purple background, muted border and descriptions, lavender commands,
violet selection with a '>' marker, match count and key hints; rows size
to content, capped at eight. The floating completion menu keeps serving
@/./path pickers, with space reserved so it is not clipped; '/'-tokens at
buffer start belong to the slash picker, mid-message absolute paths stay
path tokens.
The themed panel now renders every completion in the app — commands,
@ files/agents, . personas, and bare path tokens — with a per-kind
heading (commands / context / personas / files). The stock grey
CompletionsMenu float and its space reservation are deleted; the
in-flow panel needs neither.

Completions stream in asynchronously (the @/path pickers await the fd
listing before their first row), so the panel waits for the first row
and menu_rows tolerates the empty window — max() over an empty list
there crashed the renderer into an unhandled-exception storm that hung
the app on any path completion.
A leading '.' at buffer start collided with the path completer (a
leading '.' is also a path token), so typing '.' listed the fd listing's
dotfiles as 'personas' — thousands of rows and a very slow menu. The
buffer-start guard now covers '.' alongside '/', except './' and '../',
which stay explicit path prefixes; mid-message dotfiles and absolute
paths complete as before.

The path completer also yielded unbounded matches (every file under a
broad prefix), which made the panel rebuild thousands of rows per
keystroke. It now caps at PATH_COMPLETION_LIMIT = 20, matching the @
picker's file branch.
@wowi42
wowi42 merged commit cffa284 into main Sep 8, 2026
4 checks passed
@wowi42
wowi42 deleted the feat/slash-command-dropdown branch September 8, 2026 06:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants