Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Global 'nil' value
- NIL = {}
- -- Localise for faster access
- local pcall = pcall
- local string_len = string.len
- local string_sub = string.sub
- local string_find = string.find
- local string_gsub = string.gsub
- local table_concat = table.concat
- local table_insert = table.insert
- local table_sort = table.sort
- -- Stream interface
- local gSet -- Set grep pattern
- local gMsgF -- Print fragment
- local gMsgN -- Print newline
- local gMsgC -- Set print color
- do
- local grep_color = Color(235, 70, 70)
- -- Grep parameters (static between gBegin/gEnd)
- local grep
- local grep_raw
- local grep_proximity
- -- Current line parameters
- local buffer
- local colors
- local markers
- local baseColor
- local currColor
- local length
- -- History
- local history
- local remain
- -- Actual printing
- local function gCheckMatch( buffer )
- local raw = table_concat(buffer)
- return raw, string_find(raw, grep, 0, grep_raw)
- end
- local function gFlushEx( raw, markers, colors, baseColor )
- -- Print entire buffer
- local len = string_len(raw)
- -- Keep track of the current line properties
- local index = 1
- local marker = 1
- local currColor = baseColor
- -- Method to print to a preset area
- local function printToIndex( limit, color )
- local mark = markers and markers[marker]
- -- Print all marker areas until we would overshoot
- while mark and mark < limit do
- -- Catch up to the marker
- MsgC(color or currColor, string_sub(raw, index, mark))
- index = mark +1
- -- Set new color
- currColor = colors[marker]
- -- Select next marker
- marker = marker +1
- mark = markers[marker]
- end
- -- Print the remaining between the last marker and the limit
- MsgC(color or currColor, string_sub(raw, index, limit))
- index = limit +1
- end
- -- Grep!
- local match, last = 1
- local from, to = string_find(raw, grep, 0, grep_raw)
- while from do
- printToIndex(from -1)
- printToIndex(to, grep_color)
- last = to +1
- from, to = string_find(raw, grep, last, grep_raw)
- end
- printToIndex(len)
- MsgN()
- end
- local function gCommit()
- if grep_proximity then
- -- Check if the line has at least one match
- local raw, match = gCheckMatch(buffer)
- if match then
- -- Divide matches
- if history[grep_proximity] then
- MsgN("...")
- end
- -- Flush history
- if grep_proximity != 0 then
- local len = #history
- for index = len -1, 1, -1 do
- local entry = history[index]
- history[index] = nil
- gFlushEx( entry[1], entry[2], entry[3], entry[4] )
- end
- history[len] = nil
- end
- -- Flush line, allow next X lines to get printed
- gFlushEx( raw, markers, colors, baseColor )
- remain = grep_proximity -1
- history[grep_proximity +1] = nil
- elseif remain > 0 then
- -- Flush immediately
- gFlushEx( raw, markers, colors, baseColor )
- remain = remain -1
- else
- -- Store in history
- table_insert(history, 1, {raw, markers, colors, baseColor})
- history[grep_proximity +1] = nil
- end
- else
- -- Flush anyway
- gFlushEx( table_concat(buffer), markers, colors, baseColor )
- end
- -- Reset state
- length = 0
- buffer = {}
- markers = nil
- colors = nil
- baseColor = nil
- currColor = nil
- end
- -- State machine
- function gBegin( new, prox )
- grep = isstring(new) and new
- if grep then
- grep_raw = !pcall(string_find, ' ', grep)
- grep_proximity = isnumber(prox) and prox
- -- Reset everything
- buffer = {}
- history = {}
- end
- length = 0
- remain = 0
- baseColor = nil
- currColor = nil
- end
- function gFinish()
- if grep_proximity and history and history[1] then
- MsgN("...")
- end
- -- Free memory
- buffer = nil
- markers = nil
- colors = nil
- history = nil
- end
- function gMsgC( color )
- if grep then
- -- Try to save some memory by not immediately allocating colors
- if length == 0 then
- baseColor = color
- return
- end
- -- Record color change
- if color != currColor then
- if !markers then
- markers = {}
- colors = {}
- end
- -- Record color change
- table_insert(markers, length)
- table_insert(colors, color)
- end
- end
- currColor = color
- end
- function gMsgF( str )
- if grep then
- -- Split multiline fragments to separate ones
- local fragColor = currColor or baseColor
- local last = 1
- local from, to = string_find(str, '\n')
- while from do
- local frag = string_sub(str, last, from -1)
- local len = from - last
- -- Merge fragment to the line
- length = length + len
- table_insert(buffer, frag)
- -- Print finished line
- gCommit()
- -- Assign base color as previous fragColor
- baseColor = fragColor
- -- Look for more
- last = to +1
- from, to = string_find(str, '\n', last)
- end
- -- Push last fragment
- local frag = string_sub(str, last)
- local len = string_len(str) - last +1
- length = length + len
- table_insert(buffer, frag)
- else
- -- Push immediately
- MsgC(currColor or baseColor, str)
- end
- end
- function gMsgN()
- -- Print everything in the buffer
- if grep then
- gCommit()
- else
- MsgN()
- end
- baseColor = nil
- currColor = nil
- end
- end
- local type_weight = {
- [TYPE_FUNCTION] = 1,
- [TYPE_TABLE] = 2,
- }
- local type_colors = {
- [TYPE_BOOL] = Color(175, 130, 255),
- [TYPE_NUMBER] = Color(175, 130, 255),
- [TYPE_STRING] = Color(230, 220, 115),
- [TYPE_FUNCTION] = Color(100, 220, 240)
- }
- local color_neutral = Color(220, 220, 220)
- local color_name = Color(260, 150, 30)
- local color_reference = Color(150, 230, 50)
- local color_comment = Color( 30, 210, 30)
- local function InternalPrintValue( value )
- -- 'nil' values can also be printed
- if value == NIL then
- gMsgC(color_comment)
- gMsgF("nil")
- return
- end
- local color = type_colors[ TypeID(value) ]
- -- For strings, place quotes
- if isstring(value) then
- if string_len(value) <= 1 then
- value = string.format([['%s']], value)
- else
- value = string.format([["%s"]], value)
- end
- gMsgC(color)
- gMsgF(value)
- return
- end
- -- Workaround for userdata not using MetaName
- if string_sub(tostring(value), 0, 8) == "userdata" then
- local meta = getmetatable(value)
- if meta and meta.MetaName then
- value = string.format("%s: %p", meta.MetaName, value)
- end
- end
- -- General print
- gMsgC(color)
- gMsgF(tostring(value))
- -- For functions append source info
- if isfunction(value) then
- local info = debug.getinfo(value, 'S')
- local aux
- if info.what == 'C' then
- aux = "\t-- [C]: -1"
- else
- if info.linedefined != info.lastlinedefined then
- aux = string.format("\t-- [%s]: %i-%i", info.short_src, info.linedefined, info.lastlinedefined)
- else
- aux = string.format("\t-- [%s]: %i", info.short_src, info.linedefined)
- end
- end
- gMsgC(color_comment)
- gMsgF(aux)
- end
- end
- -- Associated to object keys
- local objID
- local function isprimitive( value )
- local id = TypeID(value)
- return id <= TYPE_FUNCTION and id != TYPE_TABLE
- end
- local function InternalPrintTable( table, path, prefix, names, todo )
- -- Collect keys and some info about them
- local keyList = {}
- local keyStr = {}
- local keyCount = 0
- for key, value in pairs( table ) do
- -- Add to key list for later sorting
- table_insert(keyList, key)
- -- Describe key as string
- if isprimitive(key) then
- keyStr[key] = tostring(key)
- else
- -- Lookup already known name
- local name = names[key]
- -- Assign a new unique identifier
- if !name then
- objID = objID +1
- name = string.format("%s: obj #%i", tostring(key), objID)
- names[key] = name
- todo[key] = true
- end
- -- Substitute object with name
- keyStr[key] = name
- end
- keyCount = keyCount +1
- end
- -- Exit early for empty tables
- if keyCount == 0 then
- return
- end
- -- Determine max key length
- local keyLen = 4
- for key, str in pairs(keyStr) do
- keyLen = math.max(keyLen, string.len(str))
- end
- -- Sort table keys
- if keyCount > 1 then
- table_sort( keyList, function( A, B )
- -- Sort numbers numerically correct
- if isnumber(A) and isnumber(B) then
- return A < B
- end
- -- Weight types
- local wA = type_weight[ TypeID( table[A] ) ] or 0
- local wB = type_weight[ TypeID( table[B] ) ] or 0
- if wA != wB then
- return wA < wB
- end
- -- Order by string representation
- return keyStr[A] < keyStr[B]
- end )
- end
- -- Determine the next level ident
- local new_prefix = string.format( "%s║%s", prefix, string.rep(' ', keyLen) )
- -- Mark object as done
- todo[table] = nil
- -- Start describing table
- for index, key in ipairs(keyList) do
- local value = table[key]
- -- Assign names to already described keys/values
- local kName = names[key]
- local vName = names[value]
- -- Decide to either fully describe, or print the value
- local describe = !isprimitive(value) and ( !vName or todo[value] )
- -- Ident
- gMsgF(prefix)
- -- Fancy table guides
- local moreLines = (index != keyCount) or describe
- if index == 1 then
- gMsgF(moreLines and '╦ ' or '═ ')
- else
- gMsgF(moreLines and '╠ ' or '╚ ')
- end
- -- Print key
- local sKey = kName or keyStr[key]
- gMsgC(kName and color_reference or color_name)
- gMsgF(sKey)
- -- Describe non primitives
- local describe = istable(value) and ( !names[value] or todo[value] ) and value != NIL
- -- Print key postfix
- local padding = keyLen - string.len(sKey)
- local postfix = string.format(describe and ":%s" or "%s = ", string.rep(' ', padding))
- gMsgC(color_neutral)
- gMsgF(postfix)
- -- Print the value
- if describe then
- gMsgN()
- -- Expand access path
- local new_path = sKey
- if isnumber(key) or kName then
- new_path = string.format("%s[%s]", path or '', key)
- elseif path then
- new_path = string.format("%s.%s", path, new_path)
- end
- -- Name the object to mark it done
- names[value] = names[value] or new_path
- -- Describe
- InternalPrintTable(value, new_path, new_prefix, names, todo)
- else
- -- Print the value (or the reference name)
- if vName and !todo[value] then
- gMsgC(color_reference)
- gMsgF(string.format("ref: %s",vName))
- else
- InternalPrintValue(value)
- end
- gMsgN()
- end
- end
- end
- function PrintTableGrep( table, grep, proximity )
- local base = {
- [_G] = "_G",
- [table] = "root"
- }
- gBegin(grep, proximity)
- objID = 0
- InternalPrintTable(table, nil, "", base, {})
- gFinish()
- end
- function PrintLocals( level )
- local level = level or 2
- local hash = {}
- for index = 1, 255 do
- local name, value = debug.getlocal(2, index)
- if !name then
- break
- end
- if value == nil then
- value = NIL
- end
- hash[name] = value
- end
- PrintTableGrep( hash )
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement