Skip to content

Commit e4e617e

Browse files
committed
feat(renderer): scroll to bottom on submit
1 parent 30dec32 commit e4e617e

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

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
@@ -284,3 +284,103 @@ describe('ui.focus_input', function()
284284
assert.same({ 1, 2 }, vim.api.nvim_win_get_cursor(input_win))
285285
end)
286286
end)
287+
288+
describe('renderer._add_message_to_buffer scrolling', function()
289+
local renderer = require('opencode.ui.renderer')
290+
local formatter = require('opencode.ui.formatter')
291+
local stub = require('luassert.stub')
292+
local buf, win
293+
294+
before_each(function()
295+
config.setup({})
296+
buf = vim.api.nvim_create_buf(false, true)
297+
vim.api.nvim_buf_set_lines(buf, 0, -1, false, { 'existing line' })
298+
299+
win = vim.api.nvim_open_win(buf, true, {
300+
relative = 'editor', width = 80, height = 10, row = 0, col = 0,
301+
})
302+
303+
state.windows = { output_win = win, output_buf = buf }
304+
state.active_session = { id = 'test-session' }
305+
state.messages = {}
306+
renderer._prev_line_count = 1
307+
renderer._render_state:reset()
308+
end)
309+
310+
after_each(function()
311+
pcall(vim.api.nvim_win_close, win, true)
312+
pcall(vim.api.nvim_buf_delete, buf, { force = true })
313+
state.windows = nil
314+
state.active_session = nil
315+
state.messages = nil
316+
renderer._prev_line_count = 0
317+
renderer._render_state:reset()
318+
end)
319+
320+
it('scrolls to bottom when user message is added', function()
321+
vim.api.nvim_win_set_cursor(win, { 1, 0 })
322+
323+
local user_message = {
324+
info = {
325+
id = 'msg-1',
326+
sessionID = 'test-session',
327+
role = 'user',
328+
},
329+
parts = {},
330+
}
331+
332+
local scroll_called_with_force = false
333+
stub(renderer, 'scroll_to_bottom').invokes(function(force)
334+
scroll_called_with_force = force == true
335+
end)
336+
337+
renderer._add_message_to_buffer(user_message)
338+
339+
assert.is_true(scroll_called_with_force)
340+
assert.stub(renderer.scroll_to_bottom).was_called_with(true)
341+
342+
renderer.scroll_to_bottom:revert()
343+
end)
344+
345+
it('does not scroll when assistant message is added', function()
346+
vim.api.nvim_win_set_cursor(win, { 1, 0 })
347+
348+
local assistant_message = {
349+
info = {
350+
id = 'msg-2',
351+
sessionID = 'test-session',
352+
role = 'assistant',
353+
},
354+
parts = {},
355+
}
356+
357+
stub(renderer, 'scroll_to_bottom')
358+
359+
renderer._add_message_to_buffer(assistant_message)
360+
361+
assert.stub(renderer.scroll_to_bottom).was_not_called()
362+
363+
renderer.scroll_to_bottom:revert()
364+
end)
365+
366+
it('does not scroll when system message is added', function()
367+
vim.api.nvim_win_set_cursor(win, { 1, 0 })
368+
369+
local system_message = {
370+
info = {
371+
id = 'msg-3',
372+
sessionID = 'test-session',
373+
role = 'system',
374+
},
375+
parts = {},
376+
}
377+
378+
stub(renderer, 'scroll_to_bottom')
379+
380+
renderer._add_message_to_buffer(system_message)
381+
382+
assert.stub(renderer.scroll_to_bottom).was_not_called()
383+
384+
renderer.scroll_to_bottom:revert()
385+
end)
386+
end)

0 commit comments

Comments
 (0)