bugfix: don't query network while panning around
I'm taking this opportunity to significantly clean up the data flow. It's easy to forget quite what A and B are supposed to do, and so to pile on additional responsibilities on them: * A rebuilds Surface * B updates just a few attributes within Surface without structurally modifying it In particular, A is not intended to modify the _inputs_ that go into rebuilding Surface, in this app Nodes. Perhaps I shouldn't call it A, but M or something to leave lots of space for phases before A. For now, hopefully a comment will suffice. 3 major code paths: - on.initialize as well as C-v initialize Input_filename (v11) or Url (v12) initialize Nodes and Root initialize Cursor_node A() ensure cursor in viewport - on pan: A() In particular, don't touch Cursor_node
This commit is contained in:
parent
c6f09b7958
commit
ee23ab653c
|
@ -1,4 +1,7 @@
|
|||
on.code_change = function()
|
||||
print('code changed')
|
||||
load_nodes_from_url()
|
||||
set_cursor(ml_from_url(Url).id)
|
||||
A() -- just in case we edited something
|
||||
ensure_cursor_node_within_viewport()
|
||||
end
|
||||
|
|
|
@ -4,7 +4,10 @@ on.initialize = function(arg)
|
|||
-- commandline arg is a url
|
||||
if #arg > 0 then
|
||||
Url = arg[1]
|
||||
load_nodes_from_url()
|
||||
set_cursor(ml_from_url(Url).id)
|
||||
A()
|
||||
ensure_cursor_node_within_viewport()
|
||||
end
|
||||
else
|
||||
-- LÖVE pre-v12 doesn't have https
|
||||
|
@ -15,14 +18,12 @@ on.initialize = function(arg)
|
|||
error('When running with LÖVE v11, please pass in a file containing a Mastodon thread, and optionally an id within it to start out focused on.\n\nThis app currently needs to be invoked from a terminal.')
|
||||
end
|
||||
Input_filename = arg[1]
|
||||
A()
|
||||
load_nodes_from_input_file()
|
||||
Cursor_node = Root
|
||||
if #arg >= 2 then
|
||||
local initial_id = arg[2]
|
||||
if Nodes[initial_id] then
|
||||
Cursor_node = Nodes[initial_id]
|
||||
end
|
||||
set_cursor(arg[2])
|
||||
end
|
||||
A()
|
||||
ensure_cursor_node_within_viewport()
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,7 +24,10 @@ on.keychord_press = function(chord, key)
|
|||
if cb:match('^%s*https://[^%s]*%s*$') then
|
||||
print('clipboard contains a URL')
|
||||
Url = trim(cb)
|
||||
load_nodes_from_url()
|
||||
set_cursor(ml_from_url(Url).id)
|
||||
A()
|
||||
ensure_cursor_node_within_viewport()
|
||||
end
|
||||
end
|
||||
elseif chord == 'C-up' then
|
||||
|
|
36
0028-A
36
0028-A
|
@ -1,34 +1,6 @@
|
|||
A = function()
|
||||
print('A')
|
||||
if Major_version >= 12 then
|
||||
-- reload Url from network
|
||||
if Url then
|
||||
-- indicate some progress
|
||||
-- load can take some time, and it's synchronous, so we'll draw to screen right here
|
||||
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||
love.graphics.print('loading '..Url..'...', 5,5)
|
||||
love.graphics.present()
|
||||
local initial_ml = ml_from_url(Url)
|
||||
local thread_data = try_load_nodes_from_url(initial_ml)
|
||||
render_thread_to_surface(thread_data)
|
||||
Cursor_node = Root
|
||||
if Nodes[initial_ml.id] then
|
||||
Cursor_node = Nodes[initial_ml.id]
|
||||
end
|
||||
ensure_cursor_node_within_viewport()
|
||||
end
|
||||
B()
|
||||
else
|
||||
-- LÖVE pre-v12 has no https
|
||||
-- reload same thread from file
|
||||
if Input_filename then
|
||||
love.graphics.setFont(love.graphics.newFont(scale(20))) -- editor objects implicitly depend on current font
|
||||
local f = io.open(Input_filename)
|
||||
assert(f)
|
||||
local thread_data = json.decode(f:read('*a'))
|
||||
f:close()
|
||||
render_thread_to_surface(thread_data)
|
||||
end
|
||||
B()
|
||||
end
|
||||
-- load Nodes to Surface
|
||||
love.graphics.setFont(love.graphics.newFont(scale(20))) -- editor objects implicitly depend on current font
|
||||
render_nodes_to_surface()
|
||||
B()
|
||||
end
|
||||
|
|
|
@ -25,4 +25,4 @@ ensure_cursor_node_within_viewport = function()
|
|||
if dirty then
|
||||
B()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
render_thread_to_surface = function(thread_data)
|
||||
-- side effects: Nodes, Root
|
||||
render_nodes_to_surface = function()
|
||||
-- design constraints:
|
||||
-- trees only, no graphs or DAGs
|
||||
-- parents above children
|
||||
|
@ -12,33 +11,6 @@ render_thread_to_surface = function(thread_data)
|
|||
Surface = {}
|
||||
-- we're going to be computing box heights
|
||||
love.graphics.setFont(love.graphics.newFont(scale(20)))
|
||||
-- compute mapping from ids to nodes
|
||||
Nodes = {} -- id to object
|
||||
Nodes[thread_data.id] = thread_data
|
||||
for _,x in ipairs(thread_data.descendants) do
|
||||
Nodes[x.id] = x
|
||||
end
|
||||
Root = thread_data
|
||||
-- compute children
|
||||
for _,x in pairs(Nodes) do
|
||||
parent_id = x.in_reply_to_id
|
||||
if x.id ~= Root.id then
|
||||
assert(parent_id)
|
||||
local parent = Nodes[parent_id]
|
||||
if parent then -- watch out for private posts
|
||||
if parent.children == nil then
|
||||
parent.children = {}
|
||||
end
|
||||
table.insert(parent.children, x.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- sort children by time
|
||||
for _,x in pairs(Nodes) do
|
||||
if x.children then
|
||||
table.sort(x.children)
|
||||
end
|
||||
end
|
||||
-- compute number of tracks needed
|
||||
for _,x in pairs(Nodes) do
|
||||
if x.ntracks == nil then
|
||||
|
@ -48,4 +20,4 @@ render_thread_to_surface = function(thread_data)
|
|||
-- prepare the tracks
|
||||
-- each track is 600px + 20px of gutter between nodes
|
||||
render_node_and_descendants(Root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * Root.ntracks)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
load_nodes_from_url = function()
|
||||
-- side effects: Nodes, Root, Cursor_node
|
||||
-- indicate some progress
|
||||
-- load can take some time, and it's synchronous, so we'll draw to screen right here
|
||||
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||
love.graphics.print('loading '..Url..'...', 5,5)
|
||||
love.graphics.present()
|
||||
-- load JSON from Url
|
||||
local initial_ml = ml_from_url(Url)
|
||||
local thread = get_toot(initial_ml)
|
||||
if thread.ancestors and #thread.ancestors > 0 then
|
||||
-- redo with oldest ancestor
|
||||
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||
love.graphics.print('reloading from earliest ancestor '..thread.ancestors[1].url..'...', 5,5)
|
||||
love.graphics.present()
|
||||
thread = get_toot(ml_from_url(thread.ancestors[1].url))
|
||||
end
|
||||
load_nodes_from_json(thread, initial_ml.id)
|
||||
end
|
|
@ -1,11 +0,0 @@
|
|||
try_load_nodes_from_url = function(initial_ml)
|
||||
local result = get_toot(initial_ml)
|
||||
if result.ancestors and #result.ancestors > 0 then
|
||||
-- redo with oldest ancestor
|
||||
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||
love.graphics.print('reloading from earliest ancestor '..result.ancestors[1].url..'...', 5,5)
|
||||
love.graphics.present()
|
||||
result = get_toot(ml_from_url(result.ancestors[1].url))
|
||||
end
|
||||
return result
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
load_nodes_from_input_file = function()
|
||||
-- side effects: Nodes, Root, Cursor_node
|
||||
-- load JSON from Input_filename
|
||||
local f = io.open(Input_filename)
|
||||
assert(f)
|
||||
local thread = json.decode(f:read('*a'))
|
||||
f:close()
|
||||
load_nodes_from_json(thread)
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
load_nodes_from_json = function(thread_data, cursor_id)
|
||||
-- massage JSON into a table from id to node
|
||||
Nodes = {} -- id to object
|
||||
Nodes[thread_data.id] = thread_data
|
||||
for _,x in ipairs(thread_data.descendants) do
|
||||
Nodes[x.id] = x
|
||||
end
|
||||
-- initialize Root
|
||||
Root = thread_data
|
||||
-- compute children
|
||||
for _,x in pairs(Nodes) do
|
||||
parent_id = x.in_reply_to_id
|
||||
if x.id ~= Root.id then
|
||||
assert(parent_id)
|
||||
local parent = Nodes[parent_id]
|
||||
if parent then -- watch out for private posts
|
||||
if parent.children == nil then
|
||||
parent.children = {}
|
||||
end
|
||||
table.insert(parent.children, x.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- sort children by time
|
||||
for _,x in pairs(Nodes) do
|
||||
if x.children then
|
||||
table.sort(x.children)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
set_cursor = function(cursor_id)
|
||||
-- position Cursor on the specific toot at Url
|
||||
Cursor_node = Root
|
||||
if Nodes[cursor_id] then
|
||||
Cursor_node = Nodes[cursor_id]
|
||||
end
|
||||
end
|
|
@ -8,6 +8,13 @@ record those here.
|
|||
- from defaults
|
||||
- default_map absent/present
|
||||
|
||||
- run app using LÖVE v11 and `lua unfurl.lua` shim. Ensure cursor is on correct node and visible.
|
||||
- run app using LÖVE v12. Ensure cursor is on correct node and visible.
|
||||
Paste in a new thread using `ctrl+v`. Ensure cursor is on correct node and visible.
|
||||
- pan around. Ensure cursor node can go out of viewport.
|
||||
- Press `ctrl`+arrow keys. Ensure cursor moves to correct node and becomes
|
||||
visible.
|
||||
|
||||
* How the screen looks. Our tests use a level of indirection to check text and
|
||||
graphics printed to screen, but not the precise pixels they translate to.
|
||||
- where exactly the cursor is drawn to highlight a given character
|
||||
|
|
Loading…
Reference in New Issue