Skip to content

fix: RichLog inside a Modal, and passing data into the model - #162

Merged
meszmate merged 1 commit into
mainfrom
fix/richlog-modal-crash-model-data
Oct 13, 2026
Merged

meszmate merged 1 commit into
mainfrom
fix/richlog-modal-crash-model-data

Conversation

@meszmate

Copy link
Copy Markdown
Owner

Closes #158
Closes #161

#158: RichLog in a modal crashes

I reproduced the reporter's program in a pty on Zig 0.16. They describe two crashes, and they have different causes:

  1. "Crash" on quit. This is the debug allocator's leak report. The model creates a RichLog with ctx.persistent_allocator but has no deinit that frees it. It is not specific to the modal.
  2. Segfault when modal.body = log.view(ctx.allocator) is set in update(). The frame arena is reset at the start of the next tick. The modal still points at that memory, so computeHeight reads freed pages.

The reporter's workaround of setting body in view() needed @constCast twice, because RichLog.view wanted a mutable pointer.

Changes:

  • RichLog.view takes *const RichLog. When the filter cache is stale it filters into scratch space in the given allocator. Follow mode now always shows the tail, including after setSize.
  • New Modal.withBody(body). It returns a copy of the modal with a per-frame body for a single render. Call it from view(): self.modal.withBody(try self.log.view(ctx.allocator)).viewWithBackdrop(...).
  • Modal body lines keep the body style after embedded resets. Pre-styled content such as RichLog's level labels ends each span with \x1b[0m, which used to drop content_bg for the rest of the line.
  • Program.deinit only calls Model.deinit after Model.init has run. Before, a failed start() (e.g. no terminal) handed deinit an undefined model. Harness already guarded this.
  • The modal example gets a "6: Log" modal that shows the right pattern, with deinit.

#161: passing extra data to the model

  • New Program(Model).initWithModel(gpa, io, environ_map, model, options). It sets the model's initial value, e.g. .{ .pool = pool }, before start(). Model.init still runs and sees those fields through self.
  • New Harness(Model).initWithModel(allocator, io, model, options) for tests, which covers the commented-out test in the issue.

Docs

REFERENCE.md now covers:

  • withBody and borrowed modal strings
  • allocator lifetimes: never keep ctx.allocator slices; free persistent state in deinit
  • a "Passing data into the model" section with a database-pool example

Tests

  • Harness test with the issue Rich log in modal crash with memory problem #158 model: a RichLog in a modal across several frame resets, testing.allocator leak check, and quit. Without deinit it fails with 15 leaks.
  • Harness test with the issue guidance on how could i pass extra data to the model #161 shape: the model receives a *Store created outside the program.
  • Program tests: initWithModel seeds the model and options, and deinit skips Model.deinit when start() never ran.
  • RichLog tests: const view honours a stale filter, and follow mode shows the tail after a resize.
  • Modal tests: withBody, and the body background after embedded resets. The background test fails without the fix.

zig build test, zig build and zig fmt --check src tests examples build.zig pass on Zig 0.16.0. I also ran the modal example in a pty (open, close, log modal, quit): it exits with status 0 and reports no leaks.

)

- RichLog.view takes *const, so it can be called from a const view()
  without @constcast; follow mode always shows the tail.
- Modal.withBody renders per-frame content (e.g. a RichLog) for one
  render instead of storing a frame-allocated slice that dangles on
  the next tick.
- Modal body lines that carry their own resets keep the body style and
  content_bg for the rest of the line.
- Program.deinit only calls Model.deinit once Model.init has run.
- Program.initWithModel / Harness.initWithModel let main hand the model
  resources it created, such as a database pool.
- Modal example gains a log modal; REFERENCE documents withBody,
  allocator lifetimes with deinit, and initWithModel.
@meszmate
meszmate merged commit e09cb46 into main Oct 13, 2026
12 checks passed
@meszmate
meszmate deleted the fix/richlog-modal-crash-model-data branch October 13, 2026 14:34
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.

guidance on how could i pass extra data to the model Rich log in modal crash with memory problem

1 participant