-- Import local LIBRARY do local thispath = ... and select('1', ...):match('.+%.') or '' local was_loaded, library = pcall(require, thispath..'library') LIBRARY = was_loaded and library or {} end -- Constants -------------------------------------------------------------------------------- -- Util local function get_function_info (f) -- NOTE: Works best in LuaJIT or Lua 5.2+ -- Regarding get-info: -- * No need to includ 'f'. Function is already known -- * No need to include 'L' (active lines) option. Ignored -- * No need to include 'n' (name and namewhat). Won't work. local info = debug.getinfo(f, 'Su') info.params = {} info.ups = {} info.env = debug.getfenv and debug.getfenv(f) info.builtin = info.source == '=[C]' for i = 1, info.nparams or 0 do info.params[i] = debug.getlocal(f, i) end if info.isvararg or not info.nparams then info.params[#info.params+1] = '...' end -- Get upvalues for i = 1, info.nups do local k, v = debug.getupvalue(f, i) if k == '_ENV' and not debug.getfenv then info.env = v else info.ups[k] = v end end if info.source:sub(1,1) == '=' then info.defined_how = 'C' elseif info.source:sub(1,1) == '@' then info.defined_how = 'file' else info.defined_how = 'string' end if info.builtin and LIBRARY[f] then info.name = LIBRARY[f].name info.params[1] = LIBRARY[f].para info.doc = LIBRARY[f].docs end return info end local function get_line_index (str, line_nr) local index = 0 for _ = 2, line_nr do index = str:find('\n', index, true) if not index then return #str end index = index + 1 end return index end local function get_full_function_str (str, start_line, end_line) local start_line_index = get_line_index(str, start_line) local end_line_index = get_line_index(str, end_line + 1) local matched_function = str:sub(start_line_index, end_line_index):match('function.+end') return matched_function end local function width_of_strings_in_l (l, start_i, end_i) -- FIXME: Copy of the one in pretty.lua local width = 0 for i = start_i or 1, (end_i or #l) do width = width + #l[i] end return width end -------------------------------------------------------------------------------- return function (value, options, depth, l, format_value) local info = get_function_info(value) if info.defined_how == 'string' then -- Function was defined as a string. l[#l+1] = get_full_function_str(info.source, info.linedefined, info.lastlinedefined) return; end -- Include function modifier, and alignment info. l[#l+1] = info.builtin and 'builtin ' or '' l[#l+1] = { #l[#l], 'func_mod'} -- Build rest of function signature l[#l+1] = 'function (' local top_before = #l for _, param in ipairs(info.params) do l[#l+1], l[#l+2] = param, ', ' end if l[#l] == ', ' then l[#l] = nil end l[#l+1] = ')' l[#l+1] = { width_of_strings_in_l(l, top_before), 'func_def' } -- Cleanup and finish if not options.more_function_info or depth ~= 0 then l[#l+1] = ' ... end' elseif options._all_function_info then -- NOTE: This is for testing/debugging/experimentation purposes. local file = io.open(info.short_src, 'r') local function_str = get_full_function_str(file:read('*all'), info.linedefined, info.lastlinedefined) file:close() l[#l+1] = '\n\t--[[ Function Body\n\t' l[#l+1] = function_str l[#l+1] = '\n\t--]]' l[#l+1] = '\n\t--[[\n\tNative repr:' l[#l+1] = tostring(value) l[#l+1] = '\n\t' format_value(info, options, depth + 1, l) l[#l+1] = '--]]' else -- More info! -- -- Name if info.name then l[#l+1] = '\n' l[#l+1] = options.indent l[#l+1] = '-- ' l[#l+1] = info.name end -- Doc if info.doc then for doc_line in info.doc:gmatch('[^\n]+') do l[#l+1] = '\n' l[#l+1] = options.indent l[#l+1] = '-- ' l[#l+1] = doc_line end end -- source if not info.builtin then l[#l+1] = '\n' l[#l+1] = options.indent l[#l+1] = '-- source_file: \'' l[#l+1] = info.short_src l[#l+1] = '\' [Line' if info.linedefined == info.lastlinedefined then l[#l+1] = ': ' l[#l+1] = tostring(info.linedefined) else l[#l+1] = 's: ' l[#l+1] = tostring(info.linedefined) l[#l+1] = ' - ' l[#l+1] = tostring(info.lastlinedefined) end l[#l+1] = ']' end -- upvalues if info.nups > 0 and not info.builtin then l[#l+1] = '\n' l[#l+1] = options.indent l[#l+1] = '-- up_values: ' format_value(info.ups, options, depth + 1, l) end l[#l+1] = '\n\n' l[#l+1] = options.indent l[#l+1] = '...\nend' end end