local editors = require'editors' local modifiers = {ctrl = false, alt = false, shift = false} local mounted_project local errhand -- PUC Lua 5.1 doesn't support function arguments in xpcall local xpacall = function(fn, err, ...) local args = {...} return xpcall(function() return fn(unpack(args)) end, err) end -- copy example project to save dir if it doesn't exist if not lovr.filesystem.isDirectory('projects') then lovr.filesystem.createDirectory('example') end if not lovr.filesystem.isFile('projects/example/main.lua') then print('copying example project into directory', lovr.filesystem.getSaveDirectory()) local content = lovr.filesystem.read('seed/main.lua') lovr.filesystem.createDirectory('projects/example') local success = lovr.filesystem.write('projects/example/main.lua', content) if not success then print('! could not write to save directory') end end -- contained callbacks that loaded user project tried to register -- init'ed as stubs, overwritten on user project load local callbacks = { draw = function (pass) end, update = function (dt) end, keypressed = function (key, scancode, isrepeat) end, keyreleased = function (key, scancode) end, textinput = function (k) end, } local function runProject() local stored = { load = lovr.load, draw = lovr.draw, update = lovr.update, keypressed = lovr.keypressed, keyreleased = lovr.keyreleased, textinput = lovr.textinput, } package.loaded['main'] = nil -- loading user project will overwrite some of indeck's callbacks xpacall(require, errhand, 'main') -- reinstate indeck's callbacks store the user project callbacks for event forwarding for _, fname in ipairs({'draw', 'update', 'keypressed', 'keyreleased', 'textinput'}) do if stored[fname] ~= lovr[fname] then lovr[fname], callbacks[fname] = stored[fname], lovr[fname] -- the switch end end if stored.load ~= lovr.load then -- call user's load() once and forget about it xpacall(lovr.load, errhand) end end local function pauseProject() print('pausing project') callbacks = { draw = function (pass) end, update = function (dt) end, keypressed = function (key, scancode, isrepeat) end, keyreleased = function (key, scancode) end, textinput = function (k) end, } end local function switchToProject(project_dir) if mounted_project then lovr.filesystem.unmount(mounted_project) end -- reloading the user project local full_path = lovr.filesystem.getSaveDirectory() .. '/projects/' .. project_dir print('loading user project', full_path) local success = lovr.filesystem.mount(full_path, '', false) if not success then print('! unsucessful; does project dir exist?') return end mounted_project = full_path runProject() -- open project's main.lua in active editor local path_to_main = 'projects/' .. project_dir .. '/main.lua' if lovr.filesystem.isFile(path_to_main) and editors.active then editors.active:openFile(path_to_main) else print(lovr.filesystem.isFile(path_to_main), path_to_main) end end function lovr.load() if lovr.headset then lovr.headset.update() end lovr.filesystem.unmount(lovr.filesystem.getSource()) lovr.filesystem.mount('lovr-api', 'help') local editor = editors.new(120, 60, switchToProject) editor:listFiles('') end function lovr.update(dt) xpacall(callbacks.update, errhand, dt) end function lovr.draw(pass) -- main pass rendering for _, editor in ipairs(editors) do editor:draw(pass) end pass:setColor(1,1,1) local _, skip = xpacall(callbacks.draw, errhand, pass) -- drawing to texture in separate passes per editor local passes = {} for _, editor in ipairs(editors) do local editor_pass = editor:drawToTexture() table.insert(passes, editor_pass) end if not skip then table.insert(passes, pass) end return lovr.graphics.submit(passes) end function lovr.keypressed(key, scancode, isrepeat) if key == 'lctrl' or key == 'rctrl' then modifiers.ctrl = true return elseif key == 'lalt' or key == 'ralt' then modifiers.alt = true return elseif key == 'lshift' or key == 'rshift' then modifiers.shift = true return end local combo = string.format('%s%s%s%s', modifiers.ctrl and 'ctrl+' or '', modifiers.alt and 'alt+' or '', modifiers.shift and 'shift+' or '', key) if combo == 'ctrl+p' then -- spawn new editor local editor = editors.new(120, 60, switchToProject) editor:listFiles() elseif combo =='ctrl+r' then -- restart project if editors.active then editors.active:saveFile() end runProject() elseif combo =='ctrl+shift+r' then lovr.event.push('restart') elseif combo =='escape' then lovr.event.push('quit') end editors.keypressed(combo) xpacall(callbacks.keypressed, errhand, key, scancode, isrepeat, combo) end function lovr.keyreleased(key, scancode) if key == 'lctrl' or key == 'rctrl' then modifiers.ctrl = false return elseif key == 'lalt' or key == 'ralt' then modifiers.alt = false return elseif key == 'lshift' or key == 'rshift' then modifiers.shift = false return end xpacall(callbacks.keyreleased, errhand, key, scancode) end function lovr.textinput(k) if k:match('[^\n]') then editors.textinput(k) end xpacall(callbacks.textinput, errhand, k) end local function wrap(str, limit) limit = limit or 60 local position = 1 local function check(sp, st, word, fi) if fi - position > limit then position = st return "\n" .. word end end return str:gsub("(%s+)()(%S+)()", check) end local function showStackTrace(info) local prev_active = editors.active local traceback_editor = editors.new(60, 30) editors.active = prev_active or editors.active traceback_editor:setText(wrap(info, traceback_editor.cols)) traceback_editor.transform:translate(-1,0,-0.4) traceback_editor.transform:rotate(-math.rad(40), 0,1,0) end local function continueRunning() if lovr.event then lovr.event.pump() for name, a, b, c, d in lovr.event.poll() do if name == 'restart' then local cookie = lovr.restart and lovr.restart() return 'restart', cookie elseif name == 'quit' and (not lovr.quit or not lovr.quit(a)) then return a or 0 end if lovr.handlers[name] then lovr.handlers[name](a, b, c, d) end end end local dt = 0 if lovr.timer then dt = lovr.timer.step() end if lovr.headset then dt = lovr.headset.update() end if lovr.update then lovr.update(dt) end if lovr.graphics then if lovr.headset then local pass = lovr.headset.getPass() if pass then local skip = lovr.draw and lovr.draw(pass) if not skip then lovr.graphics.submit(pass) end end end if lovr.system.isWindowOpen() then if lovr.mirror then local pass = lovr.graphics.getWindowPass() local skip = not pass or lovr.mirror(pass) if not skip then lovr.graphics.submit(pass) end end lovr.graphics.present() end end if lovr.headset then lovr.headset.submit() end if lovr.math then lovr.math.drain() end end errhand = function(message, traceback) traceback = traceback or debug.traceback('', 3) local error_message = message .. '\n' .. traceback print('! runtime error') print(error_message) pauseProject() showStackTrace(error_message) return continueRunning end