go.nvim/lua/go/dap.lua

466 lines
12 KiB
Lua
Raw Normal View History

local bind = require("go.keybind")
local map_cr = bind.map_cr
2021-12-16 22:02:29 +00:00
local utils = require("go.utils")
local log = utils.log
2021-12-16 22:02:29 +00:00
local sep = "." .. utils.sep()
local getopt = require("go.alt_getopt")
local long_opts = {
compile = "c",
run = "r",
attach = "a",
test = "t",
restart = "R",
stop = "s",
help = "h",
nearest = "n",
package = "p",
file = "f",
breakpoint = "b",
tag = "T",
}
local opts = "tcraRsnpfsbhT:"
local function help()
return "Usage: GoDebug [OPTION]\n"
.. "Options:\n"
.. " -c, --compile compile and run\n"
.. " -r, --run run\n"
.. " -t, --test run tests\n"
.. " -R, --restart restart\n"
.. " -s, --stop stop\n"
.. " -h, --help display this help and exit\n"
.. " -n, --nearest debug nearest file\n"
.. " -p, --package debug package\n"
.. " -f, --file display file\n"
.. " -b, --breakpoint set breakpoint\n"
.. " -T, --tag set tag"
end
2021-11-10 02:20:54 +00:00
local function setup_telescope()
2021-12-16 22:02:29 +00:00
require("telescope").setup()
require("telescope").load_extension("dap")
local ts_keys = {
2021-10-26 00:15:52 +00:00
["n|lb"] = map_cr('<cmd>lua require"telescope".extensions.dap.list_breakpoints{}'):with_noremap():with_silent(),
["n|tv"] = map_cr('<cmd>lua require"telescope".extensions.dap.variables{}'):with_noremap():with_silent(),
2021-12-16 22:02:29 +00:00
["n|bt"] = map_cr('<cmd>lua require"telescope".extensions.dap.frames{}'):with_noremap():with_silent(),
}
bind.nvim_load_mapping(ts_keys)
end
local function keybind()
2021-12-16 22:02:29 +00:00
if not _GO_NVIM_CFG.dap_debug_keymap then
return
end
local keys = {
-- DAP --
-- run
["n|r"] = map_cr('<cmd>lua require"go.dap".run()<CR>'):with_noremap():with_silent(),
["n|c"] = map_cr('<cmd>lua require"dap".continue()<CR>'):with_noremap():with_silent(),
["n|n"] = map_cr('<cmd>lua require"dap".step_over()<CR>'):with_noremap():with_silent(),
["n|s"] = map_cr('<cmd>lua require"dap".step_into()<CR>'):with_noremap():with_silent(),
["n|o"] = map_cr('<cmd>lua require"dap".step_out()<CR>'):with_noremap():with_silent(),
["n|S"] = map_cr('<cmd>lua require"go.dap".stop()<CR>'):with_noremap():with_silent(),
["n|u"] = map_cr('<cmd>lua require"dap".up()<CR>'):with_noremap():with_silent(),
["n|D"] = map_cr('<cmd>lua require"dap".down()<CR>'):with_noremap():with_silent(),
["n|C"] = map_cr('<cmd>lua require"dap".run_to_cursor()<CR>'):with_noremap():with_silent(),
["n|b"] = map_cr('<cmd>lua require"dap".toggle_breakpoint()<CR>'):with_noremap():with_silent(),
2021-12-16 22:02:29 +00:00
["n|P"] = map_cr('<cmd>lua require"dap".pause()<CR>'):with_noremap():with_silent(),
--
}
2021-11-23 23:13:40 +00:00
if _GO_NVIM_CFG.dap_debug_gui then
keys["n|p"] = map_cr('<cmd>lua require("dapui").eval()'):with_noremap():with_silent()
keys["v|p"] = map_cr('<cmd>lua require("dapui").eval()'):with_noremap():with_silent()
keys["n|K"] = map_cr('<cmd>lua require("dapui").float_element()'):with_noremap():with_silent()
keys["n|B"] = map_cr('<cmd>lua require("dapui").float_element("breakpoints")'):with_noremap():with_silent()
keys["n|R"] = map_cr('<cmd>lua require("dapui").float_element("repl")'):with_noremap():with_silent()
keys["n|O"] = map_cr('<cmd>lua require("dapui").float_element("scopes")'):with_noremap():with_silent()
keys["n|a"] = map_cr('<cmd>lua require("dapui").float_element("stacks")'):with_noremap():with_silent()
keys["n|w"] = map_cr('<cmd>lua require("dapui").float_element("watches")'):with_noremap():with_silent()
else
keys["n|p"] = map_cr('<cmd>lua require"dap.ui.widgets".hover()<CR>'):with_noremap():with_silent()
keys["v|p"] = map_cr('<cmd>lua require"dap.ui.widgets".hover()<CR>'):with_noremap():with_silent()
end
bind.nvim_load_mapping(keys)
end
local function get_build_flags()
if _GO_NVIM_CFG.build_tags ~= "" then
return "-tags " .. _GO_NVIM_CFG.build_tags
else
return ""
end
end
local M = {}
M.prepare = function()
2021-12-16 22:02:29 +00:00
utils.load_plugin("nvim-dap", "dap")
if _GO_NVIM_CFG.icons ~= false then
vim.fn.sign_define("DapBreakpoint", {
text = _GO_NVIM_CFG.icons.breakpoint,
texthl = "",
linehl = "",
numhl = "",
})
vim.fn.sign_define("DapStopped", {
text = _GO_NVIM_CFG.icons.currentpos,
texthl = "",
linehl = "",
numhl = "",
})
end
if _GO_NVIM_CFG.dap_debug_gui then
2021-12-16 22:02:29 +00:00
utils.load_plugin("nvim-dap-ui", "dapui")
end
if _GO_NVIM_CFG.dap_debug_vt then
local vt = utils.load_plugin("nvim-dap-virtual-text")
vt.setup({ enabled_commands = true, all_frames = true })
end
end
M.breakpt = function()
M.prepare()
2021-12-16 22:02:29 +00:00
require("dap").toggle_breakpoint()
end
2022-04-20 02:00:49 +00:00
local stdout, stderr, handle
M.run = function(...)
2021-12-16 22:02:29 +00:00
local args = { ... }
local mode = select(1, ...)
if mode == "test" or mode == "nearest" then
utils.warn("option test is deprecated, options are " .. opts .. " ")
return utils.info(help())
end
local optarg, optind = getopt.get_opts(args, opts, long_opts)
log(optarg, optind)
if optarg["h"] then
return utils.info(help())
end
if optarg["c"] then
local fpath = vim.fn.expand("%:p:h")
local out = vim.fn.systemlist(table.concat({
"go",
"test",
"-v",
"-cover",
"-covermode=atomic",
"-coverprofile=cover.out",
"-tags " .. _GO_NVIM_CFG.build_tags,
"-c",
fpath,
}, " "))
if #out ~= 0 then
utils.info("building " .. vim.inspect(out))
end
return
end
2022-01-16 23:31:24 +00:00
local guihua = utils.load_plugin("guihua.lua", "guihua.gui")
local original_select = vim.ui.select
if guihua then
vim.ui.select = require("guihua.gui").select
end
-- testopts = {"test", "nearest", "file", "stop", "restart"}
log("plugin loaded", mode, optarg)
if optarg["s"] and (optarg["t"] or optarg["r"]) then
M.stop(false)
elseif optarg["s"] then
return M.stop(true)
2021-11-24 09:05:02 +00:00
end
-- restart
if optarg["R"] then
2021-12-16 22:02:29 +00:00
require("go.dap").stop()
if optarg["t"] then
mode = "test"
else
mode = M.pre_mode or "file"
end
else
M.pre_mode = mode
end
M.prepare()
local session = require("dap").session()
if session ~= nil and session.initialized == true then
vim.notify("debug session already start, press c to continue", vim.lsp.log_levels.INFO)
return
end
local run_cur = optarg["r"]
if not run_cur then
keybind()
else
M.stop()
end
if _GO_NVIM_CFG.dap_debug_gui and not run_cur then
require("dapui").setup()
if not require("dapui.windows").sidebar:is_open() then
require("dapui").open()
end
end
2022-01-26 11:51:00 +00:00
local port = _GO_NVIM_CFG.dap_port
2022-01-30 05:02:18 +00:00
if _GO_NVIM_CFG.dap_port == nil or _GO_NVIM_CFG.dap_port == -1 then
2022-01-26 11:51:00 +00:00
math.randomseed(os.time())
port = 38000 + math.random(1, 1000)
end
2021-12-16 22:02:29 +00:00
local dap = require("dap")
dap.adapters.go = function(callback, config)
2022-04-20 02:00:49 +00:00
stdout = vim.loop.new_pipe(false)
stderr = vim.loop.new_pipe(false)
local pid_or_err
port = config.port or port
2022-01-26 11:51:00 +00:00
local host = config.host or "127.0.0.1"
local addr = string.format("%s:%d", host, port)
2022-04-20 02:00:49 +00:00
local function onread(err, data)
if err then
-- print('ERROR: ', err)
vim.notify("dlv exited with code " + tostring(err), vim.lsp.log_levels.WARN)
end
if not data or data == "" then
return
end
log(data)
if data:find("couldn't start") then
utils.error(data)
end
vim.schedule(function()
require("dap.repl").append(data)
end)
end
handle, pid_or_err = vim.loop.spawn("dlv", {
2022-04-20 02:00:49 +00:00
stdio = { nil, stdout, stderr },
2022-01-26 11:51:00 +00:00
args = { "dap", "-l", addr },
2021-12-16 22:02:29 +00:00
detached = true,
}, function(code)
2021-08-25 12:37:22 +00:00
if code ~= 0 then
2022-01-12 08:57:07 +00:00
vim.schedule(function()
log("Dlv exited", code)
2022-01-12 08:57:07 +00:00
vim.notify(string.format("Delve exited with exit code: %d", code), vim.lsp.log_levels.WARN)
if _GO_NVIM_CFG.dap_port ~= nil then
_GO_NVIM_CFG.dap_port = _GO_NVIM_CFG.dap_port + 1
end
2022-01-12 08:57:07 +00:00
end)
2021-08-25 12:37:22 +00:00
end
stdout:close()
2022-04-20 02:00:49 +00:00
stderr:close()
handle:close()
2022-04-20 02:00:49 +00:00
stdout = nil
stderr = nil
handle = nil
2021-08-25 12:37:22 +00:00
end)
assert(handle, "Error running dlv: " .. tostring(pid_or_err))
2022-04-20 02:00:49 +00:00
stdout:read_start(onread)
stderr:read_start(onread)
if not optarg["r"] then
dap.repl.open()
end
vim.defer_fn(function()
2022-01-26 11:51:00 +00:00
callback({ type = "server", host = host, port = port })
2022-01-12 08:57:07 +00:00
end, 500)
end
local dap_cfg = {
type = "go",
name = "Debug",
request = "launch",
dlvToolPath = vim.fn.exepath("dlv"),
2021-12-16 22:02:29 +00:00
buildFlags = get_build_flags(),
}
2021-08-31 11:19:14 +00:00
local row, col = unpack(vim.api.nvim_win_get_cursor(0))
row, col = row, col + 1
local empty = utils.empty
2021-08-31 11:19:14 +00:00
local ns = require("go.ts.go").get_func_method_node_at_pos(row, col)
if empty(ns) then
2021-12-16 22:02:29 +00:00
log("ts not not found, debug while file")
2021-08-31 11:19:14 +00:00
end
local launch = require("go.launch")
local cfg_exist, cfg_file = launch.vs_launch()
log(mode, cfg_exist, cfg_file)
-- if breakpoint is not set add breakpoint at current pos
local pts = require("dap.breakpoints").get()
if #pts == 0 then
require("dap").toggle_breakpoint()
end
if optarg["t"] then
2021-12-16 22:02:29 +00:00
dap_cfg.name = dap_cfg.name .. " test"
dap_cfg.mode = "test"
dap_cfg.request = "launch"
-- dap_cfg.program = "${workspaceFolder}"
-- dap_cfg.program = "${file}"
2021-11-10 02:20:54 +00:00
dap_cfg.program = sep .. "${relativeFileDirname}"
2021-12-16 22:02:29 +00:00
dap.configurations.go = { dap_cfg }
log(dap_cfg)
dap.continue()
elseif optarg["n"] then
2021-12-16 22:02:29 +00:00
dap_cfg.name = dap_cfg.name .. " test_nearest"
2021-08-31 11:19:14 +00:00
dap_cfg.mode = "test"
dap_cfg.request = "launch"
2021-11-10 02:20:54 +00:00
dap_cfg.program = sep .. "${relativeFileDirname}"
2021-12-16 22:02:29 +00:00
dap_cfg.args = { "-test.run", "^" .. ns.name }
2021-08-31 11:19:14 +00:00
log(dap_cfg)
2021-12-16 22:02:29 +00:00
dap.configurations.go = { dap_cfg }
2021-08-31 11:19:14 +00:00
dap.continue()
elseif optarg["a"] then
dap_cfg.name = dap_cfg.name .. " attach"
dap_cfg.mode = "local"
dap_cfg.request = "attach"
dap_cfg.processId = require("dap.utils").pick_process
log(dap_cfg)
dap.configurations.go = { dap_cfg }
dap.continue()
elseif optarg["p"] then
dap_cfg.name = dap_cfg.name .. " package"
dap_cfg.request = "launch"
dap_cfg.program = sep .. "${fileDirname}"
log(dap_cfg)
dap.configurations.go = { dap_cfg }
dap.continue()
elseif run_cur then
dap_cfg.name = dap_cfg.name .. " run current"
-- dap_cfg.mode = "test"
dap_cfg.request = "launch"
dap_cfg.program = sep .. "${relativeFileDirname}"
log(dap_cfg)
dap.configurations.go = { dap_cfg }
dap.continue()
elseif cfg_exist then
log("using cfg")
launch.load()
2022-01-15 11:14:56 +00:00
for _, cfg in ipairs(dap.configurations.go) do
cfg.dlvToolPath = vim.fn.exepath("dlv")
end
dap.continue()
else
dap_cfg.program = sep .. "${relativeFileDirname}"
dap_cfg.args = args
dap_cfg.request = "launch"
2021-12-16 22:02:29 +00:00
dap.configurations.go = { dap_cfg }
dap.continue()
end
log(dap_cfg, args)
2022-01-16 23:31:24 +00:00
vim.ui.select = original_select
end
local unmap = function()
2021-12-16 22:02:29 +00:00
if not _GO_NVIM_CFG.dap_debug_keymap then
return
end
2021-11-23 23:13:40 +00:00
local keys = {
2021-12-16 22:02:29 +00:00
"r",
"c",
"n",
"s",
"o",
"S",
"u",
"D",
"C",
"b",
"P",
"p",
"K",
"B",
"R",
"O",
"a",
"w",
2021-11-23 23:13:40 +00:00
}
for _, value in pairs(keys) do
local cmd = "silent! unmap " .. value
vim.cmd(cmd)
end
vim.cmd([[silent! vunmap p]])
end
M.stop = function(unm)
if unm then
unmap()
end
2022-01-16 23:31:24 +00:00
local has_dap, dap = pcall(require, "dap")
if has_dap then
require("dap").disconnect()
require("dap").repl.close()
end
local has_dapui, dapui = pcall(require, "dapui")
if has_dapui then
if require("dapui.windows").sidebar ~= nil then
dapui.close()
end
end
2022-04-20 02:00:49 +00:00
if stdout then
stdout:close()
stdout = nil
end
if stderr then
stderr:close()
stderr = nil
end
if handle then
handle:close()
handle = nil
end
end
function M.ultest_post()
vim.g.ultest_use_pty = 1
local builders = {
["go#richgo"] = function(cmd)
local args = {}
for i = 3, #cmd, 1 do
local arg = cmd[i]
if vim.startswith(arg, "-") then
arg = "-test." .. string.sub(arg, 2)
end
args[#args + 1] = arg
end
return {
dap = {
type = "go",
request = "launch",
mode = "test",
2021-11-10 02:20:54 +00:00
program = sep .. "${relativeFileDirname}",
dlvToolPath = vim.fn.exepath("dlv"),
args = args,
2021-12-16 22:02:29 +00:00
buildFlags = get_build_flags(),
},
parse_result = function(lines)
return lines[#lines] == "FAIL" and 1 or 0
2021-12-16 22:02:29 +00:00
end,
}
2021-12-16 22:02:29 +00:00
end,
}
ul = utils.load_plugin("vim-ultest", "ultest")
if ul then
ul.setup({ builders = builders })
end
end
return M