Skip to content

Commit dc07ea1

Browse files
Run1eigorlfs
andcommitted
fix: autoscroll in case of early terminal focus (#111)
* fix: fix autoscroll in case of early terminal focus * refactor: rename scroll functions * feat: more proper autoscroll fix * refactor: remove unused arg and debug log * refactor: add arg type comments * fix(scroll): minor tweaks --------- Co-authored-by: Igor <[email protected]>
1 parent 4f8ce88 commit dc07ea1

File tree

3 files changed

+77
-14
lines changed

3 files changed

+77
-14
lines changed

lua/dap-view/console/scroll.lua

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,49 @@ local M = {}
66

77
local api = vim.api
88

9-
local autoscroll = true
9+
---@type table<integer,boolean>
10+
local termbuf_is_autoscrolling = {}
1011

1112
-- Inspired by nvim-dap-ui
1213
-- https://github.com/rcarriga/nvim-dap-ui/blob/73a26abf4941aa27da59820fd6b028ebcdbcf932/lua/dapui/elements/console.lua#L23-L46
1314

1415
---@param bufnr integer
15-
M.scroll = function(bufnr)
16+
M.setup_autoscroll = function(bufnr)
17+
termbuf_is_autoscrolling[bufnr] = true
18+
1619
api.nvim_create_autocmd({ "InsertEnter", "CursorMoved" }, {
1720
buffer = bufnr,
21+
group = api.nvim_create_augroup("nvim-dap-view-scroll-" .. bufnr, {}),
1822
callback = function()
1923
local winnr = vim.tbl_contains(setup.config.winbar.sections, "console") and state.winnr or state.term_winnr
20-
if util.is_win_valid(winnr) then
21-
---@cast winnr integer
22-
local cursor = api.nvim_win_get_cursor(winnr)
23-
autoscroll = cursor[1] == api.nvim_buf_line_count(bufnr)
24+
25+
if not util.is_win_valid(winnr) then
26+
return
2427
end
28+
29+
---@cast winnr integer
30+
local cursor = api.nvim_win_get_cursor(winnr)
31+
32+
termbuf_is_autoscrolling[bufnr] = cursor[1] == api.nvim_buf_line_count(bufnr)
2533
end,
2634
})
2735

2836
api.nvim_buf_attach(bufnr, false, {
2937
on_lines = function()
3038
local winnr = vim.tbl_contains(setup.config.winbar.sections, "console") and state.winnr or state.term_winnr
39+
3140
if not util.is_win_valid(winnr) then
3241
return
3342
end
43+
3444
---@cast winnr integer
35-
if autoscroll and vim.fn.mode() == "n" then
45+
if M.is_autoscrolling(bufnr) and vim.fn.mode() == "n" then
3646
api.nvim_win_call(winnr, function()
3747
if api.nvim_get_current_buf() == bufnr then
38-
-- vim.schedule ensures the cursor movement happens in the main event loop
39-
-- otherwise the call may happen too early
48+
-- Ensure the cursor movement happens in the main event loop
49+
-- Otherwise the call may happen too early
4050
vim.schedule(function()
41-
api.nvim_win_set_cursor(winnr, { api.nvim_buf_line_count(bufnr), 0 })
51+
M.scroll_to_bottom(winnr, bufnr)
4252
end)
4353
end
4454
end)
@@ -47,4 +57,29 @@ M.scroll = function(bufnr)
4757
})
4858
end
4959

60+
---@param bufnr integer
61+
---@return boolean?
62+
M.is_autoscrolling = function(bufnr)
63+
return termbuf_is_autoscrolling[bufnr]
64+
end
65+
66+
---@param winnr integer
67+
---@param bufnr integer
68+
M.scroll_to_bottom = function(winnr, bufnr)
69+
if util.is_win_valid(winnr) and util.is_buf_valid(bufnr) then
70+
api.nvim_win_set_cursor(winnr, { api.nvim_buf_line_count(bufnr), 0 })
71+
72+
termbuf_is_autoscrolling[bufnr] = true
73+
end
74+
end
75+
76+
---@param bufnr integer
77+
M.cleanup_autoscroll = function(bufnr)
78+
if termbuf_is_autoscrolling[bufnr] then
79+
api.nvim_del_augroup_by_name("nvim-dap-view-scroll-" .. bufnr)
80+
end
81+
82+
termbuf_is_autoscrolling[bufnr] = nil
83+
end
84+
5085
return M

lua/dap-view/console/view.lua

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ local winbar = require("dap-view.options.winbar")
66
local setup = require("dap-view.setup")
77
local views = require("dap-view.views")
88
local util = require("dap-view.util")
9+
local scroll = require("dap-view.console.scroll")
910

1011
local M = {}
1112

@@ -58,11 +59,20 @@ M.show = function()
5859
---`cleanup_view` ensures the buffer exists
5960
---@cast term_buf integer
6061

62+
local is_autoscrolling = scroll.is_autoscrolling(term_buf)
63+
6164
api.nvim_win_call(state.winnr, function()
6265
vim.wo[state.winnr][0].winfixbuf = false
6366
api.nvim_set_current_buf(term_buf)
6467
vim.wo[state.winnr][0].winfixbuf = true
6568
end)
69+
70+
-- When showing a session for the first time, assume the user wants autoscroll to just work™
71+
-- That's necessary because when a terminal buffer is created, the number of lines is assigned to the number of
72+
-- lines in the window. This may lead to autoscroll being set to false, since the user may not be "at the bottom".
73+
if is_autoscrolling then
74+
scroll.scroll_to_bottom(state.winnr, term_buf)
75+
end
6676
end
6777

6878
---Hide the term win, does not affect the term buffer
@@ -139,7 +149,8 @@ M.setup_term_buf = function()
139149
end
140150

141151
require("dap-view.console.keymaps").set_keymaps(term_bufnr)
142-
require("dap-view.console.scroll").scroll(term_bufnr)
152+
153+
scroll.setup_autoscroll(term_bufnr)
143154
end
144155

145156
M.switch_term_buf = function()

lua/dap-view/listeners.lua

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ local setup = require("dap-view.setup")
1111
local refresher = require("dap-view.refresher")
1212
local winbar = require("dap-view.options.winbar")
1313
local traversal = require("dap-view.tree.traversal")
14+
local scroll = require("dap-view.console.scroll")
1415
local adapter_ = require("dap-view.util.adapter")
1516

1617
local SUBSCRIPTION_ID = "dap-view"
@@ -35,8 +36,20 @@ dap.listeners.on_session[SUBSCRIPTION_ID] = function(_, new)
3536
-- At this stage, the session is not fully initialized yet
3637
require("dap-view.exceptions").update_exception_breakpoints_filters()
3738

38-
if new.initialized and new.stopped_thread_id then
39-
eval.reevaluate_all_expressions()
39+
if new.initialized then
40+
-- Handle autoscrolling when switching sessions
41+
-- Straightforward way of taking into account "console" not being set
42+
if util.is_buf_valid(new.term_buf) and scroll.is_autoscrolling(new.term_buf) then
43+
local winnr = vim.tbl_contains(setup.config.winbar.sections, "console") and state.winnr
44+
or state.term_winnr
45+
if util.is_win_valid(winnr) then
46+
---@cast winnr integer
47+
scroll.scroll_to_bottom(winnr, new.term_buf)
48+
end
49+
end
50+
if new.stopped_thread_id then
51+
eval.reevaluate_all_expressions()
52+
end
4053
end
4154
else
4255
state.current_session_id = nil
@@ -183,13 +196,17 @@ dap.listeners.after.event_terminated[SUBSCRIPTION_ID] = function(session)
183196
end
184197

185198
winbar.redraw_controls()
199+
200+
scroll.cleanup_autoscroll(session.term_buf)
186201
end
187202

188203
-- The debuggee was disconnected, which may happen outside of a "regular termination"
189-
dap.listeners.after.disconnect[SUBSCRIPTION_ID] = function()
204+
dap.listeners.after.disconnect[SUBSCRIPTION_ID] = function(session)
190205
refresher.refresh_session_based_views()
191206

192207
winbar.redraw_controls()
208+
209+
scroll.cleanup_autoscroll(session.term_buf)
193210
end
194211

195212
local winbar_redraw = { "event_exited", "event_stopped", "restart" }

0 commit comments

Comments
 (0)