Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Breakpoints and Stepping Widget?

edited September 14 in Questions Posts: 3

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!

Tagged:

Comments

  • Posts: 1,326

    @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.

  • AnatolyAnatoly Mod
    Posts: 851

    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.

  • dave1707dave1707 Mod
    Posts: 7,810

    @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
    
  • edited September 13 Posts: 3

    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
    
  • dave1707dave1707 Mod
    Posts: 7,810

    @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.

  • dave1707dave1707 Mod
    Posts: 7,810

    @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={}
    
  • AnatolyAnatoly Mod
    Posts: 851

    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.

  • dave1707dave1707 Mod
    Posts: 7,810

    @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.

  • AnatolyAnatoly Mod
    Posts: 851
    @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?
  • dave1707dave1707 Mod
    Posts: 7,810

    @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
    
Sign In or Register to comment.