Skip to content

Commit f701d9e

Browse files
charley-oaicodex
andcommitted
tui: match slash popup aliases
Include builtin aliases when filtering the slash popup so valid commands like /multi-agents still surface the canonical /subagents entry. Reuse a shared command-name iterator for alias-aware builtin lookup and reserved-name filtering. Co-authored-by: Codex <noreply@openai.com>
1 parent d932510 commit f701d9e

File tree

1 file changed

+50
-5
lines changed

1 file changed

+50
-5
lines changed

codex-rs/tui/src/bottom_pane/command_popup.rs

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,29 @@ impl CommandPopup {
154154
let prompt_prefix_len = PROMPTS_CMD_PREFIX.chars().count() + 1;
155155
let indices_for = |offset| Some((offset..offset + filter_chars).collect());
156156

157+
for cmd in self.builtins.iter() {
158+
if cmd.command() == filter_lower.as_str() {
159+
exact.push((CommandItem::Builtin(*cmd), indices_for(0)));
160+
continue;
161+
}
162+
if cmd.command().starts_with(&filter_lower) {
163+
prefix.push((CommandItem::Builtin(*cmd), indices_for(0)));
164+
continue;
165+
}
166+
// Keep the popup searchable by accepted aliases, but keep rendering the
167+
// canonical command name so the list stays deduplicated and stable.
168+
if cmd.command_aliases().contains(&filter_lower.as_str()) {
169+
exact.push((CommandItem::Builtin(*cmd), None));
170+
continue;
171+
}
172+
if cmd
173+
.command_aliases()
174+
.iter()
175+
.any(|alias| alias.starts_with(&filter_lower))
176+
{
177+
prefix.push((CommandItem::Builtin(*cmd), None));
178+
}
179+
}
157180
let mut push_match =
158181
|item: CommandItem, display: &str, name: Option<&str>, name_offset: usize| {
159182
let display_lower = display.to_lowercase();
@@ -174,10 +197,6 @@ impl CommandPopup {
174197
prefix.push((item, indices_for(offset)));
175198
}
176199
};
177-
178-
for cmd in self.builtins.iter() {
179-
push_match(CommandItem::Builtin(*cmd), cmd.command(), None, 0);
180-
}
181200
// Support both search styles:
182201
// - Typing "name" should surface "/prompts:name" results.
183202
// - Typing "prompts:name" should also work.
@@ -357,7 +376,7 @@ mod tests {
357376
CommandItem::UserPrompt(_) => None,
358377
})
359378
.collect();
360-
assert_eq!(cmds, vec!["model", "mention", "mcp"]);
379+
assert_eq!(cmds, vec!["model", "mention", "mcp", "subagents"]);
361380
}
362381

363382
#[test]
@@ -508,6 +527,32 @@ mod tests {
508527
assert!(items.contains(&CommandItem::Builtin(SlashCommand::Quit)));
509528
}
510529

530+
#[test]
531+
fn multi_agents_alias_matches_subagents_entry() {
532+
let mut popup = CommandPopup::new(Vec::new(), CommandPopupFlags::default());
533+
popup.on_composer_text_change("/multi".to_string());
534+
assert_eq!(
535+
popup.selected_item(),
536+
Some(CommandItem::Builtin(SlashCommand::MultiAgents))
537+
);
538+
539+
let cmds: Vec<&str> = popup
540+
.filtered_items()
541+
.into_iter()
542+
.filter_map(|item| match item {
543+
CommandItem::Builtin(cmd) => Some(cmd.command()),
544+
CommandItem::UserPrompt(_) => None,
545+
})
546+
.collect();
547+
assert_eq!(cmds, vec!["subagents"]);
548+
549+
popup.on_composer_text_change("/multi-agents".to_string());
550+
assert_eq!(
551+
popup.selected_item(),
552+
Some(CommandItem::Builtin(SlashCommand::MultiAgents))
553+
);
554+
}
555+
511556
#[test]
512557
fn collab_command_hidden_when_collaboration_modes_disabled() {
513558
let mut popup = CommandPopup::new(Vec::new(), CommandPopupFlags::default());

0 commit comments

Comments
 (0)