Rename profiles in place and keep their description - #115
Merged
Merged
Conversation
ProfileManager.RenameProfile built a new Profile and swapped it in with TryRemove/TryAdd. Leaving out the optional description erased it, and every reference a caller already held was detached, so chords set through it never reached GetProfile or SaveAsync. The rename now updates the stored instance under the manager's lock and keeps the current description when none is passed. Fixes #113 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QPAgvLThqmty1U7AaebQMQ
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Fixes #113
What was wrong
ProfileManager.RenameProfilebuilt a newProfile, copied the chords across, and swapped it in withTryRemovefollowed byTryAdd. That caused three problems:newDescriptionis documented as optional, but it was passed straight through, so a call without it setDescription = null.CreateProfile,CreateDefaultProfileandGetActiveProfile. Chords set through such a reference never reachedGetProfileorSaveAsync, so those bindings were silently lost.GetProfilereturned null. A concurrentCreateProfile(id)in that window would make theTryAddfail and drop the renamed profile.Change
Profile.NameandProfile.Descriptionnow haveprivate set.internal Rename(name, description)method validates and trims the values the same way the constructor does. The public surface ofProfilestays read-only.RenameProfilenow renames the stored instance under the manager's existing_lock, and passesnewDescription ?? profile.Description. Since nothing is removed from the dictionary, the window in (3) is gone.IProfileManager.RenameProfiledocs now state that a null description keeps the current one, and that held references stay valid.Profileequality and hashing only useId, so renaming in place can't disturb dictionary keys or equality anywhere.Tests
The new file
Keybinding.Test/ProfileRenameTests.csadds five tests:RenameProfile_WithoutDescription_KeepsTheExistingDescriptionRenameProfile_KeepsHeldReferencesAttachedAreSame(held, GetProfile(id)), and a chord set throughheldis visibleRenameProfile_ChordsSetThroughAHeldReference_ArePersistedSaveAsync, reload in a new managerRenameProfile_WithDescription_ReplacesItRenameProfile_UnknownProfile_ReturnsFalseWith the production changes reverted, the first three fail. With the fix, the full suite passes, 57 of 57 (
dotnet test Keybinding.Test -c Release).This PR doesn't overlap with the open #110 or #111, and it leaves the
CreateProfilerace in #112 for its own change.🤖 Generated with Claude Code
https://claude.ai/code/session_01QPAgvLThqmty1U7AaebQMQ
Generated by Claude Code