Last active
August 29, 2015 14:12
-
-
Save pablomayobre/a6a0734b5b317d41dc3f to your computer and use it in GitHub Desktop.
LÖVE Error handler and Notepad++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --No credit nor license is required for this function | |
| --It is based on the original code by LÖVE developers | |
| --Just minor functionality was added, if at all. | |
| return function (src) | |
| local dir = string.gsub(src,"([\\])","/") | |
| local src = dir:match("/$") and dir or (dir.."/") | |
| function love.errhand(msg) | |
| msg = tostring(msg) | |
| print("Error:") | |
| print(debug.traceback(tostring(msg), 3):gsub("\n[^\n]+$", "")) | |
| local j = string.gsub(msg,"^(Syntax error: )","") | |
| local t = {} | |
| for i=1,2 do | |
| local pos1, pos2 = string.find(j,":", 1, true) | |
| if not pos1 then | |
| t[#t + 1] = j | |
| break | |
| end | |
| t[#t + 1] = string.sub(j, 1, pos1 - 1) | |
| j = string.sub(j, pos2 + 1) | |
| end | |
| if string.match(t[1] or "","^%[.+%]$") then | |
| print("The error is in the internal function: "..(t[1] or "")) | |
| else | |
| local f,l = ((src or "")..t[1] or ""),t[2] or "" | |
| print (string.format("FILE = %s, LINE = %s",f,l)) | |
| end | |
| if not love.window or not love.graphics or not love.event then | |
| return | |
| end | |
| if not love.graphics.isCreated() or not love.window.isCreated() then | |
| if not pcall(love.window.setMode, 800, 600) then | |
| return | |
| end | |
| end | |
| if love.mouse then | |
| love.mouse.setVisible(true) | |
| love.mouse.setGrabbed(false) | |
| end | |
| if love.joystick then | |
| for i,v in ipairs(love.joystick.getJoysticks()) do | |
| v:setVibration() | |
| end | |
| end | |
| if love.audio then love.audio.stop() end | |
| local pxs = love.window.getPixelScale and love.window.getPixelScale() or 1 | |
| love.graphics.reset() | |
| local font = love.graphics.setNewFont(math.floor(14 * pxs)) | |
| local sRGB = select(3, love.window.getMode()).srgb | |
| if sRGB then | |
| love.graphics.setBackgroundColor(love.math.gammaToLinear(89, 157, 220)) | |
| else | |
| love.graphics.setBackgroundColor(89, 157, 220) | |
| end | |
| love.graphics.setColor(255, 255, 255, 255) | |
| local trace = debug.traceback() | |
| love.graphics.clear() | |
| love.graphics.origin() | |
| local err = {} | |
| table.insert(err, "Error\n") | |
| table.insert(err, msg.."\n\n") | |
| for l in string.gmatch(trace, "(.-)\n") do | |
| if not string.match(l, "boot.lua") then | |
| l = string.gsub(l, "stack traceback:", "Traceback\n") | |
| table.insert(err, l) | |
| end | |
| end | |
| local p = table.concat(err, "\n") | |
| p = string.gsub(p, "\t", "") | |
| p = string.gsub(p, "%[string \"(.-)\"%]", "%1") | |
| local function draw() | |
| local pos = 70 * pxs | |
| love.graphics.clear() | |
| love.graphics.printf(p, pos, pos, love.graphics.getWidth() - pos) | |
| love.graphics.present() | |
| end | |
| while true do | |
| love.event.pump() | |
| for e, a, b, c in love.event.poll() do | |
| if e == "quit" then | |
| return | |
| end | |
| if e == "keypressed" and a == "escape" then | |
| return | |
| end | |
| end | |
| draw() | |
| if love.timer then | |
| love.timer.sleep(0.1) | |
| end | |
| end | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --1 | |
| -- Modified version of lurker | |
| -- Changes: | |
| -- Doesnt depend on Lume | |
| -- Better error message (now with the FILE and LINE) | |
| -- Draw function can be easily changed | |
| -- Stops all the stuff that can be annoying to the user | |
| -- Works better when sRGB or HighDPI is enabled | |
| -- Less stuff printed to the console (because that can turn to be annoying) | |
| -- More callbacks supported | |
| -- | |
| -- Copyright (c) 2015 rxi | |
| -- | |
| -- This library is free software; you can redistribute it and/or modify it | |
| -- under the terms of the MIT license. See LICENSE for details. | |
| local lurker = { _version = "1.0.1" } | |
| local lovecallbacknames = { | |
| "update", | |
| "load", | |
| "draw", | |
| "mousepressed", | |
| "mousereleased", | |
| "keypressed", | |
| "keyreleased", | |
| "focus", | |
| "quit", | |
| } | |
| function lurker.init(src) | |
| local src = string.gsub(src,"([\\])","/") | |
| lurker.src = src:match("/$") and src or (src.."/") | |
| lurker.path = "." | |
| lurker.preswap = function() end | |
| lurker.postswap = function() end | |
| lurker.interval = .5 | |
| lurker.protected = true | |
| lurker.quiet = false | |
| lurker.lastscan = 0 | |
| lurker.lasterrorfile = nil | |
| lurker.files = {} | |
| lurker.funcwrappers = {} | |
| lurker.lovefuncs = {} | |
| lurker.state = "init" | |
| for _, v in ipairs(lurker.getchanged()) do lurker.resetfile(v) end | |
| return lurker | |
| end | |
| function lurker.listdir(path, recursive, skipdotfiles, t) | |
| path = (path == ".") and "" or path | |
| local function fullpath(x) return path .. "/" .. x end | |
| local t = {} | |
| for _, f in ipairs(love.filesystem.getDirectoryItems(path)) do | |
| local f = fullpath(f) | |
| if not skipdotfiles or not f:match("/%.[^/]*$") then | |
| if recursive and love.filesystem.isDirectory(f) then | |
| lurker.listdir(f, true, skipdotfiles, t) | |
| else | |
| table.insert(t, f:match("^[/]*(.-)[/]*$")) | |
| end | |
| end | |
| end | |
| return t | |
| end | |
| function lurker.initwrappers() | |
| for _, v in pairs(lovecallbacknames) do | |
| lurker.funcwrappers[v] = function(...) | |
| local args = {...} | |
| xpcall(function() | |
| return lurker.lovefuncs[v] and lurker.lovefuncs[v](unpack(args)) | |
| end, lurker.onerror) | |
| end | |
| lurker.lovefuncs[v] = love[v] | |
| end | |
| lurker.updatewrappers() | |
| end | |
| function lurker.updatewrappers() | |
| for _, v in pairs(lovecallbacknames) do | |
| if love[v] ~= lurker.funcwrappers[v] then | |
| lurker.lovefuncs[v] = love[v] | |
| love[v] = lurker.funcwrappers[v] | |
| end | |
| end | |
| end | |
| function lurker.draw () | |
| local sRGB = select(3, love.window.getMode()).srgb | |
| if sRGB then | |
| love.graphics.setBackgroundColor(love.math.gammaToLinear(89, 157, 220)) | |
| else | |
| love.graphics.setBackgroundColor(89, 157, 220) | |
| end | |
| love.graphics.setColor(255, 255, 255, 255) | |
| local pxs = love.window.getPixelScale and love.window.getPixelScale() or 1 | |
| local pos = 70 * pxs | |
| love.graphics.printf(lurker.errmsg, pos, pos, love.graphics.getWidth() - pos*2) | |
| end | |
| function lurker.onerror(e, nostacktrace) | |
| lurker.state = "error" | |
| -- Set up callbacks | |
| for _, v in pairs(lovecallbacknames) do | |
| love[v] = function() end | |
| end | |
| msg = tostring(e) | |
| print("Error:") | |
| print(debug.traceback(msg, 2):gsub("\n[^\n]+$", "")) | |
| local j = string.gsub(msg,"^(Syntax error: )","") | |
| local t = {} | |
| for i=1, 2 do | |
| local pos1, pos2 = string.find(j,":", 1, true) | |
| if not pos1 then | |
| t[#t + 1] = j | |
| break | |
| end | |
| t[#t + 1] = string.sub(j, 1, pos1 - 1) | |
| j = string.sub(j, pos2 + 1) | |
| end | |
| if string.match(t[1] or "","^%[.+%]$") then | |
| print("The error is in the internal function: "..(t[1] or "")) | |
| else | |
| local f,l = ((lurker.src or "")..t[1] or ""),t[2] or "" | |
| print (string.format("FILE = %s, LINE = %s",f,l)) | |
| end | |
| if not love.window or not love.graphics or not love.event then | |
| love.event.quit() | |
| end | |
| if not love.graphics.isCreated() or not love.window.isCreated() then | |
| if not pcall(love.window.setMode, 800, 600) then | |
| love.event.quit() | |
| end | |
| end | |
| if love.mouse then | |
| love.mouse.setVisible(true) | |
| love.mouse.setGrabbed(false) | |
| end | |
| if love.joystick then | |
| for i,v in ipairs(love.joystick.getJoysticks()) do | |
| v:setVibration() | |
| end | |
| end | |
| if love.audio then love.audio.stop() end | |
| local err = {} | |
| table.insert(err, "Error\n") | |
| table.insert(err, msg.."\n\n") | |
| local trace = debug.traceback() | |
| for l in string.gmatch(trace, "(.-)\n") do | |
| if not string.match(l, "boot.lua") then | |
| l = string.gsub(l, "stack traceback:", "Traceback\n") | |
| table.insert(err, l) | |
| end | |
| end | |
| lurker.errmsg = table.concat(err, "\n") | |
| lurker.errmsg = string.gsub(lurker.errmsg, "\t", "") | |
| lurker.errmsg = string.gsub(lurker.errmsg, "%[string \"(.-)\"%]", "%1") | |
| local pxs = love.window.getPixelScale and love.window.getPixelScale() or 1 | |
| local font = love.graphics.setNewFont(math.ceil(14 * pxs)) | |
| love.draw = lurker.draw or function () end | |
| love.graphics.push("all") --Go back to default settings but save old ones | |
| love.graphics.reset() | |
| love.update = lurker.update | |
| love.keypressed = function(k) | |
| if k == "escape" then | |
| love.event.quit() | |
| end | |
| end | |
| end | |
| function lurker.exitinitstate() | |
| lurker.state = "normal" | |
| if lurker.protected then | |
| lurker.initwrappers() | |
| end | |
| end | |
| function lurker.exiterrorstate() | |
| lurker.state = "normal" | |
| for _, v in pairs(lovecallbacknames) do | |
| love[v] = lurker.funcwrappers[v] | |
| end | |
| love.graphics.pop() | |
| end | |
| function lurker.update() | |
| if lurker.state == "init" then | |
| lurker.exitinitstate() | |
| end | |
| local diff = love.timer.getTime() - lurker.lastscan | |
| if diff > lurker.interval then | |
| lurker.lastscan = lurker.lastscan + diff | |
| local changed = lurker.scan() | |
| if #changed > 0 and lurker.lasterrorfile then | |
| local f = lurker.lasterrorfile | |
| lurker.lasterrorfile = nil | |
| lurker.hotswapfile(f) | |
| end | |
| end | |
| end | |
| function lurker.getchanged() | |
| local function fn(f) | |
| return f:match("%.lua$") and lurker.files[f] ~= love.filesystem.getLastModified(f) | |
| end | |
| local t = lurker.listdir(lurker.path, true, true) | |
| local rtn = {} | |
| for k, v in ipairs(t) do | |
| if fn(v) then rtn[#rtn + 1] = v end | |
| end | |
| return rtn | |
| end | |
| function lurker.modname(f) | |
| return (f:gsub("%.lua$", ""):gsub("[/\\]", ".")) | |
| end | |
| function lurker.resetfile(f) | |
| lurker.files[f] = love.filesystem.getLastModified(f) | |
| end | |
| function lurker.hotswapfile(f) | |
| if lurker.state == "error" then | |
| lurker.exiterrorstate() | |
| end | |
| if lurker.preswap(f) then | |
| lurker.resetfile(f) | |
| return | |
| end | |
| local modname = lurker.modname(f) | |
| local oldglobal = {} | |
| for k, v in pairs(_G) do oldglobal[k] = v end | |
| local updated = {} | |
| local function update(old, new) | |
| if updated[old] then return end | |
| updated[old] = true | |
| local oldmt, newmt = getmetatable(old), getmetatable(new) | |
| if oldmt and newmt then update(oldmt, newmt) end | |
| for k, v in pairs(new) do | |
| if type(v) == "table" then update(old[k], v) else old[k] = v end | |
| end | |
| end | |
| local err = nil | |
| local function onerror(e) | |
| for k, v in pairs(_G) do _G[k] = oldglobal[k] end | |
| err = e | |
| end | |
| local ok, oldmod = pcall(require, modname) | |
| oldmod = ok and oldmod or nil | |
| xpcall(function() | |
| package.loaded[modname] = nil | |
| local newmod = require(modname) | |
| if type(oldmod) == "table" then update(oldmod, newmod) end | |
| for k, v in pairs(oldglobal) do | |
| if v ~= _G[k] and type(v) == "table" then | |
| update(v, _G[k]) | |
| _G[k] = v | |
| end | |
| end | |
| end, onerror) | |
| package.loaded[modname] = oldmod | |
| if err then | |
| if not lurker.quiet and lurker.protected then | |
| lurker.lasterrorfile = f | |
| lurker.onerror(err, true) | |
| lurker.resetfile(f) | |
| return | |
| end | |
| end | |
| lurker.resetfile(f) | |
| lurker.postswap(f) | |
| if lurker.protected then | |
| lurker.updatewrappers() | |
| end | |
| end | |
| function lurker.scan() | |
| if lurker.state == "init" then | |
| lurker.exitinitstate() | |
| end | |
| local changed = lurker.getchanged() | |
| for _, v in ipairs(changed) do lurker.hotswapfile(v) end | |
| return changed | |
| end | |
| return setmetatable(lurker,{__call = function(self,...) return self.init(...) end}) |
Author
Author
If you use strong or a similar library in your project, you can replace this:
for i=1,2 do
local pos1, pos2 = string.find(j,":", 1, true)
if not pos1 then
t[#t + 1] = j
break
end
t[#t + 1] = string.sub(j, 1, pos1 - 1)
j = string.sub(j, pos2 + 1)
end with this:
t = string.split(j,":",false) --False because it's not a patternStrong also supports this:
t = j / ":"
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
PS: It also fix the errors in HighDPI screens like Mac OS X Retina Displays and a bug in the color when in sRGB mode. This bugs where fixed in 0.9.2, but this file works in all 0.9.X versions.