mirror of
https://github.com/Smaug123/nix-dotfiles
synced 2025-10-06 06:58:41 +00:00
More F# and .NET stuff (#43)
This commit is contained in:
@@ -261,7 +261,7 @@
|
||||
vimdiffAlias = true;
|
||||
withPython3 = true;
|
||||
|
||||
extraLuaConfig = builtins.readFile ./nvim/build-utils.lua + "\n" + builtins.replaceStrings ["%PYTHONENV%"] ["${pythonEnv}"] (builtins.readFile ./nvim/init.lua);
|
||||
extraLuaConfig = builtins.readFile ./nvim/build-utils.lua + "\n" + builtins.readFile ./nvim/dotnet.lua + "\n" + builtins.replaceStrings ["%PYTHONENV%"] ["${pythonEnv}"] (builtins.readFile ./nvim/init.lua);
|
||||
|
||||
package = nixpkgs.neovim-nightly;
|
||||
};
|
||||
|
158
home-manager/nvim/dotnet.lua
Normal file
158
home-manager/nvim/dotnet.lua
Normal file
@@ -0,0 +1,158 @@
|
||||
local dotnet_has_set_status_line
|
||||
|
||||
function DetachSolution()
|
||||
vim.g.current_sln_path = nil
|
||||
-- TODO: unregister key bindings again
|
||||
end
|
||||
|
||||
local function on_line(data, _, context)
|
||||
-- Keep the window alive if there were warnings
|
||||
if string.match(data, "%s[1-9]%d* Warning%(s%)") then
|
||||
context.warn = context.warn + 1
|
||||
end
|
||||
end
|
||||
local function on_complete(context, code, _)
|
||||
if code ~= 0 then
|
||||
print("Exit code " .. code)
|
||||
context.errs = context.errs + 1
|
||||
end
|
||||
|
||||
if context.errs == 0 and context.warn == 0 then
|
||||
-- Close the temporary floating window (but keep it alive if the
|
||||
-- cursor is in it)
|
||||
local cur_win = vim.api.nvim_get_current_win()
|
||||
local cur_buf = vim.api.nvim_win_get_buf(cur_win)
|
||||
if cur_buf ~= context.buffer then
|
||||
vim.api.nvim_win_close(context.window, true)
|
||||
end
|
||||
print("All builds successful")
|
||||
end
|
||||
end
|
||||
|
||||
function GetCurrentSln()
|
||||
if vim.g.current_sln_path then
|
||||
return vim.g.current_sln_path
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function BuildDotNetSolution()
|
||||
if vim.g.current_sln_path then
|
||||
local context = BuildUtils.create_window()
|
||||
context.errs = 0
|
||||
context.warn = 0
|
||||
BuildUtils.run("dotnet", { "build", vim.g.current_sln_path }, "dotnet build", context, on_line, on_complete)
|
||||
end
|
||||
end
|
||||
|
||||
function TestDotNetSolution()
|
||||
if vim.g.current_sln_path then
|
||||
local context = BuildUtils.create_window()
|
||||
context.warn = 0
|
||||
context.errs = 0
|
||||
BuildUtils.run("dotnet", { "test", vim.g.current_sln_path }, "dotnet test", context, on_line, on_complete)
|
||||
end
|
||||
end
|
||||
|
||||
function CurrentSlnOrEmpty()
|
||||
local sln = GetCurrentSln()
|
||||
if sln then
|
||||
return sln
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
function RegisterSolution(sln_path)
|
||||
vim.g.current_sln_path = sln_path
|
||||
|
||||
if not dotnet_has_set_status_line then
|
||||
dotnet_has_set_status_line = true
|
||||
vim.o.statusline = vim.o.statusline .. " %{v:lua.CurrentSlnOrEmpty()}"
|
||||
end
|
||||
|
||||
local status, whichkey = pcall(require, "which-key")
|
||||
if status then
|
||||
whichkey.register({
|
||||
s = {
|
||||
name = ".NET solution",
|
||||
b = { BuildDotNetSolution, "Build .NET solution" },
|
||||
t = { TestDotNetSolution, "Test .NET solution" },
|
||||
},
|
||||
}, { prefix = vim.api.nvim_get_var("maplocalleader"), buffer = vim.api.nvim_get_current_buf() })
|
||||
else
|
||||
vim.api.nvim_set_keymap("n", "<localleader>sb", ":call BuildDotNetSolution", { noremap = true })
|
||||
end
|
||||
end
|
||||
|
||||
local function find_nearest_slns()
|
||||
local path = vim.fn.expand("%:p:h") -- Get the full path of the current buffer's directory
|
||||
|
||||
while path and path ~= "/" do
|
||||
local sln_paths = vim.fn.glob(path .. "/*.sln", nil, true)
|
||||
if #sln_paths > 0 then
|
||||
return sln_paths
|
||||
end
|
||||
path = vim.fn.fnamemodify(path, ":h") -- Move up one directory
|
||||
end
|
||||
|
||||
return {}
|
||||
end
|
||||
|
||||
local function FindAndRegisterSolution()
|
||||
local solutions = find_nearest_slns()
|
||||
if not solutions or #solutions == 0 then
|
||||
print("No .sln file found in any parent directory.")
|
||||
return
|
||||
elseif #solutions == 1 then
|
||||
-- Exactly one solution found; register it directly
|
||||
RegisterSolution(solutions[1])
|
||||
elseif #solutions > 1 then
|
||||
-- Multiple solutions found; use Telescope to pick one
|
||||
local pickers = require("telescope.pickers")
|
||||
local finders = require("telescope.finders")
|
||||
local actions = require("telescope.actions")
|
||||
local action_state = require("telescope.actions.state")
|
||||
local conf = require("telescope.config").values
|
||||
|
||||
pickers
|
||||
.new({}, {
|
||||
prompt_title = "Select a Solution File",
|
||||
finder = finders.new_table({
|
||||
results = solutions,
|
||||
entry_maker = function(entry)
|
||||
return {
|
||||
value = entry,
|
||||
display = entry,
|
||||
ordinal = entry,
|
||||
}
|
||||
end,
|
||||
}),
|
||||
sorter = conf.generic_sorter({}),
|
||||
attach_mappings = function(prompt_bufnr, _)
|
||||
actions.select_default:replace(function()
|
||||
local selection = action_state.get_selected_entry()
|
||||
actions.close(prompt_bufnr)
|
||||
RegisterSolution(selection.value)
|
||||
end)
|
||||
return true
|
||||
end,
|
||||
})
|
||||
:find()
|
||||
end
|
||||
end
|
||||
|
||||
vim.api.nvim_create_autocmd({ "BufReadPost", "BufNewFile" }, {
|
||||
pattern = "*.sln",
|
||||
callback = function()
|
||||
RegisterSolution(vim.fn.expand("%:p"))
|
||||
end,
|
||||
})
|
||||
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
pattern = { "fsharp", "cs" },
|
||||
callback = function()
|
||||
FindAndRegisterSolution()
|
||||
end,
|
||||
})
|
@@ -99,7 +99,7 @@ function HasPaste()
|
||||
return ""
|
||||
end
|
||||
|
||||
vim.o.statusline = vim.o.statusline .. "%{v:lua.HasPaste()}%F%m%r%h %w CWD: %r%{getcwd()}%h Line: %l Column: %c"
|
||||
vim.o.statusline = vim.o.statusline .. "%{v:lua.HasPaste()}%F%m%r%h %w Line: %l Column: %c"
|
||||
|
||||
--------------------------------------------------------------
|
||||
|
||||
@@ -186,7 +186,6 @@ if status then
|
||||
print("-----")
|
||||
end
|
||||
end
|
||||
-- TODO: If a command is a prefix of an existing command, prepend its description to those commands' descriptions, and append a '...' to the parent's description.
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
@@ -65,7 +65,7 @@ local function BuildFSharpProjects(projects)
|
||||
-- cursor is in it)
|
||||
local cur_win = vim.api.nvim_get_current_win()
|
||||
local cur_buf = vim.api.nvim_win_get_buf(cur_win)
|
||||
if cur_buf ~= context.buf then
|
||||
if cur_buf ~= context.buffer then
|
||||
vim.api.nvim_win_close(context.window, true)
|
||||
end
|
||||
print("All builds successful")
|
||||
@@ -94,45 +94,6 @@ local function BuildFSharpProjects(projects)
|
||||
end
|
||||
end
|
||||
|
||||
-- local function fsprojAndDirCompletion(ArgLead, _, _)
|
||||
-- local results = {}
|
||||
-- local loc = ArgLead
|
||||
-- if not loc then
|
||||
-- loc = "."
|
||||
-- end
|
||||
-- local command = string.format(
|
||||
-- "find "
|
||||
-- .. vim.fn.shellescape(loc)
|
||||
-- .. " -maxdepth 2 \\( -type f -name '*.fsproj' -o -type d \\) -print0 2> /dev/null"
|
||||
-- )
|
||||
-- local handle = io.popen(command)
|
||||
-- if handle then
|
||||
-- local stdout = handle:read("*all")
|
||||
-- handle:close()
|
||||
--
|
||||
-- local allResults = {}
|
||||
-- for match in string.gmatch(stdout, "([^%z]+)") do
|
||||
-- table.insert(allResults, match)
|
||||
-- end
|
||||
-- table.sort(allResults, function(a, b)
|
||||
-- local aEndsWithProj = a:match("proj$")
|
||||
-- local bEndsWithProj = b:match("proj$")
|
||||
-- if aEndsWithProj and not bEndsWithProj then
|
||||
-- return true
|
||||
-- elseif not aEndsWithProj and bEndsWithProj then
|
||||
-- return false
|
||||
-- else
|
||||
-- return a < b -- If both or neither end with 'proj', sort alphabetically
|
||||
-- end
|
||||
-- end)
|
||||
--
|
||||
-- for _, line in ipairs(allResults) do
|
||||
-- table.insert(results, line)
|
||||
-- end
|
||||
-- end
|
||||
-- return results
|
||||
-- end
|
||||
|
||||
vim.api.nvim_create_user_command("BuildFSharpProject", function(opts)
|
||||
if opts.fargs and opts.fargs[1] then
|
||||
BuildFSharpProjects(opts.fargs)
|
||||
@@ -144,7 +105,7 @@ vim.api.nvim_create_user_command("BuildFSharpProject", function(opts)
|
||||
local actions = require("telescope.actions")
|
||||
pickers
|
||||
.new({}, {
|
||||
prompt_title = "Actions",
|
||||
prompt_title = "Projects",
|
||||
finder = finders.new_table({
|
||||
results = captureLoadedProjects(),
|
||||
}),
|
||||
@@ -162,6 +123,101 @@ vim.api.nvim_create_user_command("BuildFSharpProject", function(opts)
|
||||
end
|
||||
end, { nargs = "?", complete = "file" })
|
||||
|
||||
local function TableConcat(tables)
|
||||
local result = {}
|
||||
for _, tab in ipairs(tables) do
|
||||
for _, v in ipairs(tab) do
|
||||
table.insert(result, v)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- args is a table that will be splatted into the command line and will be immediately
|
||||
-- followed by the project.
|
||||
local function RunDotnet(command, args, project, configuration)
|
||||
local function on_line(data, _, context) end
|
||||
|
||||
local function on_complete(context, code, signal) end
|
||||
|
||||
local context = BuildUtils.create_window()
|
||||
|
||||
BuildUtils.run(
|
||||
"dotnet",
|
||||
TableConcat({ { command }, args, { project, "--configuration", configuration } }),
|
||||
"dotnet",
|
||||
context,
|
||||
on_line,
|
||||
on_complete
|
||||
)
|
||||
end
|
||||
|
||||
-- Call this as:
|
||||
-- RunFSharpProject path/to/fsproj
|
||||
-- RunFSharpProject Debug path/to/fsproj
|
||||
vim.api.nvim_create_user_command("RunFSharpProject", function(opts)
|
||||
local configuration = "Release"
|
||||
if opts.fargs and opts.fargs[1] and opts.fargs[1]:match("sproj$") then
|
||||
RunDotnet("run", { "--project" }, opts.fargs[1], configuration)
|
||||
elseif opts.fargs and opts.fargs[1] and opts.fargs[2] then
|
||||
configuration = opts.fargs[1]
|
||||
RunDotnet("run", { "--project" }, opts.fargs[2], configuration)
|
||||
else
|
||||
configuration = opts.fargs[1]
|
||||
local pickers = require("telescope.pickers")
|
||||
local finders = require("telescope.finders")
|
||||
local conf = require("telescope.config").values
|
||||
local action_state = require("telescope.actions.state")
|
||||
local actions = require("telescope.actions")
|
||||
pickers
|
||||
.new({}, {
|
||||
prompt_title = "Projects",
|
||||
finder = finders.new_table({
|
||||
results = captureLoadedProjects(),
|
||||
}),
|
||||
sorter = conf.generic_sorter({}),
|
||||
attach_mappings = function(prompt_buf, _)
|
||||
actions.select_default:replace(function()
|
||||
actions.close(prompt_buf)
|
||||
local selection = action_state.get_selected_entry()
|
||||
RunDotnet("run", { "--project" }, selection.value, configuration)
|
||||
end)
|
||||
return true
|
||||
end,
|
||||
})
|
||||
:find()
|
||||
end
|
||||
end, { nargs = "*", complete = "file" })
|
||||
|
||||
vim.api.nvim_create_user_command("PublishFSharpProject", function(opts)
|
||||
if opts.fargs and opts.fargs[1] then
|
||||
RunDotnet("publish", {}, opts.fargs[1], "Release")
|
||||
else
|
||||
local pickers = require("telescope.pickers")
|
||||
local finders = require("telescope.finders")
|
||||
local conf = require("telescope.config").values
|
||||
local action_state = require("telescope.actions.state")
|
||||
local actions = require("telescope.actions")
|
||||
pickers
|
||||
.new({}, {
|
||||
prompt_title = "Projects",
|
||||
finder = finders.new_table({
|
||||
results = captureLoadedProjects(),
|
||||
}),
|
||||
sorter = conf.generic_sorter({}),
|
||||
attach_mappings = function(prompt_buf, _)
|
||||
actions.select_default:replace(function()
|
||||
actions.close(prompt_buf)
|
||||
local selection = action_state.get_selected_entry()
|
||||
RunDotnet("publish", {}, selection.value, "Release")
|
||||
end)
|
||||
return true
|
||||
end,
|
||||
})
|
||||
:find()
|
||||
end
|
||||
end, { nargs = "*", complete = "file" })
|
||||
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
pattern = "fsharp",
|
||||
callback = function()
|
||||
@@ -169,12 +225,21 @@ vim.api.nvim_create_autocmd("FileType", {
|
||||
if status then
|
||||
whichkey.register({
|
||||
f = {
|
||||
name = "F#",
|
||||
t = { ":call fsharp#showTooltip()<CR>", "Show F# Tooltip" },
|
||||
["si"] = { ":call fsharp#toggleFsi()<CR>", "Toggle FSI (F# Interactive)" },
|
||||
["sl"] = { ":call fsharp#sendLineToFsi()<cr>", "Send line to FSI (F# Interactive)" },
|
||||
},
|
||||
b = {
|
||||
r = {
|
||||
name = "Run F# project",
|
||||
d = { ":RunFSharpProject Debug", "Run F# project in debug configuration" },
|
||||
r = { ":RunFSharpProject Release", "Run F# project in release configuration" },
|
||||
},
|
||||
p = {
|
||||
":PublishFSharpProject",
|
||||
"Publish F# project",
|
||||
},
|
||||
b = {
|
||||
"Build F# project",
|
||||
a = { BuildFSharpProjects, "Build all projects" },
|
||||
s = { ":BuildFSharpProject", "Build specified project" },
|
||||
},
|
||||
@@ -184,7 +249,7 @@ vim.api.nvim_create_autocmd("FileType", {
|
||||
vim.api.nvim_set_keymap("n", "<localleader>ft", ":call fsharp#showTooltip()<CR>", { noremap = true })
|
||||
vim.api.nvim_set_keymap("n", "<localleader>fsi", ":call fsharp#toggleFsi()<CR>", { noremap = true })
|
||||
vim.api.nvim_set_keymap("n", "<localleader>fsl", ":call fsharp#sendLineToFsi()<CR>", { noremap = true })
|
||||
vim.api.nvim_set_keymap("n", "<localleader>bpa", BuildFSharpProjects, { noremap = true })
|
||||
vim.api.nvim_set_keymap("n", "<localleader>bpa", ":lua BuildFSharpProjects()", { noremap = true })
|
||||
vim.api.nvim_set_keymap("n", "<localleader>bps", ":BuildFSharpProject", { noremap = true })
|
||||
end
|
||||
end,
|
||||
|
Reference in New Issue
Block a user