From 2cc146f5ea50ab7a39811f38986f2907b97be39f Mon Sep 17 00:00:00 2001 From: canvrno-oai Date: Mon, 20 Apr 2026 20:46:55 -0700 Subject: [PATCH] Fallback display names for TUI skill mentions (#18786) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. Screenshot 2026-04-20 at 6 25 15 PM --- codex-rs/tui/src/bottom_pane/chat_composer.rs | 11 ++--------- codex-rs/tui/src/bottom_pane/skill_popup.rs | 2 +- codex-rs/tui/src/chatwidget/skills.rs | 2 +- codex-rs/tui/src/skills_helpers.rs | 17 ++++++++++++++--- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/codex-rs/tui/src/bottom_pane/chat_composer.rs b/codex-rs/tui/src/bottom_pane/chat_composer.rs index 470afbdab..df506fb6f 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer.rs @@ -206,6 +206,7 @@ use crate::bottom_pane::textarea::TextAreaState; use crate::clipboard_paste::normalize_pasted_path; use crate::clipboard_paste::pasted_image_format; use crate::history_cell; +use crate::skills_helpers::skill_display_name; use crate::tui::FrameRequester; use crate::ui_consts::LIVE_PREFIX_COLS; use codex_app_server_protocol::AppInfo; @@ -3455,7 +3456,7 @@ impl ChatComposer { let mut mentions = Vec::new(); if let Some(skills) = self.skills.as_ref() { 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 skill_name = skill.name.clone(); 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 { let description = skill .interface diff --git a/codex-rs/tui/src/bottom_pane/skill_popup.rs b/codex-rs/tui/src/bottom_pane/skill_popup.rs index 836bad636..a0d427839 100644 --- a/codex-rs/tui/src/bottom_pane/skill_popup.rs +++ b/codex-rs/tui/src/bottom_pane/skill_popup.rs @@ -28,7 +28,7 @@ pub(crate) struct MentionItem { pub(crate) sort_rank: u8, } -const MENTION_NAME_TRUNCATE_LEN: usize = 24; +const MENTION_NAME_TRUNCATE_LEN: usize = 28; pub(crate) struct SkillPopup { query: String, diff --git a/codex-rs/tui/src/chatwidget/skills.rs b/codex-rs/tui/src/chatwidget/skills.rs index 0f0261ffe..904678003 100644 --- a/codex-rs/tui/src/chatwidget/skills.rs +++ b/codex-rs/tui/src/chatwidget/skills.rs @@ -75,7 +75,7 @@ impl ChatWidget { .iter() .map(|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 name = core_skill.name.clone(); let path = core_skill.path_to_skills_md; diff --git a/codex-rs/tui/src/skills_helpers.rs b/codex-rs/tui/src/skills_helpers.rs index e02e929d4..730acdcaa 100644 --- a/codex-rs/tui/src/skills_helpers.rs +++ b/codex-rs/tui/src/skills_helpers.rs @@ -5,12 +5,23 @@ use crate::text_formatting::truncate_text; pub(crate) const SKILL_NAME_TRUNCATE_LEN: usize = 21; -pub(crate) fn skill_display_name(skill: &SkillMetadata) -> &str { - skill +pub(crate) fn skill_display_name(skill: &SkillMetadata) -> String { + if let Some(display_name) = skill .interface .as_ref() .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 {