From ba1d3fcb6a03312290e7ca5e4a2846dd3f8bfe42 Mon Sep 17 00:00:00 2001 From: Pauli Date: Sat, 30 Jun 2018 14:32:02 +0300 Subject: [PATCH] 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 ^ and pipe to other tools (eg grep, sed, perl, sort, uniq etc) --- library/lua/dfhack.lua | 114 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 95c31c2d7..93ab48dca 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -180,6 +180,116 @@ function printall_ipairs(table) 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('') + 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 = 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 .. "") + 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('\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('\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) local rv = {} 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' => 'print(foo)'\n".. " '~ foo' => 'printall(foo)'\n".. + " '^ foo' => 'printall_recurse(foo)'\n".. " '@ foo' => 'printall_ipairs(foo)'\n".. "All of these save the first result as '_'.") print_banner = false @@ -358,6 +469,9 @@ function dfhack.interpreter(prompt,hfile,env) print(table.unpack(data,2,data.n)) printall_ipairs(data[2]) end, + ['^'] = function(data) + printall_recurse(data[2]) + end, ['='] = function(data) for i=2,data.n do local varname = '_'..vcnt