Advertisement
Guest User

Untitled

a guest
Jan 28th, 2015
191
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.38 KB | None | 0 0
  1.  
  2. -- Global 'nil' value
  3. NIL = {}
  4.  
  5. -- Localise for faster access
  6. local pcall = pcall
  7.  
  8. local string_len = string.len
  9. local string_sub = string.sub
  10. local string_find = string.find
  11. local string_gsub = string.gsub
  12.  
  13. local table_concat = table.concat
  14. local table_insert = table.insert
  15. local table_sort = table.sort
  16.  
  17.  
  18. -- Stream interface
  19. local gSet -- Set grep pattern
  20.  
  21. local gMsgF -- Print fragment
  22. local gMsgN -- Print newline
  23. local gMsgC -- Set print color
  24.  
  25. do
  26. local grep_color = Color(235, 70, 70)
  27.  
  28. -- Grep parameters (static between gBegin/gEnd)
  29. local grep
  30. local grep_raw
  31.  
  32. local grep_proximity
  33.  
  34.  
  35. -- Current line parameters
  36. local buffer
  37. local colors
  38. local markers
  39.  
  40. local baseColor
  41. local currColor
  42.  
  43. local length
  44.  
  45. -- History
  46. local history
  47. local remain
  48.  
  49.  
  50. -- Actual printing
  51. local function gCheckMatch( buffer )
  52. local raw = table_concat(buffer)
  53.  
  54. return raw, string_find(raw, grep, 0, grep_raw)
  55. end
  56.  
  57. local function gFlushEx( raw, markers, colors, baseColor )
  58.  
  59. -- Print entire buffer
  60. local len = string_len(raw)
  61.  
  62. -- Keep track of the current line properties
  63. local index = 1
  64. local marker = 1
  65.  
  66. local currColor = baseColor
  67.  
  68. -- Method to print to a preset area
  69. local function printToIndex( limit, color )
  70. local mark = markers and markers[marker]
  71.  
  72. -- Print all marker areas until we would overshoot
  73. while mark and mark < limit do
  74.  
  75. -- Catch up to the marker
  76. MsgC(color or currColor, string_sub(raw, index, mark))
  77. index = mark +1
  78.  
  79. -- Set new color
  80. currColor = colors[marker]
  81.  
  82. -- Select next marker
  83. marker = marker +1
  84. mark = markers[marker]
  85.  
  86. end
  87.  
  88. -- Print the remaining between the last marker and the limit
  89. MsgC(color or currColor, string_sub(raw, index, limit))
  90. index = limit +1
  91. end
  92.  
  93. -- Grep!
  94. local match, last = 1
  95. local from, to = string_find(raw, grep, 0, grep_raw)
  96.  
  97. while from do
  98. printToIndex(from -1)
  99. printToIndex(to, grep_color)
  100.  
  101. last = to +1
  102. from, to = string_find(raw, grep, last, grep_raw)
  103. end
  104.  
  105. printToIndex(len)
  106. MsgN()
  107. end
  108.  
  109.  
  110. local function gCommit()
  111. if grep_proximity then
  112. -- Check if the line has at least one match
  113. local raw, match = gCheckMatch(buffer)
  114.  
  115. if match then
  116.  
  117. -- Divide matches
  118. if history[grep_proximity] then
  119. MsgN("...")
  120. end
  121.  
  122. -- Flush history
  123. if grep_proximity != 0 then
  124. local len = #history
  125.  
  126. for index = len -1, 1, -1 do
  127. local entry = history[index]
  128. history[index] = nil
  129.  
  130. gFlushEx( entry[1], entry[2], entry[3], entry[4] )
  131. end
  132.  
  133. history[len] = nil
  134. end
  135.  
  136. -- Flush line, allow next X lines to get printed
  137. gFlushEx( raw, markers, colors, baseColor )
  138. remain = grep_proximity -1
  139.  
  140. history[grep_proximity +1] = nil
  141. elseif remain > 0 then
  142. -- Flush immediately
  143. gFlushEx( raw, markers, colors, baseColor )
  144. remain = remain -1
  145. else
  146. -- Store in history
  147. table_insert(history, 1, {raw, markers, colors, baseColor})
  148. history[grep_proximity +1] = nil
  149. end
  150. else
  151. -- Flush anyway
  152. gFlushEx( table_concat(buffer), markers, colors, baseColor )
  153. end
  154.  
  155. -- Reset state
  156. length = 0
  157. buffer = {}
  158.  
  159. markers = nil
  160. colors = nil
  161.  
  162. baseColor = nil
  163. currColor = nil
  164. end
  165.  
  166. -- State machine
  167. function gBegin( new, prox )
  168. grep = isstring(new) and new
  169.  
  170. if grep then
  171. grep_raw = !pcall(string_find, ' ', grep)
  172. grep_proximity = isnumber(prox) and prox
  173.  
  174. -- Reset everything
  175. buffer = {}
  176. history = {}
  177. end
  178.  
  179. length = 0
  180. remain = 0
  181.  
  182. baseColor = nil
  183. currColor = nil
  184. end
  185.  
  186. function gFinish()
  187. if grep_proximity and history and history[1] then
  188. MsgN("...")
  189. end
  190.  
  191. -- Free memory
  192. buffer = nil
  193. markers = nil
  194. colors = nil
  195.  
  196. history = nil
  197. end
  198.  
  199.  
  200. function gMsgC( color )
  201. if grep then
  202.  
  203. -- Try to save some memory by not immediately allocating colors
  204. if length == 0 then
  205. baseColor = color
  206. return
  207. end
  208.  
  209. -- Record color change
  210. if color != currColor then
  211. if !markers then
  212. markers = {}
  213. colors = {}
  214. end
  215.  
  216. -- Record color change
  217. table_insert(markers, length)
  218. table_insert(colors, color)
  219. end
  220. end
  221.  
  222. currColor = color
  223. end
  224.  
  225. function gMsgF( str )
  226. if grep then
  227.  
  228. -- Split multiline fragments to separate ones
  229. local fragColor = currColor or baseColor
  230.  
  231. local last = 1
  232. local from, to = string_find(str, '\n')
  233.  
  234. while from do
  235. local frag = string_sub(str, last, from -1)
  236. local len = from - last
  237.  
  238. -- Merge fragment to the line
  239. length = length + len
  240. table_insert(buffer, frag)
  241.  
  242. -- Print finished line
  243. gCommit()
  244.  
  245. -- Assign base color as previous fragColor
  246. baseColor = fragColor
  247.  
  248. -- Look for more
  249. last = to +1
  250. from, to = string_find(str, '\n', last)
  251. end
  252.  
  253. -- Push last fragment
  254. local frag = string_sub(str, last)
  255. local len = string_len(str) - last +1
  256.  
  257. length = length + len
  258. table_insert(buffer, frag)
  259. else
  260. -- Push immediately
  261. MsgC(currColor or baseColor, str)
  262. end
  263. end
  264.  
  265. function gMsgN()
  266. -- Print everything in the buffer
  267. if grep then
  268. gCommit()
  269. else
  270. MsgN()
  271. end
  272.  
  273. baseColor = nil
  274. currColor = nil
  275. end
  276. end
  277.  
  278.  
  279. local type_weight = {
  280. [TYPE_FUNCTION] = 1,
  281. [TYPE_TABLE] = 2,
  282. }
  283.  
  284. local type_colors = {
  285. [TYPE_BOOL] = Color(175, 130, 255),
  286. [TYPE_NUMBER] = Color(175, 130, 255),
  287. [TYPE_STRING] = Color(230, 220, 115),
  288. [TYPE_FUNCTION] = Color(100, 220, 240)
  289. }
  290.  
  291. local color_neutral = Color(220, 220, 220)
  292. local color_name = Color(260, 150, 30)
  293.  
  294. local color_reference = Color(150, 230, 50)
  295. local color_comment = Color( 30, 210, 30)
  296.  
  297.  
  298. local function InternalPrintValue( value )
  299.  
  300. -- 'nil' values can also be printed
  301. if value == NIL then
  302. gMsgC(color_comment)
  303. gMsgF("nil")
  304. return
  305. end
  306.  
  307. local color = type_colors[ TypeID(value) ]
  308.  
  309. -- For strings, place quotes
  310. if isstring(value) then
  311. if string_len(value) <= 1 then
  312. value = string.format([['%s']], value)
  313. else
  314. value = string.format([["%s"]], value)
  315. end
  316.  
  317. gMsgC(color)
  318. gMsgF(value)
  319. return
  320. end
  321.  
  322. -- Workaround for userdata not using MetaName
  323. if string_sub(tostring(value), 0, 8) == "userdata" then
  324. local meta = getmetatable(value)
  325.  
  326. if meta and meta.MetaName then
  327. value = string.format("%s: %p", meta.MetaName, value)
  328. end
  329. end
  330.  
  331. -- General print
  332. gMsgC(color)
  333. gMsgF(tostring(value))
  334.  
  335. -- For functions append source info
  336. if isfunction(value) then
  337. local info = debug.getinfo(value, 'S')
  338. local aux
  339.  
  340. if info.what == 'C' then
  341. aux = "\t-- [C]: -1"
  342. else
  343. if info.linedefined != info.lastlinedefined then
  344. aux = string.format("\t-- [%s]: %i-%i", info.short_src, info.linedefined, info.lastlinedefined)
  345. else
  346. aux = string.format("\t-- [%s]: %i", info.short_src, info.linedefined)
  347. end
  348. end
  349.  
  350. gMsgC(color_comment)
  351. gMsgF(aux)
  352. end
  353. end
  354.  
  355.  
  356. -- Associated to object keys
  357. local objID
  358.  
  359. local function isprimitive( value )
  360. local id = TypeID(value)
  361.  
  362. return id <= TYPE_FUNCTION and id != TYPE_TABLE
  363. end
  364.  
  365. local function InternalPrintTable( table, path, prefix, names, todo )
  366.  
  367. -- Collect keys and some info about them
  368. local keyList = {}
  369. local keyStr = {}
  370.  
  371. local keyCount = 0
  372.  
  373. for key, value in pairs( table ) do
  374. -- Add to key list for later sorting
  375. table_insert(keyList, key)
  376.  
  377. -- Describe key as string
  378. if isprimitive(key) then
  379. keyStr[key] = tostring(key)
  380. else
  381. -- Lookup already known name
  382. local name = names[key]
  383.  
  384. -- Assign a new unique identifier
  385. if !name then
  386. objID = objID +1
  387. name = string.format("%s: obj #%i", tostring(key), objID)
  388.  
  389. names[key] = name
  390. todo[key] = true
  391. end
  392.  
  393. -- Substitute object with name
  394. keyStr[key] = name
  395. end
  396.  
  397. keyCount = keyCount +1
  398. end
  399.  
  400.  
  401. -- Exit early for empty tables
  402. if keyCount == 0 then
  403. return
  404. end
  405.  
  406.  
  407. -- Determine max key length
  408. local keyLen = 4
  409.  
  410. for key, str in pairs(keyStr) do
  411. keyLen = math.max(keyLen, string.len(str))
  412. end
  413.  
  414. -- Sort table keys
  415. if keyCount > 1 then
  416. table_sort( keyList, function( A, B )
  417.  
  418. -- Sort numbers numerically correct
  419. if isnumber(A) and isnumber(B) then
  420. return A < B
  421. end
  422.  
  423. -- Weight types
  424. local wA = type_weight[ TypeID( table[A] ) ] or 0
  425. local wB = type_weight[ TypeID( table[B] ) ] or 0
  426.  
  427. if wA != wB then
  428. return wA < wB
  429. end
  430.  
  431. -- Order by string representation
  432. return keyStr[A] < keyStr[B]
  433.  
  434. end )
  435. end
  436.  
  437. -- Determine the next level ident
  438. local new_prefix = string.format( "%s║%s", prefix, string.rep(' ', keyLen) )
  439.  
  440. -- Mark object as done
  441. todo[table] = nil
  442.  
  443. -- Start describing table
  444. for index, key in ipairs(keyList) do
  445. local value = table[key]
  446.  
  447. -- Assign names to already described keys/values
  448. local kName = names[key]
  449. local vName = names[value]
  450.  
  451. -- Decide to either fully describe, or print the value
  452. local describe = !isprimitive(value) and ( !vName or todo[value] )
  453.  
  454. -- Ident
  455. gMsgF(prefix)
  456.  
  457. -- Fancy table guides
  458. local moreLines = (index != keyCount) or describe
  459.  
  460. if index == 1 then
  461. gMsgF(moreLines and '╦ ' or '═ ')
  462. else
  463. gMsgF(moreLines and '╠ ' or '╚ ')
  464. end
  465.  
  466. -- Print key
  467. local sKey = kName or keyStr[key]
  468.  
  469. gMsgC(kName and color_reference or color_name)
  470. gMsgF(sKey)
  471.  
  472. -- Describe non primitives
  473. local describe = istable(value) and ( !names[value] or todo[value] ) and value != NIL
  474.  
  475. -- Print key postfix
  476. local padding = keyLen - string.len(sKey)
  477. local postfix = string.format(describe and ":%s" or "%s = ", string.rep(' ', padding))
  478.  
  479. gMsgC(color_neutral)
  480. gMsgF(postfix)
  481.  
  482. -- Print the value
  483. if describe then
  484. gMsgN()
  485.  
  486. -- Expand access path
  487. local new_path = sKey
  488.  
  489. if isnumber(key) or kName then
  490. new_path = string.format("%s[%s]", path or '', key)
  491. elseif path then
  492. new_path = string.format("%s.%s", path, new_path)
  493. end
  494.  
  495. -- Name the object to mark it done
  496. names[value] = names[value] or new_path
  497.  
  498. -- Describe
  499. InternalPrintTable(value, new_path, new_prefix, names, todo)
  500. else
  501. -- Print the value (or the reference name)
  502. if vName and !todo[value] then
  503. gMsgC(color_reference)
  504. gMsgF(string.format("ref: %s",vName))
  505. else
  506. InternalPrintValue(value)
  507. end
  508.  
  509. gMsgN()
  510. end
  511. end
  512.  
  513. end
  514.  
  515. function PrintTableGrep( table, grep, proximity )
  516. local base = {
  517. [_G] = "_G",
  518. [table] = "root"
  519. }
  520.  
  521. gBegin(grep, proximity)
  522. objID = 0
  523. InternalPrintTable(table, nil, "", base, {})
  524. gFinish()
  525. end
  526.  
  527. function PrintLocals( level )
  528. local level = level or 2
  529. local hash = {}
  530.  
  531. for index = 1, 255 do
  532. local name, value = debug.getlocal(2, index)
  533.  
  534. if !name then
  535. break
  536. end
  537.  
  538. if value == nil then
  539. value = NIL
  540. end
  541.  
  542. hash[name] = value
  543. end
  544.  
  545. PrintTableGrep( hash )
  546. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement