Advertisement
Lion4ever

CC Ingame Debugger

Dec 3rd, 2015
676
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 19.97 KB | None | 0 0
  1. local lightweightBS = true --BS == back stepping
  2. local heavyweightBS = true
  3.  
  4. local dname = shell.getRunningProgram()
  5. local function loopComplete(a,b,sLine,sParts)
  6.   table.remove(sParts,1)
  7.   return shell.complete(table.concat(sParts," ").." "..sLine)
  8. end
  9. shell.setCompletionFunction(dname,loopComplete)
  10.  
  11. local breakpoints = {}
  12. local env = {}
  13. local locals = {}
  14. local paused = true
  15. local curScope = {vars={},pScope={vars={}}} --pScope == globals; set in errorLoopBack
  16. local dlevel
  17.  
  18. local history = {}
  19. local historyIndex = 1 --set in errorLoopBack
  20. local targetHistoryIndex
  21. local makeHistory = true
  22. local luaHistory = {}
  23.  
  24. local oldENV = _ENV
  25. local loadedDocs = {}
  26.  
  27. local nilTable = {} --used instead of nil; since nil removes table entries
  28. local unsetTable = {}
  29.  
  30. local debnumber = math.random(10000)
  31.  
  32. local lastIndexedH
  33. local lastFunctionCall
  34.  
  35. local meta = {}
  36. local submeta = {}
  37.  
  38. local rtf = {} --real to fake table map
  39. local ftr = {}
  40.  
  41. local wtu = {} -- wrapped to unwrapped function map
  42. local utw = {}
  43.  
  44. local args = {...}
  45. args[1] = shell.resolveProgram(args[1] or "")
  46. if #args == 0 then
  47.   print("Usage: ".. shell.getRunningProgram() .." <prog to debug> [params]")
  48.   return
  49. end
  50.  
  51. if not fs.exists(args[1]) then
  52.   print "File not found"
  53.   return
  54. end
  55.  
  56. if not multishell then
  57.   print [[F4 - Print variables set by prog
  58. F5 - step backwards
  59. F6 - step into (if theres own function)
  60. F7 - step over
  61. F8 - run until breakpoint
  62. F9 - toggle breakpoint (enter line num before)]]
  63. end
  64.  
  65. local function varsToString(t)
  66.   local r = ""
  67.   for i,j in oldENV.pairs(t or {}) do
  68.     r = r .. oldENV.tostring(i) .. ": "
  69.     if j == nilTable then
  70.       r = r .. "nil\n"
  71.     elseif oldENV.type(j) == "table" then
  72.       r = r .. oldENV.textutils.serialize(j) .. "\n"
  73.     else
  74.       r = r .. oldENV.tostring(j) .. "\n"
  75.     end
  76.   end
  77.   return r
  78. end
  79.  
  80. local function n() return true end
  81. local draw = n
  82. local undoers = {
  83.     [sleep]=n,
  84.     [print]=n,
  85.     [write]=n,
  86.     [read]=n,
  87.     [getfenv]=n,
  88.     [getmetatable]=n,
  89.     [pairs]=n,
  90.     [ipairs]=n,
  91.     [next]=n,
  92.     [tostring]=n,
  93.     [tonumber]=n}
  94.  
  95. do
  96.   local undots = {math,term,textutils,bit,string,table,vector}
  97.   for i,j in ipairs(undots) do
  98.     for k,l in pairs(j) do
  99.       if type(l) == "function" then
  100.         undoers[l] = n
  101.       end
  102.     end
  103.   end
  104. end
  105. if turtle then
  106.   undoers[turtle.forward] = turtle.back
  107.   undoers[turtle.back] = turtle.forward
  108.   undoers[turtle.turnLeft] = turtle.turnRight
  109.   undoers[turtle.turnRight] = turtle.turnLeft
  110.   undoers[turtle.up] = turtle.down
  111.   undoers[turtle.down] = turtle.up
  112.   undoers[turtle.getFuelLevel] = n
  113.   undoers[turtle.getItemCount] = n
  114.   undoers[turtle.getItemSpace] = n
  115.   undoers[turtle.inspect] = n
  116.   undoers[turtle.inspectUp] = n
  117.   undoers[turtle.inspectDown] = n
  118.   undoers[turtle.compare] = n
  119.   undoers[turtle.compareUp] = n
  120.   undoers[turtle.compareDown] = n
  121.   undoers[turtle.detect] = n
  122.   undoers[turtle.detectUp] = n
  123.   undoers[turtle.detectDown] = n
  124.   undoers[turtle.dig] = turtle.place
  125.   undoers[turtle.place] = turtle.dig
  126.   undoers[turtle.digUp] = turtle.placeUp
  127.   undoers[turtle.placeUp] = turtle.digUp
  128.   undoers[turtle.digDown] = turtle.placeDown
  129.   undoers[turtle.placeDown] = turtle.digDown
  130. end
  131.  
  132. function env._lbpcf() -- line breakpoint call function
  133.   local a,sLine = oldENV.pcall(oldENV.error,"",3)
  134.   if sLine:match("debugger:") then
  135.     a,sLine = oldENV.pcall(oldENV.error,"",4)
  136.   end
  137.   local docname,line = sLine:match("^(.-):(%d+):")
  138.   line = oldENV.tonumber(line)
  139.   local linesToRepeat = {}
  140.   local missedEvents = {}
  141.   repeat
  142.     if (not targetHistoryIndex or historyIndex >= targetHistoryIndex) and (paused and (not dlevel or dlevel == curScope) or breakpoints[line]) then
  143.       local bline = ""
  144.       targetHistoryIndex = nil
  145.       paused = true
  146.       while paused do
  147.         draw(docname,line)
  148.         local r = {oldENV.os.pullEvent()}
  149.         if r[1] == "key" or (r[1] == "debugger_key" and r[3] == debnumber) then
  150.           if r[2] == 62 then
  151.             local localsEnd = false
  152.             local output = "CurrentLine: "..line.."\nLocals:\n"
  153.             local inScope = curScope
  154.             while inScope.pScope do
  155.               output = output .. varsToString(inScope.vars)
  156.               if not localsEnd and inScope.func then
  157.                 output = output .. "Upvalues:\n"
  158.                 localsEnd = true
  159.               end
  160.               inScope = inScope.pScope
  161.             end
  162.             output = output .. "Globals:\n" .. varsToString(inScope.vars)
  163.             if history[historyIndex] and history[historyIndex].calls then
  164.               output = output .. "Function Calls:"
  165.               for i,j in oldENV.ipairs(history[historyIndex].calls) do
  166.                 output = output .."\n"..j[1]
  167.                 for k,l in oldENV.ipairs(j[3]) do
  168.                 output = output .." "..l
  169.                 end
  170.               end
  171.               output = output .. "\n"
  172.             end
  173.             oldENV.textutils.pagedPrint(output)
  174.           elseif r[2] == 63 and historyIndex > 1 then
  175.             local lastLine = line -1
  176.             local lastBlock = loadedDocs[docname].injec[lastLine]
  177.             while loadedDocs[docname].blockedLines[lastLine] do
  178.               lastLine=lastLine-1
  179.               lastBlock = loadedDocs[docname].injec[lastLine] .. lastBlock
  180.             end
  181.             local loadedBlock = oldENV.loadstring(lastBlock,"RepeatBlock")
  182.             local allReversable = true
  183.             if history[historyIndex] and history[historyIndex].calls then
  184.               for i=#history[historyIndex].calls,1,-1 do
  185.                 if not undoers[history[historyIndex].calls[i][2]] then
  186.                   allReversable = false
  187.                   break
  188.                 end
  189.               end
  190.               if allReversable then
  191.                 for i=#history[historyIndex].calls,1,-1 do
  192.                   local cl = history[historyIndex].calls[i]
  193.                   if cl[4][1] ~= false and not undoers[cl[2]](oldENV.unpack(cl,3)) then
  194.                     for j=i,#history[historyIndex].calls do
  195.                       local clj = history[historyIndex].calls[i]
  196.                       oldENV.pcall(clj[2],oldENV.unpack(clj,3))
  197.                     end
  198.                     allReversable = false
  199.                     break
  200.                   end
  201.                 end
  202.               end
  203.             end
  204.             if allReversable then
  205.               if lightweightBS and loadedBlock and not (history[historyIndex] and history[historyIndex].ownFuncCalled) then
  206.                 if history[historyIndex] and history[historyIndex].modifs then
  207.                   for t,j in oldENV.pairs(history[historyIndex].modifs) do
  208.                     for k,v in oldENV.pairs(j) do
  209.                       if v == unsetTable then
  210.                         t[k] = nil
  211.                       else
  212.                         t[k] = v
  213.                       end
  214.                     end
  215.                   end
  216.                 end
  217.                 oldENV.setfenv(loadedBlock,env)
  218.                 history[historyIndex] = {}
  219.                 historyIndex = historyIndex - 1
  220.                 lastIndexedH = nil
  221.                 linesToRepeat[#linesToRepeat+1] = loadedBlock
  222.                 line = lastLine
  223.               elseif heavyweightBS then
  224.                 oldENV.error("backstab",0)
  225.               end
  226.             end
  227.           elseif r[2] == 64 then
  228.             dlevel = nil
  229.             break
  230.           elseif r[2] == 65 then
  231.             dlevel = curScope
  232.             break
  233.           elseif r[2] == 66 then
  234.             paused = false
  235.             break
  236.           elseif r[2] == 67 then
  237.             local bp = oldENV.tonumber(bline)
  238.             if bp then
  239.               breakpoints[bp] = not breakpoints[bp]
  240.             end
  241.           elseif r[2] == 68 then
  242.             oldENV.write"lua> "
  243.             local s = oldENV.read(nil,luaHistory)
  244.             oldENV.table.insert(luaHistory,s)
  245.             local ok = oldENV.loadstring("return "..s)
  246.             if not ok then
  247.               ok = oldENV.loadstring(s)
  248.             end
  249.             if ok then
  250.               oldENV.setfenv(ok,env)
  251.               makeHistory = false
  252.               local r={oldENV.pcall(ok)}
  253.               makeHistory = true
  254.               oldENV.table.remove(r,1)
  255.               for i,j in oldENV.ipairs(r) do
  256.                 r[i] = oldENV.type(j) == "table" and oldENV.textutils.serialize(ftr[j]) or oldENV.tostring(j)
  257.               end
  258.               oldENV.print(oldENV.table.concat(r,", "))
  259.             else
  260.               oldENV.printError"Syntax error"
  261.             end
  262.           elseif r[2] >= 2 and r[2] <= 11 then
  263.             bline = bline .. oldENV.tostring(r[2]-1):sub(-1)
  264.           end
  265.         elseif r[1] ~= "char" then
  266.           oldENV.table.insert(missedEvents,r)
  267.         end
  268.       end
  269.     end
  270.     for i,j in oldENV.ipairs(missedEvents) do
  271.       oldENV.os.queueEvent(oldENV.unpack(j))
  272.     end
  273.     missedEvents = {}
  274.     a = true
  275.     historyIndex = historyIndex + 1
  276.     if #linesToRepeat > 0 then
  277.       oldENV.pcall(linesToRepeat[#linesToRepeat])
  278.       linesToRepeat[#linesToRepeat] = nil
  279.       line = line + 1
  280.       a=false
  281.     end
  282.   until #linesToRepeat == 0 and a
  283. end
  284.  
  285. function env._bscf(loop) --block start call function
  286.   curScope = {vars={},pScope=curScope,isLoop=loop}
  287. end
  288.  
  289. function env._becf(loop) --block end call function
  290.   while loop and not curScope.isLoop do
  291.     curScope = curScope.pScope
  292.   end
  293.   if not curScope.func then
  294.     curScope = curScope.pScope
  295.   end
  296. end
  297.  
  298. local function logChange(rt,k)
  299.   history[historyIndex] = history[historyIndex] or {}
  300.   history[historyIndex].modifs = history[historyIndex].modifs or {}
  301.   history[historyIndex].modifs[rt] = history[historyIndex].modifs[rt] or {}
  302.   if history[historyIndex].modifs[rt][k] == nil then
  303.     history[historyIndex].modifs[rt][k] = rt[k] or unsetTable
  304.   end
  305. end
  306.  
  307. function env._cnlv(decla) --create new local variable
  308.   for var in oldENV.string.gmatch(decla,"%w+") do
  309.     logChange(curScope.vars,var)
  310.     curScope.vars[var] = nilTable
  311.   end
  312. end
  313.  
  314.  
  315. local function protTable(t,k,isR)
  316.   local rt = isR and t or ftr[t]
  317.   local v = rt[k]
  318.   local tp = oldENV.type(v)
  319.   if tp == "table" then
  320.     if v == nilTable then return nil end
  321.     if not rtf[v] then
  322.       local fake = oldENV.setmetatable({},submeta)
  323.       rtf[v] = fake
  324.       ftr[fake] = v
  325.     end
  326.     return rtf[v]
  327.   elseif tp == "function" then
  328.     if not utw[v] then
  329.       local function wrappy(...) --wrapping for extern
  330.         if targetHistoryIndex then
  331.           if lastIndexedH ~= historyIndex then
  332.             lastFunctionCall = 0
  333.             lastIndexedH = historyIndex
  334.           end
  335.           lastFunctionCall = lastFunctionCall + 1
  336.           oldENV.assert(history[historyIndex] and history[historyIndex].calls and history[historyIndex].calls[lastFunctionCall],"Tried to call "..k.." at step "..historyIndex.. " call no "..lastFunctionCall)
  337.           oldENV.assert(k == history[historyIndex].calls[lastFunctionCall][1],"Wrong function was called")
  338.           return oldENV.unpack(history[historyIndex].calls[lastFunctionCall][4])
  339.         elseif makeHistory then
  340.           history[historyIndex] = history[historyIndex] or {}
  341.           history[historyIndex].calls = history[historyIndex].calls or {}
  342.           local callTable = {k,v,{...}}
  343.           oldENV.table.insert(history[historyIndex].calls,callTable)
  344.           local r =  {v(...)}
  345.           callTable[4] = r
  346.           return oldENV.unpack(r)
  347.         else
  348.           return v(...)
  349.         end
  350.       end
  351.       utw[v] = wrappy
  352.       wtu[wrappy] = v
  353.     end
  354.     return utw[v]
  355.   end
  356.   return v
  357. end
  358.  
  359. submeta.__index = protTable
  360.  
  361. local function recuMakeReal(t)
  362.   for i,j in oldENV.pairs(t) do
  363.     if oldENV.type(j) == "table" then
  364.       if ftr[j] then
  365.         t[i] = ftr[j]
  366.       else
  367.         recuMakeReal(j)
  368.       end
  369.     end
  370.   end
  371. end
  372.  
  373. local function newSubIndex(t,k,v,isR)
  374.   if oldENV.type(v) == "function" and not wtu[v] then
  375.     local fScope = curScope
  376.     local function wrappy(...)  --wrapping for intern
  377.       local prevScope = curScope
  378.       curScope = {vars={},pScope=fScope}
  379.       history[historyIndex] = history[historyIndex] or {}
  380.       history[historyIndex].ownFuncCalled = true
  381.       --[[history[historyIndex].calls = history[historyIndex].calls or {}
  382.       local callTable = {k,v,{...}}
  383.       oldENV.table.insert(history[historyIndex].calls,callTable)]]
  384.       local r =  {v(...)}
  385.       --callTable[4] = r
  386.       curScope = prevScope
  387.       return oldENV.unpack(r)
  388.     end
  389.     oldENV.setfenv(wrappy,env)
  390.     wtu[wrappy] = v
  391.     utw[v] = wrappy
  392.   elseif oldENV.type(v) == "table" then
  393.     recuMakeReal(v)
  394.   end
  395.   local rt= isR and t or ftr[t]
  396.   logChange(rt,k)
  397.   rt[k] = (v == nil and nilTable or ftr[v] or v)
  398. end
  399. submeta.__newindex = newSubIndex
  400.  
  401. local metamethods = {"add","sub","mul","div","mod","pow","concat","eq","lt","le"}
  402. for i,j in ipairs(metamethods) do
  403.   local name = "__"..j
  404.   submeta[name] = function(a,b)
  405.     local ra = ftr[a]
  406.     local rb = ftr[b] or b
  407.     local mt = getmetatable(ra)
  408.     if mt then
  409.       return mt[name](ra,rb)
  410.     end
  411.   end
  412. end
  413.  
  414. function submeta.__call(a,...)
  415.   return ftr[a](...)
  416. end
  417. function submeta.__unm(a) --__len replacement
  418.   return #ftr[a]
  419. end
  420. function submeta.__len(a)
  421.   return #ftr[a]
  422. end
  423.  
  424. function meta.__index(t,k)
  425.   local inScope = curScope
  426.   while inScope.vars do
  427.     if inScope.vars[k] then
  428.       if inScope.vars[k] == nilTable then
  429.         return nil
  430.       end
  431.       return protTable(inScope.vars,k,true)
  432.     end
  433.     inScope = inScope.pScope or {}
  434.   end
  435.   return protTable(oldENV,k,true)
  436. end
  437.  
  438. function meta.__newindex(t,k,v)
  439.   local inScope = curScope
  440.   while inScope.pScope and inScope.vars[k] == nil do
  441.     inScope = inScope.pScope
  442.   end
  443.   newSubIndex(inScope.vars,k,v,true)
  444. end
  445.  
  446. function env.next(t,v)
  447.   if ftr[t] then
  448.     local k,o = oldENV.next(ftr[t],v)
  449.     if k == nil then return nil end
  450.     return k,protTable(t,k)
  451.   else
  452.     return oldENV.next(t,v)
  453.   end
  454. end
  455.  
  456. function env.pairs(t)
  457.   return env.next,t
  458. end
  459.  
  460. function env.__inext(t,v)
  461.   if ftr[t] then
  462.     local k,o = oldENV.__inext(ftr[t],v)
  463.     if k == nil then return nil end
  464.     return k,protTable(t,k)
  465.   else
  466.     return oldENV.__inext(t,v)
  467.   end
  468. end
  469.  
  470. function env.ipairs(t)
  471.   return env.__inext,t,0
  472. end
  473.  
  474. local spat = "(%s)"
  475. local epat = ""
  476. local patterns = {"then",
  477.                   "do",
  478.                   "repeat",
  479.                   "end",
  480.                   "until",
  481.                   "else",
  482.                   "elseif",
  483.                   "break(%s-) _becf%(%)",
  484.                   "return(.-) _becf%(%)",
  485.                   spat.."function(%s*)(%w+)(%s*)%(",
  486.                   spat.."local([ \t,%w]-)=",
  487.                   "local([ \t,%w]+)",
  488.                   "#"}
  489. local replaces = {"%1then _bscf();%2",
  490.                   "%1do _bscf(true);%2",
  491.                   "%1repeat _bscf(true)%2",
  492.                   "%1 _becf() end%2",
  493.                   "%1 _becf() until%2",
  494.                   "%1 _becf() else _bscf();%2",
  495.                   "%1 _becf() elseif%2",
  496.                   "%1break%2%3",
  497.                   "%1return%2%3",
  498.                   "%1%2%3 = function%4(",
  499.                   "%1_cnlv(\"%2\");%2=",
  500.                   "%1_cnlv(\"%2\");%3",
  501.                   "-"}
  502. local notSPats = {[10]=true,[11]=true,[13]=true}
  503.  
  504. function env.loadstring(s,name)
  505.   local ok,err = oldENV.loadstring(s,name)
  506.   if not ok then
  507.       return ok,err
  508.   end
  509.   local doc = s:sub(-1)~="\n" and s.."\n" or s
  510.   loadedDocs[name] = {orig={},injec={}}
  511.   local hasBreakReturn
  512.   for line in doc:gmatch("(.-)\n") do
  513.     oldENV.table.insert(loadedDocs[name].orig,line)
  514.   end
  515.   doc = " "..doc
  516.   for i,j in oldENV.ipairs(patterns) do
  517.     if notSPats[i] then
  518.       doc = doc:gsub(j,replaces[i])
  519.     else
  520.       doc = doc:gsub(spat..j..spat,replaces[i])
  521.     end
  522.   end
  523.   for line in doc:gmatch("(.-)\n") do
  524.     oldENV.table.insert(loadedDocs[name].injec,line)
  525.   end
  526.   assert(#loadedDocs[name].orig == #loadedDocs[name].injec, "Modification line numbers invalid")
  527.   local blockedLines = {}
  528.   repeat
  529.     local prog = ""
  530.     for i,j in oldENV.ipairs(loadedDocs[name].injec) do
  531.       if not blockedLines[i] then
  532.         prog = prog .."_lbpcf();"
  533.       end
  534.       prog = prog ..j .. "\n"
  535.     end
  536.     ok,err = oldENV.loadstring(prog,name)
  537.     local fh = fs.open(".crash","w")
  538.     fh.write(prog)
  539.     fh.close()
  540.     if not ok then
  541.       local ln = err:match(".-:.-:.-:(%d+):")
  542.       if ln and oldENV.tonumber(ln) and not blockedLines[oldENV.tonumber(ln)] then
  543.         blockedLines[oldENV.tonumber(ln)] = true
  544.       else
  545.         return false,"Debugger failed: "..err
  546.       end
  547.     end
  548.   until ok
  549.   loadedDocs[name].blockedLines = blockedLines
  550.   return ok,err
  551. end
  552. setmetatable(env,meta)
  553.  
  554. local fh = fs.open(args[1],"r")
  555. local fcont = fh.readAll()
  556. fh.close()
  557. local tok,terr = env.loadstring(fcont,args[1])
  558. if tok then
  559.   local function errorLoopBack(...)
  560.     local fin,err
  561.     repeat
  562.       historyIndex = 1
  563.       curScope = {vars={},pScope={vars={}}}
  564.       fin,err = oldENV.pcall(tok,...)
  565.       if not fin then
  566.         history[historyIndex] = nil
  567.         targetHistoryIndex = historyIndex - 1
  568.         paused = true
  569.         lastIndexedH = nil
  570.         if err ~= "backstab" then
  571.           oldENV.printError(err)
  572.         end
  573.       end
  574.     until fin or err == "Terminated"
  575.     return fin,err
  576.   end
  577.   setfenv(tok,env)
  578.   if multishell then
  579.     _G.mainF ={errorLoopBack,unpack(args,2)}
  580.     local fh = fs.open(".temp","w")
  581.     fh.write([[local a,b = pcall(unpack(_G.mainF))
  582. if not a then printError(b) end
  583. os.queueEvent("debugger_end",]]..debnumber..")")
  584.     fh.close()
  585.     local x,y = term.getSize()
  586.     local buttons = {"<-","->","O>","B>","SB"}
  587.     local t = term.current()
  588.     local topLine = 1
  589.     draw = function(name,line)
  590.       topLine = line-(line-1)%(y-1)
  591.       for i=0,y-1 do
  592.         t.setCursorPos(1,i+1)
  593.         t.blit(oldENV.string.format("%3d",(topLine+i)%1000),line - topLine == i and "aaa" or "fff", breakpoints[topLine+i] and "eee" or "444")
  594.         assert(loadedDocs[name],"No Doc: "..name)
  595.         t.write(((loadedDocs[name].orig[topLine+i] or "").. oldENV.string.rep(" ",x-17)):sub(1,x-17))
  596.       end
  597.       for i=1,#buttons do
  598.         t.setCursorPos(x-13,i*2-1)
  599.         t.blit(buttons[i],"11","44")
  600.       end
  601.       local i = 1
  602.       local inScope = curScope
  603.       local key,value
  604.       while i < y do
  605.         t.setCursorPos(x-11,i)
  606.         if inScope then
  607.           repeat
  608.             key,value = oldENV.next(inScope.vars,key)
  609.             if key == nil then
  610.               inScope = inScope.pScope
  611.             end
  612.           until key ~= nil or not inScope
  613.         end
  614.         i=i+1
  615.         if key ~= nil and inScope then
  616.           t.write((oldENV.tostring(key).."="..oldENV.tostring(value).."           "):sub(1,12))
  617.         else
  618.           t.write"            "
  619.         end
  620.       end
  621.     end
  622.     term.clear()
  623.     shell.openTab(".temp")
  624.     multishell.setTitle(multishell.getCount(),string.match(args[1],"(%a+)$") or "Unnamed")
  625.     local event
  626.     repeat
  627.       event = {os.pullEvent()}
  628.       if event[1] == "key" and event[2] >= 62 and event[2] <= 68 then
  629.         os.queueEvent("debugger_key",event[2],debnumber)
  630.       end
  631.       if event[1] == "key" and event[2] == 64 then
  632.         paused = true
  633.         dlevel = nil
  634.       end
  635.       if event[1] == "mouse_click" and event[2] == 1 then
  636.         if (event[3] == x-13 or event[3] == x-12) and event[4] % 2 == 1 then
  637.           os.queueEvent("debugger_key",62.5+event[4]/2,debnumber)
  638.         end
  639.         if event[3] <= 3 then
  640.           local clicked = topLine+event[4]-1
  641.           breakpoints[clicked] = not breakpoints[clicked]
  642.           os.queueEvent("update_draw")
  643.         end
  644.       end
  645.      
  646.     until event[1] == "debugger_end" and event[2] == debnumber
  647.     term.clear()
  648.     term.setCursorPos(1,1)
  649.   else
  650.     local ok,rerr = pcall(errorLoopBack,unpack(args,2))
  651.     if not ok then
  652.       print("Crashed:")
  653.       print(rerr)
  654.     end
  655.   end
  656. else
  657.   print(terr)
  658. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement