@@ -324,26 +324,74 @@ _G.opencode_fold_text = M.fold_text
324324--- @param fold_ranges table< {from : number , to : number } >
325325function M .set_folds (fold_ranges )
326326 local windows = state .windows
327- if not windows or not windows .output_buf or not vim . api . nvim_buf_is_valid ( windows . output_buf ) then
327+ if not windows or not windows .output_buf then
328328 return
329329 end
330330
331- local folds = fold_ranges or {}
332331 local buf = windows .output_buf
333- local win = windows .output_win
332+ if not vim .api .nvim_buf_is_valid (buf ) then
333+ return
334+ end
334335
335- local ok , prev_folds = pcall (vim .api .nvim_buf_get_var , buf , ' opencode_folds' )
336- if ok and vim .deep_equal (prev_folds , folds ) then
336+ local folds = fold_ranges or {}
337+
338+ local ok_prev , prev_folds = pcall (vim .api .nvim_buf_get_var , buf , ' opencode_folds' )
339+ -- Only consider folds identical if we successfully read the previous state.
340+ if ok_prev and # folds == # prev_folds and vim .deep_equal (prev_folds , folds ) then
337341 return
338342 end
343+ prev_folds = ok_prev and prev_folds or {}
339344
340- vim .api .nvim_buf_set_var (buf , ' opencode_folds' , folds )
345+ local win = windows .output_win
346+ local win_owns_buf = win and vim .api .nvim_win_is_valid (win ) and vim .api .nvim_win_get_buf (win ) == buf
341347
342- if win and vim .api .nvim_win_is_valid (win ) and vim .api .nvim_win_get_buf (win ) == buf then
348+ -- Track which folds were open
349+ local open = {}
350+ if win_owns_buf then
351+ -- Be defensive: the window may become invalid between the earlier check and
352+ -- the call, so use pcall to avoid raising an error.
343353 pcall (vim .api .nvim_win_call , win , function ()
344- vim .cmd (' silent! normal! zX' )
354+ for _ , range in ipairs (prev_folds ) do
355+ if vim .fn .foldclosed (range .from ) == - 1 then
356+ open [range .from ] = true
357+ end
358+ end
345359 end )
346360 end
361+
362+ vim .api .nvim_buf_set_var (buf , ' opencode_folds' , folds )
363+
364+ if not win_owns_buf then
365+ return
366+ end
367+
368+ pcall (vim .api .nvim_win_call , win , function ()
369+ local view = vim .fn .winsaveview ()
370+ -- Use zX to reset manual folds consistently (preserve previous behavior).
371+ vim .cmd (' silent! normal! zX' )
372+ -- 1. Create/update folds (your foldexpr / markers should already handle this)
373+ -- So we only control open/close state
374+
375+ for _ , range in ipairs (folds ) do
376+ local is_open = open [range .from ]
377+
378+ if is_open then
379+ -- ensure it's open
380+ if vim .fn .foldclosed (range .from ) ~= - 1 then
381+ vim .fn .cursor (range .from , 1 )
382+ vim .cmd (' silent! normal! zo' )
383+ end
384+ else
385+ -- ensure it's closed
386+ if vim .fn .foldclosed (range .from ) == - 1 then
387+ vim .fn .cursor (range .from , 1 )
388+ vim .cmd (' silent! normal! zc' )
389+ end
390+ end
391+ end
392+
393+ vim .fn .winrestview (view )
394+ end )
347395end
348396
349397--- Shift fold ranges
0 commit comments