aboutsummaryrefslogtreecommitdiff
path: root/error_handling.lua
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2019-02-02 19:42:14 -0800
committerBruce Hill <bruce@bruce-hill.com>2019-02-02 19:42:35 -0800
commitfb435c308a13f60253af65d0850211b75f934ef2 (patch)
tree193cef355a8479621da48d455630b2be33dabfa9 /error_handling.lua
parent26f38550aee20dd015c5200296edeba8ec0d1803 (diff)
Added spellchecker for error messages (when calling 'nil' actions)
Diffstat (limited to 'error_handling.lua')
-rw-r--r--error_handling.lua103
1 files changed, 99 insertions, 4 deletions
diff --git a/error_handling.lua b/error_handling.lua
index b7d5d13..ecf6088 100644
--- a/error_handling.lua
+++ b/error_handling.lua
@@ -57,14 +57,109 @@ debug.getinfo = function(thread, f, what)
end
return info
end
+local strdist
+strdist = function(a, b, cache)
+ if cache == nil then
+ cache = { }
+ end
+ if a == b then
+ return 0
+ end
+ if #a < #b then
+ a, b = b, a
+ end
+ if b == "" then
+ return #a
+ end
+ local k = a .. '\003' .. b
+ if not (cache[k]) then
+ cache[k] = math.min(strdist(a:sub(1, -2), b, cache) + 1, strdist(a, b:sub(1, -2), cache) + 1, strdist(a:sub(1, -2), b:sub(1, -2), cache) + (a:sub(-1) ~= b:sub(-1) and 1.1 or 0))
+ if #a >= 2 and #b >= 2 and a:sub(-1, -1) == b:sub(-2, -2) and a:sub(-2, -2) == b:sub(-1, -1) then
+ cache[k] = math.min(cache[k], strdist(a:sub(1, -3), b:sub(1, -3), cache) + 1)
+ end
+ end
+ return cache[k]
+end
local enhance_error
-enhance_error = function(error_message, start_fn, stop_fn)
+enhance_error = function(error_message)
if not (error_message and error_message:match("%d|")) then
error_message = error_message or ""
do
- local fn = (error_message:match("attempt to call a nil value %(global '(.*)'%)") or error_message:match("attempt to call global '(.*)' %(a nil value%)"))
- if fn then
- error_message = "The action '" .. tostring(fn:from_lua_id()) .. "' is not defined."
+ local fn_name = (error_message:match("attempt to call a nil value %(global '(.*)'%)") or error_message:match("attempt to call global '(.*)' %(a nil value%)"))
+ if fn_name then
+ local action_name = fn_name:from_lua_id()
+ error_message = "The action '" .. tostring(action_name) .. "' is not defined."
+ local func = debug.getinfo(2, 'f').func
+ local ename, env = debug.getupvalue(func, 1)
+ if not (ename == "_ENV" or ename == "_G") then
+ func = debug.getinfo(3, 'f').func
+ ename, env = debug.getupvalue(func, 1)
+ end
+ local THRESHOLD = math.min(4.5, .9 * #action_name)
+ local candidates = { }
+ local cache = { }
+ for i = 1, 99 do
+ local k, v = debug.getlocal(2, i)
+ if k == nil then
+ break
+ end
+ if not (k:sub(1, 1) == "(" or type(v) ~= 'function') then
+ k = k:from_lua_id()
+ if strdist(k, action_name, cache) <= THRESHOLD and k ~= "" then
+ table.insert(candidates, k)
+ end
+ end
+ end
+ for i = 1, debug.getinfo(func, 'u').nups do
+ local k, v = debug.getupvalue(func, i)
+ if not (k:sub(1, 1) == "(" or type(v) ~= 'function') then
+ k = k:from_lua_id()
+ if strdist(k, action_name, cache) <= THRESHOLD and k ~= "" then
+ table.insert(candidates, k)
+ end
+ end
+ end
+ local scan
+ scan = function(t, is_lua_id)
+ for k, v in pairs(t) do
+ if type(k) == 'string' and type(v) == 'function' then
+ if not (is_lua_id) then
+ k = k:from_lua_id()
+ end
+ if strdist(k, action_name, cache) <= THRESHOLD and k ~= "" then
+ table.insert(candidates, k)
+ end
+ end
+ end
+ end
+ scan(env.COMPILE_RULES, true)
+ scan(env.COMPILE_RULES._IMPORTS, true)
+ scan(env)
+ scan(env._IMPORTS)
+ if #candidates > 0 then
+ for _index_0 = 1, #candidates do
+ local c = candidates[_index_0]
+ THRESHOLD = math.min(THRESHOLD, strdist(c, action_name, cache))
+ end
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #candidates do
+ local c = candidates[_index_0]
+ if strdist(c, action_name, cache) <= THRESHOLD then
+ _accum_0[_len_0] = c
+ _len_0 = _len_0 + 1
+ end
+ end
+ candidates = _accum_0
+ end
+ if #candidates == 1 then
+ error_message = error_message .. "\n\x1b[3mSuggestion: Maybe you meant '" .. tostring(candidates[1]) .. "'? "
+ elseif #candidates > 0 then
+ local last = table.remove(candidates)
+ error_message = error_message .. ("\n" .. C('italic', "Suggestion: Maybe you meant '" .. tostring(table.concat(candidates, "', '")) .. "'" .. tostring(#candidates > 1 and ',' or '') .. " or '" .. tostring(last) .. "'? "))
+ end
+ end
end
end
local level = 2