Skip to content

support ctrl+z #4

@sharno

Description

@sharno

Deeper design (event‑sourced reducer)

  • Core idea: reduce(model, action) -> (model, effects) is pure and deterministic.
  • History: store a log of action items; to undo/redo, move the cursor and replay from a checkpoint snapshot.
  • Effects: network I/O, file scans, etc. are emitted as effects and processed by a separate runner that produces follow‑up actions.

What changes

  • Split Zagel into AppModel (full UI state) + Runtime (client, IO helpers, timers).
  • Rewrite update() into:
    • reduce() (pure): takes AppModel + Action, returns new AppModel + Vec.
    • run_effects() (impure): executes effects and dispatches resulting actions.
  • Convert current Message into a more explicit Action (user intents + system events).
  • Handle async results as actions that only affect model (no side effects in reducer).

Undo/redo

  • Keep History { entries: Vec, cursor, snapshots: Vec<(idx, AppModel)> }.
  • To undo: move cursor back, replay actions from the last snapshot.
  • To redo: move cursor forward and replay.
  • Optional: keep periodic snapshots (e.g., every 50 actions) for performance.

• Plan

  • Introduce AppModel (undoable state), ViewState (non‑undoable view/nav/layout), and Runtime (client, FS, timers), and move fields out of Zagel accordingly in src/app/
    lifecycle.rs plus a new module like src/app/state.rs.
  • Add a pure reducer + effect layer: define Action, Effect, and reduce(model, action) in src/app/reducer.rs, and map existing Message cases to Action in src/app/messages.rs/src/
    app/update.rs.
  • Implement history as an action log with replay + snapshots in src/app/history.rs: History { entries, cursor, snapshots, max }, store focus: Option per entry, and
    only record state‑changing actions.
  • Exclude view-only actions (pane resize, tabs, shortcuts, selection) from history; on undo/redo, apply the focus to jump the UI to the request where the action occurred.
  • Wire update() to call reduce(), push recordable actions into history, and run Effect as Task; system/async actions (Tick, file scans, response ready) update model
    without recording.
  • Add deterministic tests for reducer + history replay (including focus jump) in a new test module such as src/app/history.rs or src/app/reducer.rs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions