Add dfhack.printall_recurse to quickly print df containers

I often want to see multiple items quickly when trying to figure out
what states actually matter to an issue that I debug. I decided to make
it easier to quickly dump df structures with substructures and
containers. It will generate large amount of data which can be sometimes
slow to process manually. But processing can be automated using
dfhack-run lua ^<df data to inspect> and pipe to other tools (eg grep,
sed, perl, sort, uniq etc)
develop
Pauli 2018-06-30 14:32:02 +03:00
parent 1a4440859c
commit ba1d3fcb6a
1 changed files with 114 additions and 0 deletions

@ -180,6 +180,116 @@ function printall_ipairs(table)
end end
end end
local do_print_recurse
local function print_string(printfn, v, seen, indent)
local str = tostring(v)
printfn(str)
return #str;
end
local fill_chars = {
__index = function(table, key, value)
local rv = string.rep(' ', 23 - key) .. ' = '
rawset(table, key, rv)
return rv
end,
}
setmetatable(fill_chars, fill_chars)
local function print_fields(value, seen, indent, prefix)
local ok,f,t,k = pcall(pairs,value)
if not ok then
dfhack.print(prefix)
dfhack.println('<Type doesn\'t support iteration with pairs>')
return 0
end
local prev_value = "not a value"
local repeated = 0
for k, v in f,t,k do
-- Only show set values of bitfields
if value._kind ~= "bitfield" or v then
local continue = false
if type(k) == "number" then
if prev_value == v then
repeated = repeated + 1
continue = true
else
prev_value = v
end
else
prev_value = "not a value"
end
if not continue then
if repeated > 0 then
dfhack.println(prefix .. "<Repeated " .. repeated .. " times>")
repeated = 0
end
dfhack.print(prefix)
local len = do_print_recurse(dfhack.print, k, seen, indent + 1)
dfhack.print(fill_chars[len <= 23 and len or 23])
do_print_recurse(dfhack.println, v, seen, indent + 1)
end
end
end
if repeated > 0 then
dfhack.println(prefix .. "<Repeated " .. repeated .. " times>")
end
return 0
end
-- This should be same as print_array but userdata doesn't compare equal even if
-- they hold same pointer.
local function print_userdata(printfn, value, seen, indent)
local prefix = string.rep(' ', indent)
local strvalue = tostring(value)
dfhack.println(strvalue)
if seen[strvalue] then
dfhack.print(prefix)
dfhack.println('<Cyclic reference! Skipping fields>\n')
return 0
end
seen[strvalue] = true
return print_fields(value, seen, indent, prefix)
end
local function print_array(printfn, value, seen, indent)
local prefix = string.rep(' ', indent)
dfhack.println(tostring(value))
if seen[value] then
dfhack.print(prefix)
dfhack.println('<Cyclic reference! skipping fields>\n')
return 0
end
seen[value] = true
return print_fields(value, seen, indent, prefix)
end
local recurse_type_map = {
number = print_string,
string = print_string,
boolean = print_string,
['function'] = print_string,
['nil'] = print_string,
userdata = print_userdata,
table = print_array,
}
do_print_recurse = function(printfn, value, seen, indent)
local t = type(value)
if not recurse_type_map[t] then
printfn("Unknown type " .. t .. " " .. tostring(value))
return
end
return recurse_type_map[t](printfn, value, seen, indent)
end
function printall_recurse(value)
local seen = {}
do_print_recurse(dfhack.println, value, seen, 0)
end
function copyall(table) function copyall(table)
local rv = {} local rv = {}
for k,v in pairs(table) do rv[k] = v end for k,v in pairs(table) do rv[k] = v end
@ -334,6 +444,7 @@ function dfhack.interpreter(prompt,hfile,env)
" '= foo' => '_1,_2,... = foo'\n".. " '= foo' => '_1,_2,... = foo'\n"..
" '! foo' => 'print(foo)'\n".. " '! foo' => 'print(foo)'\n"..
" '~ foo' => 'printall(foo)'\n".. " '~ foo' => 'printall(foo)'\n"..
" '^ foo' => 'printall_recurse(foo)'\n"..
" '@ foo' => 'printall_ipairs(foo)'\n".. " '@ foo' => 'printall_ipairs(foo)'\n"..
"All of these save the first result as '_'.") "All of these save the first result as '_'.")
print_banner = false print_banner = false
@ -358,6 +469,9 @@ function dfhack.interpreter(prompt,hfile,env)
print(table.unpack(data,2,data.n)) print(table.unpack(data,2,data.n))
printall_ipairs(data[2]) printall_ipairs(data[2])
end, end,
['^'] = function(data)
printall_recurse(data[2])
end,
['='] = function(data) ['='] = function(data)
for i=2,data.n do for i=2,data.n do
local varname = '_'..vcnt local varname = '_'..vcnt