debug animations

https://merveilles.town/@akkartik/111333888472146119
This commit is contained in:
Kartik K. Agaram 2023-11-11 10:00:54 -08:00
parent d49dd49dd6
commit acc6e97db0
7 changed files with 54 additions and 0 deletions

View File

@ -0,0 +1,2 @@
-- Intermediate state during debug animations.
Debug_animations_in_progress = {}

View File

@ -0,0 +1,15 @@
-- update any in-progress debug animations
-- return whether any work remains
refresh_debug_animations = function()
local a = Debug_animations_in_progress
for i=#a,1,-1 do
if coroutine.status(a[i].co) == 'dead' then
table.remove(a, i)
elseif Current_time > a[i].next_run then
local status, err = coroutine.resume(a[i].co)
if status == false then error(err) end
a[i].next_run = Current_time + Debug_animation_period
end
end
return #a > 0
end

3
0004-on.update Normal file
View File

@ -0,0 +1,3 @@
on.update = function()
refresh_debug_animations()
end

21
0005-animate Normal file
View File

@ -0,0 +1,21 @@
-- A debugging aid to help animate intermediate results within f.
-- Pause animation in the current frame using loiter().
-- Try to only have one such call in your program.
-- You can have multiple, but things might get confusing if one of them indirectly calls the other,
-- or more generally if a single function ever loiters sometimes under the call tree of one and sometimes under the other.
animate = function(f, ...)
local args = {...}
Error_with_callstack = nil
local co = coroutine.create(
function()
xpcall(function()
f(unpack(args))
end,
save_callstack)
end)
coroutine.resume(co, ...)
if Error_with_callstack then
error(Error_with_callstack)
end
table.insert(Debug_animations_in_progress, {co=co, next_run=Current_time+0.3})
end

5
0006-loiter Normal file
View File

@ -0,0 +1,5 @@
-- A debugging aid to animate intermediate results in computations.
-- Can only be called from functions invoked using `animate()`.
loiter = function()
coroutine.yield()
end

7
0007-save_callstack Normal file
View File

@ -0,0 +1,7 @@
-- Internal helper for animate()
-- Records the stack of function calls that led to any error within a debug animation coroutine.
-- Lua normally prints out errors with callstacks, but coroutines interrupt the stack unless we do some additional work.
save_callstack = function(err)
local callstack = debug.traceback('', --[[stack frame]]2)
Error_with_callstack = 'Error: ' .. cleaned_up_frame(tostring(err))..'\n'..cleaned_up_callstack(callstack)
end

View File

@ -0,0 +1 @@
Debug_animation_period = 0.3 -- seconds between animation frames