This came up when trying to integrate my apps with the vudu debugger
(https://github.com/deltadaedalus/vudu). In general, it's a subtle part
of LÖVE's semantics that you can modify event handlers any time and your
modifications will get picked up. Now my Freewheeling Apps will follow
this norm as well.
Still klunky in one place: when you open the driver the failing test
isn't highlighted in red. I need to communicate the structured data of
test failures in run-time errors when the tests weren't triggered by a
driver command.
Changes inside on.initialize are minefields. Until now, if you made a
mistake when modifying on.initialize, you could end up in a situation
where the app would fail irrecoverably on the next startup. You'd have
to go dig up a text editor to fix it.
After this commit, errors in on.initialize wait for commands from
driver.love just like any other error.
Recovering from errors during initialization is a little different than
normal. I don't know how much of initialization completed successfully,
so I redo all of it.
I think this should be safe; the sorts of things we want to do on
startup tend to be idempotent just like the sorts of things we do within
an event loop with our existing error handling.
Things are still not ideal. Initialization by definition happens only
when the app starts up. When you make changes to it, you won't find out
about errors until you restart the app[1], which can be much later and a
big context switch. But at least you'll be able to fix it in the usual
way. Slightly more seamless[2].
One glitch to note: at least on Linux, an app with an initialization
error feels "sticky". I can't seem to switch focus away from it using
Alt-tab. Hitting F4 on the driver also jarringly brings the client app
back in focus when there was an initialization error. But the mouse does
work consistently. This feels similar to the issues I find when an app
goes unresponsive sometimes. The window manager really wants me to
respond to the dialog that it's unresponsive.
Still, feels like an improvement.
[1] I really need to provide that driver command to restart the app! But
there's no room in the menus! I really need a first-class command
palette like pensieve.love has!
[2] https://lobste.rs/s/idi1wt/open_source_vs_ux
before:
stack traceback:
[string "text.lua"]:9: in function 'draw'
[string "edit.lua"]:200: in function 'draw'
[string "run.lua"]:140: in function 'draw'
[string "main.lua"]:162: in function <[string "main.lua"]:155>
[C]: in function 'xpcall'
[string "app.lua"]:38: in function <[string "app.lua"]:20>
[C]: in function 'xpcall'
[love "boot.lua"]:370: in function <[love "boot.lua"]:337>
after:
stack traceback:
text.lua:9: in function 'draw'
edit.lua:200: in function 'draw'
run.lua:140: in function 'draw'
main.lua:162: in function <[string "main.lua"]:155>
[C]: in function 'xpcall'
app.lua:38: in function <[string "app.lua"]:20>
[C]: in function 'xpcall'
[love "boot.lua"]:370: in function <[love "boot.lua"]:337>
To do this I need some support for multiple versions. And I need an
'error' mode to go with existing 'run' and 'source' modes
(`Current_app`). Most errors will automatically transition to 'source'
editor mode, but some errors aren't really actionable in the editor. For
those we'll use 'error' mode.
The app doesn't yet work with LÖVE v12. There are some unit tests failing
because of differences in font rendering.
These are like versions in nativefs, but only support absolute paths.
I want to be thoughtful about the precise location at each call-site.
It's a little ugly that app.lua now has a dependency on file.lua. Or
source_file.lua for the source editor.
Thanks to physfs and nativefs.lua
nativefs still introduces some inconsistencies with love.filesystem with
relative paths:
* love.fs.read: reads from save dir if it exists, falls back to source dir if not
* nativefs.read: reads from save dir if it exists, falls back to source dir if not ✓
* love.fs.write: always writes to save dir
* nativefs.write: always writes to source dir (since no restrictions)
* love.fs.newFile followed by file:open('r'): reads from save dir if it exists, source dir if not
* nativefs.newFile followed by file:open('r'): always reads from working dir
* love.fs.newFile followed by file:open('w'): always writes to save dir
* nativefs.newFile followed by file:open('w'): always writes to working dir
So avoid using relative paths with App primitives.