H2KZUAWHQXTRUFDPDH4AUG6EP3OR5U3GGFPVGTCY2XJB3WOEO7TQC GUC42UKF6E736AB63KKLZ67VGO4CA422A6ECFU3ZX676XCHLNJUAC BP42JEWWJTJBVEMHQHRA7EP5NHFGDM2N7MAEEA426X24AIFEPQSAC TEY2M55SZ72OVJ6263EYWFXBHHMR7GPGBNNOGBFIOQPGGHAXSMJQC GIRNP3AO4J4U6ROFJTRHU4UNBPBNK5GIQMW73CYJCTNW6QCZRVWAC BBUGJKNA5HKOOX6KH5CGRVWJ76E2HPFLXGCTWSQZYRCP3KPXEBEAC K6ZDYZKXSLTLCCHWYK6K6WOCNXBZOXEDKDVNNJVCZUFOLLSUO5UAC R5QXEHUIZLELJGGCZAE7ATNS3CLRJ7JFRENMGH4XXH24C5WABZDQC PPVABNGQTQMPYILHDNSNXBI5IOCBSIYO45NIHUR4LYPABQZE6PAQC 25UHVUGNT3ANOGCQLL6GG6NNV4SLWLAMPME45JHWLLC2KK4GJO2QC V2R4643AZLA2QHR6C6ADAOOQXK5ZKZCR4NMKWPPZHMYTOIOIYJDAC HNXNAK7AIBISKZTTBA3RGXWXMS6UMM5656EK7EGQQIMNCUZRV3DAC QDN3KO6L3ILGTUUVTJGQ2BF4AXAIQYAXJNPOGCG7CYLDNJAJVADQC GE5W6MDN57RSM7XW5WZGTH7PP3ADB25QD2UY6R7WAANZPFOKF76AC IYJ2W4KLBV65OP73D5SMFOMTDH2NDDK2REXRKXAWBCVJPWMXT4PQC TBPJ5WSRM5IKQH7FTAVYTWWUBWW7G2CLT5M6FN7CMPLD6Y77YIWQC TTMMK6S6ILBQ6YN6H2DR5I5PH4ZUITWAGG72AJWLKLKGO5AATT2AC N5J7ZUXO45VS6GANQ4UWQTXMMQGSPRNDG4C2MG4NYVIZX5XMEB7AC 365TKW44IOQWIHK5LF4YXKM446QM5DCY4AF7DWK2O7LETPXZOIEAC 43JQEFRZ5SSMEOFHUGGB6NFJ5ZESGG27YZ3QU6AJQ7D3FK543MRQC OCEUBINPW3PZBKNQKZBZH2CHZ3YOWTHQETPS2544IOCV76CDEOYAC V2DSGKQSRTM72CG7TJSBYB3XOGVYNGWIUWKMW5GMJQJRAIF2WLZQC 4TL2FLYP36JS4K6QBXZBCFCTIBMIT7OAF7KMAAFGPAF5OWSP4QFAC OLCKKDVSDTIBX5U3IRCLRL6KQMG2RDWKGDN4OTPI3WMN4FSX6ROQC NP3LZH44LOWL2RPT7MOXWX5HJADZRFT7YFZKXSTEQ4JMFQDZPE7QC 5QTU3ODSGFLRWALAUDR27QYRB6UVDZD3Y3UJMZXISEFA7TRDI6BAC NEKDLX527DBB62P6OYFMSYAMTLRHNBRDNXNEVFT6UR4JLNOJXWKQC 6AJGWL32GZFO5CSSNKXMI24SB27I65K6LQDWWX5WVL5Z7ES4VUUQC O5F2HG2RYJ4L623VRQBXXJHTMTEAO3ZSUJYY3L7ECVD63TYVKO6AC 2S2CK2OMHYTYFRDHPXEZTWPF4CVUPR6VTNZIOVMUQVYIGM2PLXIQC HMH2GYB6BLH4HE7N6J6ZK57RKFICWXSU3KJL7EGYTXJ5DC5XHBIQC YVMVWYMCOOJPFUZRKSDMNDNY66OMJ47E3DVGSQAJ26SVPDCEKHMAC LRDM35CEK3OHXOTB7TEFJRL7P6PQWO5ZG3F2BVA7DIDFHBPJQ7KAC TLFRUXVL6JC3E5EGO3COZ2EBYTOL23A6SYKID7PT6HC7GJY3SKLAC GDBDGLRHJSMN527PHXGZVSGF55EYT4X3GFNF4LF6363JE2FGBQXQC FS2ITYYHBLFT66YUC3ENPFYI2HOYHOVEPQIN7NQR6KF5MEK4NKZAC PH6I237WRZLPA3Q3RHWITJNGIXI42PRSIQ6R5JJ6CXNTGQ3VIICAC EZHO4TSWIYYUE73S6XQWIEF3HA3H7MKCNJOT27NTWTVSPVS2SL5QC 2DVVKKVA6PJ7VKYLGPQ22AXUB6ZWFMPWB445PRDZJDNLURUFDNDQC XQZO4DUY3GDV2W6JNWDKCVIDGX7YBIONJC2V3BQEQY7XCIXREBEAC D4FEFHQCSILZFQ5VLWNXAIRZNUMCDNGJSM4UJ6T6FDMMIWYRYILQC F3NPUCCMFNMXVD2XJ5FMJ5M5FP3XICQHJRD6WFNB6OUK6LBL2TXQC E6APMVLDASF7PNTSFYKTNOJJUUQPOZN66AVYHEA4PMLYMA4THYCQC JIBCE66ZTWM5WEHEHNKKTRWBJQSQWBDDWPMOJIJR5Q676OSHYCNAC BF7TW3EKRIDYC6J2Q2J4YOBAVQF55Y3H6KGZIHNXMH4N72MR6GXQC ZQMQVMFWZIGWBRCB455IKHPTAOUYPLYCSC44NBPPET557RGVRX3AC FBDRJ53NJ5BWDQGU2GWZ6NEYHKCCRD7RODMIG7QQZBRFUB4HR7OAC J4UN4JK4DGKXKNB65JNAHYZDYP4TKRNFFDZLUAVK7SLFIQYHIFEQC X7HYGAL2QVKG7M5EMZ2VSH37UYWGE3EPUXYQBJOVL6IGJFZ2I5AAC 4WW67KAXORLJFOJVWV3CP4VNHTEIJY5WQMSDMXMFKRWSI5EEHTRAC DXFOMHQIWZ6EAUIDZQLY3ZRRDWJRB2VQHJXHBBNXQYCYCABIMJ5QC XCEP7G5GRX6WQGCROJDNZRTLSITGAETL7EFCFTR74S36VXK32HBQC Page2 = {x=500, y=300,-- pagetype='text',data={"Call me Ishmael. Some years ago--never mind how long precisely--having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen and regulating the circulation. Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people's hats off--then, I account it high time to get to sea as soon as I can. This is my substitute for pistol and ball. With a philosophical flourish Cato throws himself upon his sword; I quietly take to the ship. There is nothing surprising in this. If they but knew it, almost all men in their degree, some time or other, cherish very nearly the same feelings towards the ocean with me."},width=400, bg={r=0,g=0.8,b=0}}
A = function(preserve_screen_top_of_cursor_node)-- translate Page to Surfacewhile #Surface > 3 do table.remove(Surface) end -- HACKlocal red = falsefor x=-1000,2000,300 dofor y=-10000,10000,200 doadd_thick_line({type='line', data={x,y, x+200,y+200, x,y+400}, r=red and 1 or 0,g=red and 0 or 0.5,b=0}, 10)red = not redendendcompute_layout(Page, Page.x,Page.y, Surface, preserve_screen_top_of_cursor_node)compute_layout(Page2, Page2.x,Page2.y, Surface, preserve_screen_top_of_cursor_node)-- continue the pipelineB(preserve_screen_top_of_cursor_node)-- TODO: ugly that we're manipulating editor objects twiceend
on.mouse_press = function(x,y, mouse_button)local node_id = to_node(x,y)if node_id thenApp.setClipboardText(Nodes[node_id].url)elseendendPan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
on.mouse_press = function(x,y, mouse_button)local node_id = to_node(x,y)if node_id thenApp.setClipboardText(Nodes[node_id].url)Cursor_node = Nodes[node_id]elsePan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}endend
on.initialize = function(arg)Input_filename = arg[1]A(Input_filename)Cursor_node = Rootif #arg >= 1 thenif #arg >= 2 thenlocal initial_id = arg[2]if Nodes[initial_id] thenCursor_node = Nodes[initial_id]endendensure_cursor_node_within_viewport()endend
on.initialize = function(arg)Input_filename = arg[1]A(Input_filename)Cursor_node = Rootif #arg >= 2 thenlocal initial_id = arg[2]if Nodes[initial_id] thenCursor_node = Nodes[initial_id]endendensure_cursor_node_within_viewport()end
on.initialize = function(arg)if #arg == 0 thenerror('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.')endInput_filename = arg[1]A(Input_filename)Cursor_node = Rootif #arg >= 1 thenif #arg >= 2 thenlocal initial_id = arg[2]if Nodes[initial_id] thenCursor_node = Nodes[initial_id]endendensure_cursor_node_within_viewport()endend
xposition = function(curr, xlo, xhi)-- return the left margin to position a node atif curr.children == nil or #curr.children == 0 thenreturn xloendif #curr.children == 1 thenreturn xposition(Nodes[curr.children[1]], xlo, xhi)endlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#curr.children-1 dolocal child_id = curr.children[child_idx]local child = Nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal centerx = total_boundaries / (#curr.children-1)return centerx - 620/2end
compute_layout = function(node, x,y, nodes_to_render, preserve_screen_top_of_cursor_node)-- append to nodes_to_render flattened instructions to render a hierarchy of nodes-- return x,y rendered until (surface coordinates)if node.type == 'text' then-- leaf node containing raw textnode.x = xnode.y = y-- render background if necessarylocal node_to_renderif node.bg thennode_to_render = {type='rectangle', r=node.bg.r, g=node.bg.g, b=node.bg.b, x=node.x, y=node.y}table.insert(nodes_to_render, node_to_render)end-- render contentsif node.width thennode.w = node.widthelsenode.w = 0for i,s in ipairs(node.data) dolocal text = love.graphics.newText(font(20), node.data)local width = text:getWidth()if node.w < width then node.w = width endendendif node.editor == nil theninitialize_editor(node)elseupdate_editor_box(node, preserve_screen_top_of_cursor_node)endnode.h = box_height(node)table.insert(nodes_to_render, node)if node_to_render thennode_to_render.w = node.wnode_to_render.h = node.hendelseif node.type == 'rows' thennode.x = xnode.y = ylocal node_to_renderif node.bg thennode_to_render = {type='rectangle', r=node.bg.r, g=node.bg.g, b=node.bg.b, x=node.x, y=node.y}table.insert(nodes_to_render, node_to_render)end-- lay out children top to bottomlocal subx,suby = x,ylocal w,h = 0,0local subnodesfor _,child in ipairs(node.data) doif child.margin thensuby = suby+child.marginh = h+child.marginendif not child.width thenchild.width = node.width -- HACK: should we set child.w or child.width? Neither is quite satisfactory.endsubx,suby = compute_layout(child, x,suby, nodes_to_render)if w < child.w thenw = child.wendh = h+child.hendnode.w = wnode.h = hif node_to_render thennode_to_render.w = wnode_to_render.h = hendelseif node.type == 'cols' thennode.x = xnode.y = y-- lay out children left to rightlocal node_to_renderif node.bg thennode_to_render = {type='rectangle', r=node.bg.r, g=node.bg.g, b=node.bg.b, x=node.x, y=node.y}table.insert(nodes_to_render, node_to_render)endlocal subx,suby = x,ylocal w,h = 0,0for _,child in ipairs(node.data) doif child.margin thensubx = subx+child.marginw = w+child.marginendsubx,suby = compute_layout(child, subx,y, nodes_to_render)w = w + child.wif h < child.h thenh = child.hendendnode.w = wnode.h = hif node_to_render thennode_to_render.w = wnode_to_render.h = hendendreturn x+node.w,y+node.hend
Page = {-- pagetype='cols', x=0, y=0,width=800, data={-- editor covering left side{type='text',name='editor',doc='prose goes here, on the left half of the window',margin=Margin_left,data={"Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",'1','2','3','mno','Acb','g','hij','klm','nop',},width=400, bg={r=1,g=1,b=0}},-- a table on the right{ type='rows', name='searches', margin=50, data={{ type='text', data={''},},{ type='cols', data={{ type='text', data={'search:'},},{ type='text', name='search', bg={r=0.8,g=0.8,b=0.8}, data={''}, width=90,},}},{ type='text', data={'table:'},},{ type='cols', bg={r=0.8,g=0.8,b=0.8}, data={{ type='rows', width=90, data={{type='text', data={'abc'},},{type='text', data={'abc'},},}},{ type='rows', width=90, data={{type='text', data={'def'},},{type='text', data={'def'},},}},}},}},},}
{"box_height":345,"compute_layout":385,"ntracks":505,"B":379,"compute_ntracks":519,"Input_filename":436,"Surface":588,"on.draw":418,"vx":5,"Viewport":303,"on.text_input":587,"initialize_editor":338,"render_thread_to_surface":583,"dehtml":456,"on.mouse_press":585,"add_thick_line":400,"on.mouse_release":586,"copy_shape":396,"on.update":368,"to_text":180,"on.keychord_press":584,"load_from_iterator":463,"split_lines":469,"on.code_change":578,"scale":7,"A":582,"vy":8,"Cursor_node":172,"font":353,"add_edge":575,"y_of_schema1":364,"schema1_of_y":366,"update_editor_box":430,"line_height":365,"add_node":576,"fw_parent":587,"on":1,"fw_app":"mastodon-luaML","render_node_and_descendants":579,"on.initialize":446}
{"initialize_editor":338,"A":582,"to_text":180,"on.text_input":587,"split_lines":469,"B":379,"scale":7,"ensure_cursor_node_within_viewport":643,"add_node":650,"on.mouse_press":618,"Viewport":303,"render_node_and_descendants":646,"Cursor_node":172,"header":651,"add_thick_line":400,"box_height":345,"copy_shape":396,"compute_layout":619,"add_edge":575,"Root":654,"on.code_change":578,"Nodes":593,"Input_filename":436,"font":353,"update_editor_box":430,"fw_parent":657,"vx":5,"fw_app":"mastodon-unfurl","on.update":368,"to_node":611,"on.keychord_press":644,"vy":8,"load_from_iterator":463,"ntracks":600,"schema1_of_y":366,"y_of_schema1":364,"on.initialize":657,"render_thread_to_surface":655,"on.draw":632,"on.mouse_release":586,"dehtml":658,"compute_ntracks":598,"Surface":588,"line_height":365,"on":1}
{"on":1,"font":353,"y_of_schema1":364,"ensure_cursor_node_within_viewport":643,"header":651,"split_lines":469,"add_thick_line":400,"copy_shape":396,"Nodes":593,"Root":654,"initialize_editor":338,"box_height":345,"vx":5,"on.code_change":578,"render_node_and_descendants":646,"to_node":611,"fw_app":"mastodon-unfurl","Surface":588,"to_text":180,"line_height":365,"add_edge":575,"on.draw":632,"compute_ntracks":598,"dehtml":663,"on.mouse_release":586,"Viewport":303,"scale":7,"render_thread_to_surface":655,"on.initialize":657,"Cursor_node":172,"schema1_of_y":366,"ntracks":600,"load_from_iterator":463,"on.mouse_press":618,"on.text_input":587,"compute_layout":619,"fw_parent":662,"update_editor_box":430,"A":582,"on.keychord_press":644,"on.update":368,"add_node":650,"Input_filename":436,"B":379,"vy":8}
{"Surface":588,"Input_filename":436,"to_text":180,"on.draw":632,"line_height":365,"ensure_cursor_node_within_viewport":643,"initialize_editor":338,"ntracks":600,"on.text_input":587,"on.mouse_press":618,"render_thread_to_surface":655,"on.mouse_release":586,"dehtml":663,"Nodes":593,"Root":654,"copy_shape":396,"A":582,"B":666,"load_from_iterator":463,"to_node":611,"add_thick_line":400,"vx":5,"on.keychord_press":644,"fw_app":"mastodon-unfurl","on.initialize":665,"scale":7,"compute_layout":619,"compute_ntracks":598,"update_editor_box":430,"vy":8,"header":651,"on":1,"schema1_of_y":366,"add_node":650,"on.update":368,"box_height":345,"y_of_schema1":364,"render_node_and_descendants":646,"Cursor_node":172,"split_lines":469,"on.code_change":578,"add_edge":575,"Viewport":303,"fw_parent":665,"font":353}
{"compute_ntracks":598,"render_thread_to_surface":655,"on.initialize":665,"A":582,"dehtml":663,"B":666,"fw_app":"mastodon-unfurl","scale":7,"compute_layout":619,"add_edge":575,"vx":5,"load_from_iterator":463,"vy":8,"add_thick_line":400,"Surface":588,"copy_shape":396,"on.draw":632,"Cursor_node":172,"add_node":650,"on.text_input":587,"on.mouse_press":618,"render_node_and_descendants":646,"on.mouse_release":586,"update_editor_box":430,"on.update":368,"font":353,"on.keychord_press":644,"fw_parent":666,"Viewport":303,"on.code_change":578,"on":1,"split_lines":469,"Input_filename":436,"box_height":667,"line_height":365,"schema1_of_y":366,"header":651,"y_of_schema1":364,"Root":654,"initialize_editor":338,"to_node":611,"ensure_cursor_node_within_viewport":643,"Nodes":593,"ntracks":600,"to_text":180}
{"font":353,"add_thick_line":400,"compute_ntracks":519,"Cursor_node":172,"Input_filename":436,"on.text_input":388,"ntracks":505,"box_height":345,"Surface":434,"compute_layout":385,"line_height":365,"on.code_change":578,"dehtml":456,"Viewport":303,"schema1_of_y":366,"add_node":576,"initialize_editor":338,"on.initialize":446,"to_text":180,"A":474,"load_from_iterator":463,"B":379,"fw_parent":577,"on.draw":418,"fw_app":"mastodon-luaML","on.mouse_press":179,"render_node_and_descendants":577,"scale":7,"vx":5,"y_of_schema1":364,"split_lines":469,"vy":8,"copy_shape":396,"add_edge":575,"render_thread_to_surface":571,"on":1,"on.mouse_release":367,"update_editor_box":430,"on.update":368,"on.keychord_press":391}
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":612,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":611,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":603,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
{"schema1_of_y":366,"box_height":667,"to_node":611,"compute_layout":619,"dehtml":663,"on.text_input":587,"A":582,"add_edge":575,"B":666,"Surface":588,"on.draw":632,"Viewport":303,"ntracks":600,"split_lines":469,"scale":7,"font":353,"vy":8,"on.mouse_release":586,"initialize_editor":338,"on.update":368,"to_text":180,"on.keychord_press":644,"add_node":650,"Cursor_node":172,"add_thick_line":400,"on":1,"render_node_and_descendants":670,"render_thread_to_surface":655,"compute_ntracks":598,"ensure_cursor_node_within_viewport":643,"fw_parent":675,"Input_filename":436,"on.mouse_press":676,"load_from_iterator":463,"on.code_change":578,"header":651,"update_editor_box":430,"line_height":365,"copy_shape":396,"vx":5,"fw_app":"mastodon-unfurl","Nodes":593,"Root":654,"y_of_schema1":364,"xposition":675,"on.initialize":665}
{"split_lines":469,"on.initialize":664,"A":582,"on.mouse_release":586,"initialize_editor":338,"on.update":368,"on.keychord_press":644,"dehtml":663,"add_thick_line":400,"line_height":365,"ensure_cursor_node_within_viewport":643,"on":1,"ntracks":600,"Cursor_node":172,"copy_shape":396,"scale":7,"Root":654,"fw_parent":663,"font":353,"on.mouse_press":618,"to_text":180,"schema1_of_y":366,"box_height":345,"B":379,"compute_layout":619,"y_of_schema1":364,"fw_app":"mastodon-unfurl","on.code_change":578,"Nodes":593,"add_node":650,"Viewport":303,"update_editor_box":430,"render_thread_to_surface":655,"vy":8,"Surface":588,"on.text_input":587,"header":651,"on.draw":632,"vx":5,"Input_filename":436,"to_node":611,"load_from_iterator":463,"add_edge":575,"compute_ntracks":598,"render_node_and_descendants":646}
print('code changed')A() -- just in case we edited Pageendon.code_change = function()
dehtml = function(s)return s:gsub('<p>', '\n\n'):gsub('<br>', '\n'):gsub('<br/>', '\n')-- hacky:gsub('<[^>]*>', ''):gsub(''', "'"):gsub(''', "'"):gsub('"', '"'):gsub('“', '"'):gsub('”', '"'):gsub('<', '<'):gsub('>', '>'):gsub('&', '&')end
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]endelseif chord == 'C-down' thenif Cursor_node.children and #Cursor_node.children > 0 thenCursor_node = Nodes[Cursor_node.children[1]]endelseif chord == 'C-left' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx > 1 thenCursor_node = Nodes[parent.children[idx-1]]endendendelseif chord == 'C-right' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx < #parent.children thenCursor_node = Nodes[parent.children[idx+1]]endendendendend
{"copy_shape":396,"Surface":588,"on.draw":632,"add_node":650,"to_node":611,"render_node_and_descendants":646,"vy":8,"add_edge":575,"update_editor_box":430,"on.mouse_press":618,"box_height":345,"on.mouse_release":586,"line_height":365,"on.code_change":578,"Input_filename":436,"on.keychord_press":644,"schema1_of_y":366,"initialize_editor":338,"on.initialize":657,"y_of_schema1":364,"A":582,"ntracks":600,"compute_ntracks":598,"B":379,"render_thread_to_surface":655,"dehtml":456,"on":1,"on.text_input":587,"fw_app":"mastodon-unfurl","ensure_cursor_node_within_viewport":643,"scale":7,"to_text":180,"load_from_iterator":463,"compute_layout":619,"header":651,"Viewport":303,"vx":5,"fw_parent":656,"font":353,"split_lines":469,"Nodes":593,"Root":654,"on.update":368,"add_thick_line":400,"Cursor_node":172}
to_node = function(x,y)for _,node in ipairs(Surface) doif node.type == 'text' thenif x >= vx(node.x) and node.w and x < vx(node.x + node.w) thenif y >= vy(node.y) and node.h and y < vy(node.y + node.h) thenreturn node.toot_idendendendendend
{"dehtml":663,"schema1_of_y":366,"Viewport":303,"Cursor_node":172,"y_of_schema1":364,"on.initialize":665,"line_height":365,"A":582,"on.text_input":587,"split_lines":469,"B":379,"on.mouse_press":618,"initialize_editor":338,"on.update":368,"fw_parent":664,"box_height":345,"fw_app":"mastodon-unfurl","add_node":650,"render_node_and_descendants":646,"ensure_cursor_node_within_viewport":643,"add_thick_line":400,"to_text":180,"copy_shape":396,"scale":7,"add_edge":575,"load_from_iterator":463,"Root":654,"font":353,"Input_filename":436,"Nodes":593,"on.mouse_release":586,"vx":5,"on.draw":632,"on.keychord_press":644,"header":651,"Surface":588,"vy":8,"update_editor_box":430,"ntracks":600,"render_thread_to_surface":655,"compute_ntracks":598,"to_node":611,"compute_layout":619,"on":1,"on.code_change":578}
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if provided-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = Nodes[id]if parent.children == nil thenparent.surface_node = add_node(xlo, y, parent.content, parent.id, grandparent_surface_node)returnendlocal parent_xloif #parent.children <= 1 thenparent_xlo = xloelselocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = Nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)parent_xlo = parent_x - 620/2endparent.surface_node = add_node(parent_xlo, y, parent.content, parent.id, grandparent_surface_node)local parent_height = box_height(parent.surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = Nodes[child_id]render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent.surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]ensure_cursor_node_within_viewport()endelseif chord == 'C-down' thenif Cursor_node.children and #Cursor_node.children > 0 thenCursor_node = Nodes[Cursor_node.children[1]]ensure_cursor_node_within_viewport()endelseif chord == 'C-left' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx > 1 thenCursor_node = Nodes[parent.children[idx-1]]ensure_cursor_node_within_viewport()endendendelseif chord == 'C-right' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx < #parent.children thenCursor_node = Nodes[parent.children[idx+1]]ensure_cursor_node_within_viewport()endendendendend
{"xposition":675,"on.mouse_press":618,"on.draw":632,"box_height":667,"line_height":365,"compute_layout":619,"Viewport":303,"dehtml":663,"update_editor_box":430,"Nodes":593,"vx":5,"on.text_input":587,"on.mouse_release":586,"schema1_of_y":366,"on.update":368,"on.keychord_press":644,"split_lines":469,"to_node":611,"y_of_schema1":364,"A":582,"add_node":650,"scale":7,"render_node_and_descendants":670,"initialize_editor":338,"add_edge":575,"ensure_cursor_node_within_viewport":643,"font":353,"Surface":588,"vy":8,"on.initialize":665,"to_text":180,"B":666,"fw_app":"mastodon-unfurl","Cursor_node":172,"Root":654,"add_thick_line":400,"ntracks":600,"copy_shape":396,"compute_ntracks":598,"fw_parent":674,"on.code_change":578,"load_from_iterator":463,"Input_filename":436,"header":651,"render_thread_to_surface":655,"on":1}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- we're going to be computing box heightslove.graphics.setFont(love.graphics.newFont(scale(20)))-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(nodes, x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesN_edges = 2render_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
box_height = function(node)-- return the height of a node. The result is scaled.local y = 0for i=1,#node.editor.lines dolocal line = node.editor.lines[i]if node.editor.line_cache[i] == nil thennode.editor.line_cache[i] = {}endnode.editor.line_cache[i].fragments = nilnode.editor.line_cache[i].screen_line_starting_pos = nilText.populate_screen_line_starting_pos(node.editor, i)y = y + node.editor.line_height*#node.editor.line_cache[i].screen_line_starting_posText.clear_screen_line_cache(node.editor, i)end-- font size never changes in this appreturn y/Viewport.zoomend
{"box_height":345,"compute_layout":385,"Input_filename":436,"on":1,"Surface":434,"on.draw":418,"vx":5,"schema1_of_y":366,"Viewport":303,"dehtml":456,"on.initialize":446,"y_of_schema1":364,"A":582,"to_text":180,"on.mouse_press":585,"on.code_change":578,"initialize_editor":338,"on.update":368,"on.keychord_press":584,"load_from_iterator":463,"fw_parent":586,"split_lines":469,"fw_app":"mastodon-luaML","font":353,"Cursor_node":172,"update_editor_box":430,"ntracks":505,"line_height":365,"copy_shape":396,"on.text_input":587,"on.mouse_release":586,"compute_ntracks":519,"add_node":576,"vy":8,"render_thread_to_surface":583,"add_thick_line":400,"render_node_and_descendants":579,"scale":7,"B":379,"add_edge":575}
B = function(preserve_screen_top_of_cursor_node)-- recompute various aspects based on the current viewport settingsfor _,obj in ipairs(Surface) doif obj.type == 'line' thenobj.zdata = {}for i=1,#obj.data,2 dotable.insert(obj.zdata, vx(obj.data[i]))table.insert(obj.zdata, vy(obj.data[i+1]))endelseif obj.type == 'bezier' thenzdata = {}for i=1,#obj.data,2 dotable.insert(zdata, vx(obj.data[i]))table.insert(zdata, vy(obj.data[i+1]))endobj.zdata = love.math.newBezierCurve(zdata):render()elseif obj.type == 'text' thenif obj.w thenupdate_editor_box(obj, preserve_screen_top_of_cursor_node)elseobj.text = love.graphics.newText(love.graphics.getFont(), obj.data)endendendend
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]if Cursor_node.surface_node.y < Viewport.y thenViewport.y = Cursor_node.surface_node.y - 50B()endendelseif chord == 'C-down' thenif Cursor_node.children and #Cursor_node.children > 0 thenCursor_node = Nodes[Cursor_node.children[1]]local snode = Cursor_node.surface_nodelocal limit = snode.y + box_height(snode)if Viewport.y < limit - App.screen.height/Viewport.zoom thenViewport.y = limit - (App.screen.height-50)/Viewport.zoomB()endendelseif chord == 'C-left' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx > 1 thenCursor_node = Nodes[parent.children[idx-1]]if Cursor_node.surface_node.x < Viewport.x thenViewport.x = Cursor_node.surface_node.x - 50B()endendendendelseif chord == 'C-right' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx < #parent.children thenCursor_node = Nodes[parent.children[idx+1]]local snode = Cursor_node.surface_nodelocal limit = snode.x + 600if Viewport.x < limit - App.screen.width/Viewport.zoom thenViewport.x = limit - (App.screen.width-50)/Viewport.zoomB()endendendendendend
{"on":1,"font":353,"y_of_schema1":364,"ensure_cursor_node_within_viewport":643,"header":651,"split_lines":469,"add_thick_line":400,"copy_shape":396,"Nodes":593,"Root":654,"initialize_editor":338,"box_height":345,"vx":5,"on.code_change":578,"render_node_and_descendants":646,"to_node":611,"fw_app":"mastodon-unfurl","Surface":588,"to_text":180,"line_height":365,"add_edge":575,"on.draw":632,"compute_ntracks":598,"dehtml":662,"on.mouse_release":586,"Viewport":303,"scale":7,"render_thread_to_surface":655,"on.initialize":657,"Cursor_node":172,"schema1_of_y":366,"ntracks":600,"load_from_iterator":463,"on.mouse_press":618,"on.text_input":587,"compute_layout":619,"fw_parent":661,"update_editor_box":430,"A":582,"on.keychord_press":644,"on.update":368,"add_node":650,"Input_filename":436,"B":379,"vy":8}
{"on.code_change":578,"line_height":365,"add_thick_line":400,"Surface":588,"on.keychord_press":631,"ntracks":600,"on.mouse_press":618,"A":582,"on.mouse_release":586,"on.text_input":587,"scale":7,"Nodes":593,"on":1,"schema1_of_y":366,"font":353,"to_node":611,"y_of_schema1":364,"add_edge":575,"on.draw":627,"render_thread_to_surface":626,"B":379,"box_height":345,"on.update":368,"dehtml":456,"copy_shape":396,"add_node":590,"Input_filename":436,"vy":8,"compute_layout":619,"Viewport":303,"load_from_iterator":463,"split_lines":469,"to_text":180,"on.initialize":446,"Cursor_node":172,"compute_ntracks":598,"fw_app":"mastodon-luaML","update_editor_box":430,"fw_parent":630,"initialize_editor":338,"vx":5,"render_node_and_descendants":614}
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":607,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":610,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":603,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
xposition = function(curr, xlo, xhi)-- return the left margin to position a node atprint(curr.id, curr.children)if #curr.children == 0 thenreturn xloendif #curr.children == 1 thenreturn xposition(Nodes[curr.children[1]], xlo, xhi)endlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#curr.children-1 dolocal child_id = curr.children[child_idx]local child = Nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal centerx = total_boundaries / (#curr.children-1)return centerx - 620/2end
{"render_node_and_descendants":633,"compute_layout":619,"schema1_of_y":366,"render_thread_to_surface":626,"y_of_schema1":364,"dehtml":456,"Surface":588,"line_height":365,"on.draw":632,"load_from_iterator":463,"box_height":345,"on":1,"Viewport":303,"vx":5,"update_editor_box":430,"on.keychord_press":631,"Input_filename":436,"on.mouse_press":618,"add_thick_line":400,"on.mouse_release":586,"on.initialize":446,"on.text_input":587,"on.code_change":578,"fw_app":"mastodon-luaML","compute_ntracks":598,"Cursor_node":172,"fw_parent":632,"add_edge":575,"Nodes":593,"split_lines":469,"A":582,"to_text":180,"vy":8,"copy_shape":396,"scale":7,"add_node":590,"ntracks":600,"B":379,"initialize_editor":338,"on.update":368,"to_node":611,"font":353}
{"Surface":588,"vy":8,"on.draw":632,"Nodes":593,"add_node":590,"Viewport":303,"on.mouse_release":586,"on.initialize":446,"Input_filename":436,"on":1,"dehtml":456,"line_height":365,"ensure_cursor_node_within_viewport":643,"load_from_iterator":463,"add_edge":575,"compute_ntracks":598,"compute_layout":619,"render_thread_to_surface":626,"copy_shape":396,"on.keychord_press":644,"render_node_and_descendants":633,"Cursor_node":172,"add_thick_line":400,"ntracks":600,"update_editor_box":430,"scale":7,"y_of_schema1":364,"on.text_input":587,"on.update":368,"fw_parent":643,"initialize_editor":338,"schema1_of_y":366,"to_text":180,"box_height":345,"A":582,"font":353,"to_node":611,"fw_app":"mastodon-unfurl","on.code_change":578,"split_lines":469,"B":379,"on.mouse_press":618,"vx":5}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if provided-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content, grandparent_surface_node)returnendlocal parent_xloif #parent.children <= 1 thenparent_xlo = xloelselocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)parent_xlo = parent_x - 620/2endlocal parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent_surface_node)local parent_height = box_height(parent_surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
{"Input_filename":436,"on.update":368,"scale":7,"on.keychord_press":644,"render_thread_to_surface":655,"on.initialize":656,"dehtml":456,"add_thick_line":400,"line_height":365,"initialize_editor":338,"copy_shape":396,"header":651,"load_from_iterator":463,"ntracks":600,"Nodes":593,"compute_ntracks":598,"Root":654,"split_lines":469,"on.text_input":587,"ensure_cursor_node_within_viewport":643,"on.code_change":578,"vy":8,"Surface":588,"Cursor_node":172,"update_editor_box":430,"to_node":611,"fw_parent":655,"B":379,"fw_app":"mastodon-unfurl","add_node":650,"on.draw":632,"A":582,"to_text":180,"render_node_and_descendants":646,"y_of_schema1":364,"vx":5,"Viewport":303,"box_height":345,"schema1_of_y":366,"compute_layout":619,"font":353,"on":1,"on.mouse_press":618,"add_edge":575,"on.mouse_release":586}
{"compute_ntracks":519,"render_thread_to_surface":583,"Cursor_node":172,"dehtml":456,"add_thick_line":400,"copy_shape":396,"on.draw":418,"on.code_change":578,"A":582,"add_edge":575,"vy":8,"B":379,"font":353,"fw_app":"mastodon-luaML","on.mouse_release":367,"on.update":368,"to_text":180,"on.keychord_press":391,"schema1_of_y":366,"add_node":576,"y_of_schema1":364,"render_node_and_descendants":579,"scale":7,"vx":5,"on.initialize":446,"on.text_input":388,"Viewport":303,"Input_filename":436,"Surface":434,"on":1,"compute_layout":385,"box_height":345,"fw_parent":582,"load_from_iterator":463,"split_lines":469,"line_height":365,"on.mouse_press":179,"initialize_editor":338,"ntracks":505,"update_editor_box":430}
dehtml = function(s)return s:gsub('<p>', '\n\n'):gsub('<br>', '\n'):gsub('<br/>', '\n'):gsub('<[^>]*>', ''):gsub(''', "'"):gsub(''', "'"):gsub('"', '"'):gsub('“', '"'):gsub('”', '"'):gsub('<', '<'):gsub('>', '>'):gsub('&', '&')end
to_node = function(x,y)for _,node in ipairs(Surface) doif node.type == 'text' thenif x >= vx(node.x) and node.w and x < vx(node.x + node.w) thenif y >= vy(node.y) and node.h and y < vy(node.y + node.h) thenprint('bb', node.toot_id)return node.toot_idendendendendend
{"box_height":345,"compute_layout":385,"Input_filename":436,"on":1,"Surface":434,"on.draw":418,"vx":5,"schema1_of_y":366,"Viewport":303,"dehtml":456,"on.initialize":446,"y_of_schema1":364,"A":582,"to_text":180,"on.mouse_press":585,"on.code_change":578,"initialize_editor":338,"on.update":368,"on.keychord_press":584,"load_from_iterator":463,"fw_parent":585,"split_lines":469,"fw_app":"mastodon-luaML","font":353,"Cursor_node":172,"update_editor_box":430,"ntracks":505,"line_height":365,"copy_shape":396,"on.text_input":388,"on.mouse_release":586,"compute_ntracks":519,"add_node":576,"vy":8,"render_thread_to_surface":583,"add_thick_line":400,"render_node_and_descendants":579,"scale":7,"B":379,"add_edge":575}
on.mouse_press = function(x,y, mouse_button)local node = to_text(x,y)if node then-- TODO: copy node's urlelseendendPan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":641,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":642,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]endelseif chord == 'C-down' thenif Cursor_node.children and #Cursor_node.children > 0 thenCursor_node = Nodes[Cursor_node.children[1]]endelseif chord == 'C-left' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx > 1 thenCursor_node = Nodes[parent.children[idx-1]]endendendendend
{"box_height":667,"B":666,"compute_layout":619,"ntracks":600,"on.code_change":578,"add_thick_line":400,"render_thread_to_surface":655,"dehtml":663,"on":1,"update_editor_box":430,"load_from_iterator":463,"fw_parent":673,"on.mouse_release":586,"split_lines":469,"on.update":368,"Surface":588,"on.keychord_press":644,"to_text":180,"ensure_cursor_node_within_viewport":643,"Nodes":593,"y_of_schema1":364,"to_node":611,"header":651,"initialize_editor":338,"Root":654,"add_node":650,"schema1_of_y":366,"Viewport":303,"copy_shape":396,"render_node_and_descendants":670,"xposition":674,"line_height":365,"vx":5,"Cursor_node":172,"scale":7,"on.mouse_press":618,"add_edge":575,"fw_app":"mastodon-unfurl","compute_ntracks":598,"on.draw":632,"Input_filename":436,"on.text_input":587,"on.initialize":665,"vy":8,"A":582,"font":353}
{"font":353,"add_thick_line":400,"compute_ntracks":519,"Cursor_node":172,"Input_filename":436,"on.text_input":388,"ntracks":505,"box_height":345,"Surface":434,"compute_layout":385,"line_height":365,"on.code_change":473,"dehtml":456,"Viewport":303,"schema1_of_y":366,"add_node":576,"initialize_editor":338,"on.initialize":446,"to_text":180,"A":474,"load_from_iterator":463,"B":379,"fw_parent":576,"on.draw":418,"fw_app":"mastodon-luaML","on.mouse_press":179,"render_node_and_descendants":577,"scale":7,"vx":5,"y_of_schema1":364,"split_lines":469,"vy":8,"copy_shape":396,"add_edge":575,"render_thread_to_surface":571,"on":1,"on.mouse_release":367,"update_editor_box":430,"on.update":368,"on.keychord_press":391}
{"compute_ntracks":519,"render_thread_to_surface":571,"Cursor_node":172,"dehtml":456,"add_thick_line":400,"copy_shape":396,"on.draw":418,"on.code_change":578,"A":582,"add_edge":575,"vy":8,"B":379,"font":353,"fw_app":"mastodon-luaML","on.mouse_release":367,"on.update":368,"to_text":180,"on.keychord_press":391,"schema1_of_y":366,"add_node":576,"y_of_schema1":364,"render_node_and_descendants":579,"scale":7,"vx":5,"on.initialize":446,"on.text_input":388,"Viewport":303,"Input_filename":436,"Surface":434,"on":1,"compute_layout":385,"box_height":345,"fw_parent":581,"load_from_iterator":463,"split_lines":469,"line_height":365,"on.mouse_press":179,"initialize_editor":338,"ntracks":505,"update_editor_box":430}
{"Surface":588,"vy":8,"on.draw":632,"Nodes":593,"add_node":590,"Viewport":303,"on.mouse_release":586,"on.initialize":446,"Input_filename":436,"on":1,"dehtml":456,"line_height":365,"ensure_cursor_node_within_viewport":643,"load_from_iterator":463,"add_edge":575,"compute_ntracks":598,"compute_layout":619,"render_thread_to_surface":626,"copy_shape":396,"on.keychord_press":642,"render_node_and_descendants":633,"Cursor_node":172,"add_thick_line":400,"ntracks":600,"update_editor_box":430,"scale":7,"y_of_schema1":364,"on.text_input":587,"on.update":368,"fw_parent":642,"initialize_editor":338,"schema1_of_y":366,"to_text":180,"box_height":345,"A":582,"font":353,"to_node":611,"fw_app":"mastodon-unfurl","on.code_change":578,"split_lines":469,"B":379,"on.mouse_press":618,"vx":5}
{"vy":8,"y_of_schema1":364,"A":582,"to_node":610,"on.mouse_press":607,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":609,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":603,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
{"on":1,"font":353,"y_of_schema1":364,"ensure_cursor_node_within_viewport":643,"header":651,"split_lines":469,"add_thick_line":400,"copy_shape":396,"Nodes":593,"Root":654,"initialize_editor":338,"box_height":345,"vx":5,"on.code_change":578,"render_node_and_descendants":646,"to_node":611,"fw_app":"mastodon-unfurl","Surface":588,"to_text":180,"line_height":365,"add_edge":575,"on.draw":632,"compute_ntracks":598,"dehtml":661,"on.mouse_release":586,"Viewport":303,"scale":7,"render_thread_to_surface":655,"on.initialize":657,"Cursor_node":172,"schema1_of_y":366,"ntracks":600,"load_from_iterator":463,"on.mouse_press":618,"on.text_input":587,"compute_layout":619,"fw_parent":660,"update_editor_box":430,"A":582,"on.keychord_press":644,"on.update":368,"add_node":650,"Input_filename":436,"B":379,"vy":8}
on.draw = function()love.graphics.setColor(1,0,0)for _,obj in ipairs(Surface) dolove.graphics.setColor(obj.r or 0, obj.g or 0, obj.b or 0)if obj.type == 'rectangle' thenif obj.text_node and obj.text_node == Cursor_node.surface_node thenlove.graphics.setColor(0.7, 0.7, 0, 0.4)endlove.graphics.rectangle(obj.drawmode or 'fill', vx(obj.x),vy(obj.y), scale(obj.w),scale(obj.h))elseif obj.type == 'line' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'circle' thenlove.graphics.circle(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radius))elseif obj.type == 'arc' thenlove.graphics.arc(obj.drawmode or 'line', obj.arctype or 'open', vx(obj.x), vy(obj.y), scale(obj.radius), obj.angle1, obj.angle2, obj.segments)elseif obj.type == 'ellipse' thenlove.graphics.ellipse(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radiusx), scale(obj.radiusy))elseif obj.type == 'bezier' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'text' thenif obj.w == nil thenlove.graphics.draw(obj.text, vx(obj.x), vy(obj.y))elseedit.draw(obj.editor, obj.fg or {r=0,g=0,b=0}, not obj.show_cursor)endendendend
{"box_height":345,"compute_layout":385,"Input_filename":436,"on":1,"Surface":434,"on.draw":418,"vx":5,"schema1_of_y":366,"Viewport":303,"dehtml":456,"on.initialize":446,"y_of_schema1":364,"A":582,"to_text":180,"on.mouse_press":585,"on.code_change":578,"initialize_editor":338,"on.update":368,"on.keychord_press":584,"load_from_iterator":463,"fw_parent":584,"split_lines":469,"fw_app":"mastodon-luaML","font":353,"Cursor_node":172,"update_editor_box":430,"ntracks":505,"line_height":365,"copy_shape":396,"on.text_input":388,"on.mouse_release":367,"compute_ntracks":519,"add_node":576,"vy":8,"render_thread_to_surface":583,"add_thick_line":400,"render_node_and_descendants":579,"scale":7,"B":379,"add_edge":575}
to_node = function(x,y)for _,node in ipairs(Surface) doif node.type == 'text' thenif x >= vx(node.x) and node.w and x < vx(node.x + node.w) thenif y >= vy(node.y) and node.h and y < vy(node.y + node.h) thenprint('bb', node.id)return node.idendendendendend
xposition = function(curr, xlo, xhi)-- return the left margin to position a node atprint(curr.id, curr.children, #curr.children)if #curr.children == 0 thenreturn xloendif #curr.children == 1 thenreturn xposition(Nodes[curr.children[1]], xlo, xhi)endlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#curr.children-1 dolocal child_id = curr.children[child_idx]local child = Nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal centerx = total_boundaries / (#curr.children-1)return centerx - 620/2end
{"on.code_change":578,"line_height":365,"add_thick_line":400,"Surface":588,"on.keychord_press":630,"ntracks":600,"on.mouse_press":618,"A":582,"on.mouse_release":586,"on.text_input":587,"scale":7,"Nodes":593,"on":1,"schema1_of_y":366,"font":353,"to_node":611,"y_of_schema1":364,"add_edge":575,"on.draw":627,"render_thread_to_surface":626,"B":379,"box_height":345,"on.update":368,"dehtml":456,"copy_shape":396,"add_node":590,"Input_filename":436,"vy":8,"compute_layout":619,"Viewport":303,"load_from_iterator":463,"split_lines":469,"to_text":180,"on.initialize":446,"Cursor_node":172,"compute_ntracks":598,"fw_app":"mastodon-luaML","update_editor_box":430,"fw_parent":629,"initialize_editor":338,"vx":5,"render_node_and_descendants":614}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- we're going to be computing box heightslove.graphics.setFont(love.graphics.newFont(scale(20)))-- compute mapping from ids to nodesNodes = {} -- id to objectNodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) doNodes[x.id] = xendRoot = thread_data-- compute childrenfor _,x in pairs(Nodes) doparent_id = x.in_reply_to_idif x.id ~= Root.id thenassert(parent_id)local parent = Nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(Nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(Nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesrender_node_and_descendants(Root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * Root.ntracks)end
{"font":353,"add_thick_line":400,"compute_ntracks":519,"Cursor_node":172,"Input_filename":436,"on.text_input":388,"ntracks":505,"box_height":345,"Surface":434,"compute_layout":385,"line_height":365,"on.code_change":473,"dehtml":456,"Viewport":303,"schema1_of_y":366,"add_node":576,"initialize_editor":338,"on.initialize":446,"to_text":180,"A":474,"load_from_iterator":463,"B":379,"fw_parent":575,"on.draw":418,"fw_app":"mastodon-luaML","on.mouse_press":179,"render_node_and_descendants":565,"scale":7,"vx":5,"y_of_schema1":364,"split_lines":469,"vy":8,"copy_shape":396,"add_edge":575,"render_thread_to_surface":571,"on":1,"on.mouse_release":367,"update_editor_box":430,"on.update":368,"on.keychord_press":391}
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()endend
ensure_cursor_node_within_viewport = function()local snode = Cursor_node.surface_nodelocal dirty-- check Viewport.yif snode.y < Viewport.y thenViewport.y = snode.y - 50dirty = trueendlocal limit = snode.y + box_height(snode)if Viewport.y < limit - App.screen.height/Viewport.zoom thenViewport.y = limit - (App.screen.height-50)/Viewport.zoomdirty = trueend-- check Viewport.xif Cursor_node.surface_node.x < Viewport.x thenViewport.x = Cursor_node.surface_node.x - 50dirty = trueendlimit = snode.x + 600if Viewport.x < limit - App.screen.width/Viewport.zoom thenViewport.x = limit - (App.screen.width-50)/Viewport.zoomdirty = trueend-- refresh if necessaryif dirty thenB()endend
{"compute_ntracks":519,"render_thread_to_surface":571,"Cursor_node":172,"dehtml":456,"add_thick_line":400,"copy_shape":396,"on.draw":418,"on.code_change":578,"A":581,"add_edge":575,"vy":8,"B":379,"font":353,"fw_app":"mastodon-luaML","on.mouse_release":367,"on.update":368,"to_text":180,"on.keychord_press":391,"schema1_of_y":366,"add_node":576,"y_of_schema1":364,"render_node_and_descendants":579,"scale":7,"vx":5,"on.initialize":446,"on.text_input":388,"Viewport":303,"Input_filename":436,"Surface":434,"on":1,"compute_layout":385,"box_height":345,"fw_parent":580,"load_from_iterator":463,"split_lines":469,"line_height":365,"on.mouse_press":179,"initialize_editor":338,"ntracks":505,"update_editor_box":430}
add_node = function(x, y, text, parent_surface_node)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(text)),bg={r=0.7,g=0.7, b=1.0},}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)if parent_surface_node thenadd_edge(surface_node, parent_surface_node)endreturn surface_nodeend
{"render_node_and_descendants":614,"compute_layout":619,"schema1_of_y":366,"render_thread_to_surface":626,"y_of_schema1":364,"dehtml":456,"Surface":588,"line_height":365,"on.draw":632,"load_from_iterator":463,"box_height":345,"on":1,"Viewport":303,"vx":5,"update_editor_box":430,"on.keychord_press":631,"Input_filename":436,"on.mouse_press":618,"add_thick_line":400,"on.mouse_release":586,"on.initialize":446,"on.text_input":587,"on.code_change":578,"fw_app":"mastodon-luaML","compute_ntracks":598,"Cursor_node":172,"fw_parent":631,"add_edge":575,"Nodes":593,"split_lines":469,"A":582,"to_text":180,"vy":8,"copy_shape":396,"scale":7,"add_node":590,"ntracks":600,"B":379,"initialize_editor":338,"on.update":368,"to_node":611,"font":353}
{"on":1,"font":353,"y_of_schema1":364,"ensure_cursor_node_within_viewport":643,"header":651,"split_lines":469,"add_thick_line":400,"copy_shape":396,"Nodes":593,"Root":654,"initialize_editor":338,"box_height":345,"vx":5,"on.code_change":578,"render_node_and_descendants":646,"to_node":611,"fw_app":"mastodon-unfurl","Surface":588,"to_text":180,"line_height":365,"add_edge":575,"on.draw":632,"compute_ntracks":598,"dehtml":660,"on.mouse_release":586,"Viewport":303,"scale":7,"render_thread_to_surface":655,"on.initialize":657,"Cursor_node":172,"schema1_of_y":366,"ntracks":600,"load_from_iterator":463,"on.mouse_press":618,"on.text_input":587,"compute_layout":619,"fw_parent":659,"update_editor_box":430,"A":582,"on.keychord_press":644,"on.update":368,"add_node":650,"Input_filename":436,"B":379,"vy":8}
{"vy":8,"y_of_schema1":364,"A":582,"to_node":609,"on.mouse_press":607,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":608,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":603,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]endelseif chord == 'C-down' thenif Cursor_node.children and #Cursor_node.children > 0 thenCursor_node = Nodes[Cursor_node.children[1]]endendend
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]if Cursor_node.surface_node.y < Viewport.y thenViewport.y = Cursor_node.surface_node.y - 50B()endendelseif chord == 'C-down' thenif Cursor_node.children and #Cursor_node.children > 0 thenCursor_node = Nodes[Cursor_node.children[1]]local snode = Cursor_node.surface_nodelocal limit = snode.y + box_height(snode)if Viewport.y < limit - App.screen.height/Viewport.zoom thenViewport.y = limit - (App.screen.height-50)/Viewport.zoomB()endendelseif chord == 'C-left' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx > 1 thenCursor_node = Nodes[parent.children[idx-1]]if Cursor_node.surface_node.x < Viewport.x thenViewport.x = Cursor_node.surface_node.x - 50B()endendendendelseif chord == 'C-right' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx < #parent.children thenCursor_node = Nodes[parent.children[idx+1]]endendendendend
{"box_height":345,"compute_layout":385,"Input_filename":436,"on":1,"Surface":434,"on.draw":418,"vx":5,"schema1_of_y":366,"Viewport":303,"dehtml":456,"on.initialize":446,"y_of_schema1":364,"A":582,"to_text":180,"on.mouse_press":179,"on.code_change":578,"initialize_editor":338,"on.update":368,"on.keychord_press":584,"load_from_iterator":463,"fw_parent":583,"split_lines":469,"fw_app":"mastodon-luaML","font":353,"Cursor_node":172,"update_editor_box":430,"ntracks":505,"line_height":365,"copy_shape":396,"on.text_input":388,"on.mouse_release":367,"compute_ntracks":519,"add_node":576,"vy":8,"render_thread_to_surface":583,"add_thick_line":400,"render_node_and_descendants":579,"scale":7,"B":379,"add_edge":575}
{"box_height":667,"B":666,"compute_layout":619,"ntracks":600,"on.code_change":578,"add_thick_line":400,"render_thread_to_surface":655,"dehtml":663,"on":1,"update_editor_box":430,"load_from_iterator":463,"fw_parent":672,"on.mouse_release":586,"split_lines":469,"on.update":368,"Surface":588,"on.keychord_press":644,"to_text":180,"ensure_cursor_node_within_viewport":643,"Nodes":593,"y_of_schema1":364,"to_node":611,"header":651,"initialize_editor":338,"Root":654,"add_node":650,"schema1_of_y":366,"Viewport":303,"copy_shape":396,"render_node_and_descendants":670,"xposition":673,"line_height":365,"vx":5,"Cursor_node":172,"scale":7,"on.mouse_press":618,"add_edge":575,"fw_app":"mastodon-unfurl","compute_ntracks":598,"on.draw":632,"Input_filename":436,"on.text_input":587,"on.initialize":665,"vy":8,"A":582,"font":353}
{"Input_filename":436,"on.update":368,"scale":7,"on.keychord_press":644,"render_thread_to_surface":655,"on.initialize":446,"dehtml":456,"add_thick_line":400,"line_height":365,"initialize_editor":338,"copy_shape":396,"header":651,"load_from_iterator":463,"ntracks":600,"Nodes":593,"compute_ntracks":598,"Root":654,"split_lines":469,"on.text_input":587,"ensure_cursor_node_within_viewport":643,"on.code_change":578,"vy":8,"Surface":588,"Cursor_node":172,"update_editor_box":430,"to_node":611,"fw_parent":654,"B":379,"fw_app":"mastodon-unfurl","add_node":650,"on.draw":632,"A":582,"to_text":180,"render_node_and_descendants":646,"y_of_schema1":364,"vx":5,"Viewport":303,"box_height":345,"schema1_of_y":366,"compute_layout":619,"font":353,"on":1,"on.mouse_press":618,"add_edge":575,"on.mouse_release":586}
to_node = function(x,y)for _,node in ipairs(Surface) doif node.type == 'text' thenif x >= vx(node.x) and node.w and x < vx(node.x + node.w) thenif y >= vy(node.y) and node.h and y < vy(node.y + node.h) thenprint('bb')return node.idendendendendend
{"font":353,"add_thick_line":400,"compute_ntracks":519,"Cursor_node":172,"Input_filename":436,"on.text_input":388,"ntracks":505,"box_height":345,"Surface":434,"compute_layout":385,"line_height":365,"on.code_change":473,"dehtml":456,"Viewport":303,"schema1_of_y":366,"add_node":574,"initialize_editor":338,"on.initialize":446,"to_text":180,"A":474,"load_from_iterator":463,"B":379,"fw_parent":574,"on.draw":418,"fw_app":"mastodon-luaML","on.mouse_press":179,"render_node_and_descendants":565,"scale":7,"vx":5,"y_of_schema1":364,"split_lines":469,"vy":8,"copy_shape":396,"add_edge":575,"render_thread_to_surface":571,"on":1,"on.mouse_release":367,"update_editor_box":430,"on.update":368,"on.keychord_press":391}
{"render_node_and_descendants":579,"add_edge":575,"initialize_editor":338,"Input_filename":436,"add_thick_line":400,"copy_shape":396,"box_height":345,"compute_layout":385,"on.code_change":578,"ntracks":505,"compute_ntracks":519,"render_thread_to_surface":571,"Surface":434,"dehtml":456,"on.draw":418,"to_text":180,"line_height":365,"vy":8,"fw_parent":579,"load_from_iterator":463,"fw_app":"mastodon-luaML","on.mouse_press":179,"y_of_schema1":364,"A":580,"font":353,"on.update":368,"split_lines":469,"B":379,"on.keychord_press":391,"update_editor_box":430,"on.mouse_release":367,"on":1,"Viewport":303,"scale":7,"Cursor_node":172,"on.text_input":388,"on.initialize":446,"add_node":576,"vx":5,"schema1_of_y":366}
{"on.code_change":578,"line_height":365,"add_thick_line":400,"Surface":588,"on.keychord_press":629,"ntracks":600,"on.mouse_press":618,"A":582,"on.mouse_release":586,"on.text_input":587,"scale":7,"Nodes":593,"on":1,"schema1_of_y":366,"font":353,"to_node":611,"y_of_schema1":364,"add_edge":575,"on.draw":627,"render_thread_to_surface":626,"B":379,"box_height":345,"on.update":368,"dehtml":456,"copy_shape":396,"add_node":590,"Input_filename":436,"vy":8,"compute_layout":619,"Viewport":303,"load_from_iterator":463,"split_lines":469,"to_text":180,"on.initialize":446,"Cursor_node":172,"compute_ntracks":598,"fw_app":"mastodon-luaML","update_editor_box":430,"fw_parent":628,"initialize_editor":338,"vx":5,"render_node_and_descendants":614}
xposition = function(curr, xlo, xhi)-- return the left margin to position a node atif #curr.children == 0 thenreturn xloendif #curr.children == 1 thenreturn xposition(Nodes[curr.children[1]], xlo, xhi)endlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#curr.children-1 dolocal child_id = curr.children[child_idx]local child = Nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal centerx = total_boundaries / (#curr.children-1)return centerx - 620/2end
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":640,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":641,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
{"on":1,"font":353,"y_of_schema1":364,"ensure_cursor_node_within_viewport":643,"header":651,"split_lines":469,"add_thick_line":400,"copy_shape":396,"Nodes":593,"Root":654,"initialize_editor":338,"box_height":345,"vx":5,"on.code_change":578,"render_node_and_descendants":646,"to_node":611,"fw_app":"mastodon-unfurl","Surface":588,"to_text":180,"line_height":365,"add_edge":575,"on.draw":632,"compute_ntracks":598,"dehtml":659,"on.mouse_release":586,"Viewport":303,"scale":7,"render_thread_to_surface":655,"on.initialize":657,"Cursor_node":172,"schema1_of_y":366,"ntracks":600,"load_from_iterator":463,"on.mouse_press":618,"on.text_input":587,"compute_layout":619,"fw_parent":658,"update_editor_box":430,"A":582,"on.keychord_press":644,"on.update":368,"add_node":650,"Input_filename":436,"B":379,"vy":8}
{"vy":8,"y_of_schema1":364,"A":582,"to_node":608,"on.mouse_press":607,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":607,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":603,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
{"Input_filename":436,"on.update":368,"scale":7,"on.keychord_press":644,"render_thread_to_surface":653,"on.initialize":446,"dehtml":456,"add_thick_line":400,"line_height":365,"initialize_editor":338,"copy_shape":396,"header":651,"load_from_iterator":463,"ntracks":600,"Nodes":593,"compute_ntracks":598,"Root":654,"split_lines":469,"on.text_input":587,"ensure_cursor_node_within_viewport":643,"on.code_change":578,"vy":8,"Surface":588,"Cursor_node":172,"update_editor_box":430,"to_node":611,"fw_parent":653,"B":379,"fw_app":"mastodon-unfurl","add_node":650,"on.draw":632,"A":582,"to_text":180,"render_node_and_descendants":646,"y_of_schema1":364,"vx":5,"Viewport":303,"box_height":345,"schema1_of_y":366,"compute_layout":619,"font":353,"on":1,"on.mouse_press":618,"add_edge":575,"on.mouse_release":586}
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]endendend
on.mouse_press = function(x,y, mouse_button)local node_id = to_node(x,y)if node_id thenprint('aa', node_id, Nodes[node_id].url)App.setClipboardText(Nodes[node_id].url)elseendendPan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":571,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":573,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":574,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":573,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"box_height":667,"B":666,"compute_layout":619,"ntracks":600,"on.code_change":578,"add_thick_line":400,"render_thread_to_surface":655,"dehtml":663,"on":1,"update_editor_box":430,"load_from_iterator":463,"fw_parent":671,"on.mouse_release":586,"split_lines":469,"on.update":368,"Surface":588,"on.keychord_press":644,"to_text":180,"ensure_cursor_node_within_viewport":643,"Nodes":593,"y_of_schema1":364,"to_node":611,"header":651,"initialize_editor":338,"Root":654,"add_node":650,"schema1_of_y":366,"Viewport":303,"copy_shape":396,"render_node_and_descendants":670,"xposition":672,"line_height":365,"vx":5,"Cursor_node":172,"scale":7,"on.mouse_press":618,"add_edge":575,"fw_app":"mastodon-unfurl","compute_ntracks":598,"on.draw":632,"Input_filename":436,"on.text_input":587,"on.initialize":665,"vy":8,"A":582,"font":353}
{"on.code_change":578,"line_height":365,"add_thick_line":400,"Surface":588,"on.keychord_press":628,"ntracks":600,"on.mouse_press":618,"A":582,"on.mouse_release":586,"on.text_input":587,"scale":7,"Nodes":593,"on":1,"schema1_of_y":366,"font":353,"to_node":611,"y_of_schema1":364,"add_edge":575,"on.draw":627,"render_thread_to_surface":626,"B":379,"box_height":345,"on.update":368,"dehtml":456,"copy_shape":396,"add_node":590,"Input_filename":436,"vy":8,"compute_layout":619,"Viewport":303,"load_from_iterator":463,"split_lines":469,"to_text":180,"on.initialize":446,"Cursor_node":172,"compute_ntracks":598,"fw_app":"mastodon-luaML","update_editor_box":430,"fw_parent":627,"initialize_editor":338,"vx":5,"render_node_and_descendants":614}
add_node = function(x, y, text, parent_surface_node)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(text)),bg={r=0.7,g=0.7, b=1.0},}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)if parent_surface_node then -- and N_edges > 0 thenadd_edge(surface_node, parent_surface_node)N_edges = N_edges - 1endreturn surface_nodeend
{"vy":8,"y_of_schema1":364,"A":582,"to_node":604,"on.mouse_press":607,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":606,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":603,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
xposition = function(curr, xlo, xhi)-- return the left margin to position a node atif #curr.children <= 1 thenreturn xloendlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#curr.children-1 dolocal child_id = curr.children[child_idx]local child = Nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal centerx = total_boundaries / (#curr.children-1)return centerx - 620/2end
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if provided-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content, grandparent_surface_node)returnendlocal parent_xloif #parent.children <= 1 thenparent_xlo = xloelselocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)parent_xlo = parent_x - 620/2endlocal parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent_surface_node)local parent_height = box_height(parent_surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
on.mouse_press = function(x,y, mouse_button)local node_id = to_node(x,y)if node_id thenApp.setClipboardText(Nodes[node_id].url)elseendendPan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]if Cursor_node.surface_node.y < Viewport.y thenViewport.y = Cursor_node.surface_node.y - 50B()endendelseif chord == 'C-down' thenif Cursor_node.children and #Cursor_node.children > 0 thenCursor_node = Nodes[Cursor_node.children[1]]local snode = Cursor_node.surface_nodelocal limit = snode.y + box_height(snode)if Viewport.y < limit - App.screen.height/Viewport.zoom thenViewport.y = limit - (App.screen.height-50)/Viewport.zoomB()endendelseif chord == 'C-left' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx > 1 thenCursor_node = Nodes[parent.children[idx-1]]endendendelseif chord == 'C-right' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx < #parent.children thenCursor_node = Nodes[parent.children[idx+1]]endendendendend
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- we're going to be computing box heightslove.graphics.setFont(love.graphics.newFont(scale(20)))-- compute mapping from ids to nodesNodes = {} -- id to objectNodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) doNodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(Nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = Nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(Nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(Nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesrender_node_and_descendants(root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":571,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":572,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":568,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":573,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"render_node_and_descendants":579,"add_edge":575,"initialize_editor":338,"Input_filename":436,"add_thick_line":400,"copy_shape":396,"box_height":345,"compute_layout":385,"on.code_change":578,"ntracks":505,"compute_ntracks":519,"render_thread_to_surface":571,"Surface":434,"dehtml":456,"on.draw":418,"to_text":180,"line_height":365,"vy":8,"fw_parent":578,"load_from_iterator":463,"fw_app":"mastodon-luaML","on.mouse_press":179,"y_of_schema1":364,"A":474,"font":353,"on.update":368,"split_lines":469,"B":379,"on.keychord_press":391,"update_editor_box":430,"on.mouse_release":367,"on":1,"Viewport":303,"scale":7,"Cursor_node":172,"on.text_input":388,"on.initialize":446,"add_node":576,"vx":5,"schema1_of_y":366}
{"box_height":667,"B":666,"compute_layout":619,"ntracks":600,"on.code_change":578,"add_thick_line":400,"render_thread_to_surface":655,"dehtml":663,"on":1,"update_editor_box":430,"load_from_iterator":463,"fw_parent":670,"on.mouse_release":586,"split_lines":469,"on.update":368,"Surface":588,"on.keychord_press":644,"to_text":180,"ensure_cursor_node_within_viewport":643,"Nodes":593,"y_of_schema1":364,"to_node":611,"header":651,"initialize_editor":338,"Root":654,"add_node":650,"schema1_of_y":366,"Viewport":303,"copy_shape":396,"render_node_and_descendants":670,"xposition":671,"line_height":365,"vx":5,"Cursor_node":172,"scale":7,"on.mouse_press":618,"add_edge":575,"fw_app":"mastodon-unfurl","compute_ntracks":598,"on.draw":632,"Input_filename":436,"on.text_input":587,"on.initialize":665,"vy":8,"A":582,"font":353}
add_edge = function(node, parent)print('add edge', node.x, node.y, parent.x, parent.y)local line = {type='line',data={parent.x + 600/2, parent.y + box_height(parent),node.x + 600/2, node.y,},}print('add edge 2', line.data[2], line.data[4])table.insert(Surface, line)end
{"fw_parent":604,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":606,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":603,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"Surface":588,"line_height":365,"on.mouse_release":586,"to_text":180,"to_node":604,"render_thread_to_surface":602,"y_of_schema1":364,"schema1_of_y":366,"ntracks":600,"compute_layout":385,"on.code_change":578,"Cursor_node":172,"A":582,"on.initialize":446,"on":1,"on.keychord_press":584,"initialize_editor":338,"on.draw":418,"B":379,"box_height":345}
on.draw = function()love.graphics.setColor(1,0,0)for _,obj in ipairs(Surface) dolove.graphics.setColor(obj.r or 0, obj.g or 0, obj.b or 0)if obj.type == 'rectangle' thenif obj.text_node and obj.text_node == Cursor_node.surface_node thenlove.graphics.setColor(0.7, 0.7, 0, 0.4)endlove.graphics.rectangle(obj.drawmode or 'fill', vx(obj.x),vy(obj.y), scale(obj.w),scale(obj.h))elseif obj.type == 'line' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'circle' thenlove.graphics.circle(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radius))elseif obj.type == 'arc' thenlove.graphics.arc(obj.drawmode or 'line', obj.arctype or 'open', vx(obj.x), vy(obj.y), scale(obj.radius), obj.angle1, obj.angle2, obj.segments)elseif obj.type == 'ellipse' thenlove.graphics.ellipse(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radiusx), scale(obj.radiusy))elseif obj.type == 'bezier' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'text' thenif obj.w == nil thenlove.graphics.draw(obj.text, vx(obj.x), vy(obj.y))elseedit.draw(obj.editor, obj.fg or {r=0,g=0,b=0}, not obj.show_cursor)endendendend
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":639,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":640,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
on.mouse_press = function(x,y, mouse_button)local node_id = to_node(x,y)if node_id thenApp.setClipboardText(Nodes[node_id].urlelseendendPan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
{"Input_filename":436,"on.update":368,"scale":7,"on.keychord_press":644,"render_thread_to_surface":653,"on.initialize":446,"dehtml":456,"add_thick_line":400,"line_height":365,"initialize_editor":338,"copy_shape":396,"header":651,"load_from_iterator":463,"ntracks":600,"Nodes":593,"compute_ntracks":598,"split_lines":469,"on.text_input":587,"ensure_cursor_node_within_viewport":643,"on.code_change":578,"vy":8,"Surface":588,"Cursor_node":172,"update_editor_box":430,"to_node":611,"fw_parent":652,"B":379,"fw_app":"mastodon-unfurl","add_node":650,"on.draw":632,"A":582,"to_text":180,"render_node_and_descendants":646,"y_of_schema1":364,"vx":5,"Viewport":303,"box_height":345,"schema1_of_y":366,"compute_layout":619,"font":353,"on":1,"on.mouse_press":618,"add_edge":575,"on.mouse_release":586}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":571,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":571,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":568,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":572,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if provided-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = Nodes[id]if parent.children == nil thenparent.surface_node = add_node(xlo, y, parent, grandparent_surface_node)returnendlocal parent_xlo = xposition(parent, xlo, xhi)parent.surface_node = add_node(parent_xlo, y, parent, grandparent_surface_node)local parent_height = box_height(parent.surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = Nodes[child_id]render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent.surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
{"on.code_change":578,"line_height":365,"add_thick_line":400,"Surface":588,"on.keychord_press":584,"ntracks":600,"on.mouse_press":618,"A":582,"on.mouse_release":586,"on.text_input":587,"scale":7,"Nodes":593,"on":1,"schema1_of_y":366,"font":353,"to_node":611,"y_of_schema1":364,"add_edge":575,"on.draw":627,"render_thread_to_surface":626,"B":379,"box_height":345,"on.update":368,"dehtml":456,"copy_shape":396,"add_node":590,"Input_filename":436,"vy":8,"compute_layout":619,"Viewport":303,"load_from_iterator":463,"split_lines":469,"to_text":180,"on.initialize":446,"Cursor_node":172,"compute_ntracks":598,"fw_app":"mastodon-luaML","update_editor_box":430,"fw_parent":626,"initialize_editor":338,"vx":5,"render_node_and_descendants":614}
{"fw_parent":604,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":605,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":603,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"to_node":604,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":600,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":602,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
add_edge = function(node, parent)print('add edge', node.x, node.y, parent.x, parent.y)local line = {type='line',data={parent.x + 600/2, parent.y + box_height(node),node.x + 600/2, node.y,},}print('add edge 2', line.data[2], line.data[4])table.insert(Surface, line)end
to_node = function(x,y)for _,node in ipairs(Surface) doif node.type == 'text' thenif x >= vx(node.x) and node.w and x < vx(node.x + node.w) thenif y >= vy(node.y) and node.h and y < vy(node.y + node.h) thenreturn node.idendendendendend
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]if Cursor_node.surface_node.y < Viewport.y thenViewport.y = Cursor_node.surface_node.y - 50B()endendelseif chord == 'C-down' thenif Cursor_node.children and #Cursor_node.children > 0 thenCursor_node = Nodes[Cursor_node.children[1]]local snode = Cursor_node.surface_nodelocal limit = snode.y + box_height(snode)if Viewport.y < limit - App.screen.height/Viewport.zoom thenViewport.y = limit - (App.screen.height-50)/Viewport.zoomendendelseif chord == 'C-left' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx > 1 thenCursor_node = Nodes[parent.children[idx-1]]endendendelseif chord == 'C-right' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx < #parent.children thenCursor_node = Nodes[parent.children[idx+1]]endendendendend
{"box_height":667,"B":666,"compute_layout":619,"ntracks":600,"on.code_change":578,"add_thick_line":400,"render_thread_to_surface":655,"dehtml":663,"on":1,"update_editor_box":430,"load_from_iterator":463,"fw_parent":669,"on.mouse_release":586,"split_lines":469,"on.update":368,"Surface":588,"on.keychord_press":644,"to_text":180,"ensure_cursor_node_within_viewport":643,"Nodes":593,"y_of_schema1":364,"to_node":611,"header":651,"initialize_editor":338,"Root":654,"add_node":650,"schema1_of_y":366,"Viewport":303,"copy_shape":396,"render_node_and_descendants":670,"xposition":669,"line_height":365,"vx":5,"Cursor_node":172,"scale":7,"on.mouse_press":618,"add_edge":575,"fw_app":"mastodon-unfurl","compute_ntracks":598,"on.draw":632,"Input_filename":436,"on.text_input":587,"on.initialize":665,"vy":8,"A":582,"font":353}
{"fw_parent":603,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":603,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"to_node":604,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":600,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":602,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
xposition = function(curr, xlo, xhi)-- return the left margin to position a node atif #node.children <= 1 thenreturn xloendlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = Nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)return parent_x - 620/2end
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- we're going to be computing box heightslove.graphics.setFont(love.graphics.newFont(scale(20)))-- compute mapping from ids to nodesNodes = {} -- id to objectNodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) doNodes[x.id] = xendlocal root = thread_dataCursor_node = root-- compute childrenfor _,x in pairs(Nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = Nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(Nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(Nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesrender_node_and_descendants(root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(nodes, x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesN_edges = 2render_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":638,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":639,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
{"box_height":667,"B":666,"compute_layout":619,"ntracks":600,"on.code_change":578,"add_thick_line":400,"render_thread_to_surface":655,"dehtml":663,"on":1,"update_editor_box":430,"load_from_iterator":463,"fw_parent":668,"on.mouse_release":586,"split_lines":469,"on.update":368,"Surface":588,"on.keychord_press":644,"to_text":180,"ensure_cursor_node_within_viewport":643,"Nodes":593,"y_of_schema1":364,"to_node":611,"header":651,"initialize_editor":338,"Root":654,"add_node":650,"schema1_of_y":366,"Viewport":303,"copy_shape":396,"render_node_and_descendants":646,"xposition":669,"line_height":365,"vx":5,"Cursor_node":172,"scale":7,"on.mouse_press":618,"add_edge":575,"fw_app":"mastodon-unfurl","compute_ntracks":598,"on.draw":632,"Input_filename":436,"on.text_input":587,"on.initialize":665,"vy":8,"A":582,"font":353}
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":625,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":625,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":626,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":571,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":570,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":568,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if provided-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = Nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content, parent.id, grandparent_surface_node)returnendlocal parent_xloif #parent.children <= 1 thenparent_xlo = xloelselocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = Nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)parent_xlo = parent_x - 620/2endlocal parent_surface_node = add_node(parent_xlo, y, parent.content, parent.id, grandparent_surface_node)local parent_height = box_height(parent_surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = Nodes[child_id]render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
xposition = function(nodes, curr, xlo, xhi)-- return the left margin to position a node atif #node.children <= 1 thenreturn xloendlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = Nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)return parent_x - 620/2end
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]if Cursor_node.surface_node.y < Viewport.y thenViewport.y = Cursor_node.surface_node.y - 50B()endendelseif chord == 'C-down' thenif Cursor_node.children and #Cursor_node.children > 0 thenCursor_node = Nodes[Cursor_node.children[1]]endelseif chord == 'C-left' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx > 1 thenCursor_node = Nodes[parent.children[idx-1]]endendendelseif chord == 'C-right' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx < #parent.children thenCursor_node = Nodes[parent.children[idx+1]]endendendendend
{"fw_parent":602,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":603,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":600,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":602,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
on.draw = function()love.graphics.setColor(1,0,0)for _,obj in ipairs(Surface) dolove.graphics.setColor(obj.r or 0, obj.g or 0, obj.b or 0)if obj.type == 'rectangle' thenprint(obj.text_node)if obj.text_node and obj.text_node == Cursor_node.surface_node thenlove.graphics.setColor(0.7, 0.7, 0, 0.4)endlove.graphics.rectangle(obj.drawmode or 'fill', vx(obj.x),vy(obj.y), scale(obj.w),scale(obj.h))elseif obj.type == 'line' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'circle' thenlove.graphics.circle(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radius))elseif obj.type == 'arc' thenlove.graphics.arc(obj.drawmode or 'line', obj.arctype or 'open', vx(obj.x), vy(obj.y), scale(obj.radius), obj.angle1, obj.angle2, obj.segments)elseif obj.type == 'ellipse' thenlove.graphics.ellipse(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radiusx), scale(obj.radiusy))elseif obj.type == 'bezier' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'text' thenif obj.w == nil thenlove.graphics.draw(obj.text, vx(obj.x), vy(obj.y))elseedit.draw(obj.editor, obj.fg or {r=0,g=0,b=0}, not obj.show_cursor)endendendend
{"box_height":667,"B":666,"compute_layout":619,"ntracks":600,"on.code_change":578,"add_thick_line":400,"render_thread_to_surface":655,"dehtml":663,"on":1,"update_editor_box":430,"load_from_iterator":463,"fw_parent":667,"on.mouse_release":586,"split_lines":469,"on.update":368,"Surface":588,"on.keychord_press":644,"to_text":180,"ensure_cursor_node_within_viewport":643,"Nodes":593,"y_of_schema1":364,"to_node":611,"header":651,"initialize_editor":338,"Root":654,"add_node":650,"schema1_of_y":366,"Viewport":303,"copy_shape":396,"render_node_and_descendants":646,"xposition":668,"line_height":365,"vx":5,"Cursor_node":172,"scale":7,"on.mouse_press":618,"add_edge":575,"fw_app":"mastodon-unfurl","compute_ntracks":598,"on.draw":632,"Input_filename":436,"on.text_input":587,"on.initialize":665,"vy":8,"A":582,"font":353}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(nodes, x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesN_edges = 1render_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":637,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":638,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":624,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":625,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":602,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":570,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":569,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":568,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- we're going to be computing box heightslove.graphics.setFont(love.graphics.newFont(scale(20)))-- compute mapping from ids to nodesNodes = {} -- id to objectNodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) doNodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(Nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = Nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(Nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(Nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesrender_node_and_descendants(root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]print(Cursor_node.surface_node.y, Viewport.y)if Cursor_node.surface_node.y < Viewport.y thenViewport.y = Cursor_node.surface_node.y - 50endendelseif chord == 'C-down' thenif Cursor_node.children and #Cursor_node.children > 0 thenCursor_node = Nodes[Cursor_node.children[1]]endelseif chord == 'C-left' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx > 1 thenCursor_node = Nodes[parent.children[idx-1]]endendendelseif chord == 'C-right' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx < #parent.children thenCursor_node = Nodes[parent.children[idx+1]]endendendendend
{"fw_parent":601,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":601,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":600,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":602,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
on.draw = function()love.graphics.setColor(1,0,0)for _,obj in ipairs(Surface) dolove.graphics.setColor(obj.r or 0, obj.g or 0, obj.b or 0)if obj.type == 'rectangle' thenprint(obj.text_node)if obj.text_node and obj.text_node == Cursor_node.surface_node thenlove.graphics.setColor(0.7, 0.7, 0, 0.1)endlove.graphics.rectangle(obj.drawmode or 'fill', vx(obj.x),vy(obj.y), scale(obj.w),scale(obj.h))elseif obj.type == 'line' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'circle' thenlove.graphics.circle(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radius))elseif obj.type == 'arc' thenlove.graphics.arc(obj.drawmode or 'line', obj.arctype or 'open', vx(obj.x), vy(obj.y), scale(obj.radius), obj.angle1, obj.angle2, obj.segments)elseif obj.type == 'ellipse' thenlove.graphics.ellipse(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radiusx), scale(obj.radiusy))elseif obj.type == 'bezier' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'text' thenif obj.w == nil thenlove.graphics.draw(obj.text, vx(obj.x), vy(obj.y))elseedit.draw(obj.editor, obj.fg or {r=0,g=0,b=0}, not obj.show_cursor)endendendend
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(nodes, x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesN_edges = 2render_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":636,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":637,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":623,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":624,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":602,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":569,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":568,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":568,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if provided-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = Nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content, parent.id, grandparent_surface_node)returnendlocal parent_xloif #parent.children <= 1 thenparent_xlo = xloelselocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = Nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)parent_xlo = parent_x - 620/2endlocal parent_surface_node = add_node(parent_xlo, y, parent.content, parent.id, grandparent_surface_node)local parent_height = box_height(parent_surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = Nodes[child_id]render_node_and_descendants(Nodes, child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]for k in pairs(Cursor_node) doprint(k)endprint(Cursor_node.y, Viewport.y)if Cursor_node.y < Viewport.y thenViewport.y = Cursor_node.y - 50endendelseif chord == 'C-down' thenif Cursor_node.children and #Cursor_node.children > 0 thenCursor_node = Nodes[Cursor_node.children[1]]endelseif chord == 'C-left' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx > 1 thenCursor_node = Nodes[parent.children[idx-1]]endendendelseif chord == 'C-right' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx < #parent.children thenCursor_node = Nodes[parent.children[idx+1]]endendendendend
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":567,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":567,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":568,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
on.draw = function()love.graphics.setColor(1,0,0)for _,obj in ipairs(Surface) dolove.graphics.setColor(obj.r or 0, obj.g or 0, obj.b or 0)if obj.type == 'rectangle' thenprint(obj.text_node)if obj.text_node and obj.text_node == Cursor_node.surface_node thenlove.graphics.setColor(1, 1, 0.4)endlove.graphics.rectangle(obj.drawmode or 'fill', vx(obj.x),vy(obj.y), scale(obj.w),scale(obj.h))elseif obj.type == 'line' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'circle' thenlove.graphics.circle(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radius))elseif obj.type == 'arc' thenlove.graphics.arc(obj.drawmode or 'line', obj.arctype or 'open', vx(obj.x), vy(obj.y), scale(obj.radius), obj.angle1, obj.angle2, obj.segments)elseif obj.type == 'ellipse' thenlove.graphics.ellipse(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radiusx), scale(obj.radiusy))elseif obj.type == 'bezier' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'text' thenif obj.w == nil thenlove.graphics.draw(obj.text, vx(obj.x), vy(obj.y))elseedit.draw(obj.editor, obj.fg or {r=0,g=0,b=0}, not obj.show_cursor)endendendend
{"fw_parent":600,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":601,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":600,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":597,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
add_node = function(x, y, text, parent_surface_node)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(text)),bg={r=0.7,g=0.7, b=1.0},}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)if parent_surface_node and N_edges > 0 thenadd_edge(surface_node, parent_surface_node)N_edges = N_edges - 1endreturn surface_nodeend
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":635,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":636,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":622,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":623,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":602,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
{"fw_parent":599,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":600,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":597,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(nodes, x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesN_edges = 1render_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]for k in pairs(Cursor_node) doprint(k)endprint(Cursor_node.y, Viewport.y)if Cursor_node.y < Viewport.y thenViewport.y = Cursor_node.y - 50endendelseif chord == 'C-down' thenif Cursor_node.children and #Cursor_node.children > 0 thenCursor_node = Nodes[Cursor_node.children[1]]endelseif chord == 'C-left' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx > 1 thenCursor_node = Nodes[parent.children[idx-1]]endendendelseif chord == 'C-right' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx < #parent.children thenCursor_node = Nodes[parent.children[idx+1]]endendendendend
{"fw_parent":598,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":599,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":597,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
on.draw = function()love.graphics.setColor(1,0,0)for _,obj in ipairs(Surface) dolove.graphics.setColor(obj.r or 0, obj.g or 0, obj.b or 0)if obj.type == 'rectangle' thenprint(obj.text_node)if obj.text_node and obj.text_node == Cursor_node.surface_node thenlove.graphics.setColor(0.8, 0.8, 0.4)endlove.graphics.rectangle(obj.drawmode or 'fill', vx(obj.x),vy(obj.y), scale(obj.w),scale(obj.h))elseif obj.type == 'line' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'circle' thenlove.graphics.circle(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radius))elseif obj.type == 'arc' thenlove.graphics.arc(obj.drawmode or 'line', obj.arctype or 'open', vx(obj.x), vy(obj.y), scale(obj.radius), obj.angle1, obj.angle2, obj.segments)elseif obj.type == 'ellipse' thenlove.graphics.ellipse(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radiusx), scale(obj.radiusy))elseif obj.type == 'bezier' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'text' thenif obj.w == nil thenlove.graphics.draw(obj.text, vx(obj.x), vy(obj.y))elseedit.draw(obj.editor, obj.fg or {r=0,g=0,b=0}, not obj.show_cursor)endendendend
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":567,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":566,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":563,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":634,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":635,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
{"fw_parent":597,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":505,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":597,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":621,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":622,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":602,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
compute_ntracks = function(parent)-- leaf nodes need 1 trackif parent.children == nil thenreturn 1end-- otherwise add up the tracks needed by all children (parent will fit in among them)-- if we have a single child, it will slide into the same track. This is desirable.local result = 0for _,child_id in ipairs(parent.children) dolocal child = Nodes[child_id]result = result + ntracks(child)endreturn resultend
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(nodes, x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesrender_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
on.draw = function()love.graphics.setColor(1,0,0)for _,obj in ipairs(Surface) dolove.graphics.setColor(obj.r or 0, obj.g or 0, obj.b or 0)if obj.type == 'rectangle' thenprint(obj.text_node)if obj.text_node and obj.text_node == Cursor_node.surface_node thenlove.graphics.setColor(0.8, 0.8, 0)endlove.graphics.rectangle(obj.drawmode or 'fill', vx(obj.x),vy(obj.y), scale(obj.w),scale(obj.h))elseif obj.type == 'line' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'circle' thenlove.graphics.circle(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radius))elseif obj.type == 'arc' thenlove.graphics.arc(obj.drawmode or 'line', obj.arctype or 'open', vx(obj.x), vy(obj.y), scale(obj.radius), obj.angle1, obj.angle2, obj.segments)elseif obj.type == 'ellipse' thenlove.graphics.ellipse(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radiusx), scale(obj.radiusy))elseif obj.type == 'bezier' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'text' thenif obj.w == nil thenlove.graphics.draw(obj.text, vx(obj.x), vy(obj.y))elseedit.draw(obj.editor, obj.fg or {r=0,g=0,b=0}, not obj.show_cursor)endendendend
on.keychord_press = function(chord, key)if chord == 'C-=' then-- zoom inViewport.zoom = Viewport.zoom+0.1B()elseif chord == 'C--' then-- zoom outViewport.zoom = Viewport.zoom-0.1B()elseif chord == 'C-0' then-- reset zoomViewport.zoom = 1.0B()elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]print(Cursor_node.y, Viewport.y)if Cursor_node.y < Viewport.y thenViewport.y = Cursor_node.y - 50endendelseif chord == 'C-down' thenif Cursor_node.children and #Cursor_node.children > 0 thenCursor_node = Nodes[Cursor_node.children[1]]endelseif chord == 'C-left' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx > 1 thenCursor_node = Nodes[parent.children[idx-1]]endendendelseif chord == 'C-right' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx < #parent.children thenCursor_node = Nodes[parent.children[idx+1]]endendendendend
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":566,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":565,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":563,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- we're going to be computing box heightslove.graphics.setFont(love.graphics.newFont(scale(20)))-- compute mapping from ids to nodesNodes = {} -- id to objectNodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) doNodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(Nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = Nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(Nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(Nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesrender_node_and_descendants(Nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":620,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":621,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":602,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":633,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":634,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
{"fw_parent":596,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":596,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":505,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":597,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if provided-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content, grandparent_surface_node)returnendlocal parent_xloif #parent.children <= 1 thenparent_xlo = xloelselocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)parent_xlo = parent_x - 620/2endlocal parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent_surface_node)local parent_height = box_height(parent_surface_node)print(id, parent_height)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
on.draw = function()love.graphics.setColor(1,0,0)for _,obj in ipairs(Surface) dolove.graphics.setColor(obj.r or 0, obj.g or 0, obj.b or 0)if obj.type == 'rectangle' thenprint(obj.text_node)if obj.text_node and obj.text_node == Cursor_node.surface_node thenlove.graphics.setColor(1, 1, 0)endlove.graphics.rectangle(obj.drawmode or 'fill', vx(obj.x),vy(obj.y), scale(obj.w),scale(obj.h))elseif obj.type == 'line' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'circle' thenlove.graphics.circle(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radius))elseif obj.type == 'arc' thenlove.graphics.arc(obj.drawmode or 'line', obj.arctype or 'open', vx(obj.x), vy(obj.y), scale(obj.radius), obj.angle1, obj.angle2, obj.segments)elseif obj.type == 'ellipse' thenlove.graphics.ellipse(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radiusx), scale(obj.radiusy))elseif obj.type == 'bezier' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'text' thenif obj.w == nil thenlove.graphics.draw(obj.text, vx(obj.x), vy(obj.y))elseedit.draw(obj.editor, obj.fg or {r=0,g=0,b=0}, not obj.show_cursor)endendendend
{"fw_parent":595,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":596,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":505,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":595,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
compute_ntracks = function(parent)-- leaf nodes need 1 trackif parent.children == nil thenreturn 1end-- otherwise add up the tracks needed by all children (parent will fit in among them)-- if we have a single child, it will slide into the same track. This is desirable.local result = 0for _,child_id in ipairs(parent.children) dolocal child = Nodes[child_id]result = result + ntracks(Nodes, child)endreturn resultend
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":564,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":563,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":619,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":620,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":602,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":618,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":617,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":602,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if providedprint(id)-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content, grandparent_surface_node)returnendlocal parent_xloif #parent.children <= 1 thenparent_xlo = xloelselocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)parent_xlo = parent_x - 620/2endlocal parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent_surface_node)local parent_height = box_height(parent_surface_node)print(id, parent_height)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- we're going to be computing box heightslove.graphics.setFont(love.graphics.newFont(scale(20)))-- compute mapping from ids to nodesNodes = {} -- id to objectNodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) doNodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(Nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = Nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(Nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(Nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(Nodes, x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesrender_node_and_descendants(Nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":563,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":563,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":564,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"fw_parent":594,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":519,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":505,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":595,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":562,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":563,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":562,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
add_node = function(x, y, text, parent_surface_node)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(text)),bg={r=0.7,g=0.7, b=1.0},}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)if parent_surface_node thenadd_edge(surface_node, parent_surface_node)endreturn surface_nodeend
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- we're going to be computing box heightslove.graphics.setFont(love.graphics.newFont(scale(20)))-- compute mapping from ids to nodesNodes = {} -- id to objectNodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) doNodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = Nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(Nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(Nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(Nodes, x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesrender_node_and_descendants(Nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
on.mouse_press = function(x,y, mouse_button)local node_id = to_node(x,y)if node_id thenApp.setClipboardText(Nodes[node_id].url)Cursor_node = Nodes[node_id]print(Cursor_node)elseendendPan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
{"fw_parent":593,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":519,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":505,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":594,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if providedprint(id)-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content, grandparent_surface_node)returnendlocal parent_xloif #parent.children <= 1 thenparent_xlo = xloelselocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)parent_xlo = parent_x - 620/2endlocal parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent_surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node) + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":618,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":617,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":615,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":614,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":617,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
{"fw_parent":592,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":519,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":505,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":589,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":561,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":560,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":562,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
on.draw = function()love.graphics.setColor(1,0,0)for _,obj in ipairs(Surface) dolove.graphics.setColor(obj.r or 0, obj.g or 0, obj.b or 0)if obj.type == 'rectangle' thenif obj.text_node and obj.text_node == Cursor_node.surface_node thenlove.graphics.setColor(0.7, 0.7, 0)endlove.graphics.rectangle(obj.drawmode or 'fill', vx(obj.x),vy(obj.y), scale(obj.w),scale(obj.h))elseif obj.type == 'line' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'circle' thenlove.graphics.circle(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radius))elseif obj.type == 'arc' thenlove.graphics.arc(obj.drawmode or 'line', obj.arctype or 'open', vx(obj.x), vy(obj.y), scale(obj.radius), obj.angle1, obj.angle2, obj.segments)elseif obj.type == 'ellipse' thenlove.graphics.ellipse(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radiusx), scale(obj.radiusy))elseif obj.type == 'bezier' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'text' thenif obj.w == nil thenlove.graphics.draw(obj.text, vx(obj.x), vy(obj.y))elseedit.draw(obj.editor, obj.fg or {r=0,g=0,b=0}, not obj.show_cursor)endendendend
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if providedprint(id)-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]if parent.children == nil or #parent.children <= 1 thenadd_node(xlo, y, parent.content, grandparent_surface_node)returnendlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)local parent_xlo = parent_x - 620/2local parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent_surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node) + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":613,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":616,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":615,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":614,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":617,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if provided-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content, parent.id, grandparent_surface_node)returnendlocal parent_xloif #parent.children <= 1 thenparent_xlo = xloelselocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)parent_xlo = parent_x - 620/2endlocal parent_surface_node = add_node(parent_xlo, y, parent.content, parent.id, grandparent_surface_node)local parent_height = box_height(parent_surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":560,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":560,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":561,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"fw_parent":591,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"compute_ntracks":519,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":505,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":589,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
on.draw = function()love.graphics.setColor(1,0,0)for _,obj in ipairs(Surface) dolove.graphics.setColor(obj.r or 0, obj.g or 0, obj.b or 0)if obj.type == 'rectangle' thenif obj.text_node == Cursor_node.surface_node thenlove.graphics.setColor(0.7, 0.7, 0)endlove.graphics.rectangle(obj.drawmode or 'fill', vx(obj.x),vy(obj.y), scale(obj.w),scale(obj.h))elseif obj.type == 'line' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'circle' thenlove.graphics.circle(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radius))elseif obj.type == 'arc' thenlove.graphics.arc(obj.drawmode or 'line', obj.arctype or 'open', vx(obj.x), vy(obj.y), scale(obj.radius), obj.angle1, obj.angle2, obj.segments)elseif obj.type == 'ellipse' thenlove.graphics.ellipse(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radiusx), scale(obj.radiusy))elseif obj.type == 'bezier' thenlove.graphics.line(unpack(obj.zdata))elseif obj.type == 'text' thenif obj.w == nil thenlove.graphics.draw(obj.text, vx(obj.x), vy(obj.y))elseedit.draw(obj.editor, obj.fg or {r=0,g=0,b=0}, not obj.show_cursor)endendendend
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":559,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":560,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":554,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":613,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":615,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":615,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":614,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":616,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
add_node = function(x, y, text, parent_surface_node)print('add node', x)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(text)),bg={r=0.7,g=0.7, b=1.0},}print('aa 1', surface_node.x)compute_layout(surface_node, surface_node.x, surface_node.y, Surface)print('aa 2', surface_node.x)if parent_surface_node thenprint('aa', surface_node.x, parent_surface_node.x)add_edge(surface_node, parent_surface_node)endreturn surface_nodeend
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if provided-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content, grandparent_surface_node)returnendlocal parent_xloif #parent.children <= 1 thenparent_xlo = xloelselocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)parent_xlo = parent_x - 620/2endlocal parent_surface_node = add_node(parent_xlo, y, parent.content, parent.id, grandparent_surface_node)local parent_height = box_height(parent_surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":613,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":614,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":615,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":614,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":558,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":559,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":554,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"vy":8,"Cursor_node":172,"on.update":368,"ntracks":505,"render_thread_to_surface":589,"dehtml":456,"add_thick_line":400,"copy_shape":396,"fw_parent":590,"fw_app":"mastodon-luaML","load_from_iterator":463,"on.code_change":578,"font":353,"box_height":345,"split_lines":469,"scale":7,"add_node":590,"on.draw":418,"vx":5,"Viewport":303,"schema1_of_y":366,"on.mouse_release":586,"update_editor_box":430,"to_text":180,"Surface":588,"render_node_and_descendants":591,"y_of_schema1":364,"compute_layout":385,"Input_filename":436,"compute_ntracks":519,"A":582,"B":379,"on.keychord_press":584,"add_edge":575,"on":1,"on.text_input":587,"on.mouse_press":585,"initialize_editor":338,"line_height":365,"on.initialize":446}
add_node = function(x, y, text, parent_surface_node)print('add node', x)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(text)),bg={r=0.7,g=0.7, b=1.0},}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)if parent_surface_node thenprint('aa', surface_node.x, parent_surface_node.x)add_edge(surface_node, parent_surface_node)endreturn surface_nodeend
{"vy":8,"Cursor_node":172,"on.update":368,"ntracks":505,"render_thread_to_surface":589,"dehtml":456,"add_thick_line":400,"copy_shape":396,"fw_parent":589,"fw_app":"mastodon-luaML","load_from_iterator":463,"on.code_change":578,"font":353,"box_height":345,"split_lines":469,"scale":7,"add_node":590,"on.draw":418,"vx":5,"Viewport":303,"schema1_of_y":366,"on.mouse_release":586,"update_editor_box":430,"to_text":180,"Surface":588,"render_node_and_descendants":579,"y_of_schema1":364,"compute_layout":385,"Input_filename":436,"compute_ntracks":519,"A":582,"B":379,"on.keychord_press":584,"add_edge":575,"on":1,"on.text_input":587,"on.mouse_press":585,"initialize_editor":338,"line_height":365,"on.initialize":446}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":557,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":557,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":554,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
add_node = function(x, y, text, id, parent_surface_node)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(text)),bg={r=0.7,g=0.7, b=1.0},toot_id=id,}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)if parent_surface_node thenadd_edge(surface_node, parent_surface_node)endreturn surface_nodeend
add_edge = function(node, parent)print('add edge', node.x, node.y, parent.x, parent.y)local line = {type='line',data={parent.x + 600/2, parent.y + box_height(node),node.x + 600/2, node.y,},}table.insert(Surface, line)end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":556,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":557,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":554,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":556,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
add_node = function(x, y, text, parent_surface_node)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(text)),bg={r=0.7,g=0.7, b=1.0},}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)if parent_surface_node thenadd_edge(surface_node, parent_surface_node)endreturn surface_nodeend
compute_layout = function(node, x,y, nodes_to_render, preserve_screen_top_of_cursor_node)-- append to nodes_to_render flattened instructions to render a hierarchy of nodes-- return x,y rendered until (surface coordinates)if node.type == 'text' then-- leaf node containing raw textnode.x = xnode.y = y-- render background if necessarylocal node_to_renderif node.bg thennode_to_render = {type='rectangle', r=node.bg.r, g=node.bg.g, b=node.bg.b, x=node.x, y=node.y}table.insert(nodes_to_render, node_to_render)end-- render contentsif node.width thennode.w = node.widthelsenode.w = 0for i,s in ipairs(node.data) dolocal text = love.graphics.newText(font(20), node.data)local width = text:getWidth()if node.w < width then node.w = width endendendif node.editor == nil theninitialize_editor(node)elseupdate_editor_box(node, preserve_screen_top_of_cursor_node)endnode.h = box_height(node)table.insert(nodes_to_render, node)if node_to_render thennode_to_render.w = node.wnode_to_render.h = node.hendelseif node.type == 'rows' thennode.x = xnode.y = ylocal node_to_renderif node.bg thennode_to_render = {type='rectangle', r=node.bg.r, g=node.bg.g, b=node.bg.b, x=node.x, y=node.y, text_node=node}table.insert(nodes_to_render, node_to_render)end-- lay out children top to bottomlocal subx,suby = x,ylocal w,h = 0,0local subnodesfor _,child in ipairs(node.data) doif child.margin thensuby = suby+child.marginh = h+child.marginendif not child.width thenchild.width = node.width -- HACK: should we set child.w or child.width? Neither is quite satisfactory.endsubx,suby = compute_layout(child, x,suby, nodes_to_render)if w < child.w thenw = child.wendh = h+child.hendnode.w = wnode.h = hif node_to_render thennode_to_render.w = wnode_to_render.h = hendelseif node.type == 'cols' thennode.x = xnode.y = y-- lay out children left to rightlocal node_to_renderif node.bg thennode_to_render = {type='rectangle', r=node.bg.r, g=node.bg.g, b=node.bg.b, x=node.x, y=node.y}table.insert(nodes_to_render, node_to_render)endlocal subx,suby = x,ylocal w,h = 0,0for _,child in ipairs(node.data) doif child.margin thensubx = subx+child.marginw = w+child.marginendsubx,suby = compute_layout(child, subx,y, nodes_to_render)w = w + child.wif h < child.h thenh = child.hendendnode.w = wnode.h = hif node_to_render thennode_to_render.w = wnode_to_render.h = hendendreturn x+node.w,y+node.hend
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- we're going to be computing box heightslove.graphics.setFont(love.graphics.newFont(scale(20)))-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(nodes, x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesrender_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":555,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":555,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":554,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":556,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"schema1_of_y":366,"ntracks":505,"compute_ntracks":519,"y_of_schema1":364,"A":582,"compute_layout":385,"render_node_and_descendants":579,"B":379,"line_height":365,"on.code_change":578,"Surface":588,"Input_filename":436,"on.draw":418,"vx":5,"scale":7,"Viewport":303,"Cursor_node":172,"vy":8,"to_text":180,"on.mouse_press":585,"render_thread_to_surface":589,"initialize_editor":338,"on.update":368,"dehtml":456,"on.keychord_press":584,"copy_shape":396,"on.initialize":446,"fw_app":"mastodon-luaML","on":1,"fw_parent":588,"add_node":576,"load_from_iterator":463,"on.text_input":587,"add_edge":575,"add_thick_line":400,"box_height":345,"update_editor_box":430,"on.mouse_release":586,"split_lines":469,"font":353}
add_edge = function(node, parent)print('add edge', node.id, parent.id)local line = {type='line',data={parent.x + 600/2, parent.y + box_height(node),node.x + 600/2, node.y,},}table.insert(Surface, line)end
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if provided-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = Nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content, parent.id, grandparent_surface_node)returnendlocal parent_xloif #parent.children <= 1 thenparent_xlo = xloelselocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = Nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)parent_xlo = parent_x - 620/2endparent.surface_node = add_node(parent_xlo, y, parent.content, parent.id, grandparent_surface_node)local parent_height = box_height(parent.surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = Nodes[child_id]render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent.surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":554,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":555,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":554,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":551,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
add_node = function(x, y, text, parent_surface_node)print('add node')local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(text)),bg={r=0.7,g=0.7, b=1.0},}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)if parent_surface_node thenadd_edge(surface_node, parent_surface_node)endreturn surface_nodeend
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":613,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":613,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":614,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
on.mouse_press = function(x,y, mouse_button)local node_id = to_node(x,y)if node_id thenApp.setClipboardText(Nodes[node_id].url)Cursor_node = Nodes[node_id]elseendendPan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":613,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":612,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":603,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if providedprint(id)-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content, grandparent_surface_node)returnendlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)local parent_xlo = parent_x - 620/2local parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent_surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node) + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":553,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":552,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":554,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":551,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if providedprint(id)-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content, grandparent_surface_node)returnendlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)local parent_xlo = parent_x - 620/2local parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node) + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":552,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":552,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":553,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":551,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":551,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":552,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":547,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":551,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
add_node = function(x, y, text, parent)print('add node')local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(text)),bg={r=0.7,g=0.7, b=1.0},}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)if parent thenadd_edge(node, parent)endreturn surface_nodeend
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":550,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":550,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":547,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":551,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"schema1_of_y":366,"on.keychord_press":391,"split_lines":469,"fw_parent":549,"y_of_schema1":364,"fw_app":"mastodon-luaML","add_node":550,"render_node_and_descendants":547,"Input_filename":436,"Cursor_node":172,"compute_layout":385,"add_edge":548,"to_text":180,"scale":7,"initialize_editor":338,"on.text_input":388,"ntracks":505,"copy_shape":396,"compute_ntracks":519,"render_thread_to_surface":525,"line_height":365,"Surface":434,"add_thick_line":400,"dehtml":456,"on.draw":418,"on":1,"vx":5,"B":379,"Viewport":303,"update_editor_box":430,"on.mouse_press":179,"vy":8,"font":353,"A":474,"on.initialize":446,"load_from_iterator":463,"box_height":345,"on.mouse_release":367,"on.code_change":473,"on.update":368}
add_node = function(x, y, text, parent)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(text)),bg={r=0.7,g=0.7, b=1.0},}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)if parent thenadd_edge(node, parent)endreturn surface_nodeend
{"schema1_of_y":366,"on.keychord_press":391,"split_lines":469,"fw_parent":548,"y_of_schema1":364,"fw_app":"mastodon-luaML","add_node":549,"render_node_and_descendants":547,"Input_filename":436,"Cursor_node":172,"compute_layout":385,"add_edge":548,"to_text":180,"scale":7,"initialize_editor":338,"on.text_input":388,"ntracks":505,"copy_shape":396,"compute_ntracks":519,"render_thread_to_surface":525,"line_height":365,"Surface":434,"add_thick_line":400,"dehtml":456,"on.draw":418,"on":1,"vx":5,"B":379,"Viewport":303,"update_editor_box":430,"on.mouse_press":179,"vy":8,"font":353,"A":474,"on.initialize":446,"load_from_iterator":463,"box_height":345,"on.mouse_release":367,"on.code_change":473,"on.update":368}
add_node = function(x, y, text, parent)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(text)),bg={r=0.7,g=0.7, b=1.0},}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)add_edge(node, parent)return surface_nodeend
{"schema1_of_y":366,"on.keychord_press":391,"split_lines":469,"fw_parent":547,"y_of_schema1":364,"fw_app":"mastodon-luaML","add_node":546,"render_node_and_descendants":547,"Input_filename":436,"Cursor_node":172,"compute_layout":385,"add_edge":548,"to_text":180,"scale":7,"initialize_editor":338,"on.text_input":388,"ntracks":505,"copy_shape":396,"compute_ntracks":519,"render_thread_to_surface":525,"line_height":365,"Surface":434,"add_thick_line":400,"dehtml":456,"on.draw":418,"on":1,"vx":5,"B":379,"Viewport":303,"update_editor_box":430,"on.mouse_press":179,"vy":8,"font":353,"A":474,"on.initialize":446,"load_from_iterator":463,"box_height":345,"on.mouse_release":367,"on.code_change":473,"on.update":368}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if providedprint(id)-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content, grandparent)returnendlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)local parent_xlo = parent_x - 620/2local parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node) + 50, curr_boundary, curr_boundary + 620*child.ntracks)curr_boundary = curr_boundary + 620*child.ntracksendend
{"schema1_of_y":366,"on.keychord_press":391,"split_lines":469,"fw_parent":546,"y_of_schema1":364,"fw_app":"mastodon-luaML","add_node":546,"render_node_and_descendants":547,"Input_filename":436,"Cursor_node":172,"compute_layout":385,"to_text":180,"scale":7,"initialize_editor":338,"on.text_input":388,"ntracks":505,"copy_shape":396,"compute_ntracks":519,"render_thread_to_surface":525,"line_height":365,"Surface":434,"add_thick_line":400,"dehtml":456,"on.draw":418,"on":1,"vx":5,"B":379,"Viewport":303,"update_editor_box":430,"on.mouse_press":179,"vy":8,"font":353,"A":474,"on.initialize":446,"load_from_iterator":463,"box_height":345,"on.mouse_release":367,"on.code_change":473,"on.update":368}
{"schema1_of_y":366,"on.keychord_press":391,"split_lines":469,"fw_parent":545,"y_of_schema1":364,"fw_app":"mastodon-luaML","add_node":546,"render_node_and_descendants":545,"Input_filename":436,"Cursor_node":172,"compute_layout":385,"to_text":180,"scale":7,"initialize_editor":338,"on.text_input":388,"ntracks":505,"copy_shape":396,"compute_ntracks":519,"render_thread_to_surface":525,"line_height":365,"Surface":434,"add_thick_line":400,"dehtml":456,"on.draw":418,"on":1,"vx":5,"B":379,"Viewport":303,"update_editor_box":430,"on.mouse_press":179,"vy":8,"font":353,"A":474,"on.initialize":446,"load_from_iterator":463,"box_height":345,"on.mouse_release":367,"on.code_change":473,"on.update":368}
add_node = function(x, y, text, grandparent)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(text)),bg={r=0.7,g=0.7, b=1.0},}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)return surface_nodeend
header = function(node)local result = {}if node.account == nil thentable.insert(result, node.user)elseif node.account.display_name thentable.insert(result, node.account.display_name)elsetable.insert(result, node.account.username)endtable.insert(result, node.created_at)table.insert(result, '---')return table.concat(result, '\n')end
{"render_thread_to_surface":626,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"header":651,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.initialize":446,"on.update":368,"scale":7,"add_node":650,"render_node_and_descendants":646,"vx":5,"add_edge":575,"initialize_editor":338,"vy":8,"Nodes":593,"add_thick_line":400,"ntracks":600,"Input_filename":436,"compute_layout":619,"to_text":180,"A":582,"on.keychord_press":644,"box_height":345,"line_height":365,"B":379,"fw_parent":650,"to_node":611,"fw_app":"mastodon-unfurl","ensure_cursor_node_within_viewport":643,"on.mouse_release":586}
{"render_thread_to_surface":626,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"header":649,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.initialize":446,"on.update":368,"scale":7,"add_node":650,"render_node_and_descendants":646,"vx":5,"add_edge":575,"initialize_editor":338,"vy":8,"Nodes":593,"add_thick_line":400,"ntracks":600,"Input_filename":436,"compute_layout":619,"to_text":180,"A":582,"on.keychord_press":644,"box_height":345,"line_height":365,"B":379,"fw_parent":649,"to_node":611,"fw_app":"mastodon-unfurl","ensure_cursor_node_within_viewport":643,"on.mouse_release":586}
add_node = function(x, y, node, parent_surface_node)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(header(node)..'\n'..dehtml(node.content)),bg={r=0.7,g=0.7, b=1.0},toot_id=node.id,}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)if parent_surface_node thenadd_edge(surface_node, parent_surface_node)endreturn surface_nodeend
header = function(node)local result = {}assert(node.account)if node.account.display_name thentable.insert(result, node.account.display_name)elsetable.insert(result, node.account.username)endtable.insert(result, node.created_at)table.insert(result, '---')return table.concat(result, '\n')end
{"render_thread_to_surface":626,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"header":649,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.initialize":446,"on.update":368,"scale":7,"add_node":647,"render_node_and_descendants":646,"vx":5,"add_edge":575,"initialize_editor":338,"vy":8,"Nodes":593,"add_thick_line":400,"ntracks":600,"Input_filename":436,"compute_layout":619,"to_text":180,"A":582,"on.keychord_press":644,"box_height":345,"line_height":365,"B":379,"fw_parent":647,"to_node":611,"fw_app":"mastodon-unfurl","ensure_cursor_node_within_viewport":643,"on.mouse_release":586}
header = function(node)local result = {}assert(node.account)if node.account.display_name thentable.insert(result, node.account.display_name)elsetable.insert(result, node.account.username)endtable.insert(result, node.created_attable.insert(result, '---')return table.concat(result, '\n')end
{"render_thread_to_surface":626,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"header":648,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.mouse_release":586,"on.update":368,"scale":7,"add_node":647,"render_node_and_descendants":646,"vx":5,"compute_layout":619,"ntracks":600,"vy":8,"Nodes":593,"add_thick_line":400,"ensure_cursor_node_within_viewport":643,"Input_filename":436,"on.initialize":446,"to_text":180,"A":582,"line_height":365,"box_height":345,"on.keychord_press":644,"B":379,"fw_parent":647,"to_node":611,"fw_app":"mastodon-unfurl","initialize_editor":338,"add_edge":575}
{"render_thread_to_surface":626,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.mouse_release":586,"on.update":368,"scale":7,"add_node":647,"render_node_and_descendants":646,"vx":5,"compute_layout":619,"ntracks":600,"vy":8,"Nodes":593,"add_thick_line":400,"ensure_cursor_node_within_viewport":643,"Input_filename":436,"on.initialize":446,"to_text":180,"A":582,"line_height":365,"box_height":345,"on.keychord_press":644,"B":379,"fw_parent":646,"to_node":611,"fw_app":"mastodon-unfurl","initialize_editor":338,"add_edge":575}
add_node = function(x, y, node, parent_surface_node)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(node.content)),bg={r=0.7,g=0.7, b=1.0},toot_id=node.id,}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)if parent_surface_node thenadd_edge(surface_node, parent_surface_node)endreturn surface_nodeend
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if provided-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = Nodes[id]if parent.children == nil thenparent.surface_node = add_node(xlo, y, parent, grandparent_surface_node)returnendlocal parent_xloif #parent.children <= 1 thenparent_xlo = xloelselocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = Nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)parent_xlo = parent_x - 620/2endparent.surface_node = add_node(parent_xlo, y, parent, grandparent_surface_node)local parent_height = box_height(parent.surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = Nodes[child_id]render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent.surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
{"render_thread_to_surface":626,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.mouse_release":586,"on.update":368,"scale":7,"add_node":590,"render_node_and_descendants":646,"vx":5,"compute_layout":619,"ntracks":600,"vy":8,"Nodes":593,"add_thick_line":400,"ensure_cursor_node_within_viewport":643,"Input_filename":436,"on.initialize":446,"to_text":180,"A":582,"line_height":365,"box_height":345,"on.keychord_press":644,"B":379,"fw_parent":645,"to_node":611,"fw_app":"mastodon-unfurl","initialize_editor":338,"add_edge":575}
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if provided-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = Nodes[id]if parent.children == nil thenparent.surface_node = add_node(xlo, y, parent, grandparent_surface_node)returnendlocal parent_xloif #parent.children <= 1 thenparent_xlo = xloelselocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = Nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)parent_xlo = parent_x - 620/2endparent.surface_node = add_node(parent_xlo, y, parent.content, parent.id, grandparent_surface_node)local parent_height = box_height(parent.surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = Nodes[child_id]render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent.surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
{"render_thread_to_surface":626,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.mouse_release":586,"on.update":368,"scale":7,"add_node":590,"render_node_and_descendants":645,"vx":5,"compute_layout":619,"ntracks":600,"vy":8,"Nodes":593,"add_thick_line":400,"ensure_cursor_node_within_viewport":643,"Input_filename":436,"on.initialize":446,"to_text":180,"A":582,"line_height":365,"box_height":345,"on.keychord_press":644,"B":379,"fw_parent":644,"to_node":611,"fw_app":"mastodon-unfurl","initialize_editor":338,"add_edge":575}
render_node_and_descendants = function(nodes, id, y, xlo, xhi)print(id)-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content)returnendlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)local parent_xlo = parent_x - 620/2local parent_surface_node = add_node(parent_xlo, y, parent.content)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node) + 50, curr_boundary, curr_boundary + 620*child.ntracks)curr_boundary = curr_boundary + 620*child.ntracksendend
{"Input_filename":436,"fw_parent":544,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":545,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
{"Input_filename":436,"fw_parent":543,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":543,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
render_node_and_descendants = function(nodes, id, y, xlo, xhi)print(id)-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]if parent.children == nil thenadd_node(xlo, y, parent.content)returnendlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)local parent_xlo = parent_x - 620/2local parent_surface_node = add_node(parent_xlo, y, parent.content)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node), curr_boundary, curr_boundary + 620*child.ntracks)curr_boundary = curr_boundary + 620*child.ntracksendend
{"Input_filename":436,"fw_parent":542,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"center_x_above_children":542,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":543,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
{"Input_filename":436,"fw_parent":541,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"center_x_above_children":542,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":541,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
center_x_above_children = function(nodes, parent, xlo, xhi)-- given parent has n children, each of whom occupies various numbers of tracks, return the x of the center, somewhere between xlo and xhiif parent.children == nil thenreturn (xlo+xhi)/2endlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendreturn total_boundaries / (#parent.children-1)end
render_node_and_descendants = function(nodes, id, y, xlo, xhi)print(id)-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]local parent_x = center_x_above_children(nodes, parent, xlo, xhi)local parent_xlo = parent_x - 620/2local parent_surface_node = add_node(parent_xlo, y, parent.content)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node), curr_boundary, curr_boundary + 620*child.ntracks)curr_boundary = curr_boundary + 620*child.ntracksendend
{"Input_filename":436,"fw_parent":540,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"center_x_above_children":540,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":541,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
{"Input_filename":436,"fw_parent":539,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"center_x_above_children":540,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":539,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
center_x_above_children = function(nodes, parent, xlo, xhi)-- given parent has n children, each of whom occupies various numbers of tracks, return the x of the center, somewhere between xlo and xhiif parent.children == nil thenreturn (xlo+xheight)/2endlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendreturn total_boundaries / (#parent.children-1)end
render_node_and_descendants = function(nodes, id, y, xlo, xhi)print(id)-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]local total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)local parent_xlo = parent_x - 620/2local parent_surface_node = add_node(parent_xlo, y, parent.content)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node), curr_boundary, curr_boundary + 620*child.ntracks)curr_boundary = curr_boundary + 620*child.ntracksendend
{"Input_filename":436,"fw_parent":538,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":539,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
render_node_and_descendants = function(nodes, id, y, xlo, xhi)-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = nodes[id]local total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#parent.children-1 dolocal child_id = parent.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#parent.children-1)local parent_xlo = parent_x - 620/2local parent_surface_node = add_node(parent_xlo, y, parent.content)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node), curr_boundary, curr_boundary + 620*child.ntracks)curr_boundary = curr_boundary + 620*child.ntracksendend
{"Input_filename":436,"fw_parent":537,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":538,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
render_node_and_descendants = function(nodes, id, y, xlo, xhi)-- position the root between xlo and xhi to be closer to children with fewer trackslocal node = nodes[id]local total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#node.children-1 dolocal child_id = node.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#node.children-1)local parent_xlo = parent_x - 620/2local parent_surface_node = add_node(parent_xlo, y, node.content)local curr_boundary = xlofor _,child_id in ipairs(node.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + box_height(node), curr_boundary, curr_boundary + 620*child.ntracks)curr_boundary = curr_boundary + 620*child.ntracksendend
{"Input_filename":436,"fw_parent":536,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":537,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
{"Input_filename":436,"fw_parent":535,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":535,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
add_node = function(x, y, text)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(dehtml(text)),bg={r=0.7,g=0.7, b=1.0},}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)return surface_nodeend
render_node_and_descendants = function(nodes, id, y, xlo, xhi)-- position the root between xlo and xhi to be closer to children with fewer trackslocal node = nodes[id]local total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#node.children-1 dolocal child_id = node.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#node.children-1)local parent_xlo = parent_x - 620/2add_node(parent_xlo, y, node.content)local curr_boundary = xlofor _,child_id in ipairs(node.children) dolocal child = nodes[child_id]render_node_and_descendants(nodes, child_id, y + box_height(node), curr_boundary, curr_boundary + 620*child.ntracks)curr_boundary = curr_boundary + 620*child.ntracksendend
{"Input_filename":436,"fw_parent":534,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":480,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":535,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
render_node_and_descendants = function(nodes, id, y, xlo, xhi)-- position the root between xlo and xhi to be closer to children with fewer trackslocal node = nodes[id]local total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#node.children-1 dolocal child_id = node.children[child_idx]local child = nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal parent_x = total_boundaries / (#node.children-1)local parent_xlo = parent_x - 620/2add_node(parent_xlo, y, nodes[id].content)end
{"Input_filename":436,"fw_parent":533,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":480,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":534,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
{"Input_filename":436,"fw_parent":532,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":480,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":533,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":531,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":532,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":530,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":531,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":529,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":530,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":528,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":529,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":527,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":528,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":526,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":527,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":525,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":526,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(nodes, x)endendfor _,x in pairs(nodes) doif x.children thenfor _,y in pairs(x.children) dolocal c = nodes[y]print(x.id, c.id, c.ntracks)endendend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesrender_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":524,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":523,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":523,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":522,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":523,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(nodes, x)endendfor _,x in pairs(nodes) doif x.children thenfor _,y in pairs(x.children) dolocal c = nodes[y]print(x.id, c.id, c.ntracks)endendend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesrender_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":521,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":522,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(nodes, x)endendfor _,x in pairs(nodes) doif x.children thenfor _,y in pairs(x.children) dolocal c = nodes[y]print(x.id, c.id, c.ntracks)endendend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesrender_node_and_descendants(nodes, thread_data.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":520,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":521,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(nodes, x)endendfor _,x in pairs(nodes) doif x.children thenfor _,y in pairs(x.children) dolocal c = nodes[y]print(x.id, c.id, c.ntracks)endendend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesprint('aa', root.id, root.ntracks)-- render_node_and_descendants(nodes, thread_data.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * thread_data.ntracks)-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":519,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":520,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":518,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":518,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ntracks = function(nodes, parent)-- leaf nodes need 1 trackif parent.children == nil thenreturn 1end-- otherwise add up the tracks needed by all children (parent will fit in among them)-- if we have a single child, it will slide into the same track. This is desirable.local result = 0for _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]result = result + ntracks(nodes, child)endreturn resultend
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(nodes, x)endendfor _,x in pairs(nodes) doif x.children thenfor _,y in pairs(x.children) dolocal c = nodes[y]print(x.id, c.id, c.ntracks)endendend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesprint('aa', root.id, root.ntracks)-- render_node_and_descendants(nodes, thread_data.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * thread_data.ntracks)-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":517,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":518,"dehtml":456,"copy_shape":396,"compute_ntracks":516,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) doprint('compute ntracks', x.id)compute_ntracks(nodes, x)endfor _,x in pairs(nodes) doif x.children thenfor _,y in pairs(x.children) dolocal c = nodes[y]print(x.id, c.id, c.ntracks)endendend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesprint('aa', root.id, root.ntracks)-- render_node_and_descendants(nodes, thread_data.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * thread_data.ntracks)-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":516,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":517,"dehtml":456,"copy_shape":396,"compute_ntracks":516,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":515,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":515,"dehtml":456,"copy_shape":396,"compute_ntracks":516,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ntracks = function(nodes, parent)-- leaf nodes need 1 trackif parent.children == nil thenreturn 1end-- otherwise add up the tracks needed by all children (parent will fit in among them)-- if we have a single child, it will slide into the same track. This is desirable.local result = 0for _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]result = result + ntracks(nodes, child)endreturn resultend
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) docompute_ntracks(nodes, x)endfor _,x in pairs(nodes) doif x.children thenfor _,y in pairs(x.children) dolocal c = nodes[y]print(x.id, c.id, c.ntracks)endendend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesprint('aa', root.id, root.ntracks)-- render_node_and_descendants(nodes, thread_data.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * thread_data.ntracks)-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":514,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":515,"dehtml":456,"copy_shape":396,"compute_ntracks":506,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xendlocal root = thread_data-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) docompute_ntracks(nodes, x)endfor _,x in pairs(nodes) doif x.children thenfor _,y in pairs(x.children) dolocal c = nodes[y]print(x.id, c.id, c.ntracks)endendend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesprint('aa', root.ntracks)-- render_node_and_descendants(nodes, thread_data.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * thread_data.ntracks)-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":513,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":514,"dehtml":456,"copy_shape":396,"compute_ntracks":506,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= thread_data.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) docompute_ntracks(nodes, x)endfor _,x in pairs(nodes) doif x.children thenfor _,y in pairs(x.children) dolocal c = nodes[y]print(x.id, c.id, c.ntracks)endendend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesprint('aa', thread_data.ntracks)-- render_node_and_descendants(nodes, thread_data.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * thread_data.ntracks)-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":511,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":513,"dehtml":456,"copy_shape":396,"compute_ntracks":506,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_node_and_descendants = function(node, descendants, id, y, xlo, xhi)add_node(x, y, node[id].contents)local nchildren = #descendants[id]-- to render n children we require 600*n + 20*(n-1) px of widthlocal children = {}for i,x in ipairs(descendants[id]) doend
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":506,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":511,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":512,"on.initialize":446,"render_thread_to_surface":511,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= thread_data.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) docompute_ntracks(nodes, x)endfor _,x in pairs(nodes) doif x.children thenfor _,y in pairs(x.children) dolocal c = nodes[y]print(x.id, c.id, c.ntracks)endendend-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":506,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":510,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":511,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= thread_data.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) docompute_ntracks(nodes, x)endfor _,x in pairs(nodes) doif x.children thenfor _,y in pairs(x.children) dolocal c = nodes[y]print(x.id, c.id, c.ntracks)endendend-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":506,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":509,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":510,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= thread_data.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) docompute_ntracks(nodes, x)endfor _,x in pairs(nodes) doif x.children thenfor _,y in pairs(x.children) dolocal c = node[y]print(x.id, c.id, c.ntracks)endendend-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":506,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":508,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":509,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= thread_data.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) docompute_ntracks(nodes, x)endfor _,x in pairs(nodes) doif x.children thenfor _,y in pairs(x.children) doprint(x.id, y.id, y.ntracks)endendend-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":506,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":507,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":508,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= thread_data.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) docompute_ntracks(nodes, x)endfor _,x in pairs(nodes) dofor _,y in pairs(x.children) doprint(x.id, y.id, y.ntracks)endend-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":506,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":506,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":507,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":506,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":505,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":504,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ntracks = function(nodes, parent)-- leaf nodes need 1 trackif parent.children == nil thenreturn 1end-- otherwise add up the tracks needed by all children (parent will fit in among them)local result = 0for _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]result = result + ntracks(nodes, child)endreturn resultend
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":503,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":504,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":504,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= thread_data.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) docompute_ntracks(nodes, x)endfor _,x in pairs(nodes) doprint(x.id, x.in_reply_to_id, x.ntracks)end-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":502,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":503,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":503,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":504,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":502,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":503,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":502,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":501,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ntracks = function(nodes, parent)-- leaf nodes need 1 trackif parent.children == nil thenreturn 1end-- otherwise add up the tracks needed by all children (parent will fit in among them)local result = 0for _,child_id in ipairs(parent.children) dolocal child = nodes[child_id]result = result + ntracks(nodes, child)endreturn resultend
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":502,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":501,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":501,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= thread_data.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute number of tracks neededfor _,x in pairs(nodes) docompute_ndescendants(nodes, x)endfor _,x in pairs(nodes) doprint(x.id, x.in_reply_to_id, x.ndescendants)end-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":500,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":501,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":499,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":497,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ndescendants = function(node, parent)if parent.ndescendants then return parent.ndescendants endlocal result = 0if parent.children thenfor _,child_id in ipairs(parent.children) dolocal child = node[child_id]result = result + compute_ndescendants(node, child) + 1endendparent.ndescendants = resultreturn resultend
render_thread_to_surface = function(thread_data)-- design constraints:-- trees only, no graphs or DAGs-- parents above children-- a child shares its parent's column exactly only if it's an only child-- parents can overlap columns with children and more distant descendants-- siblings never share a column-- siblings never overlap columns-- siblings always occupy the same row-- cousins/aunts/nephews never overlap columnsSurface = {}-- we're going to be computing box heightslove.graphics.setFont(love.graphics.newFont(scale(20)))-- compute mapping from ids to nodesNodes = {} -- id to objectNodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) doNodes[x.id] = xendlocal root = thread_dataCursor_node = root-- compute childrenfor _,x in pairs(Nodes) doparent_id = x.in_reply_to_idif x.id ~= root.id thenassert(parent_id)local parent = Nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- sort children by timefor _,x in pairs(Nodes) doif x.children thentable.sort(x.children)endend-- compute number of tracks neededfor _,x in pairs(Nodes) doif x.ntracks == nil thenx.ntracks = compute_ntracks(x)endend-- prepare the tracks-- each track is 600px + 20px of gutter between nodesrender_node_and_descendants(root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)ensure_cursor_node_within_viewport()end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":499,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":498,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":497,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"render_thread_to_surface":652,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"header":651,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.initialize":446,"on.update":368,"scale":7,"add_node":650,"render_node_and_descendants":646,"vx":5,"add_edge":575,"initialize_editor":338,"vy":8,"Nodes":593,"add_thick_line":400,"ntracks":600,"Input_filename":436,"compute_layout":619,"to_text":180,"A":582,"on.keychord_press":644,"box_height":345,"line_height":365,"B":379,"fw_parent":651,"to_node":611,"fw_app":"mastodon-unfurl","ensure_cursor_node_within_viewport":643,"on.mouse_release":586}
compute_ndescendants = function(node, parent)if parent.ndescendants then return parent.ndescendants endlocal result = 1if parent.children thenfor _,child_id in ipairs(parent.children) dolocal child = node[child_id]result = result + compute_ndescendants(node, child)endendparent.ndescendants = resultreturn resultend
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":498,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":497,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":497,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ndescendants = function(node, parent)if parent.ndescendants then return parent.ndescendants endlocal result = 1if parents.children thenfor _,child_id in ipairs(parent.children) dolocal child = node[child_id]result = result + compute_ndescendants(node, child)endendparent.ndescendants = resultreturn resultend
render_thread_to_surface = function(thread_data)Surface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= thread_data.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute ndescendantsfor _,x in pairs(nodes) docompute_ndescendants(nodes, x)endfor _,x in pairs(nodes) doprint(x.id, x.in_reply_to_id, x.ndescendants)end-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":496,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":497,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)Surface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= thread_data.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute ndescendantsfor _,x in pairs(nodes) docompute_nescendants(nodes, x)endfor _,x in pairs(nodes) doprint(x.id, x.in_reply_to_id, x.ndescendants)end-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":495,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":496,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)Surface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x.id ~= thread_data.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute ndescendantsfor _,x in pairs(nodes) docompute_descendants(nodes, x)endfor _,x in pairs(nodes) doprint(x.id, x.in_reply_to_id, x.ndescendants)end-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":494,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":495,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)Surface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idif x ~= thread_data.id thenassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)endend-- compute ndescendantsfor _,x in pairs(nodes) docompute_descendants(nodes, x)endfor _,x in pairs(nodes) doprint(x.id, x.in_reply_to_id, x.ndescendants)end-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":493,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":494,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)Surface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idassert(parent_id or x.id == thread_data.id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)end-- compute ndescendantsfor _,x in pairs(nodes) docompute_descendants(nodes, x)endfor _,x in pairs(nodes) doprint(x.id, x.in_reply_to_id, x.ndescendants)end-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":492,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":493,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)Surface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in pairs(nodes) doparent_id = x.in_reply_to_idassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)end-- compute ndescendantsfor _,x in pairs(nodes) docompute_descendants(nodes, x)endfor _,x in pairs(nodes) doprint(x.id, x.in_reply_to_id, x.ndescendants)end-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":491,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":492,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)Surface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_dataprint(#nodes)for _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in ipairs(nodes) doparent_id = x.in_reply_to_idassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)end-- compute ndescendantsfor _,x in ipairs(nodes) docompute_descendants(nodes, x)endfor _,x in ipairs(nodes) doprint(x.id, x.in_reply_to_id, x.ndescendants)end-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":490,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":491,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)Surface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in ipairs(nodes) doparent_id = x.in_reply_to_idassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)end-- compute ndescendantsfor _,x in ipairs(nodes) docompute_descendants(nodes, x)endprint(#nodes)for _,x in ipairs(nodes) doprint(x.id, x.in_reply_to_id, x.ndescendants)end-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":489,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":490,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)Surface = {}print('aaa')-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in ipairs(nodes) doparent_id = x.in_reply_to_idassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)end-- compute ndescendantsfor _,x in ipairs(nodes) docompute_descendants(nodes, x)endfor _,x in ipairs(nodes) doprint(x.id, x.in_reply_to_id, x.ndescendants)end-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":488,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":489,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)Surface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in ipairs(nodes) doparent_id = x.in_reply_to_idassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)end-- compute ndescendantsfor _,x in ipairs(nodes) docompute_descendants(nodes, x)endfor _,x in ipairs(nodes) doprint(x.id, x.in_reply_to_id, x.ndescendants)end-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":487,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":488,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":486,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":486,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ndescendants = function(node, parent)if parent.ndescendants then return parent.ndescendants endlocal result = 1for _,child_id in ipairs(parent.children) dolocal child = node[child_id]result = result + compute_ndescendants(node, child)endparent.ndescendants = resultreturn resultend
render_thread_to_surface = function(thread_data)Surface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in ipairs(nodes) doparent_id = x.in_reply_to_idassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)end-- compute ndescendantsfor _,x in ipairs(nodes) docompute_descendants(nodes, x)end-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":483,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":485,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":486,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)Surface = {}-- compute mapping from ids to nodeslocal nodes = {} -- id to objectnodes[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donodes[x.id] = xend-- compute childrenfor _,x in ipairs(nodes) doparent_id = x.in_reply_to_idassert(parent_id)local parent = nodes[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)end-- compute ndescendantsfor _,x in ipairs(nodes) docompute_descendants(nodes, x)endrender_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":483,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":484,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":485,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)Surface = {}-- compute mapping from ids to nodeslocal node = {} -- id to objectnode[thread_data.id] = thread_datafor _,x in ipairs(thread_data.descendants) donode[x.id] = xend-- compute childrenfor _,x in ipairs(nodes) doparent_id = x.in_reply_to_idassert(parent_id)local parent = node[parent_id]if parent.children == nil thenparent.children = {}endtable.insert(parent.children, x.id)end-- compute ndescendantsfor _,x in ipairs(node) docompute_descendants(node, x)endrender_node_and_descendants(node, descendants, thread_data.id, 0, 0)end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":483,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":483,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":484,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":483,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":482,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":479,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ndescendants = function(node, parent)if parent.ndescendants then return parent.ndescendants endlocal result = 1for _,child_id in ipairs(parent.children) dolocal child = node[child_id]result = result + compute_ndescendants(node, child)endreturn resultend
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":480,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":479,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"render_node_and_descendants(node,":481,"on.text_input":388,"on.initialize":446,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"Surface":434,"update_editor_box":430,"fw_app":"mastodon-luaML","on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"split_lines":469,"load_from_iterator":463,"vy":8,"dehtml":456,"copy_shape":396,"fw_parent":480,"Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":479,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"on.initialize":446,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"Surface":434,"update_editor_box":430,"fw_app":"mastodon-luaML","on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"split_lines":469,"load_from_iterator":463,"vy":8,"dehtml":456,"copy_shape":396,"fw_parent":479,"Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":479,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)Surface = {}local tmp = {x=0, y=0,width=600,type='text',data=split_lines(dehtml(thread_data.content)),bg={r=0.7,g=0.7, b=1.0},}compute_layout(tmp, tmp.x, tmp.y, Surface)local node = {} -- id to objectlocal descendants = {} -- node id to array of descendant idsfor i,x in ipairs(thread_data.descendants) doprint(i, x.id, x.in_reply_to_id)node[x.id] = xparent_id = x.in_reply_to_idassert(parent_id)if descendants[parent_id] == nil thendescendants[parent_id] = {}endtable.insert(descendants[parent_id], x.id)endprint('immediate children')for i,x in ipairs(descendants[thread_data.id]) doprint(x)endend
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":473,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":478,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":479,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":474,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)Surface = {}local tmp = {x=0, y=0,width=600,type='text',data=split_lines(dehtml(thread_data.content)),bg={r=0.7,g=0.7, b=1.0},}compute_layout(tmp, tmp.x, tmp.y, Surface)local node = {} -- id to objectlocal descendants = {} -- node id to array of descendant idsfor i,x in ipairs(thread_data.descendants) doprint(i, x.id, x.in_reply_to_id)node[x.id] = xparent_id = x.in_reply_to_idassert(parent_id)if descendants[parent_id] == nil thendescendants[parent_id] = {}endtable.insert(descendants[parent_id], x.id)endend
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":473,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":477,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":478,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":474,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)Surface = {}local tmp = {x=0, y=0,width=600,type='text',data=split_lines(dehtml(thread_data.content))}compute_layout(tmp, tmp.x, tmp.y, Surface)for i,x in ipairs(thread_data.descendants) doprint(i, x.id, x.in_reply_to_id)endend
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":473,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":476,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":477,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":474,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)Surface = {}local tmp = {x=0, y=0,width=600,type='text',data=split_lines(dehtml(thread_data.content))}compute_layout(tmp, tmp.x, tmp.y, Surface)print(#thread_data.descendants)end
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":473,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":475,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":476,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":474,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)Surface = {}local tmp = {x=0, y=0,width=600,type='text',data=split_lines(dehtml(thread_data.content))}compute_layout(tmp, tmp.x, tmp.y, Surface)print(#tmp.descendants)end
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":473,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":474,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":475,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":474,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":473,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":473,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":472,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":474,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":473,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":472,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":472,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":455,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)Surface = {}local tmp = {x=0, y=0,width=600,type='text',data=split_lines(dehtml(thread_data.content))}compute_layout(tmp, tmp.x, tmp.y, Surface)end
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":458,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":471,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":472,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":455,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)Surface = {}local tmp = {x=0, y=0,w=600,type='text',data=split_lines(dehtml(thread_data.content))}compute_layout(tmp, tmp.x, tmp.y, Surface)end
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":458,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":470,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":471,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":455,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)-- Surface = {}local tmp = {x=0, y=0,w=600,type='text',data=split_lines(dehtml(thread_data.content))}compute_layout(tmp, tmp.x, tmp.y, Surface)end
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":458,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":469,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":470,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":455,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":458,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":468,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":468,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":455,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)-- Surface = {}local tmp = {x=0, y=0,w=600,type='text',data=load_from_iterator(dehtml(thread_data.content):gmatch("[^\r\n]+"))}compute_layout(tmp, tmp.x, tmp.y, Surface)end
{"on.initialize":446,"box_height":345,"A":455,"load_from_iterator":463,"B":379,"schema1_of_y":366,"font":353,"Surface":434,"y_of_schema1":364,"scale":7,"on.draw":418,"Cursor_node":172,"vx":5,"Viewport":303,"on.text_input":388,"Input_filename":436,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"on.keychord_press":391,"on":1,"render_thread_to_surface":468,"dehtml":456,"add_thick_line":400,"copy_shape":396,"fw_parent":467,"on.code_change":458,"fw_app":"mastodon-luaML","line_height":365,"to_text":180,"compute_layout":385,"vy":8,"update_editor_box":430}
render_thread_to_surface = function(thread_data)Surface = {}local tmp = {x=0, y=0,w=600,type='text',data=load_from_iterator(dehtml(thread_data.content):gmatch("[^\r\n]+"))}compute_layout(tmp, tmp.x, tmp.y, Surface)end
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":467,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"load_from_iterator":463,"B":379,"fw_parent":466,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
render_thread_to_surface = function(thread_data)Surface = {}local tmp = {x=0, y=0,w=600,type='text',data=load_from_iterator(dehtml(thread_data.content):gmatch("[^\r\n]+"))}table.insert(Surface, tmp)end
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":466,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"load_from_iterator":463,"B":379,"fw_parent":465,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
render_thread_to_surface = function(thread_data)Surface = {}local tmp = {x=0, y=0,width=600,type='text',data=load_from_iterator(dehtml(thread_data.content):gmatch("[^\r\n]+"))}print(type(tmp.data), #tmp.data)table.insert(Surface, tmp)end
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":465,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"load_from_iterator":463,"B":379,"fw_parent":464,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
render_thread_to_surface = function(thread_data)Surface = {}local tmp = {x=0, y=0,width=600,type='text',data=load_from_iterator(dehtml(thread_data.content):gmatch("[^\r\n]+"))}table.insert(Surface, tmp)end
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":464,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"load_from_iterator":463,"B":379,"fw_parent":463,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":462,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"load_from_iterator":463,"B":379,"fw_parent":462,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":462,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"B":379,"fw_parent":461,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
render_thread_to_surface = function(thread_data)Surface = {}local tmp = {x=0, y=0,width=600,type='text',data=dehtml(thread_data.content)}print('rerendering')table.insert(Surface, tmp)end
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":461,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"B":379,"fw_parent":460,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":460,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"B":379,"fw_parent":459,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
{"vy":8,"fw_parent":458,"render_thread_to_surface":459,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"add_thick_line":400,"on":1,"on.keychord_press":391,"scale":7,"update_editor_box":430,"on.initialize":446,"schema1_of_y":366,"B":379,"y_of_schema1":364,"line_height":365,"compute_layout":385,"Cursor_node":172,"on.code_change":458,"to_text":180,"font":353,"dehtml":456,"on.text_input":388,"Input_filename":436,"Surface":434,"A":455,"on.update":368,"on.draw":418,"copy_shape":396,"vx":5,"box_height":345,"Viewport":303,"fw_app":"mastodon-luaML"}
{"on.update":368,"on.keychord_press":391,"render_thread_to_surface":454,"scale":7,"add_thick_line":400,"copy_shape":396,"to_text":180,"dehtml":456,"fw_parent":457,"fw_app":"mastodon-luaML","box_height":345,"compute_layout":385,"font":353,"on.code_change":458,"schema1_of_y":366,"y_of_schema1":364,"B":379,"on.draw":418,"update_editor_box":430,"vx":5,"on":1,"Viewport":303,"on.text_input":388,"Surface":434,"vy":8,"on.initialize":446,"Input_filename":436,"Cursor_node":172,"A":455,"on.mouse_press":179,"line_height":365,"on.mouse_release":367,"initialize_editor":338}
{"on.update":368,"on.keychord_press":391,"render_thread_to_surface":454,"scale":7,"add_thick_line":400,"copy_shape":396,"to_text":180,"dehtml":456,"fw_parent":456,"fw_app":"mastodon-luaML","box_height":345,"compute_layout":385,"font":353,"on.code_change":457,"schema1_of_y":366,"y_of_schema1":364,"B":379,"on.draw":418,"update_editor_box":430,"vx":5,"on":1,"Viewport":303,"on.text_input":388,"Surface":434,"vy":8,"on.initialize":446,"Input_filename":436,"Cursor_node":172,"A":455,"on.mouse_press":179,"line_height":365,"on.mouse_release":367,"initialize_editor":338}
{"on.update":368,"on.keychord_press":391,"render_thread_to_surface":454,"scale":7,"add_thick_line":400,"copy_shape":396,"to_text":180,"dehtml":456,"fw_parent":455,"fw_app":"mastodon-luaML","box_height":345,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"y_of_schema1":364,"B":379,"on.draw":418,"update_editor_box":430,"vx":5,"on":1,"Viewport":303,"on.text_input":388,"Surface":434,"vy":8,"on.initialize":446,"Input_filename":436,"Cursor_node":172,"A":455,"on.mouse_press":179,"line_height":365,"on.mouse_release":367,"initialize_editor":338}
{"on.update":368,"on.keychord_press":391,"render_thread_to_surface":454,"scale":7,"add_thick_line":400,"copy_shape":396,"to_text":180,"dehtml":452,"fw_parent":454,"fw_app":"mastodon-luaML","box_height":345,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"y_of_schema1":364,"B":379,"on.draw":418,"update_editor_box":430,"vx":5,"on":1,"Viewport":303,"on.text_input":388,"Surface":434,"vy":8,"on.initialize":446,"Input_filename":436,"Cursor_node":172,"A":455,"on.mouse_press":179,"line_height":365,"on.mouse_release":367,"initialize_editor":338}
A = function(filename)if filename thenprint('reading', filename)local f = io.open(filename)assert(f)local thread_data = json.decode(f:read('*a'))render_thread_to_surface(thread_data)endB()end
{"on.update":368,"on.keychord_press":391,"render_thread_to_surface":454,"scale":7,"add_thick_line":400,"copy_shape":396,"to_text":180,"dehtml":452,"fw_parent":453,"fw_app":"mastodon-luaML","box_height":345,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"y_of_schema1":364,"B":379,"on.draw":418,"update_editor_box":430,"vx":5,"on":1,"Viewport":303,"on.text_input":388,"Surface":434,"vy":8,"on.initialize":446,"Input_filename":436,"Cursor_node":172,"A":449,"on.mouse_press":179,"line_height":365,"on.mouse_release":367,"initialize_editor":338}
{"on.update":368,"on.keychord_press":391,"render_thread_to_surface":453,"scale":7,"add_thick_line":400,"copy_shape":396,"to_text":180,"dehtml":452,"fw_parent":452,"fw_app":"mastodon-luaML","box_height":345,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"y_of_schema1":364,"B":379,"on.draw":418,"update_editor_box":430,"vx":5,"on":1,"Viewport":303,"on.text_input":388,"Surface":434,"vy":8,"on.initialize":446,"Input_filename":436,"Cursor_node":172,"A":449,"on.mouse_press":179,"line_height":365,"on.mouse_release":367,"initialize_editor":338}
{"on.update":368,"on.keychord_press":391,"render_thread_to_surface":451,"scale":7,"add_thick_line":400,"copy_shape":396,"to_text":180,"dehtml":452,"fw_parent":451,"fw_app":"mastodon-luaML","box_height":345,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"y_of_schema1":364,"B":379,"on.draw":418,"update_editor_box":430,"vx":5,"on":1,"Viewport":303,"on.text_input":388,"Surface":434,"vy":8,"on.initialize":446,"Input_filename":436,"Cursor_node":172,"A":449,"on.mouse_press":179,"line_height":365,"on.mouse_release":367,"initialize_editor":338}
{"on.update":368,"box_height":345,"on.keychord_press":391,"compute_layout":385,"render_thread_to_surface":451,"font":353,"on.code_change":443,"schema1_of_y":366,"initialize_editor":338,"fw_parent":450,"on.text_input":388,"scale":7,"fw_app":"mastodon-luaML","y_of_schema1":364,"on":1,"copy_shape":396,"on.draw":418,"to_text":180,"vx":5,"add_thick_line":400,"Viewport":303,"Input_filename":436,"on.mouse_release":367,"vy":8,"Surface":434,"on.initialize":446,"Cursor_node":172,"A":449,"on.mouse_press":179,"line_height":365,"update_editor_box":430,"B":379}
{"on.update":368,"box_height":345,"on.keychord_press":391,"compute_layout":385,"render_thread_to_surface":450,"font":353,"on.code_change":443,"schema1_of_y":366,"initialize_editor":338,"fw_parent":449,"on.text_input":388,"scale":7,"fw_app":"mastodon-luaML","y_of_schema1":364,"on":1,"copy_shape":396,"on.draw":418,"to_text":180,"vx":5,"add_thick_line":400,"Viewport":303,"Input_filename":436,"on.mouse_release":367,"vy":8,"Surface":434,"on.initialize":446,"Cursor_node":172,"A":449,"on.mouse_press":179,"line_height":365,"update_editor_box":430,"B":379}
{"on.update":368,"box_height":345,"on.keychord_press":391,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"initialize_editor":338,"fw_parent":448,"on.text_input":388,"scale":7,"fw_app":"mastodon-luaML","y_of_schema1":364,"on":1,"copy_shape":396,"on.draw":418,"to_text":180,"vx":5,"add_thick_line":400,"Viewport":303,"Input_filename":436,"on.mouse_release":367,"vy":8,"Surface":434,"on.initialize":446,"Cursor_node":172,"A":449,"on.mouse_press":179,"line_height":365,"update_editor_box":430,"B":379}
{"on.update":368,"box_height":345,"on.keychord_press":391,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"initialize_editor":338,"fw_parent":446,"on.text_input":388,"scale":7,"fw_app":"mastodon-luaML","y_of_schema1":364,"on":1,"copy_shape":396,"on.draw":418,"to_text":180,"vx":5,"add_thick_line":400,"Viewport":303,"Input_filename":436,"on.mouse_release":367,"vy":8,"Surface":434,"on.initialize":446,"Cursor_node":172,"A":448,"on.mouse_press":179,"line_height":365,"update_editor_box":430,"B":379}
{"on.update":368,"box_height":345,"on.keychord_press":391,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"on.text_input":388,"update_editor_box":430,"fw_app":"mastodon-luaML","scale":7,"B":379,"y_of_schema1":364,"on":1,"copy_shape":396,"on.draw":418,"to_text":180,"vx":5,"add_thick_line":400,"Viewport":303,"on.initialize":446,"Surface":434,"vy":8,"on.mouse_release":367,"Input_filename":436,"Cursor_node":172,"A":447,"on.mouse_press":179,"line_height":365,"fw_parent":446,"initialize_editor":338}
{"on.update":368,"box_height":345,"on.keychord_press":391,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"on.text_input":388,"update_editor_box":430,"fw_app":"mastodon-luaML","scale":7,"B":379,"y_of_schema1":364,"on":1,"copy_shape":396,"on.draw":418,"to_text":180,"vx":5,"add_thick_line":400,"Viewport":303,"on.initialize":446,"Surface":434,"vy":8,"on.mouse_release":367,"Input_filename":436,"Cursor_node":172,"A":444,"on.mouse_press":179,"line_height":365,"fw_parent":445,"initialize_editor":338}
{"on.mouse_press":179,"initialize_editor":338,"on.mouse_release":367,"box_height":345,"on.update":368,"compute_layout":385,"on.keychord_press":391,"on.text_input":388,"Input_filename":436,"y_of_schema1":364,"A":444,"copy_shape":396,"fw_parent":444,"line_height":365,"fw_app":"mastodon-luaML","on.code_change":443,"to_text":180,"Surface":434,"font":353,"on.initialize":445,"on.draw":418,"on":1,"vx":5,"add_thick_line":400,"Viewport":303,"B":379,"update_editor_box":430,"vy":8,"scale":7,"Cursor_node":172,"schema1_of_y":366}
{"A":444,"on.mouse_press":179,"Cursor_node":172,"y_of_schema1":364,"initialize_editor":338,"copy_shape":396,"scale":7,"box_height":345,"on.keychord_press":391,"compute_layout":385,"on.initialize":441,"B":379,"on.code_change":443,"schema1_of_y":366,"Input_filename":436,"fw_app":"mastodon-luaML","on.update":368,"fw_parent":443,"update_editor_box":430,"Surface":434,"add_thick_line":400,"on.mouse_release":367,"on.draw":418,"on":1,"vx":5,"on.text_input":388,"Viewport":303,"font":353,"to_text":180,"vy":8,"line_height":365}
{"A":438,"on.mouse_press":179,"Cursor_node":172,"y_of_schema1":364,"initialize_editor":338,"copy_shape":396,"scale":7,"box_height":345,"on.keychord_press":391,"compute_layout":385,"on.initialize":441,"B":379,"on.code_change":443,"schema1_of_y":366,"Input_filename":436,"fw_app":"mastodon-luaML","on.update":368,"fw_parent":442,"update_editor_box":430,"Surface":434,"add_thick_line":400,"on.mouse_release":367,"on.draw":418,"on":1,"vx":5,"on.text_input":388,"Viewport":303,"font":353,"to_text":180,"vy":8,"line_height":365}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"Input_filename":436,"on.code_change":442,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":441,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":441,"on.mouse_press":179,"A":438}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"Input_filename":436,"on.code_change":306,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":440,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":441,"on.mouse_press":179,"A":438}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"Input_filename":436,"on.code_change":306,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":439,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":440,"on.mouse_press":179,"A":438}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"Input_filename":436,"on.code_change":306,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":438,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":439,"on.mouse_press":179,"A":438}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"Input_filename":436,"on.code_change":306,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":437,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":437,"on.mouse_press":179,"A":438}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"Input_filename":436,"on.code_change":306,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":436,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":437,"on.mouse_press":179,"A":431}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"Input_filename":436,"on.code_change":306,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":435,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":435,"on.mouse_press":179,"A":431}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"on.code_change":306,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":434,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":435,"on.mouse_press":179,"A":431}
{"on.keychord_press":391,"schema1_of_y":366,"on.text_input":388,"initialize_editor":338,"on":1,"y_of_schema1":364,"A":431,"compute_layout":385,"to_text":180,"Surface":434,"B":379,"vy":8,"on.draw":418,"on.initialize":350,"vx":5,"line_height":365,"Viewport":303,"fw_parent":433,"update_editor_box":430,"fw_app":"mastodon-luaML","add_thick_line":400,"scale":7,"copy_shape":396,"on.code_change":306,"on.mouse_press":179,"on.update":368,"on.mouse_release":367,"Cursor_node":172,"font":353,"box_height":345}
Surface = {-- test data{type='line', data={0,-1000, 0,1000}},{type='line', data={-10000,0, 10000,0}},{type='rectangle', x=50,y=50, w=20,h=80, r=1,g=0,b=0},{type='circle', x=300,y=200, radius=40, r=1,g=0,b=1},{type='arc', x=0,y=0, radius=50, angle1=0, angle2=math.pi*2/3},{type='ellipse', x=100,y=100, radiusx=10, radiusy=50},{type='bezier', data={25,25, 25,125, 75,25, 125,25}},}
{"A":431,"on.draw":418,"on.keychord_press":391,"vx":5,"B":379,"Viewport":303,"add_thick_line":400,"schema1_of_y":366,"copy_shape":396,"initialize_editor":338,"on":1,"box_height":345,"on.mouse_press":179,"font":353,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"on.code_change":306,"scale":7,"y_of_schema1":364,"on.initialize":350,"on.text_input":388,"update_editor_box":430,"fw_parent":432,"compute_layout":385,"fw_app":"mastodon-luaML","vy":8,"Surface":422,"to_text":180,"line_height":365}
{"A":431,"on.draw":418,"on.keychord_press":391,"vx":5,"B":379,"Viewport":303,"add_thick_line":400,"schema1_of_y":366,"copy_shape":396,"initialize_editor":338,"on":1,"box_height":345,"on.mouse_press":179,"font":353,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"on.code_change":306,"scale":7,"y_of_schema1":364,"on.initialize":350,"on.text_input":388,"update_editor_box":430,"fw_parent":431,"compute_layout":385,"fw_app":"mastodon-luaML","Page2":429,"vy":8,"Surface":422,"to_text":180,"line_height":365}
{"A":431,"on.draw":418,"on.keychord_press":391,"vx":5,"B":379,"Viewport":303,"add_thick_line":400,"schema1_of_y":366,"copy_shape":396,"Page":381,"initialize_editor":338,"on":1,"box_height":345,"on.mouse_press":179,"font":353,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"on.code_change":306,"scale":7,"y_of_schema1":364,"on.initialize":350,"on.text_input":388,"update_editor_box":430,"fw_parent":430,"compute_layout":385,"fw_app":"mastodon-luaML","Page2":429,"vy":8,"Surface":422,"to_text":180,"line_height":365}
xposition = function(curr, xlo, xhi)-- return the left margin to position a node atif curr.children == nil or #curr.children == 0 thenreturn xloendif #curr.children == 1 thenreturn xposition(Nodes[curr.children[1]], xlo, xhi)endlocal total_boundaries = 0local curr_boundary = xlofor child_idx = 1,#curr.children-1 dolocal child_id = curr.children[child_idx]local child = Nodes[child_id]curr_boundary = curr_boundary + 620 * child.ntrackstotal_boundaries = total_boundaries + curr_boundaryendlocal centerx = total_boundaries / (#curr.children-1)return centerx - 620/2end
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)-- draw a parent 'id' and its children-- also draw an edge from grandparent to parent if provided-- position the root between xlo and xhi to be closer to children with fewer trackslocal parent = Nodes[id]if parent.children == nil thenparent.surface_node = add_node(xlo, y, parent, grandparent_surface_node)returnendlocal parent_xlo = xposition(parent, xlo, xhi)parent.surface_node = add_node(parent_xlo, y, parent, grandparent_surface_node)local parent_height = box_height(parent.surface_node)local curr_boundary = xlofor _,child_id in ipairs(parent.children) dolocal child = Nodes[child_id]render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent.surface_node)curr_boundary = curr_boundary + 620*child.ntracksendend
dehtml = function(s)return s:gsub('<p>', '\n\n'):gsub('<br>', '\n'):gsub('<br/>', '\n')-- hacky:gsub('<[^>]*>', ''):gsub(''', "'"):gsub(''', "'"):gsub('"', '"'):gsub('“', '"'):gsub('”', '"'):gsub('<', '<'):gsub('>', '>'):gsub('&', '&')end
Root = nil
header = function(node)local result = {}if node.account == nil thentable.insert(result, node.user)elseif node.account.display_name thentable.insert(result, node.account.display_name)elsetable.insert(result, node.account.username)endtable.insert(result, node.created_at)table.insert(result, '---')return table.concat(result, '\n')end
add_node = function(x, y, node, parent_surface_node)local surface_node = {x=x, y=y,width=600,type='text',data=split_lines(header(node)..'\n'..dehtml(node.content)),bg={r=0.7,g=0.7, b=1.0},toot_id=node.id,}compute_layout(surface_node, surface_node.x, surface_node.y, Surface)if parent_surface_node thenadd_edge(surface_node, parent_surface_node)endreturn surface_nodeend
ensure_cursor_node_within_viewport = function()local snode = Cursor_node.surface_nodelocal dirty-- check Viewport.yif snode.y < Viewport.y thenViewport.y = snode.y - 50dirty = trueendlocal limit = snode.y + box_height(snode)if Viewport.y < limit - App.screen.height/Viewport.zoom thenViewport.y = limit - (App.screen.height-50)/Viewport.zoomdirty = trueend-- check Viewport.xif Cursor_node.surface_node.x < Viewport.x thenViewport.x = Cursor_node.surface_node.x - 50dirty = trueendlimit = snode.x + 600if Viewport.x < limit - App.screen.width/Viewport.zoom thenViewport.x = limit - (App.screen.width-50)/Viewport.zoomdirty = trueend-- refresh if necessaryif dirty thenB()endend
to_node = function(x,y)for _,node in ipairs(Surface) doif node.type == 'text' thenif x >= vx(node.x) and node.w and x < vx(node.x + node.w) thenif y >= vy(node.y) and node.h and y < vy(node.y + node.h) thenreturn node.toot_idendendendendend
compute_ntracks = function(parent)-- leaf nodes need 1 trackif parent.children == nil thenreturn 1end-- otherwise add up the tracks needed by all children (parent will fit in among them)-- if we have a single child, it will slide into the same track. This is desirable.local result = 0for _,child_id in ipairs(parent.children) dolocal child = Nodes[child_id]result = result + ntracks(child)endreturn resultend
Nodes = {}
-- test data{type='line', data={0,-1000, 0,1000}},{type='line', data={-10000,0, 10000,0}},{type='text', data={'0'}, x=-20,y=-30},{type='rectangle', x=50,y=50, w=20,h=80, r=1,g=0,b=0},{type='text', data={'abc', 'def'}, x=150, y=50, w=50,h=50, fg={r=0,g=0.4, b=0.9}},{type='circle', x=300,y=200, radius=40, r=1,g=0,b=1},{type='arc', x=0,y=0, radius=50, angle1=0, angle2=math.pi*2/3},{type='ellipse', x=100,y=100, radiusx=10, radiusy=50},{type='bezier', data={25,25, 25,125, 75,25, 125,25}},
elseif Cursor_node thenlocal old_top = {line=Cursor_node.editor.screen_top1.line, pos=Cursor_node.editor.screen_top1.pos}edit.keychord_press(Cursor_node.editor, chord, key)if not eq(Cursor_node.editor.screen_top1, old_top) thenViewport.y = Cursor_node.y + y_of_schema1(Cursor_node.editor, Cursor_node.editor.screen_top1)
elseif chord == 'C-up' thenif Cursor_node.in_reply_to_id thenCursor_node = Nodes[Cursor_node.in_reply_to_id]ensure_cursor_node_within_viewport()endelseif chord == 'C-down' thenif Cursor_node.children and #Cursor_node.children > 0 thenCursor_node = Nodes[Cursor_node.children[1]]ensure_cursor_node_within_viewport()endelseif chord == 'C-left' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx > 1 thenCursor_node = Nodes[parent.children[idx-1]]ensure_cursor_node_within_viewport()endend
A(--[[preserve screen_top of cursor node]] true)elseif chord == 'up' thenViewport.y = Viewport.y - scale(20)B()elseif chord == 'down' thenViewport.y = Viewport.y + scale(20)B()elseif chord == 'left' thenViewport.x = Viewport.x - scale(50)B()elseif chord == 'right' thenViewport.x = Viewport.x + scale(50)B()elseif chord == 'pageup' thenViewport.y = Viewport.y - App.screen.height/Viewport.zoomB()elseif chord == 'S-up' thenViewport.y = Viewport.y - App.screen.height/Viewport.zoomB()elseif chord == 'pagedown' thenViewport.y = Viewport.y + App.screen.height/Viewport.zoomB()elseif chord == 'S-down' thenViewport.y = Viewport.y + App.screen.height/Viewport.zoomB()elseif chord == 'S-left' thenViewport.x = Viewport.x - App.screen.width/Viewport.zoomB()elseif chord == 'S-right' thenViewport.x = Viewport.x + App.screen.width/Viewport.zoomB()
elseif chord == 'C-right' thenif Cursor_node.in_reply_to_id thenlocal parent = Nodes[Cursor_node.in_reply_to_id]assert(parent.children)if #parent.children > 1 thenlocal idx = array.find(parent.children, Cursor_node.id)if idx < #parent.children thenCursor_node = Nodes[parent.children[idx+1]]ensure_cursor_node_within_viewport()endend
if Cursor_node thenlocal old_top = {line=Cursor_node.editor.screen_top1.line, pos=Cursor_node.editor.screen_top1.pos}edit.text_input(Cursor_node.editor, t)if not eq(Cursor_node.editor.screen_top1, old_top) thenViewport.y = Cursor_node.y + y_of_schema1(Cursor_node.editor, Cursor_node.editor.screen_top1)endA(--[[preserve screen_top of cursor node]] true)end
on.initialize = function()A()end
on.initialize = function(arg)if #arg == 0 thenerror('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.')endInput_filename = arg[1]A(Input_filename)Cursor_node = Rootif #arg >= 1 thenif #arg >= 2 thenlocal initial_id = arg[2]if Nodes[initial_id] thenCursor_node = Nodes[initial_id]endendensure_cursor_node_within_viewport()endend
if Cursor_node thenCursor_node.show_cursor = nilCursor_node = nilendlocal node = to_text(x,y)if node thenCursor_node = nodeedit.mouse_press(node.editor, x,y, mouse_button)
local node_id = to_node(x,y)if node_id thenApp.setClipboardText(Nodes[node_id].url)Cursor_node = Nodes[node_id]