@@ -4,6 +4,37 @@ local config = require('opencode.config')
44local M = {}
55M .namespace = vim .api .nvim_create_namespace (' opencode_output' )
66
7+ local _update_depth = 0
8+ local _update_buf = nil
9+
10+ --- Begin a batch of buffer writes — toggle modifiable once for the whole batch.
11+ --- Returns true if the batch was opened (buffer is valid). Must be paired with end_update().
12+ --- @return boolean
13+ function M .begin_update ()
14+ local windows = state .windows
15+ if not windows or not windows .output_buf then
16+ return false
17+ end
18+ if _update_depth == 0 then
19+ _update_buf = windows .output_buf
20+ vim .api .nvim_set_option_value (' modifiable' , true , { buf = _update_buf })
21+ end
22+ _update_depth = _update_depth + 1
23+ return true
24+ end
25+
26+ --- End a batch started by begin_update().
27+ function M .end_update ()
28+ if _update_depth == 0 then
29+ return
30+ end
31+ _update_depth = _update_depth - 1
32+ if _update_depth == 0 and _update_buf then
33+ vim .api .nvim_set_option_value (' modifiable' , false , { buf = _update_buf })
34+ _update_buf = nil
35+ end
36+ end
37+
738function M .create_buf ()
839 local output_buf = vim .api .nvim_create_buf (false , true )
940 local filetype = config .ui .output .filetype or ' opencode_output'
@@ -165,66 +196,67 @@ function M.update_dimensions(windows)
165196end
166197
167198function M .get_buf_line_count ()
168- if not M .buffer_valid () then
199+ local windows = state .windows
200+ if not windows or not windows .output_buf or not vim .api .nvim_buf_is_valid (windows .output_buf ) then
169201 return 0
170202 end
171- --- @cast state.windows { output_buf : integer }
172-
173- return vim .api .nvim_buf_line_count (state .windows .output_buf )
203+ return vim .api .nvim_buf_line_count (windows .output_buf )
174204end
175205
176206--- Set the output buffer contents
177207--- @param lines string[] The lines to set
178208--- @param start_line ? integer The starting line to set , defaults to 0
179209--- @param end_line ? integer The last line to set , defaults to -1
180210function M .set_lines (lines , start_line , end_line )
181- if not M .buffer_valid () then
211+ local windows = state .windows
212+ if not windows or not windows .output_buf or not vim .api .nvim_buf_is_valid (windows .output_buf ) then
182213 return
183214 end
184- --- @cast state.windows { output_buf : integer }
185215
216+ local buf = windows .output_buf
186217 start_line = start_line or 0
187218 end_line = end_line or - 1
188219
189- vim .api .nvim_set_option_value (' modifiable' , true , { buf = state .windows .output_buf })
190- vim .api .nvim_buf_set_lines (state .windows .output_buf , start_line , end_line , false , lines )
191- vim .api .nvim_set_option_value (' modifiable' , false , { buf = state .windows .output_buf })
220+ if _update_depth == 0 then
221+ vim .api .nvim_set_option_value (' modifiable' , true , { buf = buf })
222+ vim .api .nvim_buf_set_lines (buf , start_line , end_line , false , lines )
223+ vim .api .nvim_set_option_value (' modifiable' , false , { buf = buf })
224+ else
225+ vim .api .nvim_buf_set_lines (buf , start_line , end_line , false , lines )
226+ end
192227end
193228
194229--- Clear output buf extmarks
195230--- @param start_line ? integer Line to start clearing , defaults 0
196231--- @param end_line ? integer Line to clear until , defaults to -1
197232--- @param clear_all ? boolean If true , clears all extmarks in the buffer
198233function M .clear_extmarks (start_line , end_line , clear_all )
199- if not M .buffer_valid () then
234+ local windows = state .windows
235+ if not windows or not windows .output_buf or not vim .api .nvim_buf_is_valid (windows .output_buf ) then
200236 return
201237 end
202- --- @cast state.windows { output_buf : integer }
203238
204239 start_line = start_line or 0
205240 end_line = end_line or - 1
206241
207- pcall (
208- vim .api .nvim_buf_clear_namespace ,
209- state .windows .output_buf ,
210- clear_all and - 1 or M .namespace ,
211- start_line ,
212- end_line
213- )
242+ pcall (vim .api .nvim_buf_clear_namespace , windows .output_buf , clear_all and - 1 or M .namespace , start_line , end_line )
214243end
215244
216245--- Apply extmarks to the output buffer
217246--- @param extmarks table<number , OutputExtmark[]> Extmarks indexed by line
218247--- @param line_offset ? integer Line offset to apply to extmarks , defaults to 0
219248function M .set_extmarks (extmarks , line_offset )
220- if not M .buffer_valid () or not extmarks or type (extmarks ) ~= ' table' then
249+ if not extmarks or type (extmarks ) ~= ' table' then
250+ return
251+ end
252+ local windows = state .windows
253+ if not windows or not windows .output_buf or not vim .api .nvim_buf_is_valid (windows .output_buf ) then
221254 return
222255 end
223- --- @cast state.windows { output_buf : integer }
224256
225257 line_offset = line_offset or 0
226258
227- local output_buf = state . windows .output_buf
259+ local output_buf = windows .output_buf
228260
229261 for line_idx , marks in pairs (extmarks ) do
230262 for _ , mark in ipairs (marks ) do
0 commit comments