Debugging and live coding with Corona SDK

Corona SDK is a mobile application development framework that supports Lua scripting. While the integration and debugging of Corona applications has been available in ZeroBrane Studio since v0.34, starting from v0.35, ZeroBrane Studio also provides live coding. The video below demonstrates how you can use debugging and live coding with Corona applications (you may need to switch the video to 720p to make the text more readable):

The first thing you need to do is to open main.lua file from the project you want to work with (you can do this by using File | Open...) and then set the project directory to the directory with your main.lua file. You can do this by going to Project | Project Directory | Choose...
or using Project | Project Directory | Set From Current File.

To enable the integration shown in the demo, you need to select Corona as an interpreter in ZeroBrane Studio by going to Program | Lua Interpreters | Corona. If you installed Corona in the default location on OSX (/Applications/CoronaSDK) or on Windows (C:\Program Files\Corona Labs\Corona SDK or D:\Program Files\Corona Labs\Corona SDK), it will be found and used by the IDE.

After this is done, you can use Project | Run command to run the application. If there is a problem with finding the Corona simulator, you will see an error message in the Output window.

Enabling debugging

Add require("mobdebug").start() line to your main.lua script. This will allow you to use Project | Start Debugging to debug your application.

Debugger functions

The debugger in the IDE provides access to all debugging functions you would expect: breakpoints, stepping in/over/out, the stack view (to access a stack trace and all local/upvalue values, including complex ones), the watch view (to evaluate arbitrary expressions), and the console (to run code fragments and modify values in your application while it is suspended in the debugger). Some additional details are available in the Getting Started section of the documentation.

If you don't set a breakpoint before you start debugging your application, you can go to Project | Break (or use the toolbar button) to pause your application and inspect its state and set breakpoints you need. If the exact location where the application is stopped cannot be determined (as it may be inside the Corona engine itself), you may see a message Debugging suspended at =?:0 (couldn't activate the file). in the Output window. The application is indeed suspended and after you are done inspecting it and changing breakpoints, you can continue its execution by going to Project | Continue.

There is one more thing that is worth mentioning. The Corona SDK engine seems to include a check that automatically restarts your application when it detects that the application is "stalled". This is exactly what happens when the application is being debugged as it passes the control back to the IDE (even though for a short time), so it may look like the application is started twice (if you put a breakpoint in your main script). To avoid this effect, you can start debugging inside enterFrame event handler, which I'm going to demonstrate in the next section.

Live coding

Live coding allows you to make changes to your application and immediately see the effect of those changes (as you saw in the demo). This is enabled by going to Project | Run as Scratchpad, but before showing you the code, it may be useful to review how live coding works with ZeroBrane Studio. When a change is detected in the IDE, three things have to happen:

1. The currently executed application is suspended or aborted (this is configurable, but for Corona interpreter the application is suspended).
2. The new code is being executed in the environment of your application, thus making effective all changes to global variables and functions.
3. The application is then continued from the same point where it's suspended.

These aspects are important, because you may need to apply small changes to your code to make it "live coding" friendly. For example, a usual way to registering an event handler is this (assuming onUpdate is the event handler function):

Runtime:addEventListener("enterFrame", onUpdate)

However, if you modify this function while running as scratchpad, nothing visible happens. As you may guess, when you register an event listener, the engine stores a reference to the onUpdate function and any change to the function doesn't invalidate the reference. You may remove and re-add the event listener, but there is a simpler way: we can wrap a call to onUpdate into an anonymous function, thus allowing us make changes to onUpdate that the engine will see:

Runtime:addEventListener("enterFrame", function(event) pcall(onUpdate, event) end)

We can also add pcall around a call to onUpdate so that any run-time errors happening in that function when you make changes, don't kill your application. All the compilation error will be reported to you in the IDE and only valid Lua code will be executed in the application.

Now we can look at the onUpdate handler:

done = nil
function onUpdate(event)
  -- let the first call to onUpdate to return quickly;
  -- start the debugging during the second call to trick Corona SDK
  -- and avoid restarting the app.
  if done == nil then done = false return end
  if not done then
    require("mobdebug").start()
    done = true
  end
  -- try to modify the following three lines while running this code live
  -- (using `Project | Run as Scratchpad`)
  ball:setFillColor(0, 127, 255, 255)
  bkgd:setFillColor(127, 0, 127)
  xspeed, yspeed = 6, 9
end

In this fragment we use a global variable done to control the logic in the onUpdate handled. The first time the handler is called, the variable is nil, which sets done to false and returns from the method. On the second call the debugger is started and the variable is set to true to avoid starting the debugger again. The reason why we want to return quickly from the method during the first call is to trick that check that Corona SDK does that causes the app to be restarted when doing debugging.

The last three lines in the onUpdate method can be modified during live coding (as shown in the demo) and the changes are immediately executed with results immediately shown. You can apply the same type of structure to your projects to pick a code fragment you want to experiment with. Note that ball, bkgd, xspeed, and yspeed are global variables; the current implementation will not work with upvalues as the newly created version of onUpdate will not "see" the current values of those upvalues.

The code for this demo application is available in corona samples as part of the ZeroBraneEduPack.

You should get a copy of my slick ZeroBrane Studio IDE and follow me on twitter here.

11 Comments

Hi,

I'm trying ZBS with Corona but can't get the debugger working. The console says the debugger has started but hovering over variables (at breakpoint) doesn't show anything. When i try "evaluate in console", everything shows as nil. Any ideas would be welcome.

Also, is there a way to select the simulator used by Corona?

thanks in advance.

Sean sherlock

I have the same issue as Sean Sherlock, please help. I can give you teamviewer session if it's hard to reproduce this issue.

I have the same issue. The stack window works, but the console and direct inspection of variables don't. Any ideas?

@Sean, @Andrey, @Paulo: you don't say what platform you are on, but I assume you are on OSX. Unfortunately these functions are not available on OSX as the simulator doesn't allow loadstring() function to be called to evaluate an expression or to execute command in the remote console.

I just found out how this can be enabled by working with Corona folks. I'm working on an update that should enable this functionality on OSX in few days. This new functionality will also be included in the next release (but you will be able to get it from the repository before the release).

@Sean, you can change the simulator by specifying "path.corona='/Applications/CoronaSDK/Corona Simulator.app/Contents/MacOS/Corona Simulator'" in cfg/user.lua. You can check cfg/user-sample.lua for details and an example. There is also documentation page on this here (http://studio.zerobrane.com/doc-configuration.html).

Paul.

Excellent work on this. I just installed it for doing Corona development for iOS. Seems like this IDE will do the trick. Definitely worth a purchase!

@Micah, glad you liked the IDE! FYI, there are several recent changes that further extend debugging support for Corona on OSX (this includes remote console, watches and tooltips). These changes will be packaged in v0.36 (next release) and are also available from github repository.

Great IDE for Corona - so how do you change the skin used by the simulator? Can you modify the cmd line call that ZeroBrain uses to add switch or extra parameters for a skin?

Hi,

I am using your editor and it is really great! There is one undesirable behavior though that I'm wondering how to fix:

When I launch my app in the corona simulator using the IDE and my app causes a runtime error, the simulator exits immediately before I can view what the error was. In the IDE output it only has the stack traceback part of the error message, not the actual error! Is there a way to capture the actual error message in the IDE output window?

@spacewolf, thank you for the feedback! There are two issues at play: one is that Corona doesn't report the error message to the IDE and the other one is that the simulator is closed when the error happens. The first one should already be fixed in a daily build of Corona and the second one has been recently fixed in ZBS. You can either get the latest version from Github or wait for the coming version of ZBS (0.41), which will include this change.

Hy! I was trying to debug my first Corona APP, but when I add your code I have an error

module 'moddebug' not found:resource (moddebug.lu) does not exist in archive no field package.preload['moddebug'] no file '/Users/alberto/Library/Application Support/Corona/Simulator/Plugins/moddebug.lua' no file '/Users/alberto/Documents/Progetto/Prj1/moddebug.lua' no file '/Applications/CoronaSDK/Corona Simulator.app/Contents/Resources/moddebug.lua' no file '/Users/alberto/Library/Application Support/Corona/Simulator/Plugins/moddebug.dylib' no file './moddebug.dylib' no file '/Applications/CoronaSDK/Corona Simulator.app/Contents/Resources/moddebug.dylib' stack traceback: [C]: in function 'require' ?: in function

Alberto, you seem to have the debugger module name misspelled: try using "require('mobdebug')" instead of "require('moddebug')".

Leave a comment

what will you say?
(required)
(required)

About

I am Paul Kulchenko.
I live in Kirkland, WA with my wife and three kids.
I do consulting as a software developer.
I study robotics and artificial intelligence.
I write books and open-source software.
I teach introductory computer science.
I develop a slick Lua IDE and debugger.

Recommended

Close