Skip to content

Deleted profiles come back after SaveAsync + restart, because deletion is never persisted #106

Description

@matt-edmondson

What's wrong

  • ProfileManager.DeleteProfile removes the profile from memory only.
  • KeybindingManager.SaveAsync then upserts each in-memory profile, one at a time:
    IReadOnlyCollection<Profile> profiles = Profiles.GetAllProfiles();
    await AsyncBatchHelper.ForEachAsync(profiles, Repository.SaveProfileAsync)
  • JsonKeybindingRepository.SaveProfileAsync loads every profile already on disk, removes only the one with the same id, appends the new one, and rewrites the file. A profile that is on disk but no longer in memory is carried over unchanged.
  • IKeybindingRepository.DeleteProfileAsync exists and is implemented, but nothing in the library calls it.

Reproduction (verified against current main)

  1. Create profiles default and vim, then call SaveAsync().
  2. Call Profiles.DeleteProfile("vim"), then SaveAsync(). The in-memory profile list is now default.
  3. Create a fresh KeybindingManager on the same directory and call InitializeAsync(). The profiles are vim, default.

Why it matters

Users cannot delete a profile for good: it reappears on every launch, and any bindings it holds come back with it. Renaming a profile to a new id also leaves the old id on disk.

Suggested fix

Have SaveAsync persist the profile set as a whole, for example with a new IKeybindingRepository.SaveAllProfilesAsync(IEnumerable<Profile>) that writes profiles.json once. This also removes the current O(n²) pattern of reading and rewriting the whole file once per profile.

Alternatively, delete the stored ids that are no longer in memory, or call Repository.DeleteProfileAsync from the delete path.

Acceptance criteria: a test covers delete, save, and reload, and asserts the deleted profile is gone.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions