feat: slash-command dropdown with a themed panel - #3
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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./modnarrows tomode,model,model-subagent,models,models-subagent;/MODmatches the same as/mod.Behavior
/at input start (only there — not mid-message). Editing the command prefix reopens; a space after the command name closes it./nameinto the input without executing; a second Enter submits. Existing arguments are preserved.No matching commandsrow (shown when nothing matches) stays dismissed until the prefix changes or Tab reopens it; Enter still submits normally there.@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,commandsheading 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
prefix_matches); candidate list extracted tocommand_candidates(shared by the completer and the no-match row).CompletionsMenufloat 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_pending).Tests
/vs mid-message absolute paths)./, 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.Full suite green locally (1098 passed); only pre-existing telemetry failures remain (missing optional
opentelemetry/sentry_sdkextras).ruff checkandruff format --checkclean.