We'll end up calling Text.redraw_all anyway, which will clear starty and
much more besides.
We'll still conservatively continue clearing starty in a few places
where there's a possibility that Text.redraw_all may not be called. This
change is riskier than most.
Just checking mouse.isDown works if the editor is the entirety of the
app, as is true in this fork. However, we often want to introduce other
widgets. We'd like tapping on them to not cause the selection to flash:
https://news.ycombinator.com/context?id=38404923&submission=38397715
The right architecture to enforce this is: have each layer of the UI
maintain its own state machine between mouse_press and mouse_release
events. And only check the state machine in the next level down rather
than lower layers or the bottommost layer of raw LÖVE.
I'm not sure this can trigger everywhere (I've only been able to
exercise it in Lua Carousel), but it seems like a safety net worth
having against future modifications by anybody.
This commit doesn't guarantee we'll always catch it. But if this
invariant is violated, things can get quite difficult to debug. I found
in the Lua Carousel fork that all the xpcalls I keep around were
actively hindering my ability to notice this invariant being violated.
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.
Each one should provide a message that will show up within LÖVE. Stop
relying on nearby prints to the terminal.
I also found some unnecessary ones.
There is some potential here for performance regressions: the format()
calls will trigger whether or not the assertion fails, and cause
allocations. So far Lua's GC seems good enough to manage the load even
with Moby Dick, even in some situations that caused issues in the past
like undo.
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.
Scenario:
* run a whole new app (no save dir yet) as a .love file
* open the driver, make an edit
Before this commit, I was seeing errors due to the save dir not
existing. Let's depend on love.filesystem as needed. Another "good seam"
IMO (https://lobste.rs/s/idi1wt/open_source_vs_ux).
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
The intent of hiding errors is to see if a code change I made improved
things. But many commands from the driver don't involve a code change.
It seems more useful to leave the error up in those situations.
In particular, I want to be able to switch to 'error' mode rather than
throw a real error() on test failures, because that's a little more
responsive and might be recoverable. (On some Android devices the font
is slightly different, and tests fail as a result.)