Fallback display names for TUI skill mentions (#18786)

This updates TUI skill mentions to show a fallback label when a skill
does not define a display name, so unnamed skills remain understandable
in the picker without changing behavior for skills that already have
one.

<img width="1028" height="198" alt="Screenshot 2026-04-20 at 6 25 15 PM"
src="https://github.com/user-attachments/assets/84077b85-99d0-4db9-b533-37e1887b4506"
/>
This commit is contained in:
canvrno-oai authored and GitHub committed 2026-04-20 20:46:55 -07:00
1 parent 1132ef887c
commit 2cc146f5ea
4 files changed
+18 -14

No files matched your search

@@ -206,6 +206,7 @@ use crate::bottom_pane::textarea::TextAreaState;
use crate::clipboard_paste::normalize_pasted_path; use crate::clipboard_paste::normalize_pasted_path;
use crate::clipboard_paste::pasted_image_format; use crate::clipboard_paste::pasted_image_format;
use crate::history_cell; use crate::history_cell;
use crate::skills_helpers::skill_display_name;
use crate::tui::FrameRequester; use crate::tui::FrameRequester;
use crate::ui_consts::LIVE_PREFIX_COLS; use crate::ui_consts::LIVE_PREFIX_COLS;
use codex_app_server_protocol::AppInfo; use codex_app_server_protocol::AppInfo;
@@ -3455,7 +3456,7 @@ impl ChatComposer {
let mut mentions = Vec::new(); let mut mentions = Vec::new();
if let Some(skills) = self.skills.as_ref() { if let Some(skills) = self.skills.as_ref() {
for skill in skills { for skill in skills {
let display_name = skill_display_name(skill).to_string(); let display_name = skill_display_name(skill);
let description = skill_description(skill); let description = skill_description(skill);
let skill_name = skill.name.clone(); let skill_name = skill.name.clone();
let search_terms = if display_name == skill.name { let search_terms = if display_name == skill.name {
@@ -3659,14 +3660,6 @@ impl ChatComposer {
} }
} }
fn skill_display_name(skill: &SkillMetadata) -> &str {
skill
.interface
.as_ref()
.and_then(|interface| interface.display_name.as_deref())
.unwrap_or(&skill.name)
}
fn skill_description(skill: &SkillMetadata) -> Option<String> { fn skill_description(skill: &SkillMetadata) -> Option<String> {
let description = skill let description = skill
.interface .interface
+1 -1
View File
@@ -28,7 +28,7 @@ pub(crate) struct MentionItem {
pub(crate) sort_rank: u8, pub(crate) sort_rank: u8,
} }
const MENTION_NAME_TRUNCATE_LEN: usize = 24; const MENTION_NAME_TRUNCATE_LEN: usize = 28;
pub(crate) struct SkillPopup { pub(crate) struct SkillPopup {
query: String, query: String,
+1 -1
View File
@@ -75,7 +75,7 @@ impl ChatWidget {
.iter() .iter()
.map(|skill| { .map(|skill| {
let core_skill = protocol_skill_to_core(skill); let core_skill = protocol_skill_to_core(skill);
let display_name = skill_display_name(&core_skill).to_string(); let display_name = skill_display_name(&core_skill);
let description = skill_description(&core_skill).to_string(); let description = skill_description(&core_skill).to_string();
let name = core_skill.name.clone(); let name = core_skill.name.clone();
let path = core_skill.path_to_skills_md; let path = core_skill.path_to_skills_md;
+14 -3
View File
@@ -5,12 +5,23 @@ use crate::text_formatting::truncate_text;
pub(crate) const SKILL_NAME_TRUNCATE_LEN: usize = 21; pub(crate) const SKILL_NAME_TRUNCATE_LEN: usize = 21;
pub(crate) fn skill_display_name(skill: &SkillMetadata) -> &str { pub(crate) fn skill_display_name(skill: &SkillMetadata) -> String {
skill if let Some(display_name) = skill
.interface .interface
.as_ref() .as_ref()
.and_then(|interface| interface.display_name.as_deref()) .and_then(|interface| interface.display_name.as_deref())
.unwrap_or(&skill.name) {
return display_name.to_string();
}
if let Some((plugin_name, skill_name)) = skill.name.split_once(':')
&& !plugin_name.is_empty()
&& !skill_name.is_empty()
{
return format!("{skill_name} ({plugin_name})");
}
skill.name.clone()
} }
pub(crate) fn skill_description(skill: &SkillMetadata) -> &str { pub(crate) fn skill_description(skill: &SkillMetadata) -> &str {