help: floating help box with dynamic keybinding content
This commit is contained in:
3 files changed
+152
No files matched your search
@@ -0,0 +1,105 @@
|
|||||||
|
local config = require("tiny-debugger.config")
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
local win_id = nil
|
||||||
|
local buf_id = nil
|
||||||
|
|
||||||
|
local key_labels = {
|
||||||
|
continue = "Continue",
|
||||||
|
step_over = "Step over",
|
||||||
|
step_into = "Step into",
|
||||||
|
step_out = "Step out",
|
||||||
|
run_to_cursor = "Run to cursor",
|
||||||
|
breakpoint = "Toggle breakpoint",
|
||||||
|
cond_breakpoint = "Conditional breakpoint",
|
||||||
|
watch = "Watch expression",
|
||||||
|
hover = "Hover / inspect",
|
||||||
|
eval = "Eval in REPL",
|
||||||
|
terminate = "Quit debugging",
|
||||||
|
restart = "Restart session",
|
||||||
|
help = "Show this help",
|
||||||
|
}
|
||||||
|
|
||||||
|
-- ordered list of key names for consistent display
|
||||||
|
local key_order = {
|
||||||
|
"continue", "step_over", "step_into", "step_out", "run_to_cursor",
|
||||||
|
"breakpoint", "cond_breakpoint", "watch", "hover", "eval",
|
||||||
|
"terminate", "restart", "help",
|
||||||
|
}
|
||||||
|
|
||||||
|
local function build_lines()
|
||||||
|
local lines = { " tiny-debugger keybindings", "" }
|
||||||
|
local keys = config.opts.keys
|
||||||
|
for _, name in ipairs(key_order) do
|
||||||
|
local key = keys[name]
|
||||||
|
if key then
|
||||||
|
local label = key_labels[name] or name
|
||||||
|
table.insert(lines, string.format(" %s %s", key, label))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.insert(lines, "")
|
||||||
|
return lines
|
||||||
|
end
|
||||||
|
|
||||||
|
local function calc_width(lines)
|
||||||
|
local max = 0
|
||||||
|
for _, line in ipairs(lines) do
|
||||||
|
max = math.max(max, #line)
|
||||||
|
end
|
||||||
|
return max + 2
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.close()
|
||||||
|
if win_id and vim.api.nvim_win_is_valid(win_id) then
|
||||||
|
vim.api.nvim_win_close(win_id, true)
|
||||||
|
end
|
||||||
|
win_id = nil
|
||||||
|
if buf_id and vim.api.nvim_buf_is_valid(buf_id) then
|
||||||
|
vim.api.nvim_buf_delete(buf_id, { force = true })
|
||||||
|
end
|
||||||
|
buf_id = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.open()
|
||||||
|
M.close()
|
||||||
|
|
||||||
|
local lines = build_lines()
|
||||||
|
local width = calc_width(lines)
|
||||||
|
local height = #lines
|
||||||
|
|
||||||
|
buf_id = vim.api.nvim_create_buf(false, true)
|
||||||
|
vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)
|
||||||
|
vim.bo[buf_id].modifiable = false
|
||||||
|
vim.bo[buf_id].bufhidden = "wipe"
|
||||||
|
|
||||||
|
local editor_width = vim.o.columns
|
||||||
|
local editor_height = vim.o.lines
|
||||||
|
|
||||||
|
win_id = vim.api.nvim_open_win(buf_id, false, {
|
||||||
|
relative = "editor",
|
||||||
|
anchor = "SE",
|
||||||
|
row = editor_height - 2,
|
||||||
|
col = editor_width,
|
||||||
|
width = width,
|
||||||
|
height = height,
|
||||||
|
style = "minimal",
|
||||||
|
border = "rounded",
|
||||||
|
focusable = false,
|
||||||
|
noautocmd = true,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- auto-close on next keypress
|
||||||
|
vim.api.nvim_create_autocmd({ "CursorMoved", "InsertEnter", "CmdlineEnter" }, {
|
||||||
|
once = true,
|
||||||
|
callback = function()
|
||||||
|
M.close()
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.is_open()
|
||||||
|
return win_id ~= nil and vim.api.nvim_win_is_valid(win_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
local config = require("tiny-debugger.config")
|
local config = require("tiny-debugger.config")
|
||||||
|
local help = require("tiny-debugger.help")
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
@@ -55,6 +56,7 @@ local function setup_default_actions()
|
|||||||
M.exit()
|
M.exit()
|
||||||
end
|
end
|
||||||
actions.restart = function() dap.restart() end
|
actions.restart = function() dap.restart() end
|
||||||
|
actions.help = function() help.open() end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function set_keymaps(buf)
|
local function set_keymaps(buf)
|
||||||
@@ -103,6 +105,10 @@ function M.enter()
|
|||||||
local buf = vim.api.nvim_get_current_buf()
|
local buf = vim.api.nvim_get_current_buf()
|
||||||
set_keymaps(buf)
|
set_keymaps(buf)
|
||||||
set_cursor_highlight()
|
set_cursor_highlight()
|
||||||
|
|
||||||
|
if config.opts.help_on_enter then
|
||||||
|
help.open()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.exit()
|
function M.exit()
|
||||||
@@ -112,6 +118,7 @@ function M.exit()
|
|||||||
local buf = vim.api.nvim_get_current_buf()
|
local buf = vim.api.nvim_get_current_buf()
|
||||||
clear_keymaps(buf)
|
clear_keymaps(buf)
|
||||||
restore_cursor_highlight()
|
restore_cursor_highlight()
|
||||||
|
help.close()
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.toggle()
|
function M.toggle()
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
-- tests for help box
|
||||||
|
local help = require("tiny-debugger.help")
|
||||||
|
local config = require("tiny-debugger.config")
|
||||||
|
|
||||||
|
local function assert_eq(a, b, msg)
|
||||||
|
if a ~= b then
|
||||||
|
error(string.format("FAIL: %s — expected %s, got %s", msg, vim.inspect(b), vim.inspect(a)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- test 1: open creates a valid window
|
||||||
|
help.open()
|
||||||
|
assert_eq(help.is_open(), true, "help window is open")
|
||||||
|
|
||||||
|
-- test 2: close removes the window
|
||||||
|
help.close()
|
||||||
|
assert_eq(help.is_open(), false, "help window is closed")
|
||||||
|
|
||||||
|
-- test 3: remapped key shows in help content
|
||||||
|
config.merge({ keys = { continue = "g" } })
|
||||||
|
help.open()
|
||||||
|
-- read the buffer content
|
||||||
|
local wins = vim.api.nvim_list_wins()
|
||||||
|
local found_g = false
|
||||||
|
for _, w in ipairs(wins) do
|
||||||
|
local buf = vim.api.nvim_win_get_buf(w)
|
||||||
|
local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
|
||||||
|
for _, line in ipairs(lines) do
|
||||||
|
if line:find("g%s+Continue") then
|
||||||
|
found_g = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_eq(found_g, true, "remapped key 'g' appears in help")
|
||||||
|
help.close()
|
||||||
|
|
||||||
|
-- reset config
|
||||||
|
config.merge({})
|
||||||
|
|
||||||
|
print("ALL HELP TESTS PASSED")
|
||||||
Reference in new issue
Block a user