I’m setting up Neovim as an IDE for the first time and I got stuck trying to setup debugging in OCaml. I have general OCaml environment setup in the system, I can build and run projects. LSP and none-ls in Neovim are configured and working fine.
I created a new Hello World project with dune init proj hello
and added (modes byte exe)
to the dune file. Simple code I used for testing:
let s = "Hello, OCaml debug"
let () = print_endline s
I built it with dune build
, main.bc
is created as expected and it does print the line on dune exec hello
.
I set the breakpoint on any or both lines with <leader>b
, which causes B
markers to appear next to the line. Then I try to launch main.bc
in debugger with <F5>
and the B
breakpoint marker in Neovim window changes to R
. No DAP UI appears, just a quick screen glitch. In dap.log
it only says:
[ INFO ] 2024-08-13T00:52:39Z+0200 ] ...ster/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:911 ] "Breakpoint unverified" {
id = 1,
verified = false
}
[ INFO ] 2024-08-13T00:52:39Z+0200 ] ...ster/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:1447 ] "Process closed" 290638
Manual debugging outside of Neovim works fine. Not sure if and how can I test ocamlearlybird
itself.
❯ ocamldebug _build/default/bin/main.bc
OCaml Debugger version 5.2.0
(ocd) r
Loading program... done.
Hello, OCaml debug
Time: 32
Program exit.
(ocd)
I pretty much copied kickstart.nvim/lua/kickstart/plugins/debug.lua at master · nvim-lua/kickstart.nvim · GitHub and added setup for ocamlearlybird
as per nvim-dap documentation. My complete plugin configuration for debug is:
return {
"mfussenegger/nvim-dap",
dependencies = {
-- Creates a beautiful debugger UI
"rcarriga/nvim-dap-ui",
-- Required dependency for nvim-dap-ui
"nvim-neotest/nvim-nio",
-- Installs the debug adapters for you
-- 'williamboman/mason.nvim',
"jay-babu/mason-nvim-dap.nvim",
"hackwaly/ocamlearlybird",
},
keys = function(_, keys)
local dap = require("dap")
local dapui = require("dapui")
return {
-- Basic debugging keymaps, feel free to change to your liking!
{ "<F5>", dap.continue, desc = "Debug: Start/Continue" },
{ "<F1>", dap.step_into, desc = "Debug: Step Into" },
{ "<F2>", dap.step_over, desc = "Debug: Step Over" },
{ "<F3>", dap.step_out, desc = "Debug: Step Out" },
{ "<leader>b", dap.toggle_breakpoint, desc = "Debug: Toggle Breakpoint" },
{
"<leader>B",
function()
dap.set_breakpoint(vim.fn.input("Breakpoint condition: "))
end,
desc = "Debug: Set Breakpoint",
},
-- Toggle to see last session result. Without this, you can't see session output in case of unhandled exception.
{ "<F7>", dapui.toggle, desc = "Debug: See last session result." },
unpack(keys),
}
end,
config = function()
local dap = require("dap")
local dapui = require("dapui")
require("mason-nvim-dap").setup({
-- Makes a best effort to setup the various debuggers with
-- reasonable debug configurations
automatic_installation = true,
-- You can provide additional configuration to the handlers,
-- see mason-nvim-dap README for more information
handlers = {},
})
-- Dap UI setup
-- For more information, see |:help nvim-dap-ui|
dapui.setup({
-- Set icons to characters that are more likely to work in every terminal.
-- Feel free to remove or use ones that you like more! :)
-- Don't feel like these are good choices.
icons = { expanded = "▾", collapsed = "▸", current_frame = "*" },
controls = {
icons = {
pause = "⏸",
play = "▶",
step_into = "⏎",
step_over = "⏭",
step_out = "⏮",
step_back = "b",
run_last = "▶▶",
terminate = "⏹",
disconnect = "⏏",
},
},
})
dap.listeners.after.event_initialized["dapui_config"] = dapui.open
dap.listeners.before.event_terminated["dapui_config"] = dapui.close
dap.listeners.before.event_exited["dapui_config"] = dapui.close
dap.adapters.ocamlearlybird = {
type = 'executable',
command = 'ocamlearlybird',
args = { 'debug' }
}
dap.configurations.ocaml = {
{
name = 'OCaml Debug test.bc',
type = 'ocamlearlybird',
request = 'launch',
program = '${workspaceFolder}/_build/default/test/test.bc',
},
{
name = 'OCaml Debug main.bc',
type = 'ocamlearlybird',
request = 'launch',
program = '${workspaceFolder}/_build/default/bin/main.bc',
},
}
end,
}
I did also try to use there configurations found in set-me-up/files/conf/nvim/after/plugin/dap.lua at master · rbjorklin/set-me-up · GitHub instead, but the only difference is that DAP UI appears and it executes without hitting any breakpoints:
dap.adapters.ocaml = {
type = 'executable',
command = 'ocamlearlybird',
args = {'debug'},
}
dap.configurations.ocaml = {
{
type = "ocaml",
request = "launch",
name = "Launch debug test",
console = "integratedTerminal",
program = "_build/default/${relativeFileDirname}/${fileBasenameNoExtension}.bc",
cwd = "${workspaceFolder}",
stopOnEntry = true,
yieldSteps = 4096,
onlyDebugGlob = "<${workspaceFolder}/**/*>",
}
}
What am I missing here?