chrisgrieser / nvim-kickstart-python

A launch point for your nvim configuration for Python
MIT License
126 stars 5 forks source link

Debugging does not work #10

Closed tkreuder closed 2 months ago

tkreuder commented 2 months ago

Hey Chris,

thanks a lot for providing your template!

I have problems getting the debugger to run:

i found missing dependencies:

https://github.com/rcarriga/nvim-dap-ui

    "rcarriga/nvim-dap-ui",
         dependencies = {"mfussenegger/nvim-dap", "nvim-neotest/nvim-nio"},

afterwards i had to add (https://github.com/rcarriga/nvim-dap-ui/issues/279#issuecomment-1596258077):

    {
        "mfussenegger/nvim-dap-python",
        dependencies = "mfussenegger/nvim-dap",
        config = function()
            -- uses the debugypy installation by mason
            --
            local dap, dapui = require("dap"), require("dapui")
            dapui.setup()
            ...

When i now run: \dc dap-ui appears and quickly disappears and the output of ~/.cache/nvim/dap.log looks the following:


[ INFO ] 2024-08-21T09:07:49Z+0200 ] ...uder/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:769 ]  "Telemetry" "ptvsd"
[ INFO ] 2024-08-21T09:07:49Z+0200 ] ...uder/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:769 ]  "Telemetry" "debugpy"
[ WARN ] 2024-08-21T09:07:49Z+0200 ] ...uder/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:1034 ] "No event handler for " {
  body = {
    sockets = { {
        host = "127.0.0.1",
        internal = false,
        port = 50015
      } }
  },
  event = "debugpySockets",
  seq = 3,
  type = "event"
}
[ WARN ] 2024-08-21T09:07:49Z+0200 ] ...uder/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:1034 ] "No event handler for " {
  body = {
    sockets = { {
        host = "127.0.0.1",
        internal = false,
        port = 50015
      }, {
        host = "127.0.0.1",
        internal = true,
        port = 50016
      } }
  },
  event = "debugpySockets",
  seq = 5,
  type = "event"
}
[ WARN ] 2024-08-21T09:07:49Z+0200 ] ...uder/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:1034 ] "No event handler for " {
  body = {
    sockets = { {
        host = "127.0.0.1",
        internal = false,
        port = 50015
      }, {
        host = "127.0.0.1",
        internal = true,
        port = 50017
      }, {
        host = "127.0.0.1",
        internal = true,
        port = 50016
      } }
  },
  event = "debugpySockets",
  seq = 6,
  type = "event"
}
[ WARN ] 2024-08-21T09:07:49Z+0200 ] ...uder/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:1034 ] "No event handler for " {
  body = {
    sockets = { {
        host = "127.0.0.1",
        internal = false,
        port = 50015
      }, {
        host = "127.0.0.1",
        internal = true,
        port = 50016
      } }
  },
  event = "debugpySockets",
  seq = 7,
  type = "event"
}
[ INFO ] 2024-08-21T09:07:50Z+0200 ] ...uder/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:769 ]  "Telemetry" "ptvsd"
[ INFO ] 2024-08-21T09:07:50Z+0200 ] ...uder/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:769 ]  "Telemetry" "debugpy"
[ WARN ] 2024-08-21T09:07:50Z+0200 ] ...uder/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:1034 ] "No event handler for " {
  body = {
    sockets = { {
        host = "127.0.0.1",
        internal = false,
        port = 50015
      }, {
        host = "127.0.0.1",
        internal = true,
        port = 50016
      } }
  },
  event = "debugpySockets",
  seq = 18,
  type = "event"
}
[ WARN ] 2024-08-21T09:07:50Z+0200 ] ...uder/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:1034 ] "No event handler for " {
  body = {
    host = "127.0.0.1",
    port = 50016
  },
  event = "debugpyWaitingForServer",
  seq = 4,
  type = "event"
}
[ INFO ] 2024-08-21T09:07:50Z+0200 ] ...uder/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:769 ]  "Telemetry" "ptvsd"
[ INFO ] 2024-08-21T09:07:50Z+0200 ] ...uder/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:769 ]  "Telemetry" "debugpy"
[ WARN ] 2024-08-21T09:07:50Z+0200 ] ...uder/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:1034 ] "No event handler for " {
  body = {
    sockets = { {
        host = "127.0.0.1",
        internal = false,
        port = 50015
      }, {
        host = "127.0.0.1",
        internal = true,
        port = 50016
      } }
  },
  event = "debugpySockets",
  seq = 20,
  type = "event"
}
[ WARN ] 2024-08-21T09:07:50Z+0200 ] ...uder/.local/share/nvim/lazy/nvim-dap/lua/dap/session.lua:1034 ] "No event handler for " {
  body = {
    host = "127.0.0.1",
    port = 50016
  },
  event = "debugpyWaitingForServer",
  seq = 4,
  type = "event"
}

Any idea, what is still missing / wrong here? I would be more than happy to get some help :)

tkreuder commented 2 months ago

Probably found a solution for the remaining issue and will give an update as soon as I am back at my desk.

chrisgrieser commented 2 months ago

When I last used the debugger (been a bit), it didn't have nvim-nio as dependency. Maintainer didn't indicate a breaking change either… sigh

Not sure when I have the time to look into this, if you have a fix, you're welcome to share it.

tkreuder commented 2 months ago

That the UI disappears was due to the fact, that the process of starting my FastAPI instance immediately stopped, because the .env file in my project was not loaded, which lead to an exception in my code interrupting the debugging session.

As envFile is not an official argument for vscode (see: https://github.com/mfussenegger/nvim-dap/discussions/548) i was able to auto-load it via:

local plugins = {
    -- TOOLING: COMPLETION, DIAGNOSTICS, FORMATTING

    -- Manager for external tools (LSPs, linters, debuggers, formatters)
    -- auto-install of those external tools
     {"ellisonleao/dotenv.nvim",
    init = function()
        require("dotenv").setup({
            enable_on_load = true, -- will load your .env file upon loading a buffer
            verbose = false, 
        })
    end,
    },
....

here is the full init.lua with which debugging of python is possible again:


-- BOOTSTRAP the plugin manager `lazy.nvim` https://lazy.folke.io/installation
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
local lazyLocallyAvailable = vim.uv.fs_stat(lazypath) ~= nil
if not lazyLocallyAvailable then
    local lazyrepo = "https://github.com/folke/lazy.nvim.git"
    local out = vim.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }):wait()
    if out.code ~= 0 then
        vim.api.nvim_echo({
            { "Failed to clone lazy.nvim:\n", "ErrorMsg" },
            { out, "WarningMsg" },
            { "\nPress any key to exit..." },
        }, true, {})
        vim.fn.getchar()
        os.exit(1)
    end
end
vim.opt.rtp:prepend(lazypath)

--------------------------------------------------------------------------------

local plugins = {
    -- TOOLING: COMPLETION, DIAGNOSTICS, FORMATTING

    -- Manager for external tools (LSPs, linters, debuggers, formatters)
    -- auto-install of those external tools
     {"ellisonleao/dotenv.nvim",
    init = function()
        require("dotenv").setup({
            enable_on_load = true, -- will load your .env file upon loading a buffer
        })
    end,
    },
    {
        "WhoIsSethDaniel/mason-tool-installer.nvim",
        dependencies = {
            { "williamboman/mason.nvim", opts = true },
            { "williamboman/mason-lspconfig.nvim", opts = true },
        },
        opts = {
            ensure_installed = {
                "pyright", -- LSP for python
                "ruff", -- linter for python (includes flake8, pep8, etc.)
                "debugpy", -- debugger
                "black", -- formatter
                "isort", -- organize imports
                "taplo", -- LSP for toml (for pyproject.toml files)
            },
        },
    },

    -- Setup the LSPs
    -- `gd` and `gr` for goto definition / references
    -- `<leader>c` for code actions (organize imports, etc.)
    {
        "neovim/nvim-lspconfig",
        keys = {
            { "gd", vim.lsp.buf.definition, desc = "Goto Definition" },
            { "gr", vim.lsp.buf.references, desc = "Goto References" },
            { "<leader>c", vim.lsp.buf.code_action, desc = "Code Action" },
        },
        init = function()
            -- this snippet enables auto-completion
            local lspCapabilities = vim.lsp.protocol.make_client_capabilities()
            lspCapabilities.textDocument.completion.completionItem.snippetSupport = true

            -- setup pyright with completion capabilities
            require("lspconfig").pyright.setup({
                capabilities = lspCapabilities,
            })

            -- setup taplo with completion capabilities
            require("lspconfig").taplo.setup({
                capabilities = lspCapabilities,
            })

            -- ruff uses an LSP proxy, therefore it needs to be enabled as if it
            -- were a LSP. In practice, ruff only provides linter-like diagnostics
            -- and some code actions, and is not a full LSP yet.
            require("lspconfig").ruff.setup({
                -- organize imports disabled, since we are already using `isort` for that
                -- alternative, this can be enabled to make `organize imports`
                -- available as code action
                settings = {
                    organizeImports = false,
                },
                -- disable ruff as hover provider to avoid conflicts with pyright
                on_attach = function(client) client.server_capabilities.hoverProvider = false end,
            })
        end,
    },

    -- Formatting client: conform.nvim
    -- - configured to use black & isort in python
    -- - use the taplo-LSP for formatting in toml
    -- - Formatting is triggered via `<leader>f`, but also automatically on save
    {
        "stevearc/conform.nvim",
        event = "BufWritePre", -- load the plugin before saving
        keys = {
            {
                "<leader>f",
                function() require("conform").format({ lsp_fallback = true }) end,
                desc = "Format",
            },
        },
        opts = {
            formatters_by_ft = {
                -- first use isort and then black
                python = { "isort", "black" },
                -- "inject" is a special formatter from conform.nvim, which
                -- formats treesitter-injected code. Basically, this makes
                -- conform.nvim format python codeblocks inside a markdown file.
                markdown = { "inject" },
            },
            -- enable format-on-save
            format_on_save = {
                -- when no formatter is setup for a filetype, fallback to formatting
                -- via the LSP. This is relevant e.g. for taplo (toml LSP), where the
                -- LSP can handle the formatting for us
                lsp_fallback = true,
            },
        },
    },

    -- Completion via nvim-cmp
    -- - Confirm a completion with `<CR>` (Return)
    -- - select an item with `<Tab>`/`<S-Tab>`
    {
        "hrsh7th/nvim-cmp",
        dependencies = "hrsh7th/cmp-nvim-lsp", -- use suggestions from the LSP
        config = function()
            local cmp = require("cmp")
            cmp.setup({
                -- register the lsp as completion provider
                sources = cmp.config.sources({
                    { name = "nvim_lsp" },
                }),

                -- Define the mappings for the completion. The `fallback()` call
                -- ensures that when there is no suggestion window open, the mapping
                -- falls back to the default behavior (adding indentation).
                mappings = cmp.mapping.preset.insert({
                    ["<CR>"] = cmp.mapping.confirm({ select = true }), -- true = autoselect first entry
                    ["<Tab>"] = cmp.mapping(function(fallback)
                        if cmp.visible() then
                            cmp.select_next_item()
                        else
                            fallback()
                        end
                    end, { "i", "s" }),
                    ["<S-Tab>"] = cmp.mapping(function(fallback)
                        if cmp.visible() then
                            cmp.select_prev_item()
                        else
                            fallback()
                        end
                    end, { "i", "s" }),
                }),
            })
        end,
    },

    -----------------------------------------------------------------------------
    -- PYTHON REPL
    -- A basic REPL that opens up as a horizontal split
    -- - use `<leader>i` to toggle the REPL
    -- - use `<leader>I` to restart the REPL
    -- - `+` serves as the "send to REPL" operator. That means we can use `++`
    -- to send the current line to the REPL, and `+j` to send the current and the
    -- following line to the REPL, like we would do with other vim operators.
    {
        "Vigemus/iron.nvim",
        keys = {
            { "<leader>i", vim.cmd.IronRepl, desc = "󱠤 Toggle REPL" },
            { "<leader>I", vim.cmd.IronRestart, desc = "󱠤 Restart REPL" },

            -- these keymaps need no right-hand-side, since that is defined by the
            -- plugin config further below
            { "+", mode = { "n", "x" }, desc = "󱠤 Send-to-REPL Operator" },
            { "++", desc = "󱠤 Send Line to REPL" },
        },

        -- since irons's setup call is `require("iron.core").setup`, instead of
        -- `require("iron").setup` like other plugins would do, we need to tell
        -- lazy.nvim which module to via the `main` key
        main = "iron.core",

        opts = {
            keymaps = {
                send_line = "++",
                visual_send = "+",
                send_motion = "+",
            },
            config = {
                -- This defines how the repl is opened. Here, we set the REPL window
                -- to open in a horizontal split to the bottom, with a height of 10.
                repl_open_cmd = "horizontal bot 10 split",

                -- This defines which binary to use for the REPL. If `ipython` is
                -- available, it will use `ipython`, otherwise it will use `python3`.
                -- since the python repl does not play well with indents, it's
                -- preferable to use `ipython` or `bypython` here.
                -- (see: https://github.com/Vigemus/iron.nvim/issues/348)
                repl_definition = {
                    python = {
                        command = function()
                            local ipythonAvailable = vim.fn.executable("ipython") == 1
                            local binary = ipythonAvailable and "ipython" or "python3"
                            return { binary }
                        end,
                    },
                },
            },
        },
    },

    -----------------------------------------------------------------------------
    -- SYNTAX HIGHLIGHTING & COLORSCHEME

    -- treesitter for syntax highlighting
    -- - auto-installs the parser for python
    {
        "nvim-treesitter/nvim-treesitter",
        -- automatically update the parsers with every new release of treesitter
        build = ":TSUpdate",

        -- since treesitter's setup call is `require("nvim-treesitter.configs").setup`,
        -- instead of `require("nvim-treesitter").setup` like other plugins do, we
        -- need to tell lazy.nvim which module to via the `main` key
        main = "nvim-treesitter.configs",

        opts = {
            highlight = { enable = true }, -- enable treesitter syntax highlighting
            indent = { enable = true }, -- better indentation behavior
            ensure_installed = {
                -- auto-install the Treesitter parser for python and related languages
                "python",
                "toml",
                "rst",
                "ninja",
                "markdown",
                "markdown_inline",
            },
        },
    },

    -- COLORSCHEME
    -- In neovim, the choice of color schemes is unfortunately not purely
    -- aesthetic – treesitter-based highlighting or newer features like semantic
    -- highlighting are not always supported by a color scheme. It's therefore
    -- recommended to use one of the popular, and actively maintained ones to get
    -- the best syntax highlighting experience:
    -- https://dotfyle.com/neovim/colorscheme/top
    {
        "folke/tokyonight.nvim",
        -- ensure that the color scheme is loaded at the very beginning
        lazy = false,
        priority = 1000,
        -- enable the colorscheme
        config = function() vim.cmd.colorscheme("tokyonight") end,
    },

    -----------------------------------------------------------------------------
    -- DEBUGGING

    -- DAP Client for nvim
    -- - start the debugger with `<leader>dc`
    -- - add breakpoints with `<leader>db`
    -- - terminate the debugger `<leader>dt`
    {
        "mfussenegger/nvim-dap",
        keys = {
            {
                "<leader>dc",
                function() require("dap").continue() end,
                desc = "Start/Continue Debugger",
            },
            {
                "<leader>db",
                function() require("dap").toggle_breakpoint() end,
                desc = "Add Breakpoint",
            },
            {
                "<leader>dt",
                function() require("dap").terminate() end,
                desc = "Terminate Debugger",
            },
        },
    },

    -- UI for the debugger
    -- - the debugger UI is also automatically opened when starting/stopping the debugger
    -- - toggle debugger UI manually with `<leader>du`
    {
        "rcarriga/nvim-dap-ui",
         dependencies = {"mfussenegger/nvim-dap", "nvim-neotest/nvim-nio"},
        keys = {
            {
                "<leader>du",
                function() require("dapui").toggle() end,
                desc = "Toggle Debugger UI",
            },
        },
        -- automatically open/close the DAP UI when starting/stopping the debugger
        config = function()
            local nio = require("nio")

            local listener = require("dap").listeners
            listener.after.event_initialized["dapui_config"] = function() require("dapui").open() end
            listener.before.event_terminated["dapui_config"] = function() require("dapui").close() end
            listener.before.event_exited["dapui_config"] = function() require("dapui").close() end
        end,
    },

    -- Configuration for the python debugger
    -- - configures debugpy for us
    -- - uses the debugpy installation from mason
    {
        "mfussenegger/nvim-dap-python",
        dependencies = "mfussenegger/nvim-dap",
        config = function()
            -- uses the debugypy installation by mason
            --
            local dap, dapui = require("dap"), require("dapui")
            dapui.setup()
            local debugpyPythonPath = require("mason-registry").get_package("debugpy"):get_install_path()
                .. "/venv/bin/python3"
            require("dap-python").setup(debugpyPythonPath, {}) ---@diagnostic disable-line: missing-fields
        end,
    },

    -----------------------------------------------------------------------------
    -- EDITING SUPPORT PLUGINS
    -- some plugins that help with python-specific editing operations

    -- Docstring creation
    -- - quickly create docstrings via `<leader>a`
    {
        "danymat/neogen",
        opts = true,
        keys = {
            {
                "<leader>a",
                function() require("neogen").generate() end,
                desc = "Add Docstring",
            },
        },
    },

    -- f-strings
    -- - auto-convert strings to f-strings when typing `{}` in a string
    -- - also auto-converts f-strings back to regular strings when removing `{}`
    {
        "chrisgrieser/nvim-puppeteer",
        dependencies = "nvim-treesitter/nvim-treesitter",
    },
}

--------------------------------------------------------------------------------

-- tell lazy.nvim to load and configure all the plugins
require("lazy").setup(plugins)

--------------------------------------------------------------------------------
-- SETUP BASIC PYTHON-RELATED OPTIONS

-- The filetype-autocmd runs a function when opening a file with the filetype
-- "python". This method allows you to make filetype-specific configurations. In
-- there, you have to use `opt_local` instead of `opt` to limit the changes to
-- just that buffer. (As an alternative to using an autocmd, you can also put those
-- configurations into a file `/after/ftplugin/{filetype}.lua` in your
-- nvim-directory.)
vim.api.nvim_create_autocmd("FileType", {
    pattern = "python", -- filetype for which to run the autocmd
    callback = function()
        -- use pep8 standards
        vim.opt_local.expandtab = true
        vim.opt_local.shiftwidth = 4
        vim.opt_local.tabstop = 4
        vim.opt_local.softtabstop = 4

        -- folds based on indentation https://neovim.io/doc/user/fold.html#fold-indent
        -- if you are a heavy user of folds, consider using `nvim-ufo`
        vim.opt_local.foldmethod = "indent"

        local iabbrev = function(lhs, rhs) vim.keymap.set("ia", lhs, rhs, { buffer = true }) end
        -- automatically capitalize boolean values. Useful if you come from a
        -- different language, and lowercase them out of habit.
        iabbrev("true", "True")
        iabbrev("false", "False")

        -- in the same way, we can fix habits regarding comments or None
        iabbrev("--", "#")
        iabbrev("null", "None")
        iabbrev("none", "None")
        iabbrev("nil", "None")
    end,
})