Moved luadebug to the new structure as well
This commit is contained in:
103
debugger.lua
103
debugger.lua
@ -2,72 +2,113 @@ local core = require "core"
|
|||||||
|
|
||||||
---@class runner
|
---@class runner
|
||||||
local runner = {
|
local runner = {
|
||||||
new = function(self, o) end, ---@meta
|
new = function(self, o)
|
||||||
|
o = o or {}
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
return o
|
||||||
|
end,
|
||||||
|
|
||||||
|
caps = {
|
||||||
|
can_pause = false,
|
||||||
|
can_continue = false,
|
||||||
|
can_step_in = false,
|
||||||
|
can_step_over = false,
|
||||||
|
can_step_out = false,
|
||||||
|
can_breakpoints = false,
|
||||||
|
has_stack = false,
|
||||||
|
has_locals = false,
|
||||||
|
can_eval = false,
|
||||||
|
},
|
||||||
|
|
||||||
run = function(self, target, name) end, ---@meta
|
run = function(self, target, name) end, ---@meta
|
||||||
wait = function(sefl, time) end, ---@meta
|
pause = function(self) end, --@meta
|
||||||
|
continue = function(self) end, --@meta
|
||||||
|
step_in = function(self) end, --@meta
|
||||||
|
step_over = function(self) end, --@meta
|
||||||
|
step_out = function(self) end, --@meta
|
||||||
|
|
||||||
|
wait = function(self, time) end, ---@meta
|
||||||
kill = function(self) end, ---@meta
|
kill = function(self) end, ---@meta
|
||||||
terminate = function(self) end, ---@meta
|
terminate = function(self) end, ---@meta
|
||||||
|
|
||||||
|
-- Callbacks
|
||||||
|
log = function(msg) end, ---@meta
|
||||||
|
error = function(msg) end, ---@meta
|
||||||
|
on_stdout = function(msg) end, ---@meta
|
||||||
|
on_stderr = function(msg) end, ---@meta
|
||||||
|
on_exit = function(exitcode) end, ---@meta
|
||||||
|
on_state = function(state) end, ---@meta
|
||||||
|
on_break = function(file, line, reason) end, --@meta
|
||||||
|
on_stack = function(frames) end, ---@meta
|
||||||
|
on_locals = function(frame, vars) end, ---@meta
|
||||||
|
on_evaluated = function(expr, ok, value) end, ---@meta
|
||||||
}
|
}
|
||||||
|
|
||||||
local debugger = {}
|
local debugger = {
|
||||||
local debugwindow = nil ---@type JPDebugView
|
runner = runner, -- Set here as member to let runners extend this base class
|
||||||
local debugrunner = nil ---@type runner|nil
|
debugwindow = nil, ---@type JPDebugView
|
||||||
|
debugrunner = nil, ---@type runner|nil
|
||||||
|
}
|
||||||
|
|
||||||
function debugger.log(msg)
|
function debugger.log(msg)
|
||||||
core.log("[jpdebug][debugger] %s", msg)
|
core.log("[jpdebug][debugger] %s", msg)
|
||||||
if debugwindow then debugwindow:push("meta", "debugger] "..msg) end
|
if debugger.debugwindow then debugger.debugwindow:push("meta", "debugger] "..msg) end
|
||||||
end
|
end
|
||||||
|
|
||||||
function debugger.error(msg)
|
function debugger.error(msg)
|
||||||
core.error("[jpdebug][debugger]"..msg)
|
core.error("[jpdebug][debugger]"..msg)
|
||||||
if debugwindow then debugwindow:push("meta", "debugger] ERROR: "..msg) end
|
if debugger.debugwindow then debugger.debugwindow:push("meta", "debugger] ERROR: "..msg) end
|
||||||
end
|
end
|
||||||
|
|
||||||
function debugger.stdout(msg)
|
function debugger.on_stdout(msg)
|
||||||
if debugwindow then debugwindow:push("stdout", msg) end
|
if debugger.debugwindow then debugger.debugwindow:push("stdout", msg) end
|
||||||
end
|
end
|
||||||
|
|
||||||
function debugger.stderr(msg)
|
function debugger.on_stderr(msg)
|
||||||
if debugwindow then debugwindow:push("stderr", msg) end
|
if debugger.debugwindow then debugger.debugwindow:push("stderr", msg) end
|
||||||
end
|
end
|
||||||
|
|
||||||
function debugger.is_running()
|
function debugger.is_running()
|
||||||
return debugrunner~=nil
|
return debugger.debugrunner~=nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function debugger.run(target, name, r, view)
|
function debugger.run(target, name, r, view)
|
||||||
debugwindow = view
|
if debugger.debugrunner then
|
||||||
debugwindow:clear()
|
debugger.error("Already an active session")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
debugger.debugwindow = view
|
||||||
|
debugger.debugwindow:clear()
|
||||||
debugger.log(string.format("Running %s", name))
|
debugger.log(string.format("Running %s", name))
|
||||||
|
|
||||||
-- Create new runner object
|
-- Create new runner object
|
||||||
debugrunner = r:new({
|
debugger.debugrunner = r:new({
|
||||||
|
-- Set callbacks
|
||||||
log = debugger.log,
|
log = debugger.log,
|
||||||
error = debugger.error,
|
error = debugger.error,
|
||||||
stdout = debugger.stdout,
|
on_stdout = debugger.on_stdout,
|
||||||
stderr = debugger.stderr,
|
on_stderr = debugger.on_stderr,
|
||||||
exited = debugger.exited,
|
on_exit = debugger.on_exit,
|
||||||
})
|
})
|
||||||
-- And run
|
-- And run
|
||||||
debugrunner:run(target, name)
|
debugger.debugrunner:run(target, name)
|
||||||
end
|
end
|
||||||
|
|
||||||
function debugger.stop()
|
function debugger.stop()
|
||||||
if debugrunner then
|
if debugger.debugrunner then
|
||||||
debugrunner:kill()
|
debugger.debugrunner.on_exit = function() end
|
||||||
local exitcode = debugrunner:wait(1000)
|
debugger.debugrunner:kill()
|
||||||
|
local exitcode = debugger.debugrunner:wait(1000)
|
||||||
-- TODO terminate if needed
|
-- TODO terminate if needed
|
||||||
debugger.log(string.format("... Stoped: %d", exitcode))
|
debugger.log(string.format("... Stoped with exit code %d", exitcode))
|
||||||
end
|
end
|
||||||
debugrunner = nil
|
debugger.debugrunner = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function debugger.exited()
|
function debugger.on_exit(exitcode)
|
||||||
if debugrunner then
|
debugger.log(string.format("exit: %d", exitcode))
|
||||||
local exitcode = debugrunner:wait(process.WAIT_INFINITE)
|
debugger.debugrunner = nil
|
||||||
debugger.log(string.format("exit: %d", exitcode))
|
|
||||||
end
|
|
||||||
debugrunner = nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return debugger
|
return debugger
|
||||||
|
|||||||
5
init.lua
5
init.lua
@ -233,6 +233,11 @@ if required_toolbar_plugins and ToolbarView then
|
|||||||
else
|
else
|
||||||
table.insert(t, {symbol = "D", command = "jpdebug:stop"})
|
table.insert(t, {symbol = "D", command = "jpdebug:stop"})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if debugger.is_running() then
|
||||||
|
if debugger.debugrunner.caps.can_pause then table.insert(t, {symbol="C",command=""}) end
|
||||||
|
end
|
||||||
|
|
||||||
table.insert(t, {symbol = "E", command = "jpdebug:reload-runners"})
|
table.insert(t, {symbol = "E", command = "jpdebug:reload-runners"})
|
||||||
self.toolbar_commands = t
|
self.toolbar_commands = t
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,5 +1,12 @@
|
|||||||
local core = require "core"
|
local core = require "core"
|
||||||
local process = require "process"
|
local process = require "process"
|
||||||
|
local debugger = require "plugins.jpdebug.debugger"
|
||||||
|
|
||||||
|
---@class luadebug: runner
|
||||||
|
local luadebug = debugger.runner:new({
|
||||||
|
name = "luadebug",
|
||||||
|
proc = nil ---@type process|nil
|
||||||
|
})
|
||||||
|
|
||||||
-- tiny helpers
|
-- tiny helpers
|
||||||
local function dirname(p) return p:match("^(.*)[/\\]") or "" end
|
local function dirname(p) return p:match("^(.*)[/\\]") or "" end
|
||||||
@ -53,18 +60,44 @@ local function spawn_lua_process(entry, lua, cwd, env)
|
|||||||
return proc
|
return proc
|
||||||
end
|
end
|
||||||
|
|
||||||
---@class LDB
|
local function spawn_mdb_process(lua)
|
||||||
local LDB = {
|
local vendor_glob = join(get_plugin_root(), "vendor/?.lua")
|
||||||
name = "luadebug"
|
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, string.format([[
|
||||||
|
package.path = %q .. ";" .. package.path
|
||||||
|
require("mobdebug").listen()
|
||||||
|
]], vendor_glob))
|
||||||
|
local proc = process.start(cmd, {
|
||||||
|
stdout = process.REDIRECT_PIPE,
|
||||||
|
stderr = process.REDIRECT_PIPE,
|
||||||
|
})
|
||||||
|
return proc
|
||||||
|
end
|
||||||
|
|
||||||
---@param target table Target table
|
function luadebug:mdb_pump()
|
||||||
---@param name string Name of the target to run
|
while true do
|
||||||
---@praam debuginfo table Debugging information
|
core.redraw = true
|
||||||
---@return process|nil
|
coroutine.yield(0.016) -- 60FPS
|
||||||
function LDB:run(target, name, debuginfo)
|
local sout = self.mdb:read_stdout()
|
||||||
|
local serr = self.mdb:read_stderr()
|
||||||
|
if sout == nil and serr == nil then
|
||||||
|
-- mdb exited
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if sout and sout~="" then self.on_stdout("mdb>"..sout) end
|
||||||
|
if serr and serr~="" then self.on_stdout("mdb> ERROR: "..serr) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function luadebug:run(target, name)
|
||||||
if target.entry == nil then
|
if target.entry == nil then
|
||||||
core.error("[jpdebug][luadebug] target.entry is required")
|
self.error("target.entry is required for "..name)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local entry = target.entry
|
local entry = target.entry
|
||||||
@ -72,44 +105,70 @@ function LDB:run(target, name, debuginfo)
|
|||||||
local cwd = target.cwd or "."
|
local cwd = target.cwd or "."
|
||||||
local env = target.env or {}
|
local env = target.env or {}
|
||||||
|
|
||||||
|
-- spwawn the mobdebug process
|
||||||
|
self.mdb = spawn_mdb_process(lua)
|
||||||
|
local dbg = self
|
||||||
|
core.add_thread(function()
|
||||||
|
luadebug.mdb_pump(dbg)
|
||||||
|
end)
|
||||||
|
|
||||||
-- spawn the main lua process
|
-- spawn the main lua process
|
||||||
local proc = spawn_lua_process(entry, lua, cwd, env)
|
local proc = spawn_lua_process(entry, lua, cwd, env)
|
||||||
|
|
||||||
if proc == nil then
|
if proc == nil then
|
||||||
core.error("[jpdebug][luadebug] Failed to start "..entry)
|
self.error("Failed to start "..entry)
|
||||||
return nil
|
return
|
||||||
end
|
end
|
||||||
|
self.proc = proc
|
||||||
|
|
||||||
return {
|
-- output pump
|
||||||
luaproc=proc
|
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
|
||||||
|
local exitcode = self.proc:wait(process.WAIT_INFINITE)
|
||||||
|
self.on_exit(exitcode)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if sout and sout~="" then self.on_stdout(sout) end
|
||||||
|
if serr and serr~="" then self.on_stderr(serr) end
|
||||||
|
end
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Wait untill it ends, possibly with timeout
|
function luadebug:wait(time)
|
||||||
function LDB:wait(proc, time)
|
if not self.proc then return end
|
||||||
return proc.luaproc:wait(time)
|
return self.proc:wait(time)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Read the stdout, returns nil if process has stopped
|
function luadebug:read_stdout()
|
||||||
function LDB:read_stdout(proc)
|
if not self.proc then return end
|
||||||
local sl = proc.luaproc:read_stdout()
|
local sl = self.proc:read_stdout()
|
||||||
return sl
|
return sl
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Read the stderr
|
function luadebug:read_stderr()
|
||||||
function LDB:read_stderr(proc)
|
if not self.proc then return end
|
||||||
local sl = proc.luaproc:read_stderr()
|
local sl = self.proc:read_stderr()
|
||||||
return sl
|
return sl
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Kill the process
|
function luadebug:kill()
|
||||||
function LDB:kill(proc)
|
if self.mdb then
|
||||||
proc.luaproc:kill()
|
-- Execute ctrl-C twice to exit mobdebug
|
||||||
|
self.mdb:kill()
|
||||||
|
self.mdb:kill()
|
||||||
|
end
|
||||||
|
if not self.proc then return end
|
||||||
|
self.proc:kill()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Terminate the process
|
function luadebug:terminate()
|
||||||
function LDB:terminate(proc)
|
if not self.proc then return end
|
||||||
proc.luaproc:terminate()
|
self.proc:terminate()
|
||||||
end
|
end
|
||||||
|
|
||||||
return LDB
|
return luadebug
|
||||||
|
|
||||||
|
|||||||
@ -1,30 +1,12 @@
|
|||||||
local core = require "core"
|
local core = require "core"
|
||||||
local process = require "process"
|
local process = require "process"
|
||||||
|
local debugger = require "plugins.jpdebug.debugger"
|
||||||
|
|
||||||
---@class shell: runner
|
---@class shell: runner
|
||||||
local shell = {
|
local shell = debugger.runner:new({
|
||||||
name = "shell",
|
name = "shell",
|
||||||
proc = nil ---@type process|nil
|
proc = nil ---@type process|nil
|
||||||
}
|
})
|
||||||
|
|
||||||
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)
|
function shell:run(target, name)
|
||||||
local opts = {
|
local opts = {
|
||||||
@ -51,11 +33,12 @@ function shell:run(target, name)
|
|||||||
local sout = self.proc:read_stdout()
|
local sout = self.proc:read_stdout()
|
||||||
local serr = self.proc:read_stderr()
|
local serr = self.proc:read_stderr()
|
||||||
if sout == nil and serr == nil then
|
if sout == nil and serr == nil then
|
||||||
self.exited()
|
local exitcode = self.proc:wait(process.WAIT_INFINITE)
|
||||||
|
self.on_exit(exitcode)
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
if sout and sout~="" then self.stdout(sout) end
|
if sout and sout~="" then self.on_stdout(sout) end
|
||||||
if serr and serr~="" then self.stderr(serr) end
|
if serr and serr~="" then self.on_stderr(serr) end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user