aboutsummaryrefslogtreecommitdiffstats
path: root/neovim/.config/nvim/lua/plugins/dap-python.lua
blob: b61e0f48ad1cf755b5429dc963439af04c0c40c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
-- Python launch configs (nvim-dap-python), wired to the debugpy adapter
-- that mason-nvim-dap.nvim installs (dap.lua). Kept in its own file since
-- this is the "per-language" half of debugging, parallel to how
-- ftplugin/python.lua holds Python-only settings.
return {
  "mfussenegger/nvim-dap-python",
  -- Not left to lazy-load off `ft = "python"`: dap.lua's <leader>dc picker
  -- works from any window (not just a Python buffer) and needs
  -- dap.adapters.python already registered by the time a config is picked,
  -- even if no .py buffer has been opened yet this session.
  lazy = false,
  -- mason.nvim is listed directly (not just transitively via dap.lua)
  -- because config() below needs require("mason-registry") to be loadable
  -- from startup, same reasoning as lazy = false above.
  dependencies = { "mfussenegger/nvim-dap", "mason-org/mason.nvim" },
  config = function()
    local registry = require("mason-registry")
    local pkg = registry.get_package("debugpy")

    -- debugpy_path is the interpreter that runs the debug *adapter* itself
    -- (Mason's isolated venv) - it does not control which Python runs your
    -- script. dap-python defaults that to the active venv/system python3;
    -- project-specific venvs may need a manual `pythonPath` override in a
    -- generated launch config later.
    local debugpy_path = pkg:get_install_path() .. "/venv/bin/python"

    local function setup()
      require("dap-python").setup(debugpy_path)

      -- nvim-dap-python doesn't expose adapter.options for tuning, and
      -- nvim-dap's default terminate-request timeout (3s) is tight enough
      -- that debugpy's real response can arrive just after nvim-dap already
      -- gave up and moved on ("No callback found" in dap.log) - <leader>dt
      -- still works, but dap.session() doesn't clear for a few extra
      -- seconds, so <leader>dc right after can catch it still "active".
      -- Wrap the adapter dap-python just registered to give it more room.
      local dap = require("dap")
      local base_adapter = dap.adapters.python
      dap.adapters.python = function(cb, config)
        base_adapter(function(adapter)
          adapter.options = adapter.options or {}
          adapter.options.disconnect_timeout_sec = 8
          cb(adapter)
        end, config)
      end
    end

    if pkg:is_installed() then
      setup()
    else
      -- dap.lua's mason-nvim-dap ensure_installed triggers debugpy's
      -- install, but that's async - on a fresh machine (or before it
      -- finishes) debugpy_path doesn't exist on disk yet, and <leader>dc
      -- would fail with a raw ENOENT from debugpy itself instead of a clear
      -- message. Wire up the adapter once the install actually completes
      -- instead of pointing it at a path that isn't there yet.
      vim.notify(
        "debugpy not installed yet - dap.lua's ensure_installed should be"
          .. " installing it now (check :Mason); run :MasonInstall debugpy"
          .. " if it doesn't show up there. Debugging will work once it's"
          .. " done.",
        vim.log.levels.WARN
      )
      registry:on("package:install:success", function(installed_pkg)
        if installed_pkg.name == "debugpy" then
          setup()
        end
      end)
    end
  end,
}