Does anyone have a widget for creating breakpoints and stepping through code? I tried toffer’s utility but it depends on setfenv(), which is apparently no longer available.
This would be a fabulous feature to have in Codea 3.0!
Does anyone have a widget for creating breakpoints and stepping through code? I tried toffer’s utility but it depends on setfenv(), which is apparently no longer available.
This would be a fabulous feature to have in Codea 3.0!
@SolaFide - I agree, Lua does have some debug code which may be present but I don’t think is used. A breakpoint mechanism would be great for trapping errors mid run and stopping infinite loops. I think this is being considered at the moment.
For tracking loops, you can use the print(message)
feature. For break points there’s assert(false, message)
, but I remember I’ve talked to either Simeon or John, and a debugging feature is planned, not in the nearest future however.
@SolaFide As @Anatoly said, print statement can be use but you have to be careful where they’re placed. If they’re in a function that gets called frequently then your code will slow down and eventually crash and won’t be of any help. Another thing you can use is saveGlobalData(key,value). You can use different key values for different places in your code and save the value. After you stop your program or it crashes, you can use a separate program to read the different keys to see what the last values were. So far the print statements have worked for me.
@SolaFide setfenv is no longer an available global function, but you can implement your own.
-- https://leafo.net/guides/setfenv-in-lua52-and-above.html
local function setfenv(fn, env)
local i = 1
while true do
local name = debug.getupvalue(fn, i)
if name == "_ENV" then
debug.upvaluejoin(fn, i, (function()
return env
end), 1)
break
elseif not name then
break
end
i = i + 1
end
return fn
end
For variable tracking I created this class, VariTrack. I create a global instance and functions can post messages to it to be drawn every frame.
@HyroVitalyProtago At your suggestion, I tried defining setfenv() that way. However, the debug functions it references are not exposed either. Maybe I can track those down as well.
VariTrack = class()
function VariTrack:init()
self.messages = {}
end
function VariTrack:addMessage(str)
table.insert(self.messages, str)
end
function VariTrack:draw()
if #self.messages == 0 then
--self:addMessage("nada")
return
end
pushMatrix()
resetMatrix()
pushStyle()
textMode(CORNER)
fill(124, 39, 242, 255)
font("Didot-Bold")
fontSize(16)
for i, s in ipairs(self.messages) do
text(s, 40, 20 * i)
end
while #self.messages > 0 do
table.remove(self.messages)
end
popStyle()
popMatrix()
end
function VariTrack:touched(touch)
end
@SolaFide When you post code, put 3 ~ on a line before and after your code so it formats correctly. I added them to your code above.
@SolaFide Your while loop to clear the table can be replaced with just redefining the table.
Replace this
while #self.messages > 0 do
table.remove(self.messages)
end
with this
self.messages={}
But hey!
Since we’re talking about variable tracking, why has no one mentioned about parameters?
lua = 55
parameter.watch(‘ lua ’)
Pay attention, that’s ’lua’
, not just lua
.
@Anatoly parameter.watch doesn’t work in some situations. If you’re in a for loop, parameter.watch isn’t updated until the for loop is finished. And if you’re doing a lot of processing in the draw function, parameter.watch isn’t updated until the draw function finishes.
@dave1707 True. Didn’t thought of that situation. It’s possible however to create a temporary array x = {}
and to insert all he changes there, and then print them as one message.
This fixes both the time problem and the initial problem (debugging).
What do you think?
@Anatoly That’s what @SolaFide did in his VariTrack class above. He created a table self.messages that can be updated with VariTrack:addMessage and then displayed with VariTrack:draw(). For me, if done right, print statements gives enough information to figure out what’s going wrong.
@SolaFide Sorry, I wasn’t with my iPad, so, this is something that’s works for me :
local function findenv(f)
local level = 1
repeat
local name, value = debug.getupvalue(f, level)
if name == '_ENV' then
return level, value
end
level = level + 1
until name == nil
return nil
end
function getfenv(f)
return(select(2, findenv(f)) or _G)
end
function setfenv(f, t)
local level = findenv(f)
if level then
debug.setupvalue(f, level, t)
end
return f
end