This is a long-standing problem:
My compromise until now was to just perform B(), not A(). This tore the background rect away from the editor buffer during a move, which was ugly. You also wouldn't get any feedback at all if you tried to move a buffer without any text.
New solution: create a variant of A called A1 that only does the work of A for a single key (index) in Definitions.
This requires tracking for every shape we render in Surface, which key in Definitions it is part of. That way we can selectively delete just shapes belonging to a single key.
Caveat: key is a scalar, so this approach can't handle any nesting, only a flat array of objects. But that's good enough for both driver.love and this app.
7KX3WBFEXMIHNKWNF4NUOBW5HO3PEL3ZEFFMTAXFOQG6V7BYXZ3AC
A1 = function(key, preserve_screen_top_of_cursor_node)
-- like A, but updating a single node
-- this only works because Nodes is a flat array; we don't support row/col types here yet
-- delete previously added shapes for this node:
for i=#Surface,1,-1 do
local x = Surface[i]
if x.key == key then
table.remove(Surface, i)
end
end
local node = Definitions[key]
compute_layout(node, node.x,node.y, Surface, preserve_screen_top_of_cursor_node)
-- continue the pipeline
B(preserve_screen_top_of_cursor_node)
end