Skip to content

Commit 8c8754e

Browse files
committed
feat(renderer): scroll to bottom on submit
1 parent cb09a6f commit 8c8754e

2 files changed

Lines changed: 104 additions & 0 deletions

File tree

lua/opencode/ui/renderer.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,10 @@ function M._add_message_to_buffer(message)
567567
if range then
568568
M._render_state:set_message(message, range.line_start, range.line_end)
569569
end
570+
571+
if message.info.role == 'user' then
572+
M.scroll_to_bottom(true)
573+
end
570574
end
571575

572576
---Replace existing message header in buffer

tests/unit/cursor_tracking_spec.lua

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,103 @@ describe('renderer.scroll_to_bottom', function()
239239
config.values.ui.output.always_scroll_to_bottom = false
240240
end)
241241
end)
242+
243+
describe('renderer._add_message_to_buffer scrolling', function()
244+
local renderer = require('opencode.ui.renderer')
245+
local formatter = require('opencode.ui.formatter')
246+
local stub = require('luassert.stub')
247+
local buf, win
248+
249+
before_each(function()
250+
config.setup({})
251+
buf = vim.api.nvim_create_buf(false, true)
252+
vim.api.nvim_buf_set_lines(buf, 0, -1, false, { 'existing line' })
253+
254+
win = vim.api.nvim_open_win(buf, true, {
255+
relative = 'editor', width = 80, height = 10, row = 0, col = 0,
256+
})
257+
258+
state.windows = { output_win = win, output_buf = buf }
259+
state.active_session = { id = 'test-session' }
260+
state.messages = {}
261+
renderer._prev_line_count = 1
262+
renderer._render_state:reset()
263+
end)
264+
265+
after_each(function()
266+
pcall(vim.api.nvim_win_close, win, true)
267+
pcall(vim.api.nvim_buf_delete, buf, { force = true })
268+
state.windows = nil
269+
state.active_session = nil
270+
state.messages = nil
271+
renderer._prev_line_count = 0
272+
renderer._render_state:reset()
273+
end)
274+
275+
it('scrolls to bottom when user message is added', function()
276+
vim.api.nvim_win_set_cursor(win, { 1, 0 })
277+
278+
local user_message = {
279+
info = {
280+
id = 'msg-1',
281+
sessionID = 'test-session',
282+
role = 'user',
283+
},
284+
parts = {},
285+
}
286+
287+
local scroll_called_with_force = false
288+
stub(renderer, 'scroll_to_bottom').invokes(function(force)
289+
scroll_called_with_force = force == true
290+
end)
291+
292+
renderer._add_message_to_buffer(user_message)
293+
294+
assert.is_true(scroll_called_with_force)
295+
assert.stub(renderer.scroll_to_bottom).was_called_with(true)
296+
297+
renderer.scroll_to_bottom:revert()
298+
end)
299+
300+
it('does not scroll when assistant message is added', function()
301+
vim.api.nvim_win_set_cursor(win, { 1, 0 })
302+
303+
local assistant_message = {
304+
info = {
305+
id = 'msg-2',
306+
sessionID = 'test-session',
307+
role = 'assistant',
308+
},
309+
parts = {},
310+
}
311+
312+
stub(renderer, 'scroll_to_bottom')
313+
314+
renderer._add_message_to_buffer(assistant_message)
315+
316+
assert.stub(renderer.scroll_to_bottom).was_not_called()
317+
318+
renderer.scroll_to_bottom:revert()
319+
end)
320+
321+
it('does not scroll when system message is added', function()
322+
vim.api.nvim_win_set_cursor(win, { 1, 0 })
323+
324+
local system_message = {
325+
info = {
326+
id = 'msg-3',
327+
sessionID = 'test-session',
328+
role = 'system',
329+
},
330+
parts = {},
331+
}
332+
333+
stub(renderer, 'scroll_to_bottom')
334+
335+
renderer._add_message_to_buffer(system_message)
336+
337+
assert.stub(renderer.scroll_to_bottom).was_not_called()
338+
339+
renderer.scroll_to_bottom:revert()
340+
end)
341+
end)

0 commit comments

Comments
 (0)