return { 'mfussenegger/nvim-dap', dependencies = { 'mfussenegger/nvim-dap-python', 'theHamsta/nvim-dap-virtual-text', { 'nvim-telescope/telescope-dap.nvim', dependencies = 'telescope.nvim', }, 'rcarriga/nvim-dap-ui', 'rcarriga/cmp-dap', }, keys = { { '', function() require('dap').continue() end, desc = 'DAP start or continue' }, { '', function() require('dap').run_last() end, desc = 'DAP run last' }, { '', function() loadConfigs() end, desc = 'DAP configs' }, { '', function() require('dap').goto_() end, desc = 'DAP goto' }, { '', function() require('dap.ui.widgets').hover() end, desc = 'DAP Hover' }, { '', function() require('dap').toggle_breakpoint() end, desc = 'DAP breakpoint' }, { '', function() require('dap').step_over() end, desc = 'DAP step_over' }, { '', function() require('dap').step_into() end, desc = 'DAP step_into' }, { '', function() require('dap').step_out() end, desc = 'DAP step_out' }, }, config = function() local dap = require('dap') vim.fn.sign_define('DapBreakpoint', { text = '🛑', texthl = '', linehl = '', numhl = '' }) require('cmp_dap').is_dap_buffer() -- make sure we can exit the terminal with esc vim.api.nvim_create_autocmd({ 'TermOpen' }, { pattern = { '*dap-terminal*' }, callback = function() local opts = { noremap = true } vim.api.nvim_buf_set_keymap(0, 't', '', [[]], opts) end }) local function getVenvSuffix() if vim.loop.os_uname().sysname == 'Linux' then return 'bin/python' elseif vim.loop.os_uname().sysname == 'Windows_NT' then return 'Scripts/python.exe' end end local function getVenvFromJson(jsonfile) if not vim.fn.filereadable(jsonfile) then return nil end local f = io.open(jsonfile, 'r') if not f then return nil end local data = f:read('*a') f:close() if data then local jdata = vim.json.decode(data) if jdata['venvPath'] ~= nil and jdata['venv'] ~= nil then return jdata['venvPath'] .. '/' .. jdata['venv'] end end return nil end local function getPythonEnv() local venv = os.getenv('VIRTUAL_ENV') if venv ~= nil then return string.format('%s/%s', venv, getVenvSuffix()) end local conda = os.getenv('CONDA_PREFIX') if conda ~= nil then return string.format('%s/%s', conda, 'python.exe') end local cwd = vim.fn.getcwd() local jsonVenv = getVenvFromJson(cwd .. '/pyrightconfig.json') if jsonVenv ~= nil then return jsonVenv .. '/' .. getVenvSuffix() end if vim.fn.executable(cwd .. '/venv/' .. getVenvSuffix()) == 1 then return cwd .. '/venv/' .. getVenvSuffix() elseif vim.fn.executable(cwd .. '/.venv/' .. getVenvSuffix()) == 1 then return cwd .. '/.venv/' .. getVenvSuffix() else if vim.loop.os_uname().sysname == 'Linux' then return '/usr/bin/python' elseif vim.loop.os_uname().sysname == 'Windows_NT' then return os.getenv('SCOOP') .. '/apps/python/current/python.exe' end end end function loadConfigs() require('dap.ext.vscode').load_launchjs() -- Make sure we use the correct python env even for the configs from launch.json for _, config in pairs(dap.configurations.python) do config.pythonPath = getPythonEnv() config.cwd = vim.fn.getcwd() end require 'telescope'.extensions.dap.configurations {} end local masonpath = vim.fn.stdpath('data') .. '/mason' -- PYTHON dap.adapters.python = { type = 'executable'; command = masonpath .. '/packages/debugpy/venv/' .. getVenvSuffix(); args = { '-m', 'debugpy.adapter' }; options = { detached = true; }; } local dapui = require('dapui') dapui.setup() dap.listeners.after.event_initialized['dapui_config'] = function() dapui.open({}) end dap.listeners.before.event_terminated['dapui_config'] = function() dapui.close({}) end dap.listeners.before.event_exited['dapui_config'] = function() dapui.close({}) end dap.configurations.python = { { type = 'python'; request = 'launch'; name = 'Launch file with venv'; justMyCode = false; program = '${file}'; cwd = vim.fn.getcwd(); pythonPath = getPythonEnv }, } -- require('dap-python').setup('C:\\Users\\oli\\AppData\\Local\\nvim\\venv_debugpy\\Scripts\\python') -- table.insert(require('dap').configurations.python, { -- -- type = 'python', -- -- request = 'launch', -- -- name = 'My custom launch configuration', -- -- program = '${file}', -- justMyCode = false -- -- ... more options, see https://github.com/microsoft/debugpy/wiki/Debug-configuration-settings -- }) -- require('dap-python').setup('C:/Users/oli/AppData/Local/nvim-data/mason/packages/debugpy/venv/Scripts/python.exe') -- CPP dap.adapters.codelldb = { type = 'server', port = '${port}', executable = { -- CHANGE THIS to your path! command = masonpath .. '/bin/codelldb.cmd', args = { '--port', '${port}' }, -- On windows you may have to uncomment this: detached = false, } } dap.adapters.lldb = { type = 'executable', command = function() if vim.loop.os_uname().sysname == 'Linux' then return 'lldb-vscode' else return os.getenv('SCOOP') .. '/apps/llvm/current/bin/lldb-vscode.exe' end end, name = 'lldb' } dap.configurations.cpp = { { name = 'Launch codelldb', type = 'codelldb', request = 'launch', program = function() return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/build_nvim/', 'file') end, cwd = '${workspaceFolder}', stopOnEntry = false, }, { name = 'Launch lldb', type = 'lldb', request = 'launch', program = function() return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/build_nvim', 'file') end, cwd = '${workspaceFolder}', stopOnEntry = false, args = {}, -- 💀 -- if you change `runInTerminal` to true, you might need to change the yama/ptrace_scope setting: -- -- echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope -- -- Otherwise you might get the following error: -- -- Error on launch: Failed to attach to the target process -- -- But you should be aware of the implications: -- https://www.kernel.org/doc/html/latest/admin-guide/LSM/Yama.html -- runInTerminal = false, }, } -- EXTENSIONS require('nvim-dap-virtual-text').setup({}) require('telescope').load_extension('dap') end, }