5E7BBR7HWGOEJJ6YWPL3NJKZVBTUZWET7OQNCRU2MMNVEGCEIAWQC JZTKY7ENFBG7VQDP2OKK7PSIC7CWBXEBUDTUAENWGC6Q3GLZ3SNAC 5GL27XAZTYHUBPV2SZOZNWMFU7MDLW4JFW4HVWGGGDEGLJKL4PIQC 5XMBCKJZ7YCUOOQWWZRNLXMXD3MUYC2VAF3VKA4BIEHQRPDQMUMAC KT6NOCLNHQEAUQEAGX5NHSNFKGTNYYMYHPDJPPXFMNCKXLP5PCEQC VBU5YHLRO5ZSKFWBJRX7DWQGWPEHEWZMRRVV2WMWDJ54PKUNYCNQC R5QXEHUIZLELJGGCZAE7ATNS3CLRJ7JFRENMGH4XXH24C5WABZDQC JOPVPUSAMMU6RFVDQR4NJC4GNNUFB7GPKVH7OS5FKCYS5QZ53VLQC 7UDWUUVDIUFK3DFZ5WLZ5LZWDDFSCZN5AKVBUZCOIRKFOIG2ZGNAC 3VHUIIATPOF7FXB7NTL5MESCV5BCQACII2D7QZ4UIUCBX3CWXMMAC LLQC2M2IMEJBJQXZTKC3OAKG5WKHSERXKAKCYHQRUZZD6CVRIHAQC 3PSFWAILGRA4OYXWS2DX7VF332AIBPYBXHEA4GIQY2XEJVD65UMAC TOJA6VDEWPXDE4KE6URFLNIZBQ6ASAFDZMSYSIBDBKACBGUKZI3QC FXI74QCLOZ4BS7UVZ3U2PE3LOL7MX3FWGHZCTGH3DYFXGTXVVIRAC QSPYRABWJDUVTRV5HTCOC4FY3DGYPLQU4DJ2UDJLPIIJWMTPOA3AC GRSHSSV5ZRYOXD3SGMCOXKVFXLNZYLAN3YVBDUE6IVZBIK5S3UXQC 5YGO6JX5WTBNIRW2LKLJF7EE7Z5UNXAMLG24AUV5BK227S4AI4IQC ANVLB2TX6ODOEUY7OADTQG47W7DNRHD6NXUPIJR5LVSJFMFJ3L2AC U46N4W3QLSD5F7DNP6VB43CEE3OA2PJFLGNUG3MZ7EMNTFSUIP6AC 3LWDKR5FPZNW2ESSTTLWBBEBJ3B77UH4NEOC26PHOVG4HKOU4VQAC OTIBCAUJ3KDQJLVDN3A536DLZGNRYMGJLORZVR3WLCGXGO6UGO6AC QZ2SXLHF6G3RBSLFIOYM3AQYWLGPWRTASNNQMOQBI5ASUAYCO6UAC KKMFQDR43ZWVCDRHQLWWX3FCWCFA3ZSXYOBRJNPHUQZR2XPKWULAC MM5RQRSV5I4APUD6EJ22SO3LTG4BS4SP6M3ILC7E5YYSH7D7OWKQC KEFZWDCOCLPTLSZJKRV4VYAHRITV5T33YKG2VGT332YAUCOBS3EAC if Show_file_navigator thentextinput_on_file_navigator(t)returnendif Focus == 'edit' thenreturn edit.textinput(Editor_state, t)elsereturn log_browser.textinput(Log_browser_state, t)endendfunction source.keychord_pressed(chord, key)Cursor_time = 0 -- ensure cursor is visible immediately after it moves--? print('source keychord')if Show_file_navigator thenkeychord_pressed_on_file_navigator(chord, key)returnendif chord == 'C-l' then--? print('C-l')Show_log_browser_side = not Show_log_browser_sideif Show_log_browser_side thensource.draw_menu_bar()endfunction source.update(dt)Cursor_time = Cursor_time + dtif App.mouse_x() < Editor_state.right thenedit.update(Editor_state, dt)elseif Show_log_browser_side thenlog_browser.update(Log_browser_state, dt)endendfunction source.quit()edit.quit(Editor_state)log_browser.quit(Log_browser_state)-- convert any bifold files hereendfunction source.convert_bifold_text(infilename, outfilename)local contents = love.filesystem.read(infilename)contents = contents:gsub('\u{1e}', ';')love.filesystem.write(outfilename, contents)endfunction source.settings()if Current_app == 'source' then--? print('reading source window position')edit.draw(Editor_state, --[[hide cursor?]] Show_file_navigator)if Show_log_browser_side then-- dividerApp.color(Divider_color)love.graphics.rectangle('fill', App.screen.width/2-1,Menu_status_bar_height, 3,App.screen.height)--log_browser.draw(Log_browser_state)endlog_new('source')love.keyboard.setTextInput(true) -- bring up keyboard on touch screenlove.keyboard.setKeyRepeat(true)love.graphics.setBackgroundColor(1,1,1)if Settings and Settings.source thensource.load_settings()elsesource.initialize_default_settings()endsource.initialize_edit_side{'run.lua'}source.initialize_log_browser_side()Menu_status_bar_height = 5 + Editor_state.line_height + 5Editor_state.top = Editor_state.top + Menu_status_bar_heightLog_browser_state.top = Log_browser_state.top + Menu_status_bar_heightFile_navigation.candidates = File_navigation.all_candidates -- modified with filterfilter = '',}all_candidates = {'run','run_tests','log','edit',log_render = {}Editor_state = {}-- called both in tests and real runfunction source.initialize_globals()-- tests currently mostly clear their own stateShow_log_browser_side = falseFocus = 'edit'Show_file_navigator = falseFile_navigation = {
log_new('run')love.keyboard.setTextInput(true) -- bring up keyboard on touch screenlove.keyboard.setKeyRepeat(true)love.graphics.setBackgroundColor(1,1,1)if Settings thenrun.load_settings()elserun.initialize_default_settings()endif #arg > 0 thenEditor_state.filename = arg[1]load_from_disk(Editor_state)Text.redraw_all(Editor_state)Editor_state.screen_top1 = {line=1, pos=1}Editor_state.cursor1 = {line=1, pos=1}elseload_from_disk(Editor_state)Text.redraw_all(Editor_state)endlove.window.setTitle('text.love - '..Editor_state.filename)if #arg > 1 thenprint('ignoring commandline args after '..arg[1])endif rawget(_G, 'jit') thenjit.off()jit.flush()endendfunction run.load_settings()love.graphics.setFont(love.graphics.newFont(Settings.font_height))-- maximize window to determine maximum allowable dimensionsApp.screen.width, App.screen.height, App.screen.flags = love.window.getMode()-- set up desired window dimensions
local restline.filename, line.line_number, rest = line.data:match('%[string "([^:]*)"%]:([^:]*):%s*(.*)')if line.filename == nil thenline.filename, line.line_number, rest = line.data:match('([^:]*):([^:]*):%s*(.*)')endif rest thenline.data = restendline.filename = guess_source(line.filename)line.line_number = tonumber(line.line_number)if line.data:sub(1,1) == '{' thenlocal data = json.decode(line.data)if log_render[data.name] thenline.data = dataendline.section_stack = table.shallowcopy(Section_stack)elseif line.data:match('\u{250c}') thenline.section_stack = table.shallowcopy(Section_stack) -- as it is at the beginninglocal section_name = line.data:match('\u{250c}%s*(.*)')table.insert(Section_stack, {name=section_name})line.section_begin = trueline.section_name = section_nameline.data = nilelseif line.data:match('\u{2518}') thenlocal section_name = line.data:match('\u{2518}%s*(.*)')if array.find(Section_stack, function(x) return x.name == section_name end) thenwhile table.remove(Section_stack).name ~= section_name do--endline.section_end = trueline.section_name = section_nameline.data = nilendline.section_stack = table.shallowcopy(Section_stack)else-- stringline.section_stack = table.shallowcopy(Section_stack)endelseline.section_stack = {}endendendfunction table.shallowcopy(x)return {unpack(x)}endfunction guess_source(filename)local possible_source = filename:gsub('%.lua$', '%.splua')if file_exists(possible_source) thenreturn possible_sourceelsereturn filenameendendfunction log_browser.draw(State)assert(#State.lines == #State.line_cache)local mouse_line_index = log_browser.line_index(State, App.mouse_x(), App.mouse_y())local y = State.topfor line_index = State.screen_top1.line,#State.lines doApp.color(Text_color)local line = State.lines[line_index]if y + State.line_height > App.screen.height then break endlocal height = State.line_heightif should_show(line) thenlocal xleft = render_stack_left_margin(State, line_index, line, y)local xright = render_stack_right_margin(State, line_index, line, y)if line.section_name thenApp.color(Section_border_color)local section_text = to_text(line.section_name)if line.section_begin thenlocal sectiony = y+Section_border_padding_verticallove.graphics.line(xleft,sectiony, xleft,y+State.line_height)love.graphics.line(xright,sectiony, xright,y+State.line_height)love.graphics.line(xleft,sectiony, xleft+50-2,sectiony)love.graphics.draw(section_text, xleft+50,y)love.graphics.line(xleft+50+App.width(section_text)+2,sectiony, xright,sectiony)else assert(line.section_end)local sectiony = y+State.line_height-Section_border_padding_verticallove.graphics.line(xleft,y, xleft,sectiony)love.graphics.line(xright,y, xright,sectiony)love.graphics.line(xleft,sectiony, xleft+50-2,sectiony)love.graphics.draw(section_text, xleft+50,y)love.graphics.line(xleft+50+App.width(section_text)+2,sectiony, xright,sectiony)endelseif type(line.data) == 'string' thenlocal old_left, old_right = State.left,State.rightState.left,State.right = xleft,xrighty = Text.draw(State, line_index, y, --[[startpos]] 1)State.left,State.right = old_left,old_rightelseheight = log_render[line.data.name](line.data, xleft, y, xright-xleft)endendif App.mouse_x() > Log_browser_state.left and line_index == mouse_line_index thenApp.color(Cursor_line_background_color)love.graphics.rectangle('fill', xleft,y, xright-xleft, height)endy = y + heightendendendfunction render_stack_left_margin(State, line_index, line, y)if line.section_stack == nil then-- assertion messagefor k,v in pairs(line) doprint(k)endendApp.color(Section_border_color)for i=1,#line.section_stack dolocal x = State.left + (i-1)*Section_border_padding_horizontallove.graphics.line(x,y, x,y+log_browser.height(State, line_index))if y < 30 thenlove.graphics.print(line.section_stack[i].name, x+State.font_height+5, y+5, --[[vertically]] math.pi/2)endif y > App.screen.height-log_browser.height(State, line_index) thenlove.graphics.print(line.section_stack[i].name, x+State.font_height+5, App.screen.height-App.width(to_text(line.section_stack[i].name))-5, --[[vertically]] math.pi/2)endendreturn log_browser.left_margin(State, line)endfunction render_stack_right_margin(State, line_index, line, y)App.color(Section_border_color)for i=1,#line.section_stack dolocal x = State.right - (i-1)*Section_border_padding_horizontallove.graphics.line(x,y, x,y+log_browser.height(State, line_index))if y < 30 thenlove.graphics.print(line.section_stack[i].name, x, y+5, --[[vertically]] math.pi/2)endif y > App.screen.height-log_browser.height(State, line_index) thenlove.graphics.print(line.section_stack[i].name, x, App.screen.height-App.width(to_text(line.section_stack[i].name))-5, --[[vertically]] math.pi/2)endendreturn log_browser.right_margin(State, line)endfunction should_show(line)-- Show a line if every single section it's in is expanded.for i=1,#line.section_stack dolocal section = line.section_stack[i]if not section.expanded thenreturn falseendendreturn trueendfunction log_browser.left_margin(State, line)return State.left + #line.section_stack*Section_border_padding_horizontalendfunction log_browser.right_margin(State, line)return State.right - #line.section_stack*Section_border_padding_horizontalendfunction log_browser.update(State, dt)endfunction log_browser.quit(State)endfunction log_browser.mouse_pressed(State, x,y, mouse_button)local line_index = log_browser.line_index(State, x,y)if line_index == nil then-- below lower marginreturnend-- leave some space to click without focusinglocal line = State.lines[line_index]local xleft = log_browser.left_margin(State, line)local xright = log_browser.right_margin(State, line)if x < xleft or x > xright thenreturnend-- if it's a section begin/end and the section is collapsed, expand it-- TODO: how to collapse?if line.section_begin or line.section_end then-- HACK: get section reference from next/previous linelocal new_sectionif line.section_begin thenif line_index < #State.lines thenlocal next_section_stack = State.lines[line_index+1].section_stackif next_section_stack thennew_section = next_section_stack[#next_section_stack]endendelseif line.section_end thenif line_index > 1 thenlocal previous_section_stack = State.lines[line_index-1].section_stackif previous_section_stack thennew_section = previous_section_stack[#previous_section_stack]endendendif new_section and new_section.expanded == nil thennew_section.expanded = truereturnendend-- open appropriate file in source sideif line.filename ~= Editor_state.filename thensource.switch_to_file(line.filename)end-- set cursorEditor_state.cursor1 = {line=line.line_number, pos=1, posB=nil}-- make sure it's visible-- TODO: handle extremely long linesEditor_state.screen_top1.line = math.max(0, Editor_state.cursor1.line-5)-- show cursorFocus = 'edit'-- expand B sideEditor_state.expanded = trueendfunction log_browser.line_index(State, mx,my)-- duplicate some logic from log_browser.drawlocal y = State.topfor line_index = State.screen_top1.line,#State.lines dolocal line = State.lines[line_index]if should_show(line) theny = y + log_browser.height(State, line_index)if my < y thenreturn line_indexendif y > App.screen.height then break endendendendfunction log_browser.mouse_released(State, x,y, mouse_button)endfunction log_browser.textinput(State, t)endfunction log_browser.keychord_pressed(State, chord, key)-- moveif chord == 'up' thenwhile State.screen_top1.line > 1 doState.screen_top1.line = State.screen_top1.line-1if should_show(State.lines[State.screen_top1.line]) thenbreakendendelseif chord == 'down' thenwhile State.screen_top1.line < #State.lines doState.screen_top1.line = State.screen_top1.line+1if should_show(State.lines[State.screen_top1.line]) thenbreakendendelseif chord == 'pageup' thenlocal y = 0while State.screen_top1.line > 1 and y < App.screen.height - 100 doState.screen_top1.line = State.screen_top1.line - 1if should_show(State.lines[State.screen_top1.line]) theny = y + log_browser.height(State, State.screen_top1.line)endendelseif chord == 'pagedown' thenlocal y = 0while State.screen_top1.line < #State.lines and y < App.screen.height - 100 doif should_show(State.lines[State.screen_top1.line]) theny = y + log_browser.height(State, State.screen_top1.line)endState.screen_top1.line = State.screen_top1.line + 1endendendfunction log_browser.height(State, line_index)local line = State.lines[line_index]if line.data == nil then-- section headerreturn State.line_heightelseif type(line.data) == 'string' thenreturn State.line_heightelseif line.height == nil then--? print('nil line height! rendering off screen to calculate')line.height = log_render[line.data.name](line.data, State.left, App.screen.height, State.right-State.left)endreturn line.heightendendfunction log_browser.keyreleased(State, key, scancode)end
function log_render.file_navigator_state(o, x,y, w)-- duplicate structure of source.draw_file_navigatorlocal num_lines = source.num_lines_for_file_navigator(o.files)local h = num_lines * Editor_state.line_heightApp.color(Menu_background_color)love.graphics.rectangle('fill', x,y, w,h)-- compute the x,y,width of the current index (in offsets from top left)local x2,y2 = 0,0local width = 0for i,filename in ipairs(o.files) dolocal filename_text = to_text(filename)width = App.width(filename_text)if x2 + width > App.screen.width - 5 theny2 = y2 + Editor_state.line_heightx2 = 0endif i == o.index thenbreakendx2 = x2 + width + 30end-- figure out how much of the menu to displaylocal menu_xmin = math.max(0, x2-w/2)local menu_xmax = math.min(App.screen.width, x2+w/2)-- now selectively print out entrieslocal x3,y3 = 0,y -- x3 is relative, y3 is absolutelocal width = 0for i,filename in ipairs(o.files) dolocal filename_text = to_text(filename)width = App.width(filename_text)if x3 + width > App.screen.width - 5 theny3 = y3 + Editor_state.line_heightx3 = 0endif i == o.index thenApp.color(Menu_highlight_color)love.graphics.rectangle('fill', x + x3-menu_xmin - 5, y3-2, width+5*2, Editor_state.line_height+2*2)endif x3 >= menu_xmin and x3 + width < menu_xmax thenApp.color(Menu_command_color)App.screen.draw(filename_text, x + x3-menu_xmin, y3)endx3 = x3 + width + 30end--return h+20endfunction file_navigator_up()local y, x, width = file_coord(File_navigation.index)local index = file_index(y-Editor_state.line_height, x, width)if index thenFile_navigation.index = indexendendfunction file_navigator_down()local y, x, width = file_coord(File_navigation.index)local index = file_index(y+Editor_state.line_height, x, width)if index thenFile_navigation.index = indexendendfunction file_coord(index)local y,x = Menu_status_bar_height, 5for i,filename in ipairs(File_navigation.candidates) dolocal width = App.width(to_text(filename))if x + width > App.screen.width - 5 theny = y + Editor_state.line_heightx = 5endif i == index thenreturn y, x, widthendx = x + width + 30endendfunction file_index(fy, fx, fwidth)log_start('file index')log(2, ('for %d %d %d'):format(fy, fx, fwidth))local y,x = Menu_status_bar_height, 5local best_guess, best_guess_x, best_guess_widthfor i,filename in ipairs(File_navigation.candidates) dolocal width = App.width(to_text(filename))if x + width > App.screen.width - 5 theny = y + Editor_state.line_heightx = 5endif y == fy thenlog(2, ('%d: correct row; considering %d %s %d %d'):format(y, i, filename, x, width))if best_guess == nil thenlog(2, 'nil')best_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 = widthendlog(2, ('best guess now %d %s %d %d'):format(best_guess, File_navigation.candidates[best_guess], best_guess_x, best_guess_width))endx = x + width + 30endlog_end('file index')return best_guessendfunction textinput_on_file_navigator(t)File_navigation.filter = File_navigation.filter..tFile_navigation.candidates = source.file_navigator_candidates()endelseif chord == 'down' thenfile_navigator_down()elseif chord == 'up' thenfile_navigator_up()endendFile_navigation.index = 1File_navigation.filter = ''File_navigation.candidates = File_navigation.all_candidateselseif chord == 'backspace' thenlocal len = utf8.len(File_navigation.filter)local byte_offset = Text.offset(File_navigation.filter, len)File_navigation.filter = string.sub(File_navigation.filter, 1, byte_offset-1)File_navigation.index = 1File_navigation.candidates = source.file_navigator_candidates()elseif chord == 'left' thenif File_navigation.index > 1 thenFile_navigation.index = File_navigation.index-1endelseif chord == 'right' thenif File_navigation.index < #File_navigation.candidates thenFile_navigation.index = File_navigation.index+1endFile_navigation.index = 1File_navigation.filter = ''File_navigation.candidates = File_navigation.all_candidateselseif chord == 'return' thenlocal candidate = guess_source(File_navigation.candidates[File_navigation.index]..'.lua')source.switch_to_file(candidate)Show_file_navigator = falselog(2, 'file navigator: '..chord)log(2, {name='file_navigator_state', files=File_navigation.candidates, index=File_navigation.index})if chord == 'escape' thenShow_file_navigator = falseApp.screen.draw(s_text, x,y)x = x + width + 30return x,yendfunction keychord_pressed_on_file_navigator(chord, key)button(Editor_state, 'menu', {x=x-5, y=y-2, w=width+5*2, h=Editor_state.line_height+2*2, color=colortable(color),onpress1 = function()local candidate = guess_source(s..'.lua')source.switch_to_file(candidate)Show_file_navigator = falseend})App.color(Menu_command_color)color = Menu_highlight_colorendlocal color = Menu_background_colorif cursor_highlight thenendfunction source.file_navigator_candidates()if File_navigation.filter == '' thenreturn File_navigation.all_candidatesendlocal result = {}for _,filename in ipairs(File_navigation.all_candidates) doif starts_with(filename, File_navigation.filter) thentable.insert(result, filename)endendreturn resultendfunction source.num_lines_for_file_navigator(candidates)local result = 1local x = 5for i,filename in ipairs(candidates) dolocal width = App.width(to_text(filename))if x + width > App.screen.width - 5 thenresult = result+1x = 5 + widthelsex = x + width + 30endendreturn resultendfunction add_file_to_menu(x,y, s, cursor_highlight)local s_text = to_text(s)local width = App.width(s_text)if x + width > App.screen.width - 5 theny = y + Editor_state.line_heightx = 5endfunction draw_cursor(x, y)-- blink every 0.5sif math.floor(Cursor_time*2)%2 == 0 thenApp.color(Cursor_color)love.graphics.rectangle('fill', x,y, 3,Editor_state.line_height)endx,y = add_file_to_menu(x,y, filename, i == File_navigation.index)if Menu_cursor >= App.screen.width - 5 thenbreakendendendApp.color(Menu_command_color)local filter_text = to_text(File_navigation.filter)App.screen.draw(filter_text, 5, 5)draw_cursor(5 + App.width(filter_text), 5)if File_navigation.num_lines == nil thenFile_navigation.num_lines = source.num_lines_for_file_navigator(File_navigation.candidates)endApp.color(Menu_background_color)love.graphics.rectangle('fill', 0,Menu_status_bar_height, App.screen.width, File_navigation.num_lines * Editor_state.line_height + --[[highlight padding]] 2)local x,y = 5, Menu_status_bar_heightfor i,filename in ipairs(File_navigation.candidates) doif filename == 'source' thenApp.color(Menu_border_color)love.graphics.line(Menu_cursor-10,2, Menu_cursor-10,Menu_status_bar_height-2)endApp.screen.draw(s_text, Menu_cursor,5)Menu_cursor = Menu_cursor + width + 30endfunction source.draw_file_navigator()local s_text = to_text(s)local width = App.width(s_text)if Menu_cursor + width > App.screen.width - 5 thenreturnendApp.color(Menu_command_color)
function Text.draw(State, line_index, y, startpos, startposB, hide_cursor)if not hide_cursor and not State.search_term thenif not hide_cursor and not State.search_term then
y = y + State.line_height--? print('=> y', y)elseif line.mode == 'drawing' theny = y+Drawing_padding_topDrawing.draw(State, line_index, y)y = y + Drawing.pixels(line.h, State.width) + Drawing_padding_bottomelseprint(line.mode)assert(false)
line.filename, line.line_number, line.data = line.data:match('%[string "([^:]*)"%]:([^:]*):%s*(.*)')
local restline.filename, line.line_number, rest = line.data:match('%[string "([^:]*)"%]:([^:]*):%s*(.*)')if line.filename == nil thenline.filename, line.line_number, rest = line.data:match('([^:]*):([^:]*):%s*(.*)')endif rest thenline.data = restend
for i,file in ipairs(File_navigation.candidates) doif file == 'source' then
App.color(Menu_command_color)local filter_text = to_text(File_navigation.filter)App.screen.draw(filter_text, 5, 5)draw_cursor(5 + App.width(filter_text), 5)if File_navigation.num_lines == nil thenFile_navigation.num_lines = source.num_lines_for_file_navigator(File_navigation.candidates)endApp.color(Menu_background_color)love.graphics.rectangle('fill', 0,Menu_status_bar_height, App.screen.width, File_navigation.num_lines * Editor_state.line_height + --[[highlight padding]] 2)local x,y = 5, Menu_status_bar_heightfor i,filename in ipairs(File_navigation.candidates) doif filename == 'source' then
function add_file_to_menu(s, cursor_highlight)if Text_cache[s] == nil thenText_cache[s] = App.newText(love.graphics.getFont(), s)
function draw_cursor(x, y)-- blink every 0.5sif math.floor(Cursor_time*2)%2 == 0 thenApp.color(Cursor_color)love.graphics.rectangle('fill', x,y, 3,Editor_state.line_height)
local width = App.width(Text_cache[s])if Menu_cursor + width > App.screen.width - 5 thenreturn
endfunction source.file_navigator_candidates()if File_navigation.filter == '' thenreturn File_navigation.all_candidatesendlocal result = {}for _,filename in ipairs(File_navigation.all_candidates) doif starts_with(filename, File_navigation.filter) thentable.insert(result, filename)endendreturn resultendfunction source.num_lines_for_file_navigator(candidates)local result = 1local x = 5for i,filename in ipairs(candidates) dolocal width = App.width(to_text(filename))if x + width > App.screen.width - 5 thenresult = result+1x = 5 + widthelsex = x + width + 30endendreturn resultendfunction add_file_to_menu(x,y, s, cursor_highlight)local s_text = to_text(s)local width = App.width(s_text)if x + width > App.screen.width - 5 theny = y + Editor_state.line_heightx = 5
File_navigation.index = 1File_navigation.filter = ''File_navigation.candidates = File_navigation.all_candidateselseif chord == 'backspace' thenlocal len = utf8.len(File_navigation.filter)local byte_offset = Text.offset(File_navigation.filter, len)File_navigation.filter = string.sub(File_navigation.filter, 1, byte_offset-1)File_navigation.index = 1File_navigation.candidates = source.file_navigator_candidates()
function log_render.file_navigator_state(o, x,y, w)-- duplicate structure of source.draw_file_navigatorlocal num_lines = source.num_lines_for_file_navigator(o.files)local h = num_lines * Editor_state.line_heightApp.color(Menu_background_color)love.graphics.rectangle('fill', x,y, w,h)-- compute the x,y,width of the current index (in offsets from top left)local x2,y2 = 0,0local width = 0for i,filename in ipairs(o.files) dolocal filename_text = to_text(filename)width = App.width(filename_text)if x2 + width > App.screen.width - 5 theny2 = y2 + Editor_state.line_heightx2 = 0endif i == o.index thenbreakendx2 = x2 + width + 30end-- figure out how much of the menu to displaylocal menu_xmin = math.max(0, x2-w/2)local menu_xmax = math.min(App.screen.width, x2+w/2)-- now selectively print out entrieslocal x3,y3 = 0,y -- x3 is relative, y3 is absolutelocal width = 0for i,filename in ipairs(o.files) dolocal filename_text = to_text(filename)width = App.width(filename_text)if x3 + width > App.screen.width - 5 theny3 = y3 + Editor_state.line_heightx3 = 0endif i == o.index thenApp.color(Menu_highlight_color)love.graphics.rectangle('fill', x + x3-menu_xmin - 5, y3-2, width+5*2, Editor_state.line_height+2*2)endif x3 >= menu_xmin and x3 + width < menu_xmax thenApp.color(Menu_command_color)App.screen.draw(filename_text, x + x3-menu_xmin, y3)endx3 = x3 + width + 30end--return h+20endfunction file_navigator_up()local y, x, width = file_coord(File_navigation.index)local index = file_index(y-Editor_state.line_height, x, width)if index thenFile_navigation.index = indexendendfunction file_navigator_down()local y, x, width = file_coord(File_navigation.index)local index = file_index(y+Editor_state.line_height, x, width)if index thenFile_navigation.index = indexendendfunction file_coord(index)local y,x = Menu_status_bar_height, 5for i,filename in ipairs(File_navigation.candidates) dolocal width = App.width(to_text(filename))if x + width > App.screen.width - 5 theny = y + Editor_state.line_heightx = 5endif i == index thenreturn y, x, widthendx = x + width + 30endendfunction file_index(fy, fx, fwidth)log_start('file index')log(2, ('for %d %d %d'):format(fy, fx, fwidth))local y,x = Menu_status_bar_height, 5local best_guess, best_guess_x, best_guess_widthfor i,filename in ipairs(File_navigation.candidates) dolocal width = App.width(to_text(filename))if x + width > App.screen.width - 5 theny = y + Editor_state.line_heightx = 5endif y == fy thenlog(2, ('%d: correct row; considering %d %s %d %d'):format(y, i, filename, x, width))if best_guess == nil thenlog(2, 'nil')best_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 = widthendlog(2, ('best guess now %d %s %d %d'):format(best_guess, File_navigation.candidates[best_guess], best_guess_x, best_guess_width))endx = x + width + 30endlog_end('file index')return best_guessendfunction textinput_on_file_navigator(t)File_navigation.filter = File_navigation.filter..tFile_navigation.candidates = source.file_navigator_candidates()end