Files
reperl.nvim/lua/repl_plugin/runner.lua
Icy Avocado 73cba30662 [INIT]
2026-01-22 11:17:53 -07:00

138 lines
4.3 KiB
Lua

local M = {}
local fn = vim.fn
local api = vim.api
local function get_buf_name(repo_base)
return "REPL Output: " .. (repo_base or "repl")
end
local function find_or_create_buffer(name)
-- search for existing buffer with this name in the buffer list
for _, bufnr in ipairs(api.nvim_list_bufs()) do
if api.nvim_buf_get_name(bufnr) == name then
return bufnr
end
end
-- create new buffer
local bufnr = api.nvim_create_buf(false, true) -- listed=false, scratch
api.nvim_buf_set_name(bufnr, name)
api.nvim_buf_set_option(bufnr, 'buftype', 'nofile')
api.nvim_buf_set_option(bufnr, 'bufhidden', 'hide')
api.nvim_buf_set_option(bufnr, 'swapfile', false)
return bufnr
end
local function append_lines_to_buf(bufnr, lines)
if not bufnr or not api.nvim_buf_is_valid(bufnr) then return end
api.nvim_buf_set_option(bufnr, 'modifiable', true)
local current_lines = api.nvim_buf_get_lines(bufnr, 0, -1, false)
local start = #current_lines
api.nvim_buf_set_lines(bufnr, start, start, false, lines)
api.nvim_buf_set_option(bufnr, 'modifiable', false)
end
-- run perl file asynchronously and stream to output buffer
-- opts: { repo_base = 'name', open_split = true }
function M.run_perl(repl_file, opts)
opts = opts or {}
local target = opts.output_target or 'buffer'
local repo_base = opts.repo_base or fn.fnamemodify(repl_file, ':h:t')
if target == 'file' then
-- write output to file under repl_repo_path if provided, else next to repl_file
local out_path = opts.out_file or (opts.repl_repo_path and (opts.repl_repo_path .. '/repl_output.log')) or (fn.tempname() .. '_repl_output.log')
-- clear/initialize file
local f = io.open(out_path, 'w')
if f then f:write('-- REPL Run: ' .. os.date('%Y-%m-%d %H:%M:%S') .. '\n') f:close() end
local function append_lines_to_file(path, lines)
local fh, err = io.open(path, 'a')
if not fh then return end
for _, l in ipairs(lines) do fh:write(l .. '\n') end
fh:close()
end
local function on_stdout(data)
if data then append_lines_to_file(out_path, data) end
end
local function on_stderr(data)
if data then append_lines_to_file(out_path, data) end
end
local function on_exit(code)
append_lines_to_file(out_path, {'-- REPL exited with code: ' .. tostring(code)})
end
local abs_repl = fn.fnamemodify(repl_file, ':p')
local cmd = {'perl', abs_repl}
fn.jobstart(cmd, {
stdout_buffered = true,
stderr_buffered = true,
on_stdout = vim.schedule_wrap(function(_, data, _)
on_stdout(data)
end),
on_stderr = vim.schedule_wrap(function(_, data, _)
on_stderr(data)
end),
on_exit = vim.schedule_wrap(function(_, code, _)
on_exit(code)
end),
})
return out_path
end
-- default buffer target
local bufname = get_buf_name(repo_base)
local bufnr = find_or_create_buffer(bufname)
-- clear buffer
api.nvim_buf_set_option(bufnr, 'modifiable', true)
api.nvim_buf_set_lines(bufnr, 0, -1, false, {"-- REPL Run: " .. os.date('%Y-%m-%d %H:%M:%S')})
api.nvim_buf_set_option(bufnr, 'modifiable', false)
-- open split to show buffer
if opts.open_split ~= false then
api.nvim_command('belowright split ' .. fn.shellescape(bufname))
local win = api.nvim_get_current_win()
api.nvim_win_set_buf(win, bufnr)
end
local stdout_acc = {}
local stderr_acc = {}
local function on_stdout(data)
if data then
append_lines_to_buf(bufnr, data)
for _, l in ipairs(data) do table.insert(stdout_acc, l) end
end
end
local function on_stderr(data)
if data then
append_lines_to_buf(bufnr, data)
for _, l in ipairs(data) do table.insert(stderr_acc, l) end
end
end
local function on_exit(code)
append_lines_to_buf(bufnr, {"-- REPL exited with code: " .. tostring(code)})
api.nvim_buf_set_option(bufnr, 'modifiable', false)
end
-- spawn via jobstart
local cmd = {'perl', repl_file}
fn.jobstart(cmd, {
stdout_buffered = true,
stderr_buffered = true,
on_stdout = vim.schedule_wrap(function(_, data, _)
on_stdout(data)
end),
on_stderr = vim.schedule_wrap(function(_, data, _)
on_stderr(data)
end),
on_exit = vim.schedule_wrap(function(_, code, _)
on_exit(code)
end),
})
end
return M