2014-01-19 10:08:28 -05:00
|
|
|
View = require 'views/kinds/CocoView'
|
2014-01-21 12:03:04 -05:00
|
|
|
template = require 'templates/play/level/tome/spell_debug'
|
2014-01-19 12:14:42 -05:00
|
|
|
Range = ace.require("ace/range").Range
|
2014-01-24 16:03:04 -05:00
|
|
|
TokenIterator = ace.require("ace/token_iterator").TokenIterator
|
|
|
|
serializedClasses =
|
|
|
|
Thang: require "lib/world/thang"
|
|
|
|
Vector: require "lib/world/vector"
|
|
|
|
Rectangle: require "lib/world/rectangle"
|
2014-01-19 10:08:28 -05:00
|
|
|
|
|
|
|
module.exports = class DebugView extends View
|
2014-01-21 12:03:04 -05:00
|
|
|
className: 'spell-debug-view'
|
2014-01-19 10:08:28 -05:00
|
|
|
template: template
|
2014-01-24 16:03:04 -05:00
|
|
|
|
|
|
|
subscriptions:
|
|
|
|
'god:new-world-created': 'onNewWorld'
|
|
|
|
|
2014-01-19 10:08:28 -05:00
|
|
|
events: {}
|
|
|
|
|
|
|
|
constructor: (options) ->
|
|
|
|
super options
|
|
|
|
@ace = options.ace
|
2014-01-24 16:03:04 -05:00
|
|
|
@thang = options.thang
|
2014-01-19 10:08:28 -05:00
|
|
|
@variableStates = {}
|
|
|
|
|
|
|
|
afterRender: ->
|
|
|
|
super()
|
|
|
|
@ace.on "mousemove", @onMouseMove
|
2014-01-21 12:03:04 -05:00
|
|
|
#@ace.on "click", onClick # same ACE API as mousemove
|
2014-01-19 10:08:28 -05:00
|
|
|
|
|
|
|
setVariableStates: (@variableStates) ->
|
|
|
|
@update()
|
|
|
|
|
|
|
|
onMouseMove: (e) =>
|
|
|
|
pos = e.getDocumentPosition()
|
2014-01-24 16:03:04 -05:00
|
|
|
it = new TokenIterator e.editor.session, pos.row, pos.column
|
|
|
|
isIdentifier = (t) -> t and (t.type is 'identifier' or t.value is 'this')
|
|
|
|
while it.getCurrentTokenRow() is pos.row and not isIdentifier(token = it.getCurrentToken())
|
|
|
|
it.stepBackward()
|
|
|
|
break unless token
|
|
|
|
if isIdentifier token
|
|
|
|
# This could be a property access, like "enemy.target.pos" or "this.spawnedRectangles".
|
|
|
|
# We have to realize this and dig into the nesting of the objects.
|
|
|
|
start = it.getCurrentTokenColumn()
|
|
|
|
[chain, start, end] = [[token.value], start, start + token.value.length]
|
|
|
|
while it.getCurrentTokenRow() is pos.row
|
|
|
|
it.stepBackward()
|
|
|
|
break unless it.getCurrentToken()?.value is "."
|
|
|
|
it.stepBackward()
|
|
|
|
token = null # If we're doing a complex access like this.getEnemies().length, then length isn't a valid var.
|
|
|
|
break unless isIdentifier(prev = it.getCurrentToken())
|
|
|
|
token = prev
|
|
|
|
start = it.getCurrentTokenColumn()
|
|
|
|
chain.unshift token.value
|
|
|
|
if token and (token.value of @variableStates or token.value is "this")
|
|
|
|
@variableChain = chain
|
2014-01-21 12:03:04 -05:00
|
|
|
@pos = {left: e.domEvent.offsetX + 50, top: e.domEvent.offsetY + 50}
|
2014-01-24 16:03:04 -05:00
|
|
|
@markerRange = new Range pos.row, start, pos.row, end
|
2014-01-19 10:08:28 -05:00
|
|
|
else
|
2014-01-24 16:03:04 -05:00
|
|
|
@variableChain = @markerRange = null
|
2014-01-21 12:03:04 -05:00
|
|
|
@update()
|
|
|
|
|
|
|
|
onMouseOut: (e) =>
|
2014-01-24 16:03:04 -05:00
|
|
|
@variableChain = @markerRange = null
|
2014-01-19 10:08:28 -05:00
|
|
|
@update()
|
|
|
|
|
2014-01-24 16:03:04 -05:00
|
|
|
onNewWorld: (e) ->
|
|
|
|
@thang = @options.thang = e.world.thangMap[@thang.id] if @thang
|
|
|
|
|
2014-01-19 10:08:28 -05:00
|
|
|
update: ->
|
2014-01-24 16:03:04 -05:00
|
|
|
if @variableChain
|
|
|
|
{key, value} = @deserializeVariableChain @variableChain
|
|
|
|
@$el.find("code").text "#{key}: #{value}"
|
2014-01-19 10:08:28 -05:00
|
|
|
@$el.show().css(@pos)
|
|
|
|
else
|
|
|
|
@$el.hide()
|
2014-01-19 12:14:42 -05:00
|
|
|
@updateMarker()
|
|
|
|
|
|
|
|
updateMarker: ->
|
|
|
|
if @marker
|
|
|
|
@ace.getSession().removeMarker @marker
|
|
|
|
@marker = null
|
|
|
|
if @markerRange
|
|
|
|
@marker = @ace.getSession().addMarker @markerRange, "ace_bracket", "text"
|
2014-01-19 10:08:28 -05:00
|
|
|
|
2014-01-24 16:03:04 -05:00
|
|
|
deserializeVariableChain: (chain) ->
|
|
|
|
keys = []
|
|
|
|
for prop, i in chain
|
|
|
|
if prop is "this"
|
|
|
|
value = @thang
|
|
|
|
else
|
|
|
|
value = (if i is 0 then @variableStates else value)[prop]
|
|
|
|
keys.push prop
|
|
|
|
break unless value
|
|
|
|
if theClass = serializedClasses[value.CN]
|
|
|
|
if value.CN is "Thang"
|
|
|
|
thang = @thang.world.thangMap[value.id]
|
|
|
|
value = thang or "<Thang #{value.id} (non-existent)>"
|
|
|
|
else
|
|
|
|
value = theClass.deserializeFromAether(value)
|
|
|
|
if value and not _.isString value
|
|
|
|
if value.constructor?.className is "Thang"
|
|
|
|
value = "<#{value.spriteName} - #{value.id}, #{if value.pos then value.pos.toString() else 'non-physical'}>"
|
|
|
|
else
|
|
|
|
value = value.toString()
|
|
|
|
key: keys.join("."), value: value
|
|
|
|
|
2014-01-19 10:08:28 -05:00
|
|
|
destroy: ->
|
|
|
|
super()
|
|
|
|
@ace?.removeEventListener "mousemove", @onMouseMove
|