mdb runner/parser WIP
Do I continue like this? or just integrate the mdb runner itself into luadebug?
This commit is contained in:
19
debugger.lua
19
debugger.lua
@ -49,6 +49,7 @@ local debugger = {
|
|||||||
runner = runner, -- Set here as member to let runners extend this base class
|
runner = runner, -- Set here as member to let runners extend this base class
|
||||||
debugwindow = nil, ---@type JPDebugView
|
debugwindow = nil, ---@type JPDebugView
|
||||||
debugrunner = nil, ---@type runner|nil
|
debugrunner = nil, ---@type runner|nil
|
||||||
|
state = "idle",
|
||||||
}
|
}
|
||||||
|
|
||||||
function debugger.log(msg)
|
function debugger.log(msg)
|
||||||
@ -73,9 +74,18 @@ function debugger.is_running()
|
|||||||
return debugger.debugrunner~=nil
|
return debugger.debugrunner~=nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function debugger.on_state(state)
|
||||||
|
debugger.log(string.format("state %s -> %s", debugger.state, state))
|
||||||
|
debugger.state = state
|
||||||
|
end
|
||||||
|
|
||||||
function debugger.run(target, name, r, view)
|
function debugger.run(target, name, r, view)
|
||||||
if debugger.debugrunner then
|
if debugger.debugrunner then
|
||||||
debugger.error("Already an active session")
|
if debugger.state == "paused" then
|
||||||
|
debugger.debugrunner:continue()
|
||||||
|
else
|
||||||
|
debugger.error("Already an active session")
|
||||||
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
debugger.debugwindow = view
|
debugger.debugwindow = view
|
||||||
@ -90,6 +100,11 @@ function debugger.run(target, name, r, view)
|
|||||||
on_stdout = debugger.on_stdout,
|
on_stdout = debugger.on_stdout,
|
||||||
on_stderr = debugger.on_stderr,
|
on_stderr = debugger.on_stderr,
|
||||||
on_exit = debugger.on_exit,
|
on_exit = debugger.on_exit,
|
||||||
|
on_state = debugger.on_state,
|
||||||
|
|
||||||
|
on_break = function(file, line, reason)
|
||||||
|
debugger.log(string.format("breakpoint hit: %s:%d", file, line))
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
-- And run
|
-- And run
|
||||||
debugger.debugrunner:run(target, name)
|
debugger.debugrunner:run(target, name)
|
||||||
@ -104,11 +119,13 @@ function debugger.stop()
|
|||||||
debugger.log(string.format("... Stoped with exit code %d", exitcode))
|
debugger.log(string.format("... Stoped with exit code %d", exitcode))
|
||||||
end
|
end
|
||||||
debugger.debugrunner = nil
|
debugger.debugrunner = nil
|
||||||
|
debugger.on_state('idle')
|
||||||
end
|
end
|
||||||
|
|
||||||
function debugger.on_exit(exitcode)
|
function debugger.on_exit(exitcode)
|
||||||
debugger.log(string.format("exit: %d", exitcode))
|
debugger.log(string.format("exit: %d", exitcode))
|
||||||
debugger.debugrunner = nil
|
debugger.debugrunner = nil
|
||||||
|
debugger.on_state('idle')
|
||||||
end
|
end
|
||||||
|
|
||||||
return debugger
|
return debugger
|
||||||
|
|||||||
@ -2,6 +2,10 @@ local core = require "core"
|
|||||||
local process = require "process"
|
local process = require "process"
|
||||||
local debugger = require "plugins.jpdebug.debugger"
|
local debugger = require "plugins.jpdebug.debugger"
|
||||||
|
|
||||||
|
-- Enable hot reloading of mdb
|
||||||
|
package.loaded["plugins.jpdebug.runners.luadebug.mdb"] = nil
|
||||||
|
local mdb = require "plugins.jpdebug.runners.luadebug.mdb"
|
||||||
|
|
||||||
---@class luadebug: runner
|
---@class luadebug: runner
|
||||||
local luadebug = debugger.runner:new({
|
local luadebug = debugger.runner:new({
|
||||||
name = "luadebug",
|
name = "luadebug",
|
||||||
@ -60,41 +64,6 @@ local function spawn_lua_process(entry, lua, cwd, env)
|
|||||||
return proc
|
return proc
|
||||||
end
|
end
|
||||||
|
|
||||||
local function spawn_mdb_process(lua)
|
|
||||||
local vendor_glob = join(get_plugin_root(), "vendor/?.lua")
|
|
||||||
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
|
|
||||||
|
|
||||||
function luadebug:mdb_pump()
|
|
||||||
while true do
|
|
||||||
core.redraw = true
|
|
||||||
coroutine.yield(0.016) -- 60FPS
|
|
||||||
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)
|
function luadebug:run(target, name)
|
||||||
if target.entry == nil then
|
if target.entry == nil then
|
||||||
self.error("target.entry is required for "..name)
|
self.error("target.entry is required for "..name)
|
||||||
@ -106,11 +75,22 @@ function luadebug:run(target, name)
|
|||||||
local env = target.env or {}
|
local env = target.env or {}
|
||||||
|
|
||||||
-- spwawn the mobdebug process
|
-- spwawn the mobdebug process
|
||||||
self.mdb = spawn_mdb_process(lua)
|
self.mdb = mdb:new({
|
||||||
local dbg = self
|
log = self.log,
|
||||||
core.add_thread(function()
|
error = self.error,
|
||||||
luadebug.mdb_pump(dbg)
|
|
||||||
end)
|
on_connected = function()
|
||||||
|
self.on_state('running')
|
||||||
|
self.mdb:setb('test.lua', 6)
|
||||||
|
self.mdb:run()
|
||||||
|
end,
|
||||||
|
on_pause = function(file, line)
|
||||||
|
self.on_state('paused')
|
||||||
|
self.on_break(file, line, "breakpoint")
|
||||||
|
end,
|
||||||
|
|
||||||
|
})
|
||||||
|
self.mdb:spawn(lua, get_plugin_root())
|
||||||
|
|
||||||
-- 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)
|
||||||
@ -120,6 +100,8 @@ function luadebug:run(target, name)
|
|||||||
end
|
end
|
||||||
self.proc = proc
|
self.proc = proc
|
||||||
|
|
||||||
|
self.on_state('connecting')
|
||||||
|
|
||||||
-- output pump
|
-- output pump
|
||||||
core.add_thread(function()
|
core.add_thread(function()
|
||||||
while true do
|
while true do
|
||||||
@ -138,6 +120,11 @@ function luadebug:run(target, name)
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function luadebug:continue()
|
||||||
|
if not self.proc then return end
|
||||||
|
self.mdb:run()
|
||||||
|
end
|
||||||
|
|
||||||
function luadebug:wait(time)
|
function luadebug:wait(time)
|
||||||
if not self.proc then return end
|
if not self.proc then return end
|
||||||
return self.proc:wait(time)
|
return self.proc:wait(time)
|
||||||
@ -156,11 +143,7 @@ function luadebug:read_stderr()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function luadebug:kill()
|
function luadebug:kill()
|
||||||
if self.mdb then
|
if self.mdb then self.mdb:kill() end
|
||||||
-- Execute ctrl-C twice to exit mobdebug
|
|
||||||
self.mdb:kill()
|
|
||||||
self.mdb:kill()
|
|
||||||
end
|
|
||||||
if not self.proc then return end
|
if not self.proc then return end
|
||||||
self.proc:kill()
|
self.proc:kill()
|
||||||
end
|
end
|
||||||
120
runners/luadebug/mdb.lua
Normal file
120
runners/luadebug/mdb.lua
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
local core = require "core"
|
||||||
|
local process = require "process"
|
||||||
|
|
||||||
|
-- tiny helpers
|
||||||
|
local function join(a, b) return (a:sub(-1) == "/" and a or (a .. "/")) .. b end
|
||||||
|
|
||||||
|
---@class mdb
|
||||||
|
local mdb = {
|
||||||
|
proc = nil, ---@type process|nil
|
||||||
|
state = 'idle',
|
||||||
|
}
|
||||||
|
|
||||||
|
---@meta
|
||||||
|
function mdb.log(msg) end
|
||||||
|
---@meta
|
||||||
|
function mdb.error(msg) end
|
||||||
|
---@meta
|
||||||
|
function mdb.on_connected() end
|
||||||
|
---@meta
|
||||||
|
function mdb.on_pause(file, line) end
|
||||||
|
|
||||||
|
function mdb:new(o)
|
||||||
|
o = o or {}
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
|
||||||
|
function mdb:set_state(newstate)
|
||||||
|
self.state = newstate
|
||||||
|
end
|
||||||
|
|
||||||
|
function mdb:parse_line(line)
|
||||||
|
self.log('mdb> '..line)
|
||||||
|
local words = {}
|
||||||
|
for w in line:gmatch("%w+") do table.insert(words, w) end
|
||||||
|
|
||||||
|
if words[1] == 'Paused' then
|
||||||
|
-- Breakpoint hit
|
||||||
|
if #words ~= 7 then return end
|
||||||
|
local file = words[4]
|
||||||
|
local linenr = tonumber(words[7])
|
||||||
|
self:set_state("paused")
|
||||||
|
core.add_thread(function() self.on_pause(file, linenr) end)
|
||||||
|
elseif words[1] == "Type" then
|
||||||
|
-- mobdebug started
|
||||||
|
self:set_state("paused")
|
||||||
|
core.add_thread(function() self.on_connected() end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mdb:spawn(lua, root)
|
||||||
|
local vendor_glob = join(root, "vendor/?.lua")
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
self:set_state('spawning')
|
||||||
|
|
||||||
|
local proc = process.start(cmd, {
|
||||||
|
stdout = process.REDIRECT_PIPE,
|
||||||
|
stderr = process.REDIRECT_PIPE,
|
||||||
|
})
|
||||||
|
self.proc = proc
|
||||||
|
|
||||||
|
self:set_state('connecting')
|
||||||
|
|
||||||
|
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
|
||||||
|
-- mdb exited
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if sout and sout~="" then
|
||||||
|
for l in string.gmatch(sout, "([^\n]+)") do
|
||||||
|
self:parse_line(l)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mdb:cmd(c)
|
||||||
|
-- commands are only possible when mdb is paused
|
||||||
|
if self.state == "paused" then
|
||||||
|
self.log('>>>'..c)
|
||||||
|
self.proc:write(c..'\n')
|
||||||
|
else
|
||||||
|
self.error('mdb not paused')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mdb:run()
|
||||||
|
self:cmd("run")
|
||||||
|
end
|
||||||
|
|
||||||
|
function mdb:setb(file, line)
|
||||||
|
self:cmd(string.format("setb %s %d", file, line))
|
||||||
|
end
|
||||||
|
|
||||||
|
function mdb:kill()
|
||||||
|
self.proc:kill()
|
||||||
|
self.proc:kill()
|
||||||
|
end
|
||||||
|
|
||||||
|
return mdb
|
||||||
|
|
||||||
@ -25,6 +25,8 @@ function shell:run(target, name)
|
|||||||
self.error(string.format("command not specified for target %s", name))
|
self.error(string.format("command not specified for target %s", name))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self.on_state('running')
|
||||||
|
|
||||||
-- output pump
|
-- output pump
|
||||||
core.add_thread(function()
|
core.add_thread(function()
|
||||||
while true do
|
while true do
|
||||||
|
|||||||
Reference in New Issue
Block a user