mirror of
https://github.com/Smaug123/nix-dotfiles
synced 2025-10-05 14:48:38 +00:00
Commonise floating-window logic (#41)
This commit is contained in:
@@ -262,7 +262,7 @@
|
||||
vimdiffAlias = true;
|
||||
withPython3 = true;
|
||||
|
||||
extraLuaConfig = builtins.replaceStrings ["%PYTHONENV%"] ["${pythonEnv}"] (builtins.readFile ./nvim/init.lua);
|
||||
extraLuaConfig = builtins.readFile ./nvim/build-utils.lua + "\n" + builtins.replaceStrings ["%PYTHONENV%"] ["${pythonEnv}"] (builtins.readFile ./nvim/init.lua);
|
||||
|
||||
package = nixpkgs.neovim-nightly;
|
||||
};
|
||||
|
110
home-manager/nvim/build-utils.lua
Normal file
110
home-manager/nvim/build-utils.lua
Normal file
@@ -0,0 +1,110 @@
|
||||
BuildUtils = {}
|
||||
|
||||
-- Create a new buffer and a new floating window to hold that buffer.
|
||||
local function create_floating_window()
|
||||
-- Create a new buffer for build output
|
||||
local buf = vim.api.nvim_create_buf(false, true) -- No listed, scratch buffer
|
||||
|
||||
-- Calculate window size and position here (example: full width, 10 lines high at the bottom)
|
||||
local width = vim.api.nvim_get_option_value("columns", {})
|
||||
local height = vim.api.nvim_get_option_value("lines", {})
|
||||
local win_height = math.min(10, math.floor(height * 0.2)) -- 20% of total height or 10 lines
|
||||
local win_opts = {
|
||||
relative = "editor",
|
||||
width = width,
|
||||
height = win_height,
|
||||
col = 0,
|
||||
row = height - win_height,
|
||||
style = "minimal",
|
||||
border = "single",
|
||||
}
|
||||
|
||||
local win = vim.api.nvim_open_win(buf, false, win_opts)
|
||||
|
||||
return { window = win, buffer = buf }
|
||||
end
|
||||
|
||||
local function _on_output(context, is_stdout, err, data, on_line)
|
||||
local prefix
|
||||
if is_stdout then
|
||||
prefix = "OUT"
|
||||
else
|
||||
prefix = "ERR"
|
||||
end
|
||||
if err or data then
|
||||
vim.schedule(function()
|
||||
if err then
|
||||
-- Append the error message to the buffer
|
||||
local count = vim.api.nvim_buf_line_count(context.buffer)
|
||||
vim.api.nvim_buf_set_lines(context.buffer, count, count, false, { "error " .. prefix .. ": " .. err })
|
||||
end
|
||||
if data then
|
||||
-- Append the data to the buffer
|
||||
local count = vim.api.nvim_buf_line_count(context.buffer)
|
||||
vim.api.nvim_buf_set_lines(
|
||||
context.buffer,
|
||||
count,
|
||||
count,
|
||||
false,
|
||||
vim.tbl_map(function(line)
|
||||
return prefix .. ": " .. line
|
||||
end, vim.split(data, "\n"))
|
||||
)
|
||||
end
|
||||
if vim.api.nvim_win_is_valid(context.window) then
|
||||
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
|
||||
local new_line_count = vim.api.nvim_buf_line_count(context.buffer)
|
||||
vim.api.nvim_win_set_cursor(context.window, { new_line_count, 0 })
|
||||
end
|
||||
end
|
||||
|
||||
on_line(data, is_stdout, context)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- Arguments:
|
||||
-- * exe, a string (no need to escape this)
|
||||
-- * args, a table like { "-m", "venv", vim.fn.shellescape(some_path) }
|
||||
-- * description of this process, visible to the user, e.g. "venv creation"
|
||||
-- * context, the result of `create_floating_window`
|
||||
-- * on_line, a function which takes "the string written", (true if stdout else false), and the context table; should return nothing. We'll call that on every line of stdout and stderr.
|
||||
-- * on_complete, takes `context`, `code` (exit code) and `signal` ("documented" with neovim's uv.spawn, hah)
|
||||
local function run_external(exe, args, description, context, on_line, on_complete)
|
||||
local handle
|
||||
local stdout = vim.uv.new_pipe(false)
|
||||
local stderr = vim.uv.new_pipe(false)
|
||||
handle, _ = vim.uv.spawn(
|
||||
exe,
|
||||
{
|
||||
args = args,
|
||||
stdio = { nil, stdout, stderr },
|
||||
},
|
||||
vim.schedule_wrap(function(code, signal)
|
||||
stdout:read_stop()
|
||||
stderr:read_stop()
|
||||
stdout:close()
|
||||
stderr:close()
|
||||
handle:close()
|
||||
print("External process " .. description .. " completed, exit code " .. code .. " and signal " .. signal)
|
||||
on_complete(context, code, signal)
|
||||
end)
|
||||
)
|
||||
|
||||
if not handle then
|
||||
print("Failed to start " .. description .. " process.")
|
||||
return
|
||||
end
|
||||
|
||||
vim.uv.read_start(stdout, function(err, data)
|
||||
_on_output(context, true, err, data, on_line)
|
||||
end)
|
||||
vim.uv.read_start(stderr, function(err, data)
|
||||
_on_output(context, false, err, data, on_line)
|
||||
end)
|
||||
end
|
||||
|
||||
BuildUtils.create_window = create_floating_window
|
||||
BuildUtils.run = run_external
|
@@ -21,46 +21,48 @@ end
|
||||
|
||||
-- Supply nil to get all loaded F# projects and build them.
|
||||
local function BuildFSharpProjects(projects)
|
||||
local function on_output(context, prefix, err, data)
|
||||
if err or data then
|
||||
vim.schedule(function()
|
||||
if err then
|
||||
-- Append the error message to the buffer
|
||||
local count = vim.api.nvim_buf_line_count(context.buf)
|
||||
vim.api.nvim_buf_set_lines(context.buf, count, count, false, { "error " .. prefix .. ": " .. err })
|
||||
end
|
||||
if data then
|
||||
-- Append the data to the buffer
|
||||
local count = vim.api.nvim_buf_line_count(context.buf)
|
||||
vim.api.nvim_buf_set_lines(
|
||||
context.buf,
|
||||
count,
|
||||
count,
|
||||
false,
|
||||
vim.tbl_map(function(line)
|
||||
return prefix .. ": " .. line
|
||||
end, vim.split(data, "\n"))
|
||||
)
|
||||
end
|
||||
if vim.api.nvim_win_is_valid(context.window) then
|
||||
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
|
||||
local new_line_count = vim.api.nvim_buf_line_count(context.buf)
|
||||
vim.api.nvim_win_set_cursor(context.window, { new_line_count, 0 })
|
||||
end
|
||||
end
|
||||
-- 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_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 on_complete
|
||||
local function spawn_next(context)
|
||||
BuildUtils.run(
|
||||
"dotnet",
|
||||
{ "build", context.projects[context.completed + 1] },
|
||||
"dotnet build",
|
||||
context,
|
||||
on_line,
|
||||
on_complete
|
||||
)
|
||||
end
|
||||
|
||||
on_complete = function(context, code, signal)
|
||||
print("Build process exited with code " .. code .. " and signal " .. signal)
|
||||
if code ~= 0 then
|
||||
context.errs = context.errs + 1
|
||||
end
|
||||
context.completed = context.completed + 1
|
||||
|
||||
print(
|
||||
"Completed: "
|
||||
.. context.completed
|
||||
.. " out of "
|
||||
.. context.expected
|
||||
.. " (errors: "
|
||||
.. context.errs
|
||||
.. ", warnings: "
|
||||
.. context.warn
|
||||
.. ")"
|
||||
)
|
||||
|
||||
if context.completed == context.expected then
|
||||
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.buf then
|
||||
@@ -69,55 +71,7 @@ local function BuildFSharpProjects(projects)
|
||||
print("All builds successful")
|
||||
end
|
||||
else
|
||||
local handle
|
||||
local stdout = vim.uv.new_pipe(false)
|
||||
local stderr = vim.uv.new_pipe(false)
|
||||
|
||||
handle, _ = vim.uv.spawn(
|
||||
"dotnet",
|
||||
{
|
||||
args = { "build", context.projects[context.completed + 1] },
|
||||
stdio = { nil, stdout, stderr },
|
||||
},
|
||||
vim.schedule_wrap(function(code, signal)
|
||||
stdout:read_stop()
|
||||
stderr:read_stop()
|
||||
stdout:close()
|
||||
stderr:close()
|
||||
handle:close()
|
||||
print("Build process exited with code " .. code .. " and signal " .. signal)
|
||||
if code ~= 0 then
|
||||
context.errs = context.errs + 1
|
||||
end
|
||||
context.completed = context.completed + 1
|
||||
|
||||
print(
|
||||
"Completed: "
|
||||
.. context.completed
|
||||
.. " out of "
|
||||
.. context.expected
|
||||
.. " (errors: "
|
||||
.. context.errs
|
||||
.. ", warnings: "
|
||||
.. context.warn
|
||||
.. ")"
|
||||
)
|
||||
|
||||
spawn_next(context)
|
||||
end)
|
||||
)
|
||||
|
||||
if not handle then
|
||||
print("Failed to start build process.")
|
||||
return
|
||||
end
|
||||
|
||||
vim.uv.read_start(stdout, function(err, data)
|
||||
on_output(context, "OUT", err, data)
|
||||
end)
|
||||
vim.uv.read_start(stderr, function(err, data)
|
||||
on_output(context, "ERR", err, data)
|
||||
end)
|
||||
spawn_next(context)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -129,40 +83,14 @@ local function BuildFSharpProjects(projects)
|
||||
for _, _ in ipairs(projects) do
|
||||
total_projects = total_projects + 1
|
||||
end
|
||||
local context = BuildUtils.create_window()
|
||||
context.warn = 0
|
||||
context.errs = 0
|
||||
context.completed = 0
|
||||
context.expected = total_projects
|
||||
context.projects = projects
|
||||
|
||||
-- Create a new buffer for build output
|
||||
local buf = vim.api.nvim_create_buf(false, true) -- No listed, scratch buffer
|
||||
|
||||
-- Calculate window size and position here (example: full width, 10 lines high at the bottom)
|
||||
local width = vim.api.nvim_get_option_value("columns", {})
|
||||
local height = vim.api.nvim_get_option_value("lines", {})
|
||||
local win_height = math.min(10, math.floor(height * 0.2)) -- 20% of total height or 10 lines
|
||||
local original_win = vim.api.nvim_get_current_win()
|
||||
local win_opts = {
|
||||
relative = "editor",
|
||||
width = width,
|
||||
height = win_height,
|
||||
col = 0,
|
||||
row = height - win_height,
|
||||
style = "minimal",
|
||||
border = "single",
|
||||
}
|
||||
|
||||
local win = vim.api.nvim_open_win(buf, true, win_opts)
|
||||
-- Switch back to the original window
|
||||
vim.api.nvim_set_current_win(original_win)
|
||||
|
||||
local build_context = {
|
||||
warn = 0,
|
||||
errs = 0,
|
||||
completed = 0,
|
||||
expected = total_projects,
|
||||
window = win,
|
||||
projects = projects,
|
||||
buf = buf,
|
||||
}
|
||||
|
||||
spawn_next(build_context)
|
||||
spawn_next(context)
|
||||
end
|
||||
end
|
||||
|
||||
|
@@ -65,108 +65,17 @@ function CreateVenv()
|
||||
-- Install requirements
|
||||
if requirements_path then
|
||||
print("Installing requirements from " .. requirements_path)
|
||||
local handle
|
||||
local stdout = vim.uv.new_pipe(false)
|
||||
local stderr = vim.uv.new_pipe(false)
|
||||
|
||||
local function on_output(context, prefix, err, data)
|
||||
if err or data then
|
||||
vim.schedule(function()
|
||||
if err then
|
||||
-- Append the error message to the buffer
|
||||
local count = vim.api.nvim_buf_line_count(context.buf)
|
||||
vim.api.nvim_buf_set_lines(
|
||||
context.buf,
|
||||
count,
|
||||
count,
|
||||
false,
|
||||
{ "error " .. prefix .. ": " .. err }
|
||||
)
|
||||
end
|
||||
if data then
|
||||
-- Append the data to the buffer
|
||||
local count = vim.api.nvim_buf_line_count(context.buf)
|
||||
vim.api.nvim_buf_set_lines(
|
||||
context.buf,
|
||||
count,
|
||||
count,
|
||||
false,
|
||||
vim.tbl_map(function(line)
|
||||
return prefix .. ": " .. line
|
||||
end, vim.split(data, "\n"))
|
||||
)
|
||||
end
|
||||
if vim.api.nvim_win_is_valid(context.window) then
|
||||
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
|
||||
local new_line_count = vim.api.nvim_buf_line_count(context.buf)
|
||||
vim.api.nvim_win_set_cursor(context.window, { new_line_count, 0 })
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO: commonise wth what's in ionide-vim
|
||||
|
||||
-- Create a new buffer for build output
|
||||
local buf = vim.api.nvim_create_buf(false, true) -- No listed, scratch buffer
|
||||
|
||||
-- Calculate window size and position here (example: full width, 10 lines high at the bottom)
|
||||
local width = vim.api.nvim_get_option_value("columns", {})
|
||||
local height = vim.api.nvim_get_option_value("lines", {})
|
||||
local win_height = math.min(10, math.floor(height * 0.2)) -- 20% of total height or 10 lines
|
||||
local original_win = vim.api.nvim_get_current_win()
|
||||
local win_opts = {
|
||||
relative = "editor",
|
||||
width = width,
|
||||
height = win_height,
|
||||
col = 0,
|
||||
row = height - win_height,
|
||||
style = "minimal",
|
||||
border = "single",
|
||||
}
|
||||
|
||||
local win = vim.api.nvim_open_win(buf, true, win_opts)
|
||||
-- Switch back to the original window
|
||||
vim.api.nvim_set_current_win(original_win)
|
||||
|
||||
local context = {
|
||||
window = win,
|
||||
buf = buf,
|
||||
}
|
||||
|
||||
handle, _ = vim.uv.spawn(
|
||||
-- TODO: do we need to escape this? Don't know whether spawn goes via a shell
|
||||
local context = BuildUtils.create_window()
|
||||
BuildUtils.run(
|
||||
venv_dir .. "/bin/python",
|
||||
{
|
||||
-- TODO: and do we need to escape this?
|
||||
args = { "-m", "pip", "install", "-r", requirements_path },
|
||||
stdio = { nil, stdout, stderr },
|
||||
},
|
||||
vim.schedule_wrap(function(code, signal)
|
||||
stdout:read_stop()
|
||||
stderr:read_stop()
|
||||
stdout:close()
|
||||
stderr:close()
|
||||
handle:close()
|
||||
print("Venv creation completed, exit code " .. code .. " and signal " .. signal)
|
||||
{ "-m", "pip", "install", "-r", requirements_path },
|
||||
"venv creation",
|
||||
context,
|
||||
function(_, _, _) end,
|
||||
function(_, _, _)
|
||||
load_venv(venv_dir)
|
||||
end)
|
||||
end
|
||||
)
|
||||
|
||||
if not handle then
|
||||
print("Failed to start venv install process.")
|
||||
return
|
||||
end
|
||||
|
||||
vim.uv.read_start(stdout, function(err, data)
|
||||
on_output(context, "OUT", err, data)
|
||||
end)
|
||||
vim.uv.read_start(stderr, function(err, data)
|
||||
on_output(context, "ERR", err, data)
|
||||
end)
|
||||
else
|
||||
load_venv(venv_dir)
|
||||
end
|
||||
|
Reference in New Issue
Block a user