Added separate debugger file and fixed shell to new form

This commit is contained in:
2025-10-25 20:07:49 +02:00
parent f6c031849f
commit abedca2394
4 changed files with 148 additions and 110 deletions

73
debugger.lua Normal file
View File

@ -0,0 +1,73 @@
local core = require "core"
---@class runner
local runner = {
new = function(self, o) end, ---@meta
run = function(self, target, name) end, ---@meta
wait = function(sefl, time) end, ---@meta
kill = function(self) end, ---@meta
terminate = function(self) end, ---@meta
}
local debugger = {}
local debugwindow = nil ---@type JPDebugView
local debugrunner = nil ---@type runner|nil
function debugger.log(msg)
core.log("[jpdebug][debugger] %s", msg)
if debugwindow then debugwindow:push("meta", "debugger] "..msg) end
end
function debugger.error(msg)
core.error("[jpdebug][debugger]"..msg)
if debugwindow then debugwindow:push("meta", "debugger] ERROR: "..msg) end
end
function debugger.stdout(msg)
if debugwindow then debugwindow:push("stdout", msg) end
end
function debugger.stderr(msg)
if debugwindow then debugwindow:push("stderr", msg) end
end
function debugger.is_running()
return debugrunner~=nil
end
function debugger.run(target, name, r, view)
debugwindow = view
debugwindow:clear()
debugger.log(string.format("Running %s", name))
-- Create new runner object
debugrunner = r:new({
log = debugger.log,
error = debugger.error,
stdout = debugger.stdout,
stderr = debugger.stderr,
exited = debugger.exited,
})
-- And run
debugrunner:run(target, name)
end
function debugger.stop()
if debugrunner then
debugrunner:kill()
local exitcode = debugrunner:wait(1000)
-- TODO terminate if needed
debugger.log(string.format("... Stoped: %d", exitcode))
end
debugrunner = nil
end
function debugger.exited()
if debugrunner then
local exitcode = debugrunner:wait(process.WAIT_INFINITE)
debugger.log(string.format("exit: %d", exitcode))
end
debugrunner = nil
end
return debugger

View File

@ -8,6 +8,8 @@ local config = require "core.config"
local TreeView = require "plugins.treeview"
local ToolbarView = require "plugins.toolbarview"
local debugger = require "plugins.jpdebug.debugger"
core.jpdebug = core.jpdebug or {}
-- Global list of all the runners
@ -19,10 +21,6 @@ local active_view = nil
-- The selected target
local selected_target = nil
-- The running system
local running_proc = nil
local running_runner = nil
-- Table containing all debug information (like breakpoints)
local debug_info = {}
@ -156,12 +154,7 @@ end
-- ---------- run target & pipe stdout/stderr into the view ----------
local function run_target(target, name)
-- Check if something is alredy running
if running_proc then
core.error("[jpdebug] Already a runner active")
return
end
-- Create/get view to push text to
-- TODO fix this, it throws a node is locked error once in a while
local view = nil
if active_view then
@ -177,53 +170,16 @@ local function run_target(target, name)
-- Check if we have a runner
for runner_name,runner in pairs(core.jpdebug.runners) do
if runner_name == target.type then
-- Found a runner
running_proc = runner:run(target, name, debug_info)
running_runner = runner
if running_proc == nil then
core.error("[jpdebug] Could not run the target")
view:push("stderr", "Could not run the target")
return
end
view:clear()
-- background pump (non-blocking I/O)
core.add_thread(function()
while true do
core.redraw = true
coroutine.yield(0.016) -- ~60fps
if running_proc == nil then
return
end
local out = runner:read_stdout(running_proc)
if out == nil then
-- stdout pipe closed: try drain stderr and break when both closed
local err = runner:read_stderr(running_proc)
if err ~= nil and err ~= "" then view:push("stderr", err) end
break
end
if out ~= "" then view:push("stdout", out) end
local err = runner:read_stderr(running_proc)
if err ~= nil and err ~= "" then view:push("stderr", err) end
end
if running_proc then
local code = runner:wait(running_proc, process.WAIT_INFINITE)
view:push("stdout", ("\n[exit] code=%s\n"):format(tostring(code)))
end
running_proc = nil
running_runner = nil
end)
debugger.run(target, name, runner, view)
return view
end
end
-- No suitable runners found
core.error("[jpdebug] No suitable runners found for target %s", name)
view:push("stderr", "No suitable runners found for target "..name)
debugger.error(string.format("No suitable runners found for target %s", name))
end
-- ---------- Reload a module on the go ------------------------------
local function hot_require(name, into)
-- blow away the cached module
package.loaded[name] = nil
@ -243,7 +199,11 @@ local function hot_require(name, into)
end
end
-- Load the runners table on the go
local function load_runners()
-- TODO Remove: reload debugger as well here
debugger = hot_require("plugins.jpdebug.debugger", core.jpdebug.debugger)
local runner_shell = hot_require("plugins.jpdebug.runners.shell", core.jpdebug.runners.shell)
local runner_luadebug = hot_require("plugins.jpdebug.runners.luadebug", core.jpdebug.runners.luadebug)
core.jpdebug.runners[runner_shell.name] = runner_shell
@ -268,7 +228,7 @@ if required_toolbar_plugins and ToolbarView then
local t = {
{symbol = "A", command = "jpdebug:set-target"},
}
if running_proc == nil then
if not debugger.is_running() then
table.insert(t, {symbol = "B", command = "jpdebug:run"})
else
table.insert(t, {symbol = "D", command = "jpdebug:stop"})
@ -311,16 +271,7 @@ command.add(nil, {
end,
["jpdebug:stop"] = function()
core.log(dump(running_proc))
if running_runner then
running_runner:kill(running_proc)
end
core.log("[jpdebug] Stopped runner")
if active_view then
active_view:push("stdout", " ... Stopped")
end
running_proc = nil
running_runner = nil
debugger.stop()
end,
-- The set target command

View File

@ -18,7 +18,6 @@ end
local function spawn_lua_process(entry, lua, cwd, env)
local host = "localhost"
local port = 8172
local nowait = false
-- Resolve vendor/?.lua so "require('mobdebug')" finds the bundled file
local vendor_glob = join(get_plugin_root(), "vendor/?.lua")
@ -28,9 +27,8 @@ local function spawn_lua_process(entry, lua, cwd, env)
local ok, m = pcall(require, "mobdebug"); if ok then
print("Connecting to "..%q..":"..tostring(%d))
local connected = m.start(%q, %d)
if not connected and %s then m.off() end
end
]], host, port, host, port, nowait and "true" or "false")
]], host, port, host, port)
local launcher = string.format([[
package.path = %q .. ";" .. package.path
%s
@ -74,8 +72,6 @@ function LDB:run(target, name, debuginfo)
local cwd = target.cwd or "."
local env = target.env or {}
-- TODO spawn the mobdebugger
-- spawn the main lua process
local proc = spawn_lua_process(entry, lua, cwd, env)
@ -85,7 +81,7 @@ function LDB:run(target, name, debuginfo)
end
return {
luaproc=proc,
luaproc=proc
}
end
@ -96,12 +92,14 @@ end
-- Read the stdout, returns nil if process has stopped
function LDB:read_stdout(proc)
return proc.luaproc:read_stdout()
local sl = proc.luaproc:read_stdout()
return sl
end
-- Read the stderr
function LDB:read_stderr(proc)
return proc.luaproc:read_stderr()
local sl = proc.luaproc:read_stderr()
return sl
end
-- Kill the process

View File

@ -1,19 +1,32 @@
local core = require "core"
local process = require "process"
---@class M
local M = {
name = "shell"
---@class shell: runner
local shell = {
name = "shell",
proc = nil ---@type process|nil
}
-- Run a shell command
---@param target table Target table
---@param name string Name of the target to run
---@praam debuginfo table Debugging information
---@return process|nil
---@diagnostic disable-next-line: unused-local
function M:run(target, name, debuginfo)
core.log("[jpdebug] Running shell command")
function shell:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
---@meta
function shell.log(msg) end
---@meta
function shell.error(msg) end
---@meta
function shell.stdout(msg) end
---@meta
function shell.stderr(msg) end
---@meta
function shell.exited() end
function shell:run(target, name)
local opts = {
cwd = target.cwd or ".",
env = target.env or {},
@ -21,43 +34,46 @@ function M:run(target, name, debuginfo)
stderr = process.REDIRECT_PIPE
}
if target.cmd then
local proc = process.start(target.cmd, opts)
return proc
self.proc = process.start(target.cmd, opts)
if not self.proc then
self.error("Could not start process...")
return
end
else
core.error("[jpdebug] command not specified for target %s", name)
end
self.error(string.format("command not specified for target %s", name))
end
-- Wait untill it ends, possibly with timeout
---@param proc process Process object
---@param time any Time field, process.WAIT_INFINITE
function M:wait(proc, time)
return proc:wait(time)
-- output pump
core.add_thread(function()
while true do
core.redraw = true
coroutine.yield(0.016) -- 60FPS
local sout = self.proc:read_stdout()
local serr = self.proc:read_stderr()
if sout == nil and serr == nil then
self.exited()
break
end
if sout and sout~="" then self.stdout(sout) end
if serr and serr~="" then self.stderr(serr) end
end
end)
end
-- Read the stdout, returns nil if process has stopped
---@param proc process Process object
function M:read_stdout(proc)
return proc:read_stdout()
function shell:wait(time)
if not self.proc then return end
return self.proc:wait(time)
end
-- Read the stderr
---@param proc process Process object
function M:read_stderr(proc)
return proc:read_stderr()
function shell:kill()
if not self.proc then return end
self.proc:kill()
end
-- Kill the process
---@param proc process Process object
function M:kill(proc)
proc:kill()
function shell:terminate()
if not self.proc then return end
self.proc:terminate()
end
-- Terminate the process
---@param proc process Process object
function M:terminate(proc)
proc:terminate()
end
return M
return shell