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