Skip to content

Commit b7818e4

Browse files
committed
feat: multi session support
1 parent 960e219 commit b7818e4

File tree

6 files changed

+139
-64
lines changed

6 files changed

+139
-64
lines changed

lua/dap-view/console/init.lua

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
local state = require("dap-view.state")
2+
local winbar = require("dap-view.options.winbar")
3+
4+
local M = {}
5+
6+
local api = vim.api
7+
8+
---@param winnr integer
9+
M.setup_console = function(winnr)
10+
api.nvim_win_call(winnr, function()
11+
local term_bufnr = state.term_bufnrs[state.current_session_id]
12+
13+
api.nvim_set_current_buf(term_bufnr)
14+
15+
require("dap-view.term.options").set_options(winnr, term_bufnr)
16+
17+
winbar.set_winbar_action_keymaps(term_bufnr)
18+
19+
winbar.update_section("console")
20+
end)
21+
end
22+
23+
return M

lua/dap-view/events.lua

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,40 +10,40 @@ local term = require("dap-view.term.init")
1010
local eval = require("dap-view.watches.eval")
1111
local setup = require("dap-view.setup")
1212
local winbar = require("dap-view.options.winbar")
13+
local util = require("dap-view.util")
14+
local console = require("dap-view.console")
1315

1416
local SUBSCRIPTION_ID = "dap-view"
1517

1618
dap.listeners.before.initialize[SUBSCRIPTION_ID] = function(session, _)
17-
local adapter = session.config.type
18-
-- When initializing a new session, there might a leftover terminal buffer
19-
-- Usually, this wouldn't be a problem, but it can cause inconsistencies when starting a session that
20-
--
21-
-- (A) Doesn't use the terminal, after a session that does
22-
-- The problem here is that the terminal could be used if it was left open from the earlier session
23-
--
24-
-- (B) Uses the terminal, after a session that doesn't
25-
-- The terminal wouldn't show up, since it's hidden
26-
--
27-
-- To handle these scenarios, we have to delete the terminal buffer
28-
-- However, if we always close the terminal, dap-view will be shifted very quickly (if open),
29-
-- causing a flickering effect.
30-
--
31-
-- To address that, we only delete the terminal buffer if the new session has a different adapter
32-
-- (which should cover most scenarios where the flickering would occur)
33-
--
34-
-- However, do not try to delete the buffer on the first session,
35-
-- as it conflicts with bootstrapping the terminal window.
36-
-- See: https://github.com/igorlfs/nvim-dap-view/issues/18
37-
if state.last_active_adapter and state.last_active_adapter ~= adapter then
38-
term.force_delete_term_buf()
19+
state.current_adapter = session.config.type
20+
state.current_session_id = session.id
21+
22+
if state.fallback_term_bufnr then
23+
state.term_bufnrs[state.current_session_id] = state.fallback_term_bufnr
24+
state.fallback_term_bufnr = nil
3925
end
40-
state.last_active_adapter = adapter
4126

4227
term.setup_term_win_cmd()
4328

29+
dap.defaults.fallback.terminal_win_cmd = function()
30+
local term_bufnr = state.term_bufnrs[state.current_session_id]
31+
32+
assert(term_bufnr, "Failed to get term bufnr")
33+
34+
return term_bufnr
35+
end
36+
4437
local separate_term_win = not vim.tbl_contains(setup.config.winbar.sections, "console")
45-
if not setup.config.windows.terminal.start_hidden and separate_term_win then
46-
term.open_term_buf_win()
38+
39+
local is_console = state.current_section == "console"
40+
41+
if not setup.config.windows.terminal.start_hidden then
42+
if separate_term_win then
43+
term.open_term_buf_win()
44+
elseif util.is_win_valid(state.winnr) and is_console then
45+
console.setup_console(state.winnr)
46+
end
4747
end
4848
end
4949

@@ -78,6 +78,24 @@ dap.listeners.after.stackTrace[SUBSCRIPTION_ID] = function()
7878
end
7979
end
8080

81+
dap.listeners.after.event_stopped[SUBSCRIPTION_ID] = function(session)
82+
state.current_session_id = session.id
83+
84+
local separate_term_win = not vim.tbl_contains(setup.config.winbar.sections, "console")
85+
local is_console = state.current_section == "console"
86+
87+
local cond_main_win = not separate_term_win and util.is_win_valid(state.winnr) and is_console
88+
local cond_term_win = separate_term_win and util.is_win_valid(state.term_winnr)
89+
90+
local winnr = separate_term_win and state.term_winnr or state.winnr
91+
92+
if winnr and (cond_main_win or cond_term_win) then
93+
console.setup_console(winnr)
94+
end
95+
96+
winbar.redraw_controls()
97+
end
98+
8199
dap.listeners.after.setExpression[SUBSCRIPTION_ID] = function()
82100
eval.reeval()
83101
end
@@ -107,6 +125,8 @@ dap.listeners.after.initialize[SUBSCRIPTION_ID] = function(session, _)
107125
end
108126

109127
dap.listeners.after.event_terminated[SUBSCRIPTION_ID] = function()
128+
state.current_session_id = nil
129+
110130
-- Refresh threads view on exit to avoid showing outdated trace
111131
if state.current_section == "threads" then
112132
threads.show()
@@ -115,12 +135,16 @@ dap.listeners.after.event_terminated[SUBSCRIPTION_ID] = function()
115135
winbar.redraw_controls()
116136
end
117137

138+
dap.listeners.after.disconnect[SUBSCRIPTION_ID] = function()
139+
state.current_session_id = nil
140+
141+
winbar.redraw_controls()
142+
end
143+
118144
--- Refresh winbar on dap session state change events not having a dedicated event handler
119145
local events = {
120146
"continue",
121-
"disconnect",
122147
"event_exited",
123-
"event_stopped",
124148
"restart",
125149
"threads",
126150
}

lua/dap-view/options/winbar.lua

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ local state = require("dap-view.state")
22
local setup = require("dap-view.setup")
33
local controls = require("dap-view.options.controls")
44
local statusline = require("dap-view.util.statusline")
5+
local util = require("dap-view.util")
56
local module = ...
67

78
local M = {}
@@ -69,21 +70,29 @@ local winbar_info = {
6970
keymap = "C",
7071
action = function()
7172
if vim.tbl_contains(setup.config.winbar.sections, "console") then
72-
if not state.winnr or not api.nvim_win_is_valid(state.winnr) then
73+
if not util.is_win_valid(state.winnr) then
7374
return
7475
end
7576

76-
if not state.term_bufnr then
77-
require("dap-view.term.init").setup_term_win_cmd()
77+
local term_bufnr = state.term_bufnrs[state.current_session_id]
78+
79+
if not term_bufnr then
80+
term_bufnr = require("dap-view.term.init").setup_term_win_cmd()
81+
end
82+
83+
if not util.is_buf_valid(term_bufnr) then
84+
vim.notify("Something went wrong when setting up the terminal buffer")
85+
return
7886
end
7987

8088
api.nvim_win_call(state.winnr, function()
81-
api.nvim_set_current_buf(state.term_bufnr)
89+
api.nvim_set_current_buf(term_bufnr)
8290
end)
8391

84-
require("dap-view.term.options").set_options(state.winnr, state.term_bufnr)
92+
require("dap-view.term.options").set_options(state.winnr, term_bufnr)
93+
94+
M.set_winbar_action_keymaps(term_bufnr)
8595

86-
M.set_winbar_action_keymaps(state.term_bufnr)
8796
M.update_section("console")
8897
end
8998
end,

lua/dap-view/state.lua

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@
2525
---@class dapview.State
2626
---@field bufnr? integer
2727
---@field winnr? integer
28-
---@field term_bufnr? integer
28+
---@field term_bufnrs {[number]: number}
29+
---@field fallback_term_bufnr? integer
2930
---@field term_winnr? integer
30-
---@field last_active_adapter? string
31+
---@field current_adapter? string
3132
---@field subtle_frames boolean
3233
---@field current_section? dapview.SectionType
34+
---@field current_session_id? number
3335
---@field exceptions_options dapview.ExceptionsOption[]
3436
---@field threads dapview.ThreadWithErr[]
3537
---@field threads_err? string
@@ -38,6 +40,7 @@
3840
---@field variables_by_line table<integer, {response: dap.Variable, reference: number}>
3941
---@field watched_expressions table<string, dapview.ExpressionPack>
4042
local M = {
43+
term_bufnrs = {},
4144
exceptions_options = {},
4245
threads = {},
4346
frames_by_line = {},

lua/dap-view/term/init.lua

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,37 @@
11
local dap = require("dap")
22

33
local state = require("dap-view.state")
4-
local autocmd = require("dap-view.options.autocmd")
54
local setup = require("dap-view.setup")
5+
local util = require("dap-view.util")
66

77
local M = {}
88

99
local api = vim.api
1010

1111
---Hide the term win, does not affect the term buffer
1212
M.hide_term_buf_win = function()
13-
if state.term_winnr and api.nvim_win_is_valid(state.term_winnr) then
13+
if util.is_win_valid(state.term_winnr) then
1414
api.nvim_win_hide(state.term_winnr)
1515
end
1616
end
1717

18-
M.force_delete_term_buf = function()
19-
if state.term_bufnr then
20-
api.nvim_buf_delete(state.term_bufnr, { force = true })
21-
end
22-
end
23-
2418
---Open the term buf in a new window if
2519
---I. A session is active
26-
---II. The term buf exists
20+
---II. There's term term buf
2721
---III. The adapter isn't configured to be hidden
2822
---IV. There's no term win or it is invalid
2923
---@return integer?
3024
M.open_term_buf_win = function()
3125
local windows_config = setup.config.windows
32-
local term_config = windows_config.terminal
33-
local should_term_be_hidden = vim.tbl_contains(term_config.hide, state.last_active_adapter)
26+
local term_config = setup.config.windows.terminal
27+
local should_term_be_hidden = vim.tbl_contains(term_config.hide, state.current_adapter)
3428

35-
if dap.session() and state.term_bufnr and not should_term_be_hidden then
29+
if not state.current_session_id then
30+
return nil
31+
end
32+
local term_bufnr = state.term_bufnrs[state.current_session_id]
33+
34+
if term_bufnr and not should_term_be_hidden then
3635
if not state.term_winnr or state.term_winnr and not api.nvim_win_is_valid(state.term_winnr) then
3736
local is_win_valid = state.winnr ~= nil and api.nvim_win_is_valid(state.winnr)
3837

@@ -45,36 +44,41 @@ M.open_term_buf_win = function()
4544
or term_config.width,
4645
})
4746

48-
require("dap-view.term.options").set_options(state.term_winnr, state.term_bufnr)
47+
require("dap-view.term.options").set_options(state.term_winnr, term_bufnr)
4948
end
5049
end
5150

5251
return state.term_winnr
5352
end
5453

55-
local quit_term_buf = function()
56-
if state.term_bufnr then
57-
state.term_bufnr = nil
54+
---Create the term buf and setup nvim-dap's
55+
M.setup_term_win_cmd = function()
56+
-- Can't use an unlisted term buffers
57+
-- See https://github.com/igorlfs/nvim-dap-view/pull/37#issuecomment-2785076872
58+
--
59+
60+
local session = dap.session()
61+
if session then
62+
state.current_session_id = session.id
5863
end
59-
end
6064

61-
---Create the term buf and setup nvim-dap's `terminal_win_cmd` to use it
62-
M.setup_term_win_cmd = function()
63-
if not state.term_bufnr then
64-
-- Can't use an unlisted buffer here
65-
-- See https://github.com/igorlfs/nvim-dap-view/pull/37#issuecomment-2785076872
66-
state.term_bufnr = api.nvim_create_buf(true, false)
65+
if not state.current_session_id and not state.fallback_term_bufnr then
66+
state.fallback_term_bufnr = api.nvim_create_buf(true, false)
67+
68+
return state.fallback_term_bufnr
69+
end
6770

68-
assert(state.term_bufnr ~= 0, "Failed to create nvim-dap-view buffer")
71+
local term_bufnr = state.term_bufnrs[state.current_session_id]
6972

70-
autocmd.quit_buf_autocmd(state.term_bufnr, quit_term_buf)
73+
vim.print(term_bufnr)
7174

72-
dap.defaults.fallback.terminal_win_cmd = function()
73-
assert(state.term_bufnr, "Failed to get term bufnr")
75+
if not term_bufnr then
76+
term_bufnr = api.nvim_create_buf(true, false)
7477

75-
return state.term_bufnr
76-
end
78+
state.term_bufnrs[state.current_session_id] = term_bufnr
7779
end
80+
81+
return term_bufnr
7882
end
7983

8084
return M

lua/dap-view/util/init.lua

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
local M = {}
22

3+
local api = vim.api
4+
35
M.inverted_directions = {
46
["above"] = "below",
57
["below"] = "above",
68
["right"] = "left",
79
["left"] = "right",
810
}
911

12+
---@param bufnr integer
13+
M.is_buf_valid = function(bufnr)
14+
return bufnr and api.nvim_buf_is_valid(bufnr)
15+
end
16+
17+
---@param winnr integer
18+
M.is_win_valid = function(winnr)
19+
return winnr and api.nvim_win_is_valid(winnr)
20+
end
21+
1022
return M

0 commit comments

Comments
 (0)