local core = require "core" local process = require "process" -- tiny helpers local function dirname(p) return p:match("^(.*)[/\\]") or "" end local function join(a, b) return (a:sub(-1) == "/" and a or (a .. "/")) .. b end -- returns absolute path to the plugin root (…/jpdebug) local function get_plugin_root() -- debug.getinfo(1, "S").source gives "@/full/path/to/this/file.lua" local src = debug.getinfo(1, "S").source if src:sub(1, 1) == "@" then src = src:sub(2) end local here = dirname(src) -- …/jpdebug/runners return dirname(here) -- …/jpdebug end -- Main lua process spawner local function spawn_lua_process(entry, lua, cwd, env) local host = "localhost" local port = 8172 -- Resolve vendor/?.lua so "require('mobdebug')" finds the bundled file local vendor_glob = join(get_plugin_root(), "vendor/?.lua") -- Build the inline lua launcher local dbg_call = string.format([[ local ok, m = pcall(require, "mobdebug"); if ok then print("Connecting to "..%q..":"..tostring(%d)) local connected = m.start(%q, %d) end ]], host, port, host, port) local launcher = string.format([[ package.path = %q .. ";" .. package.path %s dofile(%q) ]], vendor_glob, dbg_call, entry) -- Spawn the process local cmd = {} if type(lua) == "table" then for i=1, #lua do table.insert(cmd, lua[i]) end else table.insert(cmd, lua) end table.insert(cmd, "-e") table.insert(cmd, launcher) local proc = process.start(cmd, { cwd = cwd, env = env, stdout = process.REDIRECT_PIPE, stderr = process.REDIRECT_PIPE, }) return proc end ---@class LDB local LDB = { name = "luadebug" } ---@param target table Target table ---@param name string Name of the target to run ---@praam debuginfo table Debugging information ---@return process|nil function LDB:run(target, name, debuginfo) if target.entry == nil then core.error("[jpdebug][luadebug] target.entry is required") return end local entry = target.entry local lua = target.lua or "lua" local cwd = target.cwd or "." local env = target.env or {} -- spawn the main lua process local proc = spawn_lua_process(entry, lua, cwd, env) if proc == nil then core.error("[jpdebug][luadebug] Failed to start "..entry) return nil end return { luaproc=proc } end -- Wait untill it ends, possibly with timeout function LDB:wait(proc, time) return proc.luaproc:wait(time) end -- Read the stdout, returns nil if process has stopped function LDB:read_stdout(proc) local sl = proc.luaproc:read_stdout() return sl end -- Read the stderr function LDB:read_stderr(proc) local sl = proc.luaproc:read_stderr() return sl end -- Kill the process function LDB:kill(proc) proc.luaproc:kill() end -- Terminate the process function LDB:terminate(proc) proc.luaproc:terminate() end return LDB