Skip to content

feat(ui): persist_state window/buffer persistence#281

Merged
sudo-tee merged 2 commits intosudo-tee:mainfrom
jensenojs:pr/persist-state
Feb 24, 2026
Merged

feat(ui): persist_state window/buffer persistence#281
sudo-tee merged 2 commits intosudo-tee:mainfrom
jensenojs:pr/persist-state

Conversation

@jensenojs
Copy link
Contributor

When ui.persist_state = true (default), toggle hides windows without deleting buffers and restores them on next toggle, preserving input draft content, scroll/cursor position, focused pane, and input_hidden state.

Three-state window model:
closed → visible → hidden → visible
↑___________↓____________↑
(teardown) (restore)

Decision engine resolves (status, persist_state, has_display_route, in_tab) → action:

# status in_tab persist_state has_display_route action
1 hidden any true any restore_hidden
2 hidden any false any close_hidden
3 visible false any any migrate
4 visible true any true close
5 visible true false any close
6 visible true true false hide
7 closed any any any open

Note: Multiple opencode instances across tabs are not currently supported.

@jensenojs
Copy link
Contributor Author

jensenojs commented Feb 14, 2026

TODO : A complete video demonstration is needed to show the effects after merging my three pull requests

iShot_2026-02-15_09.33.20.mp4
图片

benchmark

If you have any suggestions regarding code maintainability, please don't hesitate to point them out, as this is very helpful for my growth and the maintenance of the code.

Nevertheless, I would prefer to complete it further in subsequent PRs. The current split is making me a bit exhausted.

@sudo-tee
Copy link
Owner

@jensenojs

Is this MR ready to re-review ?

There is some conflicts at the moment against main.

@jensenojs jensenojs force-pushed the pr/persist-state branch 3 times, most recently from eef2ee7 to 3edc1fe Compare February 20, 2026 03:38
When ui.persist_state = true (default), toggle hides windows without
deleting buffers and restores them on next toggle, preserving input
draft content, scroll/cursor position, focused pane, and input_hidden
state.

Three-state window model:
closed → visible → hidden → visible
  ↑___________↓____________↑
   (teardown)   (restore)

Decision engine resolves (status, persist_state, has_display_route, in_tab) → action:

| # | status  | in_tab | persist_state | has_display_route | action         |
|---|---------|--------|---------------|-------------------|----------------|
| 1 | hidden  | any    | true          | any               | restore_hidden |
| 2 | hidden  | any    | false         | any               | close_hidden   |
| 3 | visible | false  | any           | any               | migrate        |
| 4 | visible | true   | any           | true              | close          |
| 5 | visible | true   | false         | any               | close          |
| 6 | visible | true   | true          | false             | hide           |
| 7 | closed  | any    | any           | any               | open           |

Note: Multiple opencode instances across tabs are not currently supported.
@jensenojs
Copy link
Contributor Author

yes, The core is implementing the persist_state tri-state model (closed/hidden/visible) + decision-driven toggle logic.

Major Changes (4 Files)

File Changes Core Content
state.lua +304/-13 Added OpencodeHiddenBuffers type, OpencodeToggleDecision type, decision logic resolve_toggle_decision, window state management methods
ui.lua +276/-29 Hide/restore window lifecycle, cursor position snapshot/restore, close_windows_impl unifies teardown vs hide handling
api.lua +84/-21 toggle() completely refactored to decision-table pattern, added hide() API, uses state.resolve_toggle_decision()
core.lua +59/-39 M.open() supports restore_hidden flow, multiple state.windows → state.is_visible() replacements

Actually, the close_windows_impl function is a bit messy because the specific logic for hide and close is coupled with the common logic. I'm considering cleaning it up to make it more streamlined later on.

Secondary Changes (Adaptation Adjustments)

File Changes Description
tests/unit/persist_state_spec.lua +678 New test file (largest line count)
input/output_window.lua +12/-4 Cursor tracking migrated to new API (get_window_cursor + set_cursor_position)
footer.lua +5/-2 Added preserve_buffer parameter support
cursor_tracking_spec.lua +9/-6 Tests adapted to new function names
input_window.lua +4/-0 Added cursor position save in _hide() for auto_hide scenario
7 other files minor README, config, types, autocmds, renderer, etc.

Thanks for your hard work (both you and me). I definitely won't take on such a big PR again. I would rather bother you a few more times. @sudo-tee

Copy link
Owner

@sudo-tee sudo-tee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested a bit and it works well, I like it overall

I left a couple of comments regarding the structure of the code as this is quite complex.

I feel like this should be simplified a little bit before merging.

Thanks a lot for your efforts on this.

It's almost there :)

- Align toggle decision rules with ordered first-match evaluation shared across state checks.
- Split hide/teardown paths and inline finalization in UI close logic.
- Replace toggle branching with action-handler dispatch while preserving behavior.
@sudo-tee
Copy link
Owner

@jensenojs

Thanks for addressing the comments I made.

It definitely is easier to understand this way.

I will do a final testing this weekend and it should be good to go

@sudo-tee sudo-tee merged commit f18d895 into sudo-tee:main Feb 24, 2026
5 checks passed
@jensenojs jensenojs deleted the pr/persist-state branch February 24, 2026 17:07
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.

2 participants