@@ -13,7 +13,7 @@ use language::CodeLabelBuilder;
use language::HighlightId;
use language::{BufferSnapshot, CodeLabel, LspAdapterDelegate, OffsetRangeExt};
pub use language_model::Role;
-use serde::{Deserialize, Serialize};
+use serde::{Deserialize, Deserializer, Serialize};
use std::{
ops::Range,
sync::{Arc, atomic::AtomicBool},
@@ -21,6 +21,18 @@ use std::{
use ui::ActiveTheme;
use workspace::{Workspace, ui::IconName};
+/// Deserializes IconName, falling back to Code for unknown variants.
+/// This handles old saved data that may contain removed or renamed icon variants.
+fn deserialize_icon_with_fallback<'de, D>(deserializer: D) -> Result<IconName, D::Error>
+where
+ D: Deserializer<'de>,
+{
+ Ok(String::deserialize(deserializer)
+ .ok()
+ .and_then(|string| serde_json::from_value(serde_json::Value::String(string)).ok())
+ .unwrap_or(IconName::Code))
+}
+
pub fn init(cx: &mut App) {
SlashCommandRegistry::default_global(cx);
extension_slash_command::init(cx);
@@ -256,6 +268,7 @@ impl SlashCommandOutput {
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct SlashCommandOutputSection<T> {
pub range: Range<T>,
+ #[serde(deserialize_with = "deserialize_icon_with_fallback")]
pub icon: IconName,
pub label: SharedString,
pub metadata: Option<serde_json::Value>,
@@ -570,4 +583,35 @@ mod tests {
assert_eq!(new_output, output);
}
}
+
+ #[test]
+ fn test_deserialize_with_valid_icon_pascal_case() {
+ // Test that PascalCase icons (serde default) deserialize correctly
+ let json = json!({
+ "range": {
+ "start": 0,
+ "end": 5
+ },
+ "icon": "AcpRegistry",
+ "label": "Test",
+ "metadata": null
+ });
+ let section: SlashCommandOutputSection<usize> = serde_json::from_value(json).unwrap();
+ assert_eq!(section.icon, IconName::AcpRegistry);
+ }
+ #[test]
+ fn test_deserialize_with_unknown_icon() {
+ // Test that unknown icon variants fall back to Code
+ let json = json!({
+ "range": {
+ "start": 0,
+ "end": 5
+ },
+ "icon": "removed_icon",
+ "label": "Old Icon",
+ "metadata": null
+ });
+ let section: SlashCommandOutputSection<usize> = serde_json::from_value(json).unwrap();
+ assert_eq!(section.icon, IconName::Code);
+ }
}