chore: update inspect.lua to 3.1.3

This commit is contained in:
Christian Clason 2022-04-21 16:23:10 +02:00
parent 5c4ec25478
commit 64784dccb5
2 changed files with 197 additions and 193 deletions

View File

@ -87,6 +87,7 @@ These dependencies are "vendored" (inlined), we need to update the sources manua
- [xdiff](https://github.com/git/git/tree/master/xdiff) - [xdiff](https://github.com/git/git/tree/master/xdiff)
- [lua-cjson](https://github.com/openresty/lua-cjson) - [lua-cjson](https://github.com/openresty/lua-cjson)
- [Klib](https://github.com/attractivechaos/klib) - [Klib](https://github.com/attractivechaos/klib)
- [inspect.lua](https://github.com/kikito/inspect.lua)
We also maintain some forks, particularly for Windows, if we are waiting on upstream changes: We also maintain some forks, particularly for Windows, if we are waiting on upstream changes:
https://github.com/neovim/neovim/wiki/Deps https://github.com/neovim/neovim/wiki/Deps

View File

@ -1,7 +1,7 @@
local inspect ={ local inspect = {
_VERSION = 'inspect.lua 3.1.0', _VERSION = "inspect.lua 3.1.0",
_URL = 'http://github.com/kikito/inspect.lua', _URL = "http://github.com/kikito/inspect.lua",
_DESCRIPTION = 'human-readable representations of tables', _DESCRIPTION = "human-readable representations of tables",
_LICENSE = [[ _LICENSE = [[
MIT LICENSE MIT LICENSE
@ -25,13 +25,26 @@ local inspect ={
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]] ]],
} }
local tostring = tostring inspect.KEY = setmetatable({}, {
__tostring = function()
return "inspect.KEY"
end,
})
inspect.METATABLE = setmetatable({}, {
__tostring = function()
return "inspect.METATABLE"
end,
})
inspect.KEY = setmetatable({}, {__tostring = function() return 'inspect.KEY' end}) local tostring = tostring
inspect.METATABLE = setmetatable({}, {__tostring = function() return 'inspect.METATABLE' end}) local rep = string.rep
local match = string.match
local char = string.char
local gsub = string.gsub
local fmt = string.format
local function rawpairs(t) local function rawpairs(t)
return next, t, nil return next, t, nil
@ -40,299 +53,289 @@ end
-- Apostrophizes the string if it has quotes, but not aphostrophes -- Apostrophizes the string if it has quotes, but not aphostrophes
-- Otherwise, it returns a regular quoted string -- Otherwise, it returns a regular quoted string
local function smartQuote(str) local function smartQuote(str)
if str:match('"') and not str:match("'") then if match(str, '"') and not match(str, "'") then
return "'" .. str .. "'" return "'" .. str .. "'"
end end
return '"' .. str:gsub('"', '\\"') .. '"' return '"' .. gsub(str, '"', '\\"') .. '"'
end end
-- \a => '\\a', \0 => '\\0', 31 => '\31' -- \a => '\\a', \0 => '\\0', 31 => '\31'
local shortControlCharEscapes = { local shortControlCharEscapes = {
["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", ["\a"] = "\\a",
["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v" ["\b"] = "\\b",
["\f"] = "\\f",
["\n"] = "\\n",
["\r"] = "\\r",
["\t"] = "\\t",
["\v"] = "\\v",
["\127"] = "\\127",
} }
local longControlCharEscapes = {} -- \a => nil, \0 => \000, 31 => \031 local longControlCharEscapes = { ["\127"] = "\127" }
for i=0, 31 do for i = 0, 31 do
local ch = string.char(i) local ch = char(i)
if not shortControlCharEscapes[ch] then if not shortControlCharEscapes[ch] then
shortControlCharEscapes[ch] = "\\"..i shortControlCharEscapes[ch] = "\\" .. i
longControlCharEscapes[ch] = string.format("\\%03d", i) longControlCharEscapes[ch] = fmt("\\%03d", i)
end end
end end
local function escape(str) local function escape(str)
return (str:gsub("\\", "\\\\") return (gsub(gsub(gsub(str, "\\", "\\\\"), "(%c)%f[0-9]", longControlCharEscapes), "%c", shortControlCharEscapes))
:gsub("(%c)%f[0-9]", longControlCharEscapes)
:gsub("%c", shortControlCharEscapes))
end end
local function isIdentifier(str) local function isIdentifier(str)
return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" ) return type(str) == "string" and not not str:match("^[_%a][_%a%d]*$")
end end
local flr = math.floor
local function isSequenceKey(k, sequenceLength) local function isSequenceKey(k, sequenceLength)
return type(k) == 'number' return type(k) == "number" and flr(k) == k and 1 <= k and k <= sequenceLength
and 1 <= k
and k <= sequenceLength
and math.floor(k) == k
end end
local defaultTypeOrders = { local defaultTypeOrders = {
['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4, ["number"] = 1,
['function'] = 5, ['userdata'] = 6, ['thread'] = 7 ["boolean"] = 2,
["string"] = 3,
["table"] = 4,
["function"] = 5,
["userdata"] = 6,
["thread"] = 7,
} }
local function sortKeys(a, b) local function sortKeys(a, b)
local ta, tb = type(a), type(b) local ta, tb = type(a), type(b)
-- strings and numbers are sorted numerically/alphabetically -- strings and numbers are sorted numerically/alphabetically
if ta == tb and (ta == 'string' or ta == 'number') then return a < b end if ta == tb and (ta == "string" or ta == "number") then
return a < b
local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb]
-- Two default types are compared according to the defaultTypeOrders table
if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb]
elseif dta then return true -- default types before custom ones
elseif dtb then return false -- custom types after default ones
end end
local dta = defaultTypeOrders[ta] or 100
local dtb = defaultTypeOrders[tb] or 100
-- Two default types are compared according to the defaultTypeOrders table
-- custom types are sorted out alphabetically -- custom types are sorted out alphabetically
return ta < tb return dta == dtb and ta < tb or dta < dtb
end end
-- For implementation reasons, the behavior of rawlen & # is "undefined" when local function getKeys(t)
-- tables aren't pure sequences. So we implement our own # operator. local seqLen = 1
local function getSequenceLength(t) while rawget(t, seqLen) ~= nil do
local len = 1 seqLen = seqLen + 1
local v = rawget(t,len)
while v ~= nil do
len = len + 1
v = rawget(t,len)
end end
return len - 1 seqLen = seqLen - 1
end
local function getNonSequentialKeys(t) local keys, keysLen = {}, 0
local keys, keysLength = {}, 0 for k in rawpairs(t) do
local sequenceLength = getSequenceLength(t) if not isSequenceKey(k, seqLen) then
for k,_ in rawpairs(t) do keysLen = keysLen + 1
if not isSequenceKey(k, sequenceLength) then keys[keysLen] = k
keysLength = keysLength + 1
keys[keysLength] = k
end end
end end
table.sort(keys, sortKeys) table.sort(keys, sortKeys)
return keys, keysLength, sequenceLength return keys, keysLen, seqLen
end end
local function countTableAppearances(t, tableAppearances) local function countCycles(x, cycles)
tableAppearances = tableAppearances or {} if type(x) == "table" then
if cycles[x] then
if type(t) == 'table' then cycles[x] = cycles[x] + 1
if not tableAppearances[t] then
tableAppearances[t] = 1
for k,v in rawpairs(t) do
countTableAppearances(k, tableAppearances)
countTableAppearances(v, tableAppearances)
end
countTableAppearances(getmetatable(t), tableAppearances)
else else
tableAppearances[t] = tableAppearances[t] + 1 cycles[x] = 1
for k, v in rawpairs(x) do
countCycles(k, cycles)
countCycles(v, cycles)
end
countCycles(getmetatable(x), cycles)
end end
end end
return tableAppearances
end end
local copySequence = function(s) local function makePath(path, a, b)
local copy, len = {}, #s local newPath = {}
for i=1, len do copy[i] = s[i] end local len = #path
return copy, len for i = 1, len do
end newPath[i] = path[i]
local function makePath(path, ...)
local keys = {...}
local newPath, len = copySequence(path)
for i=1, #keys do
newPath[len + i] = keys[i]
end end
newPath[len + 1] = a
newPath[len + 2] = b
return newPath return newPath
end end
local function processRecursive(process, item, path, visited) local function processRecursive(process, item, path, visited)
if item == nil then return nil end if item == nil then
if visited[item] then return visited[item] end return nil
end
if visited[item] then
return visited[item]
end
local processed = process(item, path) local processed = process(item, path)
if type(processed) == 'table' then if type(processed) == "table" then
local processedCopy = {} local processedCopy = {}
visited[item] = processedCopy visited[item] = processedCopy
local processedKey local processedKey
for k,v in rawpairs(processed) do for k, v in rawpairs(processed) do
processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited) processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited)
if processedKey ~= nil then if processedKey ~= nil then
processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited) processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited)
end end
end end
local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited)
if type(mt) ~= 'table' then mt = nil end -- ignore not nil/table __metatable field if type(mt) ~= "table" then
mt = nil
end
setmetatable(processedCopy, mt) setmetatable(processedCopy, mt)
processed = processedCopy processed = processedCopy
end end
return processed return processed
end end
local function puts(buf, str)
buf.n = buf.n + 1
------------------------------------------------------------------- buf[buf.n] = str
end
local Inspector = {} local Inspector = {}
local Inspector_mt = {__index = Inspector}
function Inspector:puts(...) local Inspector_mt = { __index = Inspector }
local args = {...}
local buffer = self.buffer
local len = #buffer
for i=1, #args do
len = len + 1
buffer[len] = args[i]
end
end
function Inspector:down(f) local function tabify(inspector)
self.level = self.level + 1 puts(inspector.buf, inspector.newline .. rep(inspector.indent, inspector.level))
f()
self.level = self.level - 1
end
function Inspector:tabify()
self:puts(self.newline, string.rep(self.indent, self.level))
end
function Inspector:alreadyVisited(v)
return self.ids[v] ~= nil
end end
function Inspector:getId(v) function Inspector:getId(v)
local id = self.ids[v] local id = self.ids[v]
local ids = self.ids
if not id then if not id then
local tv = type(v) local tv = type(v)
id = (self.maxIds[tv] or 0) + 1 id = (ids[tv] or 0) + 1
self.maxIds[tv] = id ids[v], ids[tv] = id, id
self.ids[v] = id
end end
return tostring(id) return tostring(id)
end end
function Inspector:putKey(k) function Inspector:putValue(v)
if isIdentifier(k) then return self:puts(k) end local buf = self.buf
self:puts("[") local tv = type(v)
self:putValue(k) if tv == "string" then
self:puts("]") puts(buf, smartQuote(escape(v)))
end elseif
tv == "number"
or tv == "boolean"
or tv == "nil"
or tv == "cdata"
or tv == "ctype"
or (vim and v == vim.NIL)
then
puts(buf, tostring(v))
elseif tv == "table" and not self.ids[v] then
local t = v
function Inspector:putTable(t) if t == inspect.KEY or t == inspect.METATABLE then
if t == inspect.KEY or t == inspect.METATABLE then puts(buf, tostring(t))
self:puts(tostring(t)) elseif self.level >= self.depth then
elseif self:alreadyVisited(t) then puts(buf, "{...}")
self:puts('<table ', self:getId(t), '>') else
elseif self.level >= self.depth then if self.cycles[t] > 1 then
self:puts('{...}') puts(buf, fmt("<%d>", self:getId(t)))
else
if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end
local nonSequentialKeys, nonSequentialKeysLength, sequenceLength = getNonSequentialKeys(t)
local mt = getmetatable(t)
if (vim and sequenceLength == 0 and nonSequentialKeysLength == 0
and mt == vim._empty_dict_mt) then
self:puts(tostring(t))
return
end
self:puts('{')
self:down(function()
local count = 0
for i=1, sequenceLength do
if count > 0 then self:puts(',') end
self:puts(' ')
self:putValue(t[i])
count = count + 1
end end
for i=1, nonSequentialKeysLength do local keys, keysLen, seqLen = getKeys(t)
local k = nonSequentialKeys[i] local mt = getmetatable(t)
if count > 0 then self:puts(',') end
self:tabify() if vim and seqLen == 0 and keysLen == 0 and mt == vim._empty_dict_mt then
self:putKey(k) puts(buf, tostring(t))
self:puts(' = ') return
self:putValue(t[k])
count = count + 1
end end
if type(mt) == 'table' then puts(buf, "{")
if count > 0 then self:puts(',') end self.level = self.level + 1
self:tabify()
self:puts('<metatable> = ') for i = 1, seqLen + keysLen do
if i > 1 then
puts(buf, ",")
end
if i <= seqLen then
puts(buf, " ")
self:putValue(t[i])
else
local k = keys[i - seqLen]
tabify(self)
if isIdentifier(k) then
puts(buf, k)
else
puts(buf, "[")
self:putValue(k)
puts(buf, "]")
end
puts(buf, " = ")
self:putValue(t[k])
end
end
if type(mt) == "table" then
if seqLen + keysLen > 0 then
puts(buf, ",")
end
tabify(self)
puts(buf, "<metatable> = ")
self:putValue(mt) self:putValue(mt)
end end
end)
if nonSequentialKeysLength > 0 or type(mt) == 'table' then -- result is multi-lined. Justify closing } self.level = self.level - 1
self:tabify()
elseif sequenceLength > 0 then -- array tables have one extra space before closing } if keysLen > 0 or type(mt) == "table" then
self:puts(' ') tabify(self)
elseif seqLen > 0 then
puts(buf, " ")
end
puts(buf, "}")
end end
self:puts('}')
end
end
function Inspector:putValue(v)
local tv = type(v)
if tv == 'string' then
self:puts(smartQuote(escape(v)))
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
tv == 'cdata' or tv == 'ctype' or (vim and v == vim.NIL) then
self:puts(tostring(v))
elseif tv == 'table' then
self:putTable(v)
else else
self:puts('<', tv, ' ', self:getId(v), '>') puts(buf, fmt("<%s %d>", tv, self:getId(v)))
end end
end end
-------------------------------------------------------------------
function inspect.inspect(root, options) function inspect.inspect(root, options)
options = options or {} options = options or {}
local depth = options.depth or math.huge local depth = options.depth or math.huge
local newline = options.newline or '\n' local newline = options.newline or "\n"
local indent = options.indent or ' ' local indent = options.indent or " "
local process = options.process local process = options.process
if process then if process then
root = processRecursive(process, root, {}, {}) root = processRecursive(process, root, {}, {})
end end
local cycles = {}
countCycles(root, cycles)
local inspector = setmetatable({ local inspector = setmetatable({
depth = depth, buf = { n = 0 },
level = 0, ids = {},
buffer = {}, cycles = cycles,
ids = {}, depth = depth,
maxIds = {}, level = 0,
newline = newline, newline = newline,
indent = indent, indent = indent,
tableAppearances = countTableAppearances(root)
}, Inspector_mt) }, Inspector_mt)
inspector:putValue(root) inspector:putValue(root)
return table.concat(inspector.buffer) return table.concat(inspector.buf)
end end
setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end }) setmetatable(inspect, {
__call = function(_, root, options)
return inspect.inspect(root, options)
end,
})
return inspect return inspect