Fixed regression that broke fuzzy matching for slash commands (#7859)

This addresses bug #7857 which was introduced recently as part of PR
#7704.
This commit is contained in:
Eric Traut 2025-12-10 22:42:45 -06:00 committed by GitHub
parent 3fc8b2894f
commit 057250020a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 31 additions and 4 deletions

View file

@ -43,6 +43,7 @@ use crate::render::renderable::Renderable;
use crate::slash_command::SlashCommand;
use crate::slash_command::built_in_slash_commands;
use crate::style::user_message_style;
use codex_common::fuzzy_match::fuzzy_match;
use codex_protocol::custom_prompts::CustomPrompt;
use codex_protocol::custom_prompts::PROMPTS_CMD_PREFIX;
@ -1621,7 +1622,7 @@ impl ChatComposer {
let builtin_match = built_in_slash_commands()
.into_iter()
.any(|(cmd_name, _)| cmd_name.starts_with(name));
.any(|(cmd_name, _)| fuzzy_match(cmd_name, name).is_some());
if builtin_match {
return true;
@ -1630,7 +1631,7 @@ impl ChatComposer {
let prompt_prefix = format!("{PROMPTS_CMD_PREFIX}:");
self.custom_prompts
.iter()
.any(|p| format!("{prompt_prefix}{}", p.name).starts_with(name))
.any(|p| fuzzy_match(&format!("{prompt_prefix}{}", p.name), name).is_some())
}
/// Synchronize `self.command_popup` with the current text in the
@ -3982,8 +3983,15 @@ mod tests {
"'/re' should activate slash popup via prefix match"
);
// Case 3: invalid prefix "/zzz" still allowed to open popup if it
// matches no built-in command, our current logic will *not* open popup.
// Case 3: fuzzy match "/ac" (subsequence of /compact and /feedback)
composer.set_text_content("/ac".to_string());
assert!(
matches!(composer.active_popup, ActivePopup::Command(_)),
"'/ac' should activate slash popup via fuzzy match"
);
// Case 4: invalid prefix "/zzz" still allowed to open popup if it
// matches no built-in command; our current logic will not open popup.
// Verify that explicitly.
composer.set_text_content("/zzz".to_string());
assert!(

View file

@ -373,4 +373,23 @@ mod tests {
let description = rows.first().and_then(|row| row.description.as_deref());
assert_eq!(description, Some("send saved prompt"));
}
#[test]
fn fuzzy_filter_matches_subsequence_for_ac() {
let mut popup = CommandPopup::new(Vec::new(), false);
popup.on_composer_text_change("/ac".to_string());
let cmds: Vec<&str> = popup
.filtered_items()
.into_iter()
.filter_map(|item| match item {
CommandItem::Builtin(cmd) => Some(cmd.command()),
CommandItem::UserPrompt(_) => None,
})
.collect();
assert!(
cmds.contains(&"compact") && cmds.contains(&"feedback"),
"expected fuzzy search for '/ac' to include compact and feedback, got {cmds:?}"
);
}
}