@@ -3,6 +3,7 @@ local config = require('opencode.config')
33
44local M = {}
55M .namespace = vim .api .nvim_create_namespace (' opencode_output' )
6+ M .viewport_at_bottom = true
67
78function M .create_buf ()
89 local output_buf = vim .api .nvim_create_buf (false , true )
@@ -27,6 +28,36 @@ function M.mounted(windows)
2728 return windows and windows .output_buf and windows .output_win and vim .api .nvim_win_is_valid (windows .output_win )
2829end
2930
31+ --- Check if the output window is currently at the bottom
32+ --- @param win ? integer Window ID , defaults to state.windows.output_win
33+ --- @return boolean true if at bottom , false otherwise
34+ function M .is_at_bottom (win )
35+ if config .ui .output .always_scroll_to_bottom then
36+ return true
37+ end
38+
39+ win = win or (state .windows and state .windows .output_win )
40+
41+ if not win or not vim .api .nvim_win_is_valid (win ) then
42+ return true
43+ end
44+
45+ if not state .windows or not state .windows .output_buf then
46+ return true
47+ end
48+
49+ local ok , line_count = pcall (vim .api .nvim_buf_line_count , state .windows .output_buf )
50+ if not ok or not line_count or line_count == 0 then
51+ return true
52+ end
53+
54+ local botline = vim .fn .line (' w$' , win )
55+
56+ -- Consider at bottom if bottom visible line is at or near the end
57+ -- Use -1 tolerance for wrapped lines
58+ return botline >= line_count - 1
59+ end
60+
3061function M .setup (windows )
3162 vim .api .nvim_set_option_value (' winhighlight' , config .ui .window_highlight , { win = windows .output_win })
3263 vim .api .nvim_set_option_value (' wrap' , true , { win = windows .output_win })
@@ -177,13 +208,23 @@ function M.setup_autocmds(windows, group)
177208 state .subscribe (' current_permission' , function ()
178209 require (' opencode.keymap' ).toggle_permission_keymap (windows .output_buf )
179210 end )
211+
212+ -- Track scroll position when window is scrolled
213+ vim .api .nvim_create_autocmd (' WinScrolled' , {
214+ group = group ,
215+ buffer = windows .output_buf ,
216+ callback = function ()
217+ M .viewport_at_bottom = M .is_at_bottom (windows .output_win )
218+ end ,
219+ })
180220end
181221
182222function M .clear ()
183223 M .set_lines ({})
184224 -- clear extmarks in all namespaces as I've seen RenderMarkdown leave some
185225 -- extmarks behind
186226 M .clear_extmarks (0 , - 1 , true )
227+ M .viewport_at_bottom = true
187228end
188229
189230return M
0 commit comments