Skip to content

How the integration works

Enough of the mechanism to reason about it when something misbehaves. The internals proper are in Development.

Who talks to whom

   Neovim  ── source frontend protocol ──►  bugsaur  ── DAP ──►  adapter ──►  your program
   (Lua)         over a Unix socket          (core)                (dlv, codelldb, …)

Neovim is not a DAP client and never speaks to the adapter. It sends intentions — start this, toggle a breakpoint here, step — and receives state to display. Bugsaur owns the DAP session.

The socket

bugsaur gui --socket <path> starts the GUI and the backend session, then accepts a source frontend on that socket. With gui = true, the Lua plugin starts this mode itself, which is why no separate terminal is needed.

The socket is created automatically at /tmp/rust-debugger-nvim-<pid>.sock.

The lifecycle: the editor is not the owner

Closing Neovim does not end the session. The backend keeps running, and a reconnecting frontend receives the current state through a hello exchange — not a replay of what it missed, but a snapshot of how things are now.

This is the practical consequence of the ownership model: your editor is a viewer that can leave and come back.

With auto_attach = true, starting Neovim silently reattaches to the project's running session instead of starting a new one.

What crosses the boundary

Direction What
Neovim → Bugsaur start a session with a profile; the breakpoint set; execution commands; a request to focus the window
Bugsaur → Neovim current stop location; breakpoint states from the adapter; session phase

Notably absent: variables, stack contents and watch results. Those are drawn by the debugger window, which already holds them — sending them to the editor as well would mean two owners of the same state.

Why the window is a separate process

The debugger window is not a Neovim buffer. It is a native window belonging to the bugsaur process, which is why:

  • it survives the editor;
  • its keyboard handling is its own, and Neovim mappings do not reach it — see Keymaps;
  • it can be raised independently, which is what :DebugFocus and gui_focus_on_stop do.

When there is no connection

Check, in this order:

  1. bugsaur.state.last_error in Lua;
  2. that the socket exists: /tmp/rust-debugger-nvim-<pid>.sock;
  3. that binary in setup() points at an existing executable.

More: Troubleshooting → Neovim integration.