Scope skill completions to /skill
Keep individual skills out of the top-level slash command menu so large skill collections do not crowd out built-in commands. Skills still complete after `/skill`, including both the full skill list after `/skill ` and prefix matches after `/skill <prefix>`. (cherry picked from commit 57f8e3ad84dad9cf46290c0dc23e2b26504196df)
This commit is contained in:
@@ -1986,23 +1986,20 @@ pub(crate) fn slash_completion_hints(
|
||||
}
|
||||
}
|
||||
|
||||
// Cached skills
|
||||
let skill_prefix = completing_skill_arg.unwrap_or(prefix);
|
||||
let prefix_lower = skill_prefix.to_ascii_lowercase();
|
||||
for (skill_name, skill_desc) in cached_skills {
|
||||
let skill_name_lower = skill_name.to_ascii_lowercase();
|
||||
let command_prefix_matches = completing_skill_arg.is_none()
|
||||
&& (prefix_lower.is_empty()
|
||||
|| "skill".starts_with(&prefix_lower)
|
||||
|| skill_name_lower.starts_with(&prefix_lower));
|
||||
let skill_arg_matches =
|
||||
completing_skill_arg.is_some() && skill_name_lower.starts_with(&prefix_lower);
|
||||
if command_prefix_matches || skill_arg_matches {
|
||||
entries.push(SlashMenuEntry {
|
||||
name: format!("/skill {skill_name}"),
|
||||
description: skill_desc.clone(),
|
||||
is_skill: true,
|
||||
});
|
||||
// Cached skills are arguments to `/skill`, not top-level commands. Keep
|
||||
// the top-level slash menu focused on commands and expand skills only
|
||||
// after the user has selected the skill command.
|
||||
let prefix_lower = completing_skill_arg.unwrap_or(prefix).to_ascii_lowercase();
|
||||
if completing_skill_arg.is_some() {
|
||||
for (skill_name, skill_desc) in cached_skills {
|
||||
let skill_name_lower = skill_name.to_ascii_lowercase();
|
||||
if skill_name_lower.starts_with(&prefix_lower) {
|
||||
entries.push(SlashMenuEntry {
|
||||
name: format!("/skill {skill_name}"),
|
||||
description: skill_desc.clone(),
|
||||
is_skill: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2373,39 +2370,41 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slash_completion_hints_include_skills() {
|
||||
fn slash_completion_hints_hide_skills_from_top_level_menu() {
|
||||
let cached_skills = vec![
|
||||
("search-files".to_string(), "Search files".to_string()),
|
||||
("my-review".to_string(), "Review code".to_string()),
|
||||
];
|
||||
let hints = slash_completion_hints("/", 128, &cached_skills, Locale::En, None);
|
||||
assert!(
|
||||
hints
|
||||
.iter()
|
||||
.any(|hint| hint.name == "/skill search-files" && hint.is_skill)
|
||||
);
|
||||
assert!(
|
||||
hints
|
||||
.iter()
|
||||
.any(|hint| hint.name == "/skill my-review" && hint.is_skill)
|
||||
);
|
||||
assert!(hints.iter().any(|hint| hint.name == "/skill"));
|
||||
assert!(hints.iter().any(|hint| hint.name == "/skills"));
|
||||
assert!(!hints.iter().any(|hint| hint.is_skill));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slash_completion_hints_skills_match_prefix() {
|
||||
fn slash_completion_hints_hide_skills_from_top_level_prefix() {
|
||||
let cached_skills = vec![
|
||||
("search-files".to_string(), "Search files".to_string()),
|
||||
("my-review".to_string(), "Review code".to_string()),
|
||||
];
|
||||
let hints = slash_completion_hints("/se", 128, &cached_skills, Locale::En, None);
|
||||
assert!(
|
||||
hints
|
||||
.iter()
|
||||
.any(|hint| hint.name == "/skill search-files" && hint.is_skill)
|
||||
);
|
||||
assert!(!hints.iter().any(|hint| hint.name == "/skill search-files"));
|
||||
assert!(!hints.iter().any(|hint| hint.name == "/skill my-review"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slash_completion_hints_complete_skill_argument_all() {
|
||||
let cached_skills = vec![
|
||||
("search-files".to_string(), "Search files".to_string()),
|
||||
("my-review".to_string(), "Review code".to_string()),
|
||||
];
|
||||
let hints = slash_completion_hints("/skill ", 128, &cached_skills, Locale::En, None);
|
||||
assert_eq!(hints.len(), 2);
|
||||
assert!(hints.iter().any(|hint| hint.name == "/skill search-files"));
|
||||
assert!(hints.iter().any(|hint| hint.name == "/skill my-review"));
|
||||
assert!(hints.iter().all(|hint| hint.is_skill));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slash_completion_hints_complete_skill_argument_prefix() {
|
||||
let cached_skills = vec![
|
||||
|
||||
Reference in New Issue
Block a user