This document specifies the CommandPalette v1 for XenoAtom.Terminal.UI and how it integrates with the unified
Command system (Command Specs).
The goal is to make commands discoverable, searchable, and easy to invoke, while staying consistent with:
Ctrl+P, configurable)Up/Down, PageUp/PageDown, Home/End, Enter)TerminalApp.GlobalCommandsCommandPresentation.CommandPaletteCanExecute and IsVisible affect the list and automatically invalidate when their dependencies change>, :) and pluggable non-command providers (files, symbols, etc.).Existing controls:
Controls/CommandPalette.cs:
TextBox search + OptionList<CommandPaletteItem> resultsPopup (fullscreen only)Controls/CommandPaletteItem.cs:
ActionThe current implementation is not integrated with Command (it is a separate “item” model).
Command directlyThe palette should operate on XenoAtom.Terminal.UI.Commands.Command.
For v1, we do not want a separate CommandPaletteItem abstraction:
Command (LabelMarkup, DescriptionMarkup, shortcut).Proposal:
BindableList<Command>.CommandPaletteItem.Command.Introduce a single internal helper that all command surfaces can use:
internal static class CommandQuery
{
public static void Collect(
TerminalApp app,
Visual? target,
CommandPresentation presentation,
List<Command> output);
}
Rules:
target (usually TerminalApp.FocusedElement) up to the root, collecting commands from each visual:
command.Presentation.HasFlag(presentation)command.IsVisibleFor(targetVisual)Command.Id (first wins).CommandImportance then insertion orderThis is the same philosophy as CommandBar, but centralized so CommandPalette and future ContextMenu use the same logic.
Command palette needs a searchable string for each command.
Command API changes)Search text is computed as:
LabelMarkup with markup tags ignored for matching (e.g. [primary]Save[/] matches “save”)DescriptionMarkup ignored for matching (optional)Implementation note: do not allocate for search. Instead:
LabelMarkup on the fly while skipping markup tokens ([...])This is enough for v1 and avoids adding new API surface to Command.
Name / SearchTextIf we want command palette and future “command prompt” (/help) to be first-class, consider extending Command with:
string? Name (a stable textual name, no markup, e.g. save, open, theme.set)string? SearchText (additional terms, synonyms, tags)Matching then uses:
Name (if present)LabelMarkup (markup-stripped)SearchText (if present)DescriptionMarkup (optional, and only for low-priority matches)Note: this is safe for NativeAOT and minimal overhead because it is static metadata per command.
Given query q and candidate text t, rank as:
Ties:
CommandImportance firstThe v1 implementation can be simple and deterministic (no fuzzy scoring required).
When user activates a selected item:
target:
TerminalApp.FocusedElement ?? rootCanExecuteFor(target) is true:
Execute(target)CanExecuteFor(target) is false:
Popup hosted by the app window layer (fullscreen only).Esc pressedWhen opened:
While open:
Tab stays within the palette (search box ↔ results list)OptionList<Command>)Gesture or Sequence formatted as textIntroduce CommandPaletteStyle (or update existing one) with:
PopupTemplateFactory (already used elsewhere)ItemTemplate (DataTemplate<Command>) used by the results listDescriptionVisible / ShowDescriptionMaxWidth, ResultsHeight, padding, etc.Default row visual (single line):
<LabelMarkup> <ShortcutText>
If description enabled:
<LabelMarkup> <ShortcutText>
<DescriptionMarkup>
Shortcut formatting:
command.Sequence?.ToString() ?? command.Gesture?.ToString()The palette itself should be opened by a command registered by the app:
Id = "App.CommandPalette"Presentation includes at least CommandPresentation.CommandPalette and probably CommandBarCtrl+P (recommended)Ctrl+K Ctrl+P (common in editors)While the palette is open:
CanExecute / IsVisible should update the list automatically (dependency tracking)Id)IsVisible exclusion worksCommandQuery helper (internal) used by command surfaces.CommandPalette to operate on Command directly.CommandPaletteItem and update demos/docs/tests.Command.Name / Command.SearchText if we agree it’s needed for the future “command prompt” feature.