diff --git a/rslib/src/decks/add.rs b/rslib/src/decks/add.rs index 452050efb..ca723f5b7 100644 --- a/rslib/src/decks/add.rs +++ b/rslib/src/decks/add.rs @@ -7,6 +7,9 @@ impl Collection { /// Rename deck if not unique. Bumps mtime and usn if /// name was changed, but otherwise leaves it the same. pub(super) fn prepare_deck_for_update(&mut self, deck: &mut Deck, usn: Usn) -> Result<()> { + if deck.name.maybe_normalize() { + deck.set_modified(usn); + } self.ensure_deck_name_unique(deck, usn) } diff --git a/rslib/src/decks/name.rs b/rslib/src/decks/name.rs index 9d6f3ac1a..3b1db1b4e 100644 --- a/rslib/src/decks/name.rs +++ b/rslib/src/decks/name.rs @@ -40,6 +40,20 @@ impl NativeDeckName { self.0.split('\x1f') } + /// Normalize the name's components if necessary. True if mutation took place. + pub(crate) fn maybe_normalize(&mut self) -> bool { + let needs_normalization = self + .components() + .any(|comp| matches!(normalized_deck_name_component(comp), Cow::Owned(_))); + if needs_normalization { + self.0 = self + .components() + .map(normalized_deck_name_component) + .join("\x1f"); + } + needs_normalization + } + /// Determine name to rename a deck to, when `self` is dropped on `target`. /// `target` being unset represents a drop at the top or bottom of the deck list. /// The returned name should be used to replace `self`. @@ -193,11 +207,26 @@ mod test { assert_eq!(native_name("foo"), "foo"); assert_eq!(native_name("foo::bar"), "foo\x1fbar"); assert_eq!(native_name("foo::::baz"), "foo\x1fblank\x1fbaz"); - // normalize + // implicitly normalize assert_eq!(native_name("fo\x1fo::ba\nr"), "foo\x1fbar"); assert_eq!(native_name("fo\u{a}o\x1fbar"), "foobar"); } + #[test] + fn normalize() { + fn normalize_res(name: &str) -> (bool, String) { + let mut name = NativeDeckName::from_native_str(name); + (name.maybe_normalize(), name.0) + } + + assert_eq!(normalize_res("foo\x1fbar"), (false, "foo\x1fbar".into())); + assert_eq!( + normalize_res("fo\x1fo::ba\nr"), + (true, "fo\x1fo::bar".into()) + ); + assert_eq!(normalize_res("fo\u{a}obar"), (true, "foobar".into())); + } + #[test] fn drag_drop() { // use custom separator to make the tests easier to read