From 510d1a4a82021dc12df014cf5b10f66e31bb6880 Mon Sep 17 00:00:00 2001 From: Eval Exec Date: Thu, 8 Oct 2026 01:50:15 +0800 Subject: [PATCH] refactor(runtime): derive clipboard text MIME conversions --- .../src/clipboard/tests/text_policy_test.rs | 31 +++++++++++++++++++ .../src/clipboard/text_policy.rs | 21 ++++++------- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/crates/neomacs-display-runtime/src/clipboard/tests/text_policy_test.rs b/crates/neomacs-display-runtime/src/clipboard/tests/text_policy_test.rs index 79ed06c13a..4c2abef519 100644 --- a/crates/neomacs-display-runtime/src/clipboard/tests/text_policy_test.rs +++ b/crates/neomacs-display-runtime/src/clipboard/tests/text_policy_test.rs @@ -225,3 +225,34 @@ fn only_text_reaches_the_evaluator_facing_wire() { assert_eq!(TextRead::TargetUnavailable.into_option(), None); assert_eq!(TextRead::Indeterminate.into_option(), None); } + +#[test] +fn text_mime_spellings_round_trip_exactly() { + for (mime, spelling) in [ + (TextMime::TextPlainUtf8, "text/plain;charset=utf-8"), + (TextMime::Utf8String, "UTF8_STRING"), + (TextMime::TextPlain, "text/plain"), + ] { + assert_eq!(mime.as_str(), spelling); + assert_eq!(spelling.parse::(), Ok(mime)); + assert_eq!(TextMime::choose(&offered(&[spelling])), Some(mime)); + } +} + +#[test] +fn text_mime_recognition_does_not_accept_aliases_or_normalize_names() { + for spelling in [ + "TextPlainUtf8", + "Utf8String", + "TextPlain", + "utf8_string", + "TEXT/PLAIN", + "text/plain;charset=UTF-8", + " text/plain", + "text/plain ", + "text/plain; charset=utf-8", + ] { + assert!(spelling.parse::().is_err(), "{spelling}"); + assert_eq!(TextMime::choose(&offered(&[spelling])), None, "{spelling}"); + } +} diff --git a/crates/neomacs-display-runtime/src/clipboard/text_policy.rs b/crates/neomacs-display-runtime/src/clipboard/text_policy.rs index e77610ed0e..428e3415b3 100644 --- a/crates/neomacs-display-runtime/src/clipboard/text_policy.rs +++ b/crates/neomacs-display-runtime/src/clipboard/text_policy.rs @@ -99,21 +99,20 @@ impl TextRead { /// The text MIME spellings, in smithay-clipboard's preference order. #[cfg(target_os = "linux")] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, strum::EnumString, strum::IntoStaticStr)] pub(super) enum TextMime { + #[strum(serialize = "text/plain;charset=utf-8")] TextPlainUtf8, + #[strum(serialize = "UTF8_STRING")] Utf8String, + #[strum(serialize = "text/plain")] TextPlain, } #[cfg(target_os = "linux")] impl TextMime { pub(super) fn as_str(self) -> &'static str { - match self { - Self::TextPlainUtf8 => "text/plain;charset=utf-8", - Self::Utf8String => "UTF8_STRING", - Self::TextPlain => "text/plain", - } + self.into() } /// The first UTF-8 type offered, else plain text as a fallback; mirrors @@ -122,11 +121,11 @@ impl TextMime { pub(super) fn choose(offered: &[String]) -> Option { let mut fallback = None; for mime in offered { - match mime.as_str() { - "text/plain;charset=utf-8" => return Some(Self::TextPlainUtf8), - "UTF8_STRING" => return Some(Self::Utf8String), - "text/plain" => fallback = Some(Self::TextPlain), - _ => {} + match mime.parse::() { + Ok(Self::TextPlainUtf8) => return Some(Self::TextPlainUtf8), + Ok(Self::Utf8String) => return Some(Self::Utf8String), + Ok(Self::TextPlain) => fallback = Some(Self::TextPlain), + Err(_) => {} } } fallback