diff --git a/lua/tiny-debugger/adapters/c.lua b/lua/tiny-debugger/adapters/c.lua new file mode 100644 index 0000000..a564707 --- /dev/null +++ b/lua/tiny-debugger/adapters/c.lua @@ -0,0 +1 @@ +return {} diff --git a/lua/tiny-debugger/adapters/cs.lua b/lua/tiny-debugger/adapters/cs.lua new file mode 100644 index 0000000..a564707 --- /dev/null +++ b/lua/tiny-debugger/adapters/cs.lua @@ -0,0 +1 @@ +return {} diff --git a/lua/tiny-debugger/adapters/go.lua b/lua/tiny-debugger/adapters/go.lua new file mode 100644 index 0000000..1bae3f1 --- /dev/null +++ b/lua/tiny-debugger/adapters/go.lua @@ -0,0 +1,32 @@ +local loader = require("tiny-debugger.adapters.init") + +local M = {} + +function M.register(dap) + local dlv = loader.find_executable({ "dlv" }) + if not dlv then return end + + loader.register(dap, "delve", { + type = "server", + port = "${port}", + executable = { + command = dlv, + args = { "dap", "-l", "127.0.0.1:${port}" }, + }, + }, { + { + type = "delve", + request = "launch", + name = "Launch file", + program = "${file}", + }, + { + type = "delve", + request = "launch", + name = "Launch package", + program = "./${relativeFileDirname}", + }, + }, { "go" }) +end + +return M diff --git a/lua/tiny-debugger/adapters/init.lua b/lua/tiny-debugger/adapters/init.lua new file mode 100644 index 0000000..e49f81b --- /dev/null +++ b/lua/tiny-debugger/adapters/init.lua @@ -0,0 +1,63 @@ +local config = require("tiny-debugger.config") + +local M = {} + +local mason_bin = vim.fn.stdpath("data") .. "/mason/bin/" + +function M.find_executable(names) + for _, name in ipairs(names) do + -- check PATH + if vim.fn.executable(name) == 1 then + return name + end + -- check mason + local mason_path = mason_bin .. name + if vim.fn.executable(mason_path) == 1 then + return mason_path + end + end + return nil +end + +function M.register(dap, name, adapter, configurations, filetypes) + -- don't override user-configured adapters + if dap.adapters[name] then return end + + dap.adapters[name] = adapter + + for _, ft in ipairs(filetypes) do + if not dap.configurations[ft] then + dap.configurations[ft] = configurations + end + end +end + +function M.setup() + if not config.opts.builtin_adapters then return end + + local dap = require("dap") + + -- load built-in adapter modules + local adapters = { + "python", "go", "c", "javascript", "cs", "java", "kotlin", "php", "ruby", "lua", + } + + for _, name in ipairs(adapters) do + local ok, adapter_mod = pcall(require, "tiny-debugger.adapters." .. name) + if ok and adapter_mod.register then + adapter_mod.register(dap) + end + end + + -- apply user adapter overrides + for name, adapter_config in pairs(config.opts.adapters) do + if adapter_config.adapter then + dap.adapters[name] = adapter_config.adapter + end + if adapter_config.configurations then + dap.configurations[name] = adapter_config.configurations + end + end +end + +return M diff --git a/lua/tiny-debugger/adapters/java.lua b/lua/tiny-debugger/adapters/java.lua new file mode 100644 index 0000000..a564707 --- /dev/null +++ b/lua/tiny-debugger/adapters/java.lua @@ -0,0 +1 @@ +return {} diff --git a/lua/tiny-debugger/adapters/javascript.lua b/lua/tiny-debugger/adapters/javascript.lua new file mode 100644 index 0000000..a564707 --- /dev/null +++ b/lua/tiny-debugger/adapters/javascript.lua @@ -0,0 +1 @@ +return {} diff --git a/lua/tiny-debugger/adapters/kotlin.lua b/lua/tiny-debugger/adapters/kotlin.lua new file mode 100644 index 0000000..a564707 --- /dev/null +++ b/lua/tiny-debugger/adapters/kotlin.lua @@ -0,0 +1 @@ +return {} diff --git a/lua/tiny-debugger/adapters/lua.lua b/lua/tiny-debugger/adapters/lua.lua new file mode 100644 index 0000000..a564707 --- /dev/null +++ b/lua/tiny-debugger/adapters/lua.lua @@ -0,0 +1 @@ +return {} diff --git a/lua/tiny-debugger/adapters/php.lua b/lua/tiny-debugger/adapters/php.lua new file mode 100644 index 0000000..a564707 --- /dev/null +++ b/lua/tiny-debugger/adapters/php.lua @@ -0,0 +1 @@ +return {} diff --git a/lua/tiny-debugger/adapters/python.lua b/lua/tiny-debugger/adapters/python.lua new file mode 100644 index 0000000..e407535 --- /dev/null +++ b/lua/tiny-debugger/adapters/python.lua @@ -0,0 +1,52 @@ +local loader = require("tiny-debugger.adapters.init") + +local M = {} + +local function find_python() + -- check active virtualenv + local venv = vim.env.VIRTUAL_ENV + if venv then + local path = venv .. "/bin/python" + if vim.fn.executable(path) == 1 then return path end + end + + -- check conda + local conda = vim.env.CONDA_PREFIX + if conda then + local path = conda .. "/bin/python" + if vim.fn.executable(path) == 1 then return path end + end + + -- probe common venv directories relative to cwd + local cwd = vim.fn.getcwd() + for _, dir in ipairs({ ".venv", "venv", "env", ".env" }) do + local path = cwd .. "/" .. dir .. "/bin/python" + if vim.fn.executable(path) == 1 then return path end + end + + -- fallback to system python + if vim.fn.executable("python3") == 1 then return "python3" end + if vim.fn.executable("python") == 1 then return "python" end + return nil +end + +function M.register(dap) + local python = find_python() + if not python then return end + + loader.register(dap, "debugpy", { + type = "executable", + command = python, + args = { "-m", "debugpy.adapter" }, + }, { + { + type = "debugpy", + request = "launch", + name = "Launch file", + program = "${file}", + pythonPath = function() return find_python() end, + }, + }, { "python" }) +end + +return M diff --git a/lua/tiny-debugger/adapters/ruby.lua b/lua/tiny-debugger/adapters/ruby.lua new file mode 100644 index 0000000..a564707 --- /dev/null +++ b/lua/tiny-debugger/adapters/ruby.lua @@ -0,0 +1 @@ +return {} diff --git a/lua/tiny-debugger/init.lua b/lua/tiny-debugger/init.lua index 120c02f..d7b32dc 100644 --- a/lua/tiny-debugger/init.lua +++ b/lua/tiny-debugger/init.lua @@ -1,12 +1,14 @@ local config = require("tiny-debugger.config") local mode = require("tiny-debugger.mode") local breakpoints = require("tiny-debugger.breakpoints") +local adapters = require("tiny-debugger.adapters") local M = {} function M.setup(opts) config.merge(opts) breakpoints.setup() + adapters.setup() end function M.toggle() diff --git a/tests/test_adapters.lua b/tests/test_adapters.lua new file mode 100644 index 0000000..3ef39a6 --- /dev/null +++ b/tests/test_adapters.lua @@ -0,0 +1,42 @@ +-- tests for adapter loader and path resolution +local loader = require("tiny-debugger.adapters.init") + +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: find_executable returns nil for non-existent binaries +assert_eq(loader.find_executable({ "totally-fake-binary-xyz" }), nil, "non-existent binary returns nil") + +-- test 2: find_executable finds common system binaries +local found = loader.find_executable({ "sh" }) +assert_eq(found ~= nil, true, "find_executable finds sh") + +-- test 3: python adapter module loads and has register function +local py = require("tiny-debugger.adapters.python") +assert_eq(type(py.register), "function", "python adapter has register()") + +-- test 4: go adapter module loads and has register function +local go = require("tiny-debugger.adapters.go") +assert_eq(type(go.register), "function", "go adapter has register()") + +-- test 5: register doesn't override existing adapter +local dap = require("dap") +dap.adapters.test_adapter = { type = "executable", command = "test" } +loader.register(dap, "test_adapter", { type = "executable", command = "new" }, {}, {}) +assert_eq(dap.adapters.test_adapter.command, "test", "register doesn't override existing") +dap.adapters.test_adapter = nil + +-- test 6: register sets adapter and configs for new adapter +loader.register(dap, "test_new", { type = "executable", command = "test" }, { + { type = "test_new", request = "launch", name = "test" }, +}, { "testlang" }) +assert_eq(dap.adapters.test_new.command, "test", "new adapter registered") +assert_eq(#dap.configurations.testlang, 1, "configs registered for filetype") +-- cleanup +dap.adapters.test_new = nil +dap.configurations.testlang = nil + +print("ALL ADAPTER TESTS PASSED")