Skip to content

CommandPalette owns its command strings#95

Merged
meszmate merged 1 commit intomainfrom
fix/command-palette-ownership
Apr 24, 2026
Merged

CommandPalette owns its command strings#95
meszmate merged 1 commit intomainfrom
fix/command-palette-ownership

Conversation

@meszmate
Copy link
Copy Markdown
Owner

Summary

Better fix for the leak that PR #94 patched in user code: solve it in the library so no caller has to think about it.

The real problem

`CommandPalette` stored `Command` structs verbatim — `id`, `label`, `description`, and `shortcut` were all borrowed slices. That forced every caller to keep the source strings alive for as long as the palette existed, and to free them on shutdown. Easy to get wrong: the `action_system` example leaked 8 shortcut strings on exit until PR #94 added a manual ownership tracker on the user side.

That workaround should never have been the caller's job. Other widgets in the codebase (`Table`, `List`, `Tree`) all clone their content; `CommandPalette` was the odd one out.

Library changes

  • `addCommand` and `setCommands` now `dupe` every string into the palette's allocator
  • `deinit` frees them
  • New `setFromRegistry(*const ActionRegistry)` that wires the registry → palette in one call, formatting bindings as shortcut hints

Example collapses

`action_system.zig` loses ~17 lines of manual `palette_cmds` building plus the ownership workaround, replaced by:

```zig
self.palette.setFromRegistry(&self.registry) catch {};
```

Test plan

  • `zig build` passes
  • `zig build test` — full suite passes
  • `./zig-out/bin/action_system` then `q` — zero `memory address … leaked` reports
  • Stress test: open palette, run a command, open again, run another, cancel — zero leaks across multiple set/clear cycles

Previously CommandPalette stored Command structs verbatim — id, label,
description, and shortcut were all borrowed slices. That forced every
caller to keep the source strings alive for as long as the palette
existed, and to free them itself on shutdown. Easy to get wrong (the
action_system example leaked 8 shortcut strings on exit before the
band-aid in PR #94).

Library-side fix: addCommand and setCommands now clone every string
into the palette's own allocator. deinit frees them. Callers can pass
arena-allocated, formatted, or otherwise short-lived strings — no
lifetime tracking required, like Table/List/Tree already do.

Also adds:

  CommandPalette.setFromRegistry(*const ActionRegistry)

A one-line integration that pulls every enabled action into the
palette and formats bindings as shortcut hints. The
action_system example collapses from a 17-line manual loop (and the
PR #94 ownership workaround) down to a single line.

Verified: action_system exits with zero gpa leak reports, even after
repeated palette open/close cycles.
@meszmate meszmate merged commit eaf408a into main Apr 24, 2026
9 checks passed
@meszmate meszmate deleted the fix/command-palette-ownership branch April 24, 2026 13:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant