MAI7M665OPEDNICH67IUYSIVLRDL4JPC5BO2EWG2JVQTXATU72MAC O5GJ6PNNBYHH4X3DU4XOB7IDJ4QEW5KXFETIDUJESBUKJYXBSYYAC SUPHTPXYKS4JBDPASHAYA5OBVJ45QT7ZV2HYNTF7OJYOKKS6DW5QC JRHL6P5PWAVQCUZYUHT2ZZCMPXMDTVHYTVPWGYPJQNTEN4GYW2VAC R5QXEHUIZLELJGGCZAE7ATNS3CLRJ7JFRENMGH4XXH24C5WABZDQC 7TQAF4BYIK75EEYCCK7VEUSZHNCWMWIA3HZGQKIILYESUZ5ZZRVQC Y6O2RFHV5UGHFS3ZZEH5HPKN5I7SV74GEV47MTI4WGJPAINJMBZAC DTD5IPV57A3Q7MSJ3Y7C4G6HG366WHVUWUBSWWNQZFNIS7DTSAHAC WVKFFN6FAJVKUL6NGAOWSS33WFD63GPOPSLDQ7JT4WM27KV7H65QC BF7TW3EKRIDYC6J2Q2J4YOBAVQF55Y3H6KGZIHNXMH4N72MR6GXQC TBPJ5WSRM5IKQH7FTAVYTWWUBWW7G2CLT5M6FN7CMPLD6Y77YIWQC load_definition = function(name)if Cursor_node thenCursor_node.show_cursor = falseend-- just one copy per definition for nowendViewport.x = Definitions[name].x-30Viewport.y = Definitions[name].y-30Cursor_node = Definitions[name]Cursor_node.show_cursor = trueendif Definitions[name] == nil thenDefinitions[name] = {type='text',data=load_from_iterator(get_definition_from_app(name):gmatch("[^\r\n]+")),x=0, y=0,width=600,bg=definition_background_color(name),}move_candidate_to_front_of_manifest(name)
initialize_manifest_navigator = function()Manifest_navigator.candidates = ManifestManifest_navigator.num_lines = num_lines_for_manifest_navigator(Manifest_navigator.candidates)end
Manifest = {-- list of definitions to display in command palette-- Don't confuse this with Live.manifest, the manifest for the current (driver) app.-- Manifest is for the client app.}
get_manifest = function()live.send_to_app('MANIFEST')repeatlove.timer.sleep(0.01)local result = {}-- error; retryreturn resultelse-- stop retryingManifest_navigator.reload = falseendtable.insert(result, name)elseif name == 'fw_app' thenapp_name = valueendendendreturn result, app_namelocal app_namelocal manifest_version = json.decode(response)for name, value in pairs(manifest_version) doif not starts_with(name, 'fw_') thenif #response == 0 thenresponse = live.receive_from_app()until responselocal response
keychord_press_on_manifest_navigator = function(chord, key)if chord == 'escape' thenreset_manifest_navigator()elseif chord == 'return' thenif Manifest_navigator.for_delete thendelete_definition(Manifest_navigator.candidates[Manifest_navigator.index])elseload_definition(Manifest_navigator.candidates[Manifest_navigator.index])endA()reset_manifest_navigator()elseif chord == 'backspace' thenlocal len = utf8.len(Manifest_navigator.filter)local byte_offset = Text.offset(Manifest_navigator.filter, len)Manifest_navigator.filter = string.sub(Manifest_navigator.filter, 1, byte_offset-1)Manifest_navigator.index = 1Manifest_navigator.candidates = manifest_navigator_candidates()elseif chord == 'left' thenif Manifest_navigator.index > 1 thenManifest_navigator.index = Manifest_navigator.index-1endelseif chord == 'right' thenif Manifest_navigator.index < #Manifest_navigator.candidates thenManifest_navigator.index = Manifest_navigator.index+1endelseif chord == 'down' thenmanifest_navigator_down()elseif chord == 'up' thenmanifest_navigator_up()endend
load_manifest = function()-- preserve existing order-- 1. add new definitions in frontfor _,name in ipairs(new_manifest) doif not array.find(Manifest, name) thentable.insert(Manifest, 1, name)endend-- 2. remove missing definitionsfor idx=#Manifest,1,-1 dolocal name = Manifest[idx]if not array.find(new_manifest, name) thentable.remove(Manifest, idx)endendreturn app_nameend-- Connect to an app and load its manifest into global Manifest.-- Also return the name of the app we have connected to.local new_manifest, app_name = get_manifest()
num_lines_for_manifest_navigator = function(candidates)local result = 1local x = 5for i,def in ipairs(candidates) dolocal width = to_hud_text(def):getWidth()if x + width > App.screen.width - 5 thenresult = result+1x = 5endx = x + width + 30endreturn resultend
delete_definition = function(name)live.send_to_app('DELETE '..name)Manifest_navigator.reload = trueendwhile true dolocal response_string = live.receive_from_app()if Load_time_error then-- no buffer, so show error at bottom of windowRun_time_error = Load_time_errorLoad_time_error = nilbreakendif live.receive_run_time_error_from_app() thenbreakendif response_string thenbreakendlove.timer.sleep(0.001)end
add_def_to_menu = function(x,y, s, cursor_highlight)local s_text = to_hud_text(s)local width = s_text:getWidth()if x + width > App.screen.width - 5 theny = y + HUD_line_height + --[[highlight padding]] 5x = 5endlocal color = Menu_background_colorif cursor_highlight thencolor = Menu_highlight_colorendbutton(HUD, 'menu', {x=x-5, y=y-2, w=width+5*2, h=HUD_line_height+2*2, color=colortable(color),onpress1 = function()load_definition(s)end})App.color(Menu_command_color)App.screen.draw(s_text, x,y)x = x + width + 30return x,yend
manifest_navigator_candidates = function()if Manifest_navigator.filter == '' thenreturn Manifestendlocal result = {}for _,def in ipairs(Manifest) doif starts_with(def, Manifest_navigator.filter) thentable.insert(result, def)endendreturn resultend
manifest_index = function(fy, fx, fwidth)local y,x = Menu_bar_height, 5local best_guess, best_guess_x, best_guess_widthfor i,definition in ipairs(Manifest_navigator.candidates) dolocal width = to_hud_text(definition):getWidth()if x + width > App.screen.width - 5 theny = y + HUD_line_heightx = 5endif y == fy thenif best_guess == nil thenbest_guess = ibest_guess_x = xbest_guess_width = widthelseif math.abs(fx + fwidth/2 - x - width/2) < math.abs(fx + fwidth/2 - best_guess_x - best_guess_width/2) thenbest_guess = ibest_guess_x = xbest_guess_width = widthendendx = x + width + 30endreturn best_guessend
manifest_coord = function(index)local y,x = Menu_bar_height, 5for i,definition in ipairs(Manifest_navigator.candidates) dolocal width = to_hud_text(definition):getWidth()if x + width > App.screen.width - 5 theny = y + HUD_line_heightx = 5endif i == index thenreturn y, x, widthendx = x + width + 30endend
manifest_navigator_down = function()local y, x, width = manifest_coord(Manifest_navigator.index)local index = manifest_index(y+HUD_line_height, x, width)if index thenManifest_navigator.index = indexendend
text_input_on_manifest_navigator = function(t)Manifest_navigator.filter = Manifest_navigator.filter..tManifest_navigator.candidates = manifest_navigator_candidates()Manifest_navigator.index = 1end
move_candidate_to_front_of_manifest = function(name)local index = array.find(Manifest, name)if index thentable.remove(Manifest, index)table.insert(Manifest, 1, name)endend
manifest_navigator_up = function()local y, x, width = manifest_coord(Manifest_navigator.index)local index = manifest_index(y-HUD_line_height, x, width)if index thenManifest_navigator.index = indexendend
Manifest_navigator = {-- state for the command palettedisplay = false, -- display navigator on screenfor_delete = false, -- if true, delete selected definition from navigatorreload = false, -- if true, refresh manifest to display on next keystrokenum_lines = nil, -- number of screen lines of space to devote to the navigatorindex = 1, -- where the cursor is right now. Modified on arrow keys, reset on any non-arrow keystroke.filter = '', -- prefix being typed into the command palettebottom_y = nil, -- cache a tiny bit of state in display logic}-- candidates: list of candidates matching the filter