initialize with first MVP

This commit is contained in:
2025-12-23 14:10:06 +01:00
commit 4de8921a42
14 changed files with 733 additions and 0 deletions

175
lua/test-samurai/core.lua Normal file
View File

@@ -0,0 +1,175 @@
local config = require("test-samurai.config")
local M = {}
local state = {
runners = {},
last_win = nil,
last_buf = nil,
}
local function load_runners()
state.runners = {}
local opts = config.get()
local mods = opts.runner_modules or {}
for _, mod in ipairs(mods) do
local ok, runner = pcall(require, mod)
if ok and type(runner) == "table" then
table.insert(state.runners, runner)
else
vim.notify("[test-samurai] Failed to load runner " .. mod, vim.log.levels.WARN)
end
end
end
function M.setup()
load_runners()
end
function M.reload_runners()
load_runners()
end
function M.get_runner_for_buf(bufnr)
for _, runner in ipairs(state.runners) do
if type(runner.is_test_file) == "function" then
local ok, is_test = pcall(runner.is_test_file, bufnr)
if ok and is_test then
return runner
end
end
end
return nil
end
local function open_float(lines)
if state.last_win and vim.api.nvim_win_is_valid(state.last_win) then
pcall(vim.api.nvim_win_close, state.last_win, true)
end
if state.last_buf and vim.api.nvim_buf_is_valid(state.last_buf) then
pcall(vim.api.nvim_buf_delete, state.last_buf, { force = true })
end
local width = math.floor(vim.o.columns * 0.8)
local height = math.floor(vim.o.lines * 0.8)
local row = math.floor((vim.o.lines - height) / 2)
local col = math.floor((vim.o.columns - width) / 2)
local buf = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_option(buf, "bufhidden", "wipe")
vim.api.nvim_buf_set_option(buf, "filetype", "test-samurai-output")
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
local win = vim.api.nvim_open_win(buf, true, {
relative = "editor",
width = width,
height = height,
row = row,
col = col,
style = "minimal",
border = "rounded",
})
vim.keymap.set("n", "<esc><esc>", function()
if vim.api.nvim_win_is_valid(win) then
vim.api.nvim_win_close(win, true)
end
end, { buffer = buf, nowait = true, silent = true })
state.last_win = win
state.last_buf = buf
end
local function run_cmd(cmd, cwd, on_exit)
if vim.system then
vim.system(cmd, { cwd = cwd, text = true }, function(obj)
local code = obj.code or -1
local stdout = obj.stdout or ""
local stderr = obj.stderr or ""
vim.schedule(function()
on_exit(code, stdout, stderr)
end)
end)
else
local stdout_chunks = {}
local stderr_chunks = {}
vim.fn.jobstart(cmd, {
cwd = cwd,
stdout_buffered = true,
stderr_buffered = true,
on_stdout = function(_, data)
if data then
table.insert(stdout_chunks, table.concat(data, "\n"))
end
end,
on_stderr = function(_, data)
if data then
table.insert(stderr_chunks, table.concat(data, "\n"))
end
end,
on_exit = function(_, code)
local stdout = table.concat(stdout_chunks, "\n")
local stderr = table.concat(stderr_chunks, "\n")
on_exit(code, stdout, stderr)
end,
})
end
end
function M.run_nearest()
local bufnr = vim.api.nvim_get_current_buf()
local pos = vim.api.nvim_win_get_cursor(0)
local row = pos[1] - 1
local col = pos[2]
local runner = M.get_runner_for_buf(bufnr)
if not runner then
vim.notify("[test-samurai] No runner for this file", vim.log.levels.WARN)
return
end
if type(runner.find_nearest) ~= "function" or type(runner.build_command) ~= "function" then
vim.notify("[test-samurai] Runner missing methods", vim.log.levels.ERROR)
return
end
local ok, spec_or_err = pcall(runner.find_nearest, bufnr, row, col)
if not ok or not spec_or_err then
local msg = "[test-samurai] No test found"
if type(spec_or_err) == "string" then
msg = "[test-samurai] " .. spec_or_err
end
vim.notify(msg, vim.log.levels.WARN)
return
end
local spec = spec_or_err
local ok_cmd, command = pcall(runner.build_command, spec)
if not ok_cmd or not command or type(command.cmd) ~= "table" or #command.cmd == 0 then
vim.notify("[test-samurai] Runner failed to build command", vim.log.levels.ERROR)
return
end
local cmd = command.cmd
local cwd = command.cwd or vim.loop.cwd()
run_cmd(cmd, cwd, function(code, stdout, stderr)
local header = "$ " .. table.concat(cmd, " ")
local lines = { header, "" }
if stdout ~= "" then
local out_lines = vim.split(stdout, "\n", { plain = true })
vim.list_extend(lines, out_lines)
end
if stderr ~= "" then
table.insert(lines, "")
table.insert(lines, "[stderr]")
local err_lines = vim.split(stderr, "\n", { plain = true })
vim.list_extend(lines, err_lines)
end
table.insert(lines, "")
table.insert(lines, "[exit code] " .. tostring(code))
open_float(lines)
end)
end
return M