1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-24 05:20:04 +08:00
SpaceVim/bundle/plenary.nvim/lua/luassert/formatters/init.lua
2022-05-16 22:20:10 +08:00

217 lines
5.5 KiB
Lua
Vendored

-- module will not return anything, only register formatters with the main assert engine
local assert = require('luassert.assert')
local colors = setmetatable({
none = function(c) return c end
},{ __index = function(self, key)
local ok, term = pcall(require, 'term')
local isatty = io.type(io.stdout) == 'file' and ok and term.isatty(io.stdout)
if not ok or not isatty or not term.colors then
return function(c) return c end
end
return function(c)
for token in key:gmatch("[^%.]+") do
c = term.colors[token](c)
end
return c
end
end
})
local function fmt_string(arg)
if type(arg) == "string" then
return string.format("(string) '%s'", arg)
end
end
-- A version of tostring which formats numbers more precisely.
local function tostr(arg)
if type(arg) ~= "number" then
return tostring(arg)
end
if arg ~= arg then
return "NaN"
elseif arg == 1/0 then
return "Inf"
elseif arg == -1/0 then
return "-Inf"
end
local str = string.format("%.20g", arg)
if math.type and math.type(arg) == "float" and not str:find("[%.,]") then
-- Number is a float but looks like an integer.
-- Insert ".0" after first run of digits.
str = str:gsub("%d+", "%0.0", 1)
end
return str
end
local function fmt_number(arg)
if type(arg) == "number" then
return string.format("(number) %s", tostr(arg))
end
end
local function fmt_boolean(arg)
if type(arg) == "boolean" then
return string.format("(boolean) %s", tostring(arg))
end
end
local function fmt_nil(arg)
if type(arg) == "nil" then
return "(nil)"
end
end
local type_priorities = {
number = 1,
boolean = 2,
string = 3,
table = 4,
["function"] = 5,
userdata = 6,
thread = 7
}
local function is_in_array_part(key, length)
return type(key) == "number" and 1 <= key and key <= length and math.floor(key) == key
end
local function get_sorted_keys(t)
local keys = {}
local nkeys = 0
for key in pairs(t) do
nkeys = nkeys + 1
keys[nkeys] = key
end
local length = #t
local function key_comparator(key1, key2)
local type1, type2 = type(key1), type(key2)
local priority1 = is_in_array_part(key1, length) and 0 or type_priorities[type1] or 8
local priority2 = is_in_array_part(key2, length) and 0 or type_priorities[type2] or 8
if priority1 == priority2 then
if type1 == "string" or type1 == "number" then
return key1 < key2
elseif type1 == "boolean" then
return key1 -- put true before false
end
else
return priority1 < priority2
end
end
table.sort(keys, key_comparator)
return keys, nkeys
end
local function fmt_table(arg, fmtargs)
if type(arg) ~= "table" then
return
end
local tmax = assert:get_parameter("TableFormatLevel")
local showrec = assert:get_parameter("TableFormatShowRecursion")
local errchar = assert:get_parameter("TableErrorHighlightCharacter") or ""
local errcolor = assert:get_parameter("TableErrorHighlightColor") or "none"
local crumbs = fmtargs and fmtargs.crumbs or {}
local cache = {}
local type_desc
if getmetatable(arg) == nil then
type_desc = "(" .. tostring(arg) .. ") "
elseif not pcall(setmetatable, arg, getmetatable(arg)) then
-- cannot set same metatable, so it is protected, skip id
type_desc = "(table) "
else
-- unprotected metatable, temporary remove the mt
local mt = getmetatable(arg)
setmetatable(arg, nil)
type_desc = "(" .. tostring(arg) .. ") "
setmetatable(arg, mt)
end
local function ft(t, l, with_crumbs)
if showrec and cache[t] and cache[t] > 0 then
return "{ ... recursive }"
end
if next(t) == nil then
return "{ }"
end
if l > tmax and tmax >= 0 then
return "{ ... more }"
end
local result = "{"
local keys, nkeys = get_sorted_keys(t)
cache[t] = (cache[t] or 0) + 1
local crumb = crumbs[#crumbs - l + 1]
for i = 1, nkeys do
local k = keys[i]
local v = t[k]
local use_crumbs = with_crumbs and k == crumb
if type(v) == "table" then
v = ft(v, l + 1, use_crumbs)
elseif type(v) == "string" then
v = "'"..v.."'"
end
local ch = use_crumbs and errchar or ""
local indent = string.rep(" ",l * 2 - ch:len())
local mark = (ch:len() == 0 and "" or colors[errcolor](ch))
result = result .. string.format("\n%s%s[%s] = %s", indent, mark, tostr(k), tostr(v))
end
cache[t] = cache[t] - 1
return result .. " }"
end
return type_desc .. ft(arg, 1, true)
end
local function fmt_function(arg)
if type(arg) == "function" then
local debug_info = debug.getinfo(arg)
return string.format("%s @ line %s in %s", tostring(arg), tostring(debug_info.linedefined), tostring(debug_info.source))
end
end
local function fmt_userdata(arg)
if type(arg) == "userdata" then
return string.format("(userdata) '%s'", tostring(arg))
end
end
local function fmt_thread(arg)
if type(arg) == "thread" then
return string.format("(thread) '%s'", tostring(arg))
end
end
assert:add_formatter(fmt_string)
assert:add_formatter(fmt_number)
assert:add_formatter(fmt_boolean)
assert:add_formatter(fmt_nil)
assert:add_formatter(fmt_table)
assert:add_formatter(fmt_function)
assert:add_formatter(fmt_userdata)
assert:add_formatter(fmt_thread)
-- Set default table display depth for table formatter
assert:set_parameter("TableFormatLevel", 3)
assert:set_parameter("TableFormatShowRecursion", false)
assert:set_parameter("TableErrorHighlightCharacter", "*")
assert:set_parameter("TableErrorHighlightColor", "none")