fix: fold error when using max_messages - #469
Merged
Merged
Conversation
Owner
|
Is the MR ready for review or you still need to adjust some things ? |
Contributor
Author
|
not yet, I will take a look again asap |
Problem: when buffer shrinks faster than the cached fold ranges get updated, vim.fn.foldclosed() reports ranges that no longer exist in the buffer. The fold creation loop already had a line_count guard but the foldopen! loop did not, surfacing as 'E16: Invalid range'. Solution: mirror the same line_count guard on the foldopen! loop so out-of-range entries are silently skipped instead of raising.
… buffer var The opencode_folds b:var had to round-trip through vim's lua bridge on every set_folds call (one nvim_buf_set_var write plus one nvim_buf_get_var read). Microbench on a freshly created buffer: bridge set+get round-trip: 1.04 us bridge set only: 0.70 us bridge get only: 0.45 us pure Lua ref: 0.003 us Move fold state to state.windows.output_folds, sitting alongside output_buf and output_was_at_bottom. set_windows replaces the whole windows object on every mount, so output_folds resets with it automatically - no separate clear path needed. Fold state is now fetched with state.ui.get_output_folds(), a pure Lua table read. Also drops the fold_state.starts field that shift_folds was maintaining but nothing was reading.
Problem: diff computations were duplicated across flush + buffer. flush.format_message did a full lines_equal + extmarks_equal walk, and buffer.upsert_*_now each computed unchanged_prefix_len that extmark_clear_range then recomputed internally. append.lua held a hand-rolled tail walk duplicating the same primitive. Solution: introduce output_diff.lua with shared prefix walks, slice helpers, mark equality, and the high-level is_unchanged / is_append_only predicates. Make extmark_clear_range accept a precomputed prefix_len and extract write_in_place so both upsert paths walk once. Collapse append.lua into output_diff.lua.
phanen
force-pushed
the
fix/fold
branch
2 times, most recently
from
July 25, 2026 02:19
8c8ba24 to
ebef0ec
Compare
phanen
marked this pull request as ready for review
July 25, 2026 02:24
phanen
marked this pull request as draft
July 25, 2026 02:50
Problem: update_part_folds aggregated new_global from ctx.part_folds, which stores absolute coordinates computed at the time each part was last updated. When a part's line_start shifts (upsert/append path did not call shift_all before c451c90+x, remove paths still do not), the stored entry becomes stale and the next update_part_folds re-emits fold ranges referencing lines that no longer host the part's content. Solution: rebuild new_global from ctx.formatted_parts (source of truth for what's currently rendered) on every update, recomputing each part's absolute folds from its current cached_part.line_start. This mirrors set_all_folds and stops stale entries from leaking into set_folds. test(renderer): align 'merges existing folds' with formatted_parts source
fix(renderer): shift siblings on in-place upsert_part_now size change fix(renderer): shift siblings on append_part_now fix(renderer): drop redundant shift_all around render_state mutators
phanen
marked this pull request as ready for review
July 25, 2026 03:41
jugarpeupv
pushed a commit
to jugarpeupv/opencode.nvim
that referenced
this pull request
Jul 29, 2026
* fix(output_window): guard foldopen! against out-of-range fold ranges Problem: when buffer shrinks faster than the cached fold ranges get updated, vim.fn.foldclosed() reports ranges that no longer exist in the buffer. The fold creation loop already had a line_count guard but the foldopen! loop did not, surfacing as 'E16: Invalid range'. Solution: mirror the same line_count guard on the foldopen! loop so out-of-range entries are silently skipped instead of raising. * perf(output_window): batch fold commands into single nvim_exec2 call * refactor(output_window): store fold state in state.windows instead of buffer var The opencode_folds b:var had to round-trip through vim's lua bridge on every set_folds call (one nvim_buf_set_var write plus one nvim_buf_get_var read). Microbench on a freshly created buffer: bridge set+get round-trip: 1.04 us bridge set only: 0.70 us bridge get only: 0.45 us pure Lua ref: 0.003 us Move fold state to state.windows.output_folds, sitting alongside output_buf and output_was_at_bottom. set_windows replaces the whole windows object on every mount, so output_folds resets with it automatically - no separate clear path needed. Fold state is now fetched with state.ui.get_output_folds(), a pure Lua table read. Also drops the fold_state.starts field that shift_folds was maintaining but nothing was reading. * chore: unused * chore: fix types * fix: skip check when debug not enable * chore: dedup code * refactor(renderer): extract output_diff and dedupe upsert path Problem: diff computations were duplicated across flush + buffer. flush.format_message did a full lines_equal + extmarks_equal walk, and buffer.upsert_*_now each computed unchanged_prefix_len that extmark_clear_range then recomputed internally. append.lua held a hand-rolled tail walk duplicating the same primitive. Solution: introduce output_diff.lua with shared prefix walks, slice helpers, mark equality, and the high-level is_unchanged / is_append_only predicates. Make extmark_clear_range accept a precomputed prefix_len and extract write_in_place so both upsert paths walk once. Collapse append.lua into output_diff.lua. * chore: unused function * style: fmt * fix(renderer): derive global folds from formatted_parts Problem: update_part_folds aggregated new_global from ctx.part_folds, which stores absolute coordinates computed at the time each part was last updated. When a part's line_start shifts (upsert/append path did not call shift_all before c451c90+x, remove paths still do not), the stored entry becomes stale and the next update_part_folds re-emits fold ranges referencing lines that no longer host the part's content. Solution: rebuild new_global from ctx.formatted_parts (source of truth for what's currently rendered) on every update, recomputing each part's absolute folds from its current cached_part.line_start. This mirrors set_all_folds and stops stale entries from leaking into set_folds. test(renderer): align 'merges existing folds' with formatted_parts source * fix(renderer): shift render_state and drop part_folds on remove fix(renderer): shift siblings on in-place upsert_part_now size change fix(renderer): shift siblings on append_part_now fix(renderer): drop redundant shift_all around render_state mutators
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
often get error like this when use
max_messages