138 lines
4.3 KiB
Lua
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
|