Merge pull request #73 from horriblename/feature/nvim-debug

feature: DAP support
This commit is contained in:
NotAShelf 2023-06-27 08:08:32 +03:00 committed by GitHub
commit b269f69dfb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 515 additions and 14 deletions

View file

@ -1,6 +1,5 @@
[[sec-release-0.4]]
== Release 0.4
Following the release of v0.3, I have decided to release v0.4 with a massive new change: customizable keybinds. As of the 0.4 release, keybinds will no longer be hardcoded and instead provided by each module's own keybinds section. The old keybind system (`vim.keybinds = {}`) is now considered deprecated and the new lib functions are recommended to be used for adding keybinds for new plugins, or adding keybinds to existing plugins.
Alongside customizable keybinds, there are a few quality of life updates, such as `lazygit` integration and the new experimental Lua loader of Neovim 0.9 thanks to our awesome contributors who made this update possible during my absence.
@ -34,6 +33,10 @@ https://github.com/horriblename[horriblename]:
* Added new option `enableluaLoader` to enable neovim's experimental module loader for faster startup time.
* Fixed bug where flutter-tools can't find `dart` LSP
* Added Debug Adapter (DAP) support for clang, rust, go, python and dart.
https://github.com/notashelf[notashelf]:
* Made Copilot's Node package configurable. It is recommended to keep as default, but providing a different NodeJS version is now possible.

View file

@ -39,6 +39,13 @@ inputs: let
lspSignature.enable = true;
};
vim.debugger = {
nvim-dap = {
enable = true;
ui.enable = true;
};
};
vim.languages = {
enableLSP = true;
enableFormat = true;
@ -217,6 +224,7 @@ inputs: let
image_text = "The Superior Text Editor";
client_id = "793271441293967371";
main_image = "neovim";
show_time = true;
rich_presence = {
editing_text = "Editing %s";
};

View file

@ -1012,6 +1012,38 @@
"type": "github"
}
},
"nvim-dap": {
"flake": false,
"locked": {
"lastModified": 1682077642,
"narHash": "sha256-l5sJ6PKW10CtOzSBKzWasWVMZq/mAkgpgWOecIVuV+0=",
"owner": "mfussenegger",
"repo": "nvim-dap",
"rev": "6cedcb527e264c8f25e86afa8dae74c6692dee51",
"type": "github"
},
"original": {
"owner": "mfussenegger",
"repo": "nvim-dap",
"type": "github"
}
},
"nvim-dap-ui": {
"flake": false,
"locked": {
"lastModified": 1683055722,
"narHash": "sha256-8TavZqkTCr2/jaO3C8fp+r7qfN6mCzVvidbHGtJGLfs=",
"owner": "rcarriga",
"repo": "nvim-dap-ui",
"rev": "749bfe12d1447703899fa823c1c075fbe2d42c24",
"type": "github"
},
"original": {
"owner": "rcarriga",
"repo": "nvim-dap-ui",
"type": "github"
}
},
"nvim-lightbulb": {
"flake": false,
"locked": {
@ -1360,6 +1392,8 @@
"nvim-colorizer-lua": "nvim-colorizer-lua",
"nvim-compe": "nvim-compe",
"nvim-cursorline": "nvim-cursorline",
"nvim-dap": "nvim-dap",
"nvim-dap-ui": "nvim-dap-ui",
"nvim-lightbulb": "nvim-lightbulb",
"nvim-lspconfig": "nvim-lspconfig",
"nvim-neoclip": "nvim-neoclip",

View file

@ -162,6 +162,17 @@
inputs.flake-utils.follows = "flake-utils";
};
# Debuggers
nvim-dap = {
url = "github:mfussenegger/nvim-dap";
flake = false;
};
nvim-dap-ui = {
url = "github:rcarriga/nvim-dap-ui";
flake = false;
};
# Filetrees
nvim-tree-lua = {
url = "github:nvim-tree/nvim-tree.lua";

View file

@ -73,6 +73,7 @@ with lib; let
"diffview-nvim"
"todo-comments"
"flutter-tools"
"flutter-tools-patched"
"hop-nvim"
"leap-nvim"
"modes-nvim"
@ -84,6 +85,8 @@ with lib; let
"nvim-colorizer-lua"
"vim-illuminate"
"nvim-surround"
"nvim-dap"
"nvim-dap-ui"
];
# You can either use the name of the plugin or a package.
pluginsType = with types;

View file

@ -0,0 +1,5 @@
_: {
imports = [
./nvim-dap
];
}

View file

@ -0,0 +1,70 @@
{
config,
lib,
...
}:
with lib;
with builtins; let
cfg = config.vim.debugger.nvim-dap;
self = import ./nvim-dap.nix {
inherit lib;
};
mappingDefinitions = self.options.vim.debugger.nvim-dap.mappings;
mappings = addDescriptionsToMappings cfg.mappings mappingDefinitions;
in {
config = mkMerge [
(mkIf cfg.enable {
vim.startPlugins = ["nvim-dap"];
vim.luaConfigRC =
{
# TODO customizable keymaps
nvim-dap = nvim.dag.entryAnywhere ''
local dap = require("dap")
vim.fn.sign_define("DapBreakpoint", { text = "🛑", texthl = "ErrorMsg", linehl = "", numhl = "" })
'';
}
// mapAttrs (_: v: (nvim.dag.entryAfter ["nvim-dap"] v)) cfg.sources;
vim.maps.normal = mkMerge [
(mkSetLuaBinding mappings.continue "require('dap').continue")
(mkSetLuaBinding mappings.restart "require('dap').restart")
(mkSetLuaBinding mappings.terminate "require('dap').terminate")
(mkSetLuaBinding mappings.runLast "require('dap').run_last")
(mkSetLuaBinding mappings.toggleRepl "require('dap').repl.toggle")
(mkSetLuaBinding mappings.hover "require('dap.ui.widgets').hover")
(mkSetLuaBinding mappings.toggleBreakpoint "require('dap').toggle_breakpoint")
(mkSetLuaBinding mappings.runToCursor "require('dap').run_to_cursor")
(mkSetLuaBinding mappings.stepInto "require('dap').step_into")
(mkSetLuaBinding mappings.stepOut "require('dap').step_out")
(mkSetLuaBinding mappings.stepOver "require('dap').step_over")
(mkSetLuaBinding mappings.stepBack "require('dap').step_back")
(mkSetLuaBinding mappings.goUp "require('dap').up")
(mkSetLuaBinding mappings.goDown "require('dap').down")
];
})
(mkIf (cfg.enable && cfg.ui.enable) {
vim.startPlugins = ["nvim-dap-ui"];
vim.luaConfigRC.nvim-dap-ui = nvim.dag.entryAfter ["nvim-dap"] (''
local dapui = require("dapui")
dapui.setup()
''
+ optionalString cfg.ui.autoStart ''
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
'');
vim.maps.normal = mkSetLuaBinding mappings.toggleDapUI "require('dapui').toggle";
})
];
}

View file

@ -0,0 +1,6 @@
_: {
imports = [
./config.nix
./nvim-dap.nix
];
}

View file

@ -0,0 +1,43 @@
{lib, ...}:
with lib; {
options.vim.debugger.nvim-dap = {
enable = mkEnableOption "Enable debugging via nvim-dap";
ui = {
enable = mkEnableOption "Enable UI extension for nvim-dap";
autoStart = mkOption {
type = types.bool;
default = true;
description = "Automatically Opens and Closes DAP-UI upon starting/closing a debugging session";
};
};
sources = mkOption {
default = {};
description = "List of debuggers to install";
type = with types; attrsOf string;
};
mappings = {
continue = mkMappingOption "Contiue" "<leader>dc";
restart = mkMappingOption "Restart" "<leader>dR";
terminate = mkMappingOption "Terminate" "<leader>dq";
runLast = mkMappingOption "Re-run Last Debug Session" "<leader>d.";
toggleRepl = mkMappingOption "Toggle Repl" "<leader>dr";
hover = mkMappingOption "Hover" "<leader>dh";
toggleBreakpoint = mkMappingOption "Toggle breakpoint" "<leader>db";
runToCursor = mkMappingOption "Continue to the current cursor" "<leader>dgc";
stepInto = mkMappingOption "Step into function" "<leader>dgi";
stepOut = mkMappingOption "Step out of function" "<leader>dgo";
stepOver = mkMappingOption "Next step" "<leader>dgj";
stepBack = mkMappingOption "Step back" "<leader>dgk";
goUp = mkMappingOption "Go up stacktrace" "<leader>dvo";
goDown = mkMappingOption "Go down stacktrace" "<leader>dvi";
toggleDapUI = mkMappingOption "Toggle DAP-UI" "<leader>du";
};
};
}

View file

@ -25,13 +25,13 @@ inputs: {
// extraSpecialArgs;
};
buildPlug = name:
buildVimPluginFrom2Nix rec {
pname = name;
buildPlug = {pname, ...} @ args:
assert lib.asserts.assertMsg (pname != "nvim-treesitter") "Use buildTreesitterPlug for building nvim-treesitter.";
buildVimPluginFrom2Nix (args
// {
version = "master";
src = assert lib.asserts.assertMsg (name != "nvim-treesitter") "Use buildTreesitterPlug for building nvim-treesitter.";
getAttr pname inputs;
};
src = getAttr pname inputs;
});
buildTreesitterPlug = grammars: vimPlugins.nvim-treesitter.withPlugins (_: grammars);
@ -45,7 +45,13 @@ inputs: {
(
if (plug == "nvim-treesitter")
then (buildTreesitterPlug vimOptions.treesitter.grammars)
else (buildPlug plug)
else if (plug == "flutter-tools-patched")
then
(buildPlug {
pname = "flutter-tools";
patches = [../patches/flutter-tools.patch];
})
else (buildPlug {pname = plug;})
)
else plug
))

View file

@ -36,6 +36,35 @@ with builtins; let
'';
};
};
defaultDebugger = "lldb-vscode";
debuggers = {
lldb-vscode = {
package = pkgs.lldb;
dapConfig = ''
dap.adapters.lldb = {
type = 'executable',
command = '${cfg.dap.package}/bin/lldb-vscode',
name = 'lldb'
}
dap.configurations.cpp = {
{
name = 'Launch',
type = 'lldb',
request = 'launch',
program = function()
return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/', 'file')
end,
cwd = "''${workspaceFolder}",
stopOnEntry = false,
args = {},
},
}
dap.configurations.c = dap.configurations.cpp
'';
};
};
in {
options.vim.languages.clang = {
enable = mkEnableOption "C/C++ language support";
@ -76,6 +105,24 @@ in {
default = null;
};
};
dap = {
enable = mkOption {
description = "Enable clang Debug Adapter";
type = types.bool;
default = config.vim.languages.enableDAP;
};
debugger = mkOption {
description = "clang debugger to use";
type = with types; enum (attrNames debuggers);
default = defaultDebugger;
};
package = mkOption {
description = "clang debugger package.";
type = types.package;
default = debuggers.${cfg.dap.debugger}.package;
};
};
};
config = mkIf cfg.enable (mkMerge [
@ -93,5 +140,10 @@ in {
vim.lsp.lspconfig.sources.clang-lsp = servers.${cfg.lsp.server}.lspConfig;
})
(mkIf cfg.dap.enable {
vim.debugger.nvim-dap.enable = true;
vim.debugger.nvim-dap.sources.clang-debugger = debuggers.${cfg.dap.debugger}.dapConfig;
})
]);
}

View file

@ -35,7 +35,10 @@ in {
})
(mkIf (ftcfg.enable) {
vim.startPlugins = ["flutter-tools"];
vim.startPlugins =
if ftcfg.enableNoResolvePatch
then ["flutter-tools-patched"]
else ["flutter-tools"];
vim.luaConfigRC.flutter-tools = nvim.dag.entryAnywhere ''
require('flutter-tools').setup {
@ -52,8 +55,12 @@ in {
on_attach = default_on_attach;
flags = lsp_flags,
},
${optionalString cfg.dap.enable ''
debugger = {
enabled = true,
},
''}
}
'';
})
]);

View file

@ -49,6 +49,14 @@ in {
};
};
dap = {
enable = mkOption {
description = "Enable Dart DAP support via flutter-tools";
type = types.bool;
default = config.vim.languages.enableDAP;
};
};
flutter-tools = {
enable = mkOption {
description = "Enable flutter-tools for flutter support";
@ -56,6 +64,16 @@ in {
default = config.vim.languages.enableLSP;
};
enableNoResolvePatch = mkOption {
description = ''
Patch flutter-tools so that it doesn't resolve symlinks when detecting flutter path.
This is required if you want to use a flutter package built with nix.
If you are using a flutter SDK installed from a different source and encounter the error "`dart` missing from PATH", disable this option.
'';
type = types.bool;
default = true;
};
color = {
enable = mkEnableOption "Whether or mot to highlight color variables at all";

View file

@ -27,6 +27,7 @@ in {
options.vim.languages = {
enableLSP = mkEnable "LSP";
enableDAP = mkEnable "Debug Adapter";
enableTreesitter = mkEnable "treesitter";
enableFormat = mkEnable "formatting";
enableExtraDiagnostics = mkEnable "extra diagnostics";

View file

@ -21,6 +21,46 @@ with builtins; let
'';
};
};
defaultDebugger = "delve";
debuggers = {
delve = {
package = pkgs.delve;
dapConfig = ''
dap.adapters.delve = {
type = "server",
port = "''${port}",
executable = {
command = "${getExe cfg.dap.package}",
args = { "dap", "-l", "127.0.0.1:''${port}" },
},
}
dap.configurations.go = {
{
type = "delve",
name = "Debug",
request = "launch",
program = "''${file}",
},
{
type = "delve",
name = "Debug test", -- configuration for debugging test files
request = "launch",
mode = "test",
program = "''${file}",
},
-- works with go.mod packages and sub packages
{
type = "delve",
name = "Debug test (go.mod)",
request = "launch",
mode = "test",
program = "./''${relativeFileDirname}",
},
}
'';
};
};
in {
options.vim.languages.go = {
enable = mkEnableOption "Go language support";
@ -46,6 +86,24 @@ in {
default = servers.${cfg.lsp.server}.package;
};
};
dap = {
enable = mkOption {
description = "Enable Go Debug Adapter";
type = types.bool;
default = config.vim.languages.enableDAP;
};
debugger = mkOption {
description = "Go debugger to use";
type = with types; enum (attrNames debuggers);
default = defaultDebugger;
};
package = mkOption {
description = "Go debugger package.";
type = types.package;
default = debuggers.${cfg.dap.debugger}.package;
};
};
};
config = mkIf cfg.enable (mkMerge [
@ -58,5 +116,10 @@ in {
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.go-lsp = servers.${cfg.lsp.server}.lspConfig;
})
(mkIf cfg.dap.enable {
vim.debugger.nvim-dap.enable = true;
vim.debugger.nvim-dap.sources.go-debugger = debuggers.${cfg.dap.debugger}.dapConfig;
})
]);
}

View file

@ -36,6 +36,69 @@ with builtins; let
'';
};
};
defaultDebugger = "debugpy";
debuggers = {
debugpy = {
# idk if this is the best way to install/run debugpy
package = pkgs.python3.withPackages (ps: with ps; [debugpy]);
dapConfig = ''
dap.adapters.python = function(cb, config)
if config.request == 'attach' then
---@diagnostic disable-next-line: undefined-field
local port = (config.connect or config).port
---@diagnostic disable-next-line: undefined-field
local host = (config.connect or config).host or '127.0.0.1'
cb({
type = 'server',
port = assert(port, '`connect.port` is required for a python `attach` configuration'),
host = host,
options = {
source_filetype = 'python',
},
})
else
cb({
type = 'executable',
command = '${getExe cfg.dap.package}',
args = { '-m', 'debugpy.adapter' },
options = {
source_filetype = 'python',
},
})
end
end
dap.configurations.python = {
{
-- The first three options are required by nvim-dap
type = 'python'; -- the type here established the link to the adapter definition: `dap.adapters.python`
request = 'launch';
name = "Launch file";
-- Options below are for debugpy, see https://github.com/microsoft/debugpy/wiki/Debug-configuration-settings for supported options
program = "''${file}"; -- This configuration will launch the current file if used.
pythonPath = function()
-- debugpy supports launching an application with a different interpreter then the one used to launch debugpy itself.
-- The code below looks for a `venv` or `.venv` folder in the current directly and uses the python within.
-- You could adapt this - to for example use the `VIRTUAL_ENV` environment variable.
local cwd = vim.fn.getcwd()
if vim.fn.executable(cwd .. '/venv/bin/python') == 1 then
return cwd .. '/venv/bin/python'
elseif vim.fn.executable(cwd .. '/.venv/bin/python') == 1 then
return cwd .. '/.venv/bin/python'
elseif vim.fn.executable("python") == 1 then
return vim.fn.exepath("python")
else -- WARNING cfg.dap.package probably has NO libraries other than builtins and debugpy
return '${getExe cfg.dap.package}'
end
end;
},
}
'';
};
};
in {
options.vim.languages.python = {
enable = mkEnableOption "Python language support";
@ -80,6 +143,29 @@ in {
default = formats.${cfg.format.type}.package;
};
};
# TODO this implementation is very bare bones, I don't know enough python to implement everything
dap = {
enable = mkOption {
description = "Enable Python Debug Adapter";
type = types.bool;
default = config.vim.languages.enableDAP;
};
debugger = mkOption {
description = "Python debugger to use";
type = with types; enum (attrNames debuggers);
default = defaultDebugger;
};
package = mkOption {
description = ''
Python debugger package.
This is a python package with debugpy installed, see https://nixos.wiki/wiki/Python#Install_Python_Packages.
'';
example = literalExpression "with pkgs; python39.withPackages (ps: with ps; [debugpy])";
type = types.package;
default = debuggers.${cfg.dap.debugger}.package;
};
};
};
config = mkIf cfg.enable (mkMerge [
(mkIf cfg.treesitter.enable {
@ -96,5 +182,10 @@ in {
vim.lsp.null-ls.enable = true;
vim.lsp.null-ls.sources.python-format = formats.${cfg.format.type}.nullConfig;
})
(mkIf cfg.dap.enable {
vim.debugger.nvim-dap.enable = true;
vim.debugger.nvim-dap.sources.python-debugger = debuggers.${cfg.dap.debugger}.dapConfig;
})
]);
}

View file

@ -40,6 +40,19 @@ in {
default = "";
};
};
dap = {
enable = mkOption {
description = "Rust Debug Adapter support";
type = types.bool;
default = config.vim.languages.enableDAP;
};
package = mkOption {
description = "lldb pacakge";
type = types.package;
default = pkgs.lldb;
};
};
};
config = mkIf cfg.enable (mkMerge [
@ -62,8 +75,8 @@ in {
vim.treesitter.enable = true;
vim.treesitter.grammars = [cfg.treesitter.package];
})
(mkIf cfg.lsp.enable {
vim.startPlugins = ["rust-tools"];
(mkIf (cfg.lsp.enable || cfg.dap.enable) {
vim.startPlugins = ["rust-tools"] ++ optionals cfg.dap.enable [cfg.dap.package];
vim.lsp.lspconfig.enable = true;
vim.lsp.lspconfig.sources.rust-lsp = ''
@ -78,6 +91,21 @@ in {
vim.keymap.set("n", "<leader>rm", rt.expand_macro.expand_macro, opts)
vim.keymap.set("n", "<leader>rc", rt.open_cargo_toml.open_cargo_toml, opts)
vim.keymap.set("n", "<leader>rg", function() rt.crate_graph.view_crate_graph("x11", nil) end, opts)
${optionalString cfg.dap.enable ''
vim.keymap.set("n", "<leader>rd", ":RustDebuggables<cr>", opts)
vim.keymap.set(
"n", "${config.vim.debugger.nvim-dap.mappings.continue}",
function()
local dap = require("dap")
if dap.status() == "" then
vim.cmd "RustDebuggables"
else
dap.continue()
end
end,
opts
)
''}
end
local rustopts = {
tools = {
@ -94,7 +122,17 @@ in {
settings = {
${cfg.lsp.opts}
}
}
},
${optionalString cfg.dap.enable ''
dap = {
adapter = {
type = "executable",
command = "${cfg.dap.package}/bin/lldb-vscode",
name = "rt_lldb",
},
},
''}
}
rt.setup(rustopts)
'';

View file

@ -29,6 +29,7 @@
./comments
./projects
./languages
./debugger
];
pkgsModule = {config, ...}: {

View file

@ -0,0 +1,41 @@
diff --git a/lua/flutter-tools/executable.lua b/lua/flutter-tools/executable.lua
index 3807a4f..3345760 100644
--- a/lua/flutter-tools/executable.lua
+++ b/lua/flutter-tools/executable.lua
@@ -31,12 +31,12 @@ local function _dart_sdk_root(paths)
end
if utils.executable("flutter") then
- local flutter_path = fn.resolve(fn.exepath("flutter"))
+ local flutter_path = fn.exepath("flutter")
local flutter_bin = fn.fnamemodify(flutter_path, ":h")
return path.join(flutter_bin, dart_sdk)
end
- if utils.executable("dart") then return fn.resolve(fn.exepath("dart")) end
+ if utils.executable("dart") then return fn.exepath("dart") end
return ""
end
@@ -50,10 +50,10 @@ end
---Get paths for flutter and dart based on the binary locations
---@return table<string, string>
local function get_default_binaries()
- local flutter_bin = fn.resolve(fn.exepath("flutter"))
+ local flutter_bin = fn.exepath("flutter")
return {
flutter_bin = flutter_bin,
- dart_bin = fn.resolve(fn.exepath("dart")),
+ dart_bin = fn.exepath("dart"),
flutter_sdk = _flutter_sdk_root(flutter_bin),
}
end
@@ -119,7 +119,7 @@ function M.get(callback)
end
if config.flutter_path then
- local flutter_path = fn.resolve(config.flutter_path)
+ local flutter_path = config.flutter_path
_paths = { flutter_bin = flutter_path, flutter_sdk = _flutter_sdk_root(flutter_path) }
_paths.dart_sdk = _dart_sdk_root(_paths)
_paths.dart_bin = _flutter_sdk_dart_bin(_paths.flutter_sdk)