feat(debugger): golang adapter for dap
This commit is contained in:
272
lua/dap-go/init.lua
Normal file
272
lua/dap-go/init.lua
Normal file
@@ -0,0 +1,272 @@
|
||||
local ts = require("dap-go.ts")
|
||||
|
||||
local M = {
|
||||
last_testname = "",
|
||||
last_testpath = "",
|
||||
test_buildflags = "",
|
||||
test_verbose = false,
|
||||
}
|
||||
|
||||
local default_config = {
|
||||
delve = {
|
||||
path = "dlv",
|
||||
initialize_timeout_sec = 20,
|
||||
port = "${port}",
|
||||
args = {},
|
||||
build_flags = "",
|
||||
-- Automatically handle the issue on delve Windows versions < 1.24.0
|
||||
-- where delve needs to be run in attched mode or it will fail (actually crashes).
|
||||
detached = vim.fn.has("win32") == 0,
|
||||
output_mode = "remote",
|
||||
},
|
||||
tests = {
|
||||
verbose = false,
|
||||
},
|
||||
}
|
||||
|
||||
local internal_global_config = {}
|
||||
|
||||
local function load_module(module_name)
|
||||
local ok, module = pcall(require, module_name)
|
||||
assert(ok, string.format("dap-go dependency error: %s not installed", module_name))
|
||||
return module
|
||||
end
|
||||
|
||||
local function get_arguments()
|
||||
return coroutine.create(function(dap_run_co)
|
||||
local args = {}
|
||||
vim.ui.input({ prompt = "Args: " }, function(input)
|
||||
args = vim.split(input or "", " ")
|
||||
coroutine.resume(dap_run_co, args)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
local function get_build_flags(config)
|
||||
return coroutine.create(function(dap_run_co)
|
||||
local build_flags = config.build_flags
|
||||
vim.ui.input({ prompt = "Build Flags: " }, function(input)
|
||||
build_flags = vim.split(input or "", " ")
|
||||
coroutine.resume(dap_run_co, build_flags)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
local function filtered_pick_process()
|
||||
local opts = {}
|
||||
vim.ui.input(
|
||||
{ prompt = "Search by process name (lua pattern), or hit enter to select from the process list: " },
|
||||
function(input)
|
||||
opts["filter"] = input or ""
|
||||
end
|
||||
)
|
||||
return require("dap.utils").pick_process(opts)
|
||||
end
|
||||
|
||||
local function setup_delve_adapter(dap, config)
|
||||
local args = { "dap", "-l", "127.0.0.1:" .. config.delve.port }
|
||||
vim.list_extend(args, config.delve.args)
|
||||
|
||||
local delve_config = {
|
||||
type = "server",
|
||||
port = config.delve.port,
|
||||
executable = {
|
||||
command = config.delve.path,
|
||||
args = args,
|
||||
detached = config.delve.detached,
|
||||
cwd = config.delve.cwd,
|
||||
},
|
||||
options = {
|
||||
initialize_timeout_sec = config.delve.initialize_timeout_sec,
|
||||
},
|
||||
}
|
||||
|
||||
dap.adapters.go = function(callback, client_config)
|
||||
if client_config.port == nil then
|
||||
callback(delve_config)
|
||||
return
|
||||
end
|
||||
|
||||
local host = client_config.host
|
||||
if host == nil then
|
||||
host = "127.0.0.1"
|
||||
end
|
||||
|
||||
local listener_addr = host .. ":" .. client_config.port
|
||||
delve_config.port = client_config.port
|
||||
delve_config.executable.args = { "dap", "-l", listener_addr }
|
||||
|
||||
callback(delve_config)
|
||||
end
|
||||
end
|
||||
|
||||
local function setup_go_configuration(dap, configs)
|
||||
local common_debug_configs = {
|
||||
{
|
||||
type = "go",
|
||||
name = "Debug",
|
||||
request = "launch",
|
||||
program = "${file}",
|
||||
buildFlags = configs.delve.build_flags,
|
||||
outputMode = configs.delve.output_mode,
|
||||
},
|
||||
{
|
||||
type = "go",
|
||||
name = "Debug (Arguments)",
|
||||
request = "launch",
|
||||
program = "${file}",
|
||||
args = get_arguments,
|
||||
buildFlags = configs.delve.build_flags,
|
||||
outputMode = configs.delve.output_mode,
|
||||
},
|
||||
{
|
||||
type = "go",
|
||||
name = "Debug (Arguments & Build Flags)",
|
||||
request = "launch",
|
||||
program = "${file}",
|
||||
args = get_arguments,
|
||||
buildFlags = get_build_flags,
|
||||
outputMode = configs.delve.output_mode,
|
||||
},
|
||||
{
|
||||
type = "go",
|
||||
name = "Debug Package",
|
||||
request = "launch",
|
||||
program = "${fileDirname}",
|
||||
buildFlags = configs.delve.build_flags,
|
||||
outputMode = configs.delve.output_mode,
|
||||
},
|
||||
{
|
||||
type = "go",
|
||||
name = "Attach",
|
||||
mode = "local",
|
||||
request = "attach",
|
||||
processId = filtered_pick_process,
|
||||
buildFlags = configs.delve.build_flags,
|
||||
},
|
||||
{
|
||||
type = "go",
|
||||
name = "Debug test",
|
||||
request = "launch",
|
||||
mode = "test",
|
||||
program = "${file}",
|
||||
buildFlags = configs.delve.build_flags,
|
||||
outputMode = configs.delve.output_mode,
|
||||
},
|
||||
{
|
||||
type = "go",
|
||||
name = "Debug test (go.mod)",
|
||||
request = "launch",
|
||||
mode = "test",
|
||||
program = "./${relativeFileDirname}",
|
||||
buildFlags = configs.delve.build_flags,
|
||||
outputMode = configs.delve.output_mode,
|
||||
},
|
||||
}
|
||||
|
||||
if dap.configurations.go == nil then
|
||||
dap.configurations.go = {}
|
||||
end
|
||||
|
||||
for _, config in ipairs(common_debug_configs) do
|
||||
table.insert(dap.configurations.go, config)
|
||||
end
|
||||
|
||||
if configs == nil or configs.dap_configurations == nil then
|
||||
return
|
||||
end
|
||||
|
||||
for _, config in ipairs(configs.dap_configurations) do
|
||||
if config.type == "go" then
|
||||
table.insert(dap.configurations.go, config)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup(opts)
|
||||
internal_global_config = vim.tbl_deep_extend("force", default_config, opts or {})
|
||||
M.test_buildflags = internal_global_config.delve.build_flags
|
||||
M.test_verbose = internal_global_config.tests.verbose
|
||||
|
||||
local dap = load_module("dap")
|
||||
setup_delve_adapter(dap, internal_global_config)
|
||||
setup_go_configuration(dap, internal_global_config)
|
||||
end
|
||||
|
||||
local function debug_test(testname, testpath, build_flags, extra_args, custom_config)
|
||||
local dap = load_module("dap")
|
||||
|
||||
local config = {
|
||||
type = "go",
|
||||
name = testname,
|
||||
request = "launch",
|
||||
mode = "test",
|
||||
program = testpath,
|
||||
args = { "-test.run", "^" .. testname .. "$" },
|
||||
buildFlags = build_flags,
|
||||
outputMode = "remote",
|
||||
}
|
||||
config = vim.tbl_deep_extend("force", config, custom_config or {})
|
||||
|
||||
if not vim.tbl_isempty(extra_args) then
|
||||
table.move(extra_args, 1, #extra_args, #config.args + 1, config.args)
|
||||
end
|
||||
|
||||
dap.run(config)
|
||||
end
|
||||
|
||||
function M.debug_test(custom_config)
|
||||
local test = ts.closest_test()
|
||||
|
||||
if test.name == "" or test.name == nil then
|
||||
vim.notify("no test found")
|
||||
return false
|
||||
end
|
||||
|
||||
M.last_testname = test.name
|
||||
M.last_testpath = test.package
|
||||
|
||||
local msg = string.format("starting debug session '%s : %s'...", test.package, test.name)
|
||||
vim.notify(msg)
|
||||
|
||||
local extra_args = {}
|
||||
if M.test_verbose then
|
||||
extra_args = { "-test.v" }
|
||||
end
|
||||
|
||||
debug_test(test.name, test.package, M.test_buildflags, extra_args, custom_config)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function M.debug_last_test()
|
||||
local testname = M.last_testname
|
||||
local testpath = M.last_testpath
|
||||
|
||||
if testname == "" then
|
||||
vim.notify("no last run test found")
|
||||
return false
|
||||
end
|
||||
|
||||
local msg = string.format("starting debug session '%s : %s'...", testpath, testname)
|
||||
vim.notify(msg)
|
||||
|
||||
local extra_args = {}
|
||||
if M.test_verbose then
|
||||
extra_args = { "-test.v" }
|
||||
end
|
||||
|
||||
debug_test(testname, testpath, M.test_buildflags, extra_args)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function M.get_build_flags()
|
||||
return get_build_flags(internal_global_config)
|
||||
end
|
||||
|
||||
function M.get_arguments()
|
||||
return get_arguments()
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user