From 157a2d51727808038657c498410524f607d1292f Mon Sep 17 00:00:00 2001 From: "Alexandre Cavalheiro S. Tiago da Silva" Date: Thu, 13 Feb 2025 13:01:39 -0300 Subject: [PATCH] feat(neovim): add csharp ftplugin to aid on nvim-dap --- .../home-manager/programs/neovim/default.nix | 5 + .../programs/neovim/ftplugin/cs.lua | 137 ++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 modules/home-manager/programs/neovim/ftplugin/cs.lua diff --git a/modules/home-manager/programs/neovim/default.nix b/modules/home-manager/programs/neovim/default.nix index 0cf20ce..79db868 100644 --- a/modules/home-manager/programs/neovim/default.nix +++ b/modules/home-manager/programs/neovim/default.nix @@ -143,6 +143,11 @@ in source = ./queries; }; + xdg.configFile."nvim/ftplugin" = { + recursive = true; + source = ./ftplugin; + }; + xdg.configFile."nvim/lua/plugins/astrolsp.lua".source = pkgs.runCommand "astrolsp.lua" { } '' cp ${./lsp.lua} $out diff --git a/modules/home-manager/programs/neovim/ftplugin/cs.lua b/modules/home-manager/programs/neovim/ftplugin/cs.lua new file mode 100644 index 0000000..3b69f26 --- /dev/null +++ b/modules/home-manager/programs/neovim/ftplugin/cs.lua @@ -0,0 +1,137 @@ +---@class CSFTPlugin.Project +---@field dll_path string +---@field name string +---@field target_framework string + +---@class CSFTPlugin +---@field dotnet_cmd string? +---@field projects CSFTPlugin.Project[] +local M = { + dotnet_cmd = vim.fn.exepath "dotnet", + projects = {}, +} + +---@param command string The shell command to execute +---@return string[] +function M.cmd(command) + -- execute command + local exec_return = vim.fn.execute("!" .. command) + + -- get the output by line + local output = vim.tbl_filter( + ---@param item string + ---@return boolean + function(item) + if item == "" then + return false + else + return true + end + end, + vim.split(exec_return, "[\n]") + ) + + -- remove echo line (":!") + table.remove(output, 1) + + return output +end + +---@return CSFTPlugin.Project[] +function M.find_projects() + local projects = {} + + local csproj_extension = ".csproj" + + local csproj_files = M.cmd("find . -name '*" .. csproj_extension .. "'") + + for _, file_path in ipairs(csproj_files) do + local sub_start, sub_end = string.find(file_path, "%w+%" .. csproj_extension) + + local project_name = string.sub(file_path, sub_start or 1, sub_end - #csproj_extension) + local project_location = string.sub(file_path, 1, sub_start - 1) + + local target_framework = M.cmd("rg -e 'TargetFramework>(.*)<' -r '$1' -o " .. file_path)[1] + + projects[#projects + 1] = { + dll_path = project_location .. "bin/Debug/" .. target_framework .. "/" .. project_name .. ".dll", + name = project_name, + target_framework = target_framework, + } + end + + return projects +end + +---@param command string The dotnet CLI command to run +---@return string[] +function M:run(command) + return M.cmd(self.dotnet_cmd .. " " .. command) +end + +---@return boolean +function M:check_version() + local cmd_output = self:run "--version" + + local sub_start = string.find(cmd_output[1], "%d+%.%d+%.%d+") + if not sub_start then + return false + end + + return true +end + +---@return thread +function M:choose_dll() + return coroutine.create(function(search_coroutine) + vim.ui.select( + self.projects, + { + prompt = "Select project to debug:", + ---@param item CSFTPlugin.Project + ---@return string + format_item = function(item) + return item.name + end, + }, + ---@param item CSFTPlugin.Project + function(item) + self:run "build" + + coroutine.resume(search_coroutine, item and item.dll_path or require("dap").ABORT) + end + ) + end) +end + +function M:start() + local has_dotnet = self:check_version() + + if not has_dotnet then + vim.notify_once("dotnet executable not present of malfunctioning", vim.log.levels.ERROR) + return + end + + self.projects = self.find_projects() + + local dap = require "dap" + + dap.configurations.cs = { + { + type = "netcoredbg", + name = "Launch project DLL", + request = "launch", + program = function() + return self:choose_dll() + end, + }, + } + + vim.notify_once("Loaded projects for nvim-dap", vim.log.levels.INFO) + + vim.g.loaded_csftplugin = true +end + +if not vim.g.loaded_csftplugin then + M:start() +end