diff --git a/app/application.coffee b/app/application.coffee index 11dc4ba15..b3f1d4bc3 100644 --- a/app/application.coffee +++ b/app/application.coffee @@ -8,6 +8,8 @@ CocoView = require 'views/kinds/CocoView' preventBackspace = (event) -> if event.keyCode is 8 and not elementAcceptsKeystrokes(event.srcElement or event.target) event.preventDefault() + else if (key.ctrl or key.command) and not key.alt and event.keyCode in [219, 221] # prevent Ctrl/Cmd + [ / ] + event.preventDefault() elementAcceptsKeystrokes = (el) -> # http://stackoverflow.com/questions/1495219/how-can-i-prevent-the-backspace-key-from-navigating-back diff --git a/app/lib/God.coffee b/app/lib/God.coffee index 71d91d82d..816bf3f92 100644 --- a/app/lib/God.coffee +++ b/app/lib/God.coffee @@ -152,7 +152,7 @@ class Angel @ids[@lastID] # https://github.com/codecombat/codecombat/issues/81 -- TODO: we need to wait for worker initialization first - infiniteLoopIntervalDuration: 15000 # check this often (must be more than the others added) + infiniteLoopIntervalDuration: 1500000 # check this often (must be more than the others added) infiniteLoopTimeoutDuration: 1500 # wait this long when we check abortTimeoutDuration: 500 # give in-process or dying workers this long to give up constructor: (@god) -> diff --git a/app/lib/surface/Mark.coffee b/app/lib/surface/Mark.coffee index ab9fef4cd..54cead432 100644 --- a/app/lib/surface/Mark.coffee +++ b/app/lib/surface/Mark.coffee @@ -140,7 +140,7 @@ module.exports = class Mark extends CocoClass worldZ = @sprite.thang.pos.z - @sprite.thang.depth / 2 @mark.alpha = 0.451 / Math.sqrt(worldZ / 2 + 1) else - pos ?= @sprite.displayObject + pos ?= @sprite?.displayObject @mark.x = pos.x @mark.y = pos.y if @name is 'highlight' diff --git a/app/lib/surface/SpriteBoss.coffee b/app/lib/surface/SpriteBoss.coffee index d9ecf8ed0..e5da46c50 100644 --- a/app/lib/surface/SpriteBoss.coffee +++ b/app/lib/surface/SpriteBoss.coffee @@ -259,6 +259,6 @@ module.exports = class SpriteBoss extends CocoClass target = thang?.target targetPos = thang?.targetPos targetPos = null if targetPos?.isZero?() # Null targetPos get serialized as (0, 0, 0) - @targetMark.toggle target or targetPos @targetMark.setSprite if target then @sprites[target.id] else null + @targetMark.toggle @targetMark.sprite or targetPos @targetMark.update if targetPos then @camera.worldToSurface targetPos else null diff --git a/app/styles/play/level/tome/cast_button.sass b/app/styles/play/level/tome/cast_button.sass index a77eeb3c7..6543804f9 100644 --- a/app/styles/play/level/tome/cast_button.sass +++ b/app/styles/play/level/tome/cast_button.sass @@ -30,11 +30,13 @@ color: white #cast-button-view + display: none + .cast-button-group position: absolute - // Bottom/right margins must appear to scroll to size of any paper gashes - top: 2% - right: 4% + top: 55px + left: 20px + z-index: 2 @include opacity(77) .button-progress-overlay diff --git a/app/styles/play/level/tome/spell.sass b/app/styles/play/level/tome/spell.sass index 0ff18cf23..684181e16 100644 --- a/app/styles/play/level/tome/spell.sass +++ b/app/styles/play/level/tome/spell.sass @@ -32,10 +32,11 @@ .ace_editor @include box-sizing(border-box) + margin-top: 40px width: 100% - height: 90% - height: -webkit-calc(100% - 60px) - height: calc(100% - 60px) + height: 83% + height: -webkit-calc(100% - 60px - 40px) + height: calc(100% - 60px - 40px) position: relative background-color: transparent line-height: 20px @@ -75,11 +76,10 @@ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMjgwMTE3NDA3MjA2ODExOEE2REU4Q0M1MTM1MkIxRiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpBQjVEQUNDMzQ4RUIxMUUxOEVGRUUyNzFENDM3RDVFMCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpBQjVEQUNDMjQ4RUIxMUUxOEVGRUUyNzFENDM3RDVFMCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QTU1MjE3RDIzMTIwNjgxMThEQkI4NTlBMjQ1QTEwOTUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDI4MDExNzQwNzIwNjgxMThBNkRFOENDNTEzNTJCMUYiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7SazaGAAAAiElEQVR42mL8//8/AzUBEwOVweA3kAWboI2jCyhgDwBx4ZH9ey5Qy4UOQHweaHg/EAtQ08sFUIMDqBmGCkC8HmgoCCtQM1ICoK5toGYsg8KzHmjo+UGbDj8AcSMwORkSnQ7xgA3QtPmApISNBTyAGrSBGl6eAMSGxBhGyIVkZT3G0fKQYgAQYACL+C2ZM6PC7AAAAABJRU5ErkJggg==) background-position: 0px center - //.user-code-problem - //.ace_scroller - // background-color: #470000 - .ace_marker-layer .ace_bracket // Override faint gray - border-color: #0FF + border-color: #8FF + + .ace_identifier + background-color: rgba(255, 128, 128, 0.15) diff --git a/app/styles/play/level/tome/spell_debug.sass b/app/styles/play/level/tome/spell_debug.sass new file mode 100644 index 000000000..d0f97a28f --- /dev/null +++ b/app/styles/play/level/tome/spell_debug.sass @@ -0,0 +1,10 @@ +@import "../../../bootstrap/mixins" + +.spell-debug-view + position: absolute + z-index: 9001 + max-width: 400px + padding: 10px + background: transparent url(/images/level/popover_background.png) + background-size: 100% 100% + diff --git a/app/styles/play/level/tome/spell_toolbar.sass b/app/styles/play/level/tome/spell_toolbar.sass new file mode 100644 index 000000000..7db7a8e40 --- /dev/null +++ b/app/styles/play/level/tome/spell_toolbar.sass @@ -0,0 +1,54 @@ +@import "../../../bootstrap/mixins" + +.spell-toolbar-view + position: absolute + z-index: 2 + top: 2px + left: 5px + box-sizing: border-box + padding-left: 150px + height: 36px + width: 95% + width: -webkit-calc(95% - 5px) + width: calc(95% - 5px) + background-color: rgba(100, 45, 210, 0.05) + + .spell-progress + position: relative + height: 100% + width: 50% + display: inline-block + + .progress + position: absolute + left: 0px + top: 8px + bottom: 0px + width: 100% + cursor: pointer + overflow: visible + + .bar + @include transition(width .0s linear) + position: relative + pointer-events: none + background-color: #67A4C8 + width: 50% + + .scrubber-handle + position: absolute + pointer-events: none + right: -16px + top: -7px + background: transparent url(/images/level/playback_thumb.png) + width: 32px + height: 32px + + .btn-group + // I don't know, I can figure this out for real later + margin: -26px 0 0 18px + + .metrics + display: inline-block + margin: -30px 0 0 10px + vertical-align: middle diff --git a/app/templates/play/level/playback.jade b/app/templates/play/level/playback.jade index e8f25e17c..e18b55f6a 100644 --- a/app/templates/play/level/playback.jade +++ b/app/templates/play/level/playback.jade @@ -1,4 +1,4 @@ -button.btn.btn-mini.btn-inverse#play-button.playing(title="Alt-P: Toggle level play/pause") +button.btn.btn-mini.btn-inverse#play-button.playing(title="Ctrl/Cmd + P: Toggle level play/pause") i.icon-play.icon-white.big i.icon-pause.icon-white.big i.icon-repeat.icon-white.big @@ -16,19 +16,19 @@ button.btn.btn-mini.btn-inverse#music-button(title="Toggle Music") .scrubber-handle .btn-group.dropup#playback-settings - button.btn.btn-mini.btn-inverse#zoom-in-button + button.btn.btn-mini.btn-inverse#zoom-in-button(title="Zoom In (or scroll down)") i.icon-zoom-in.icon-white - button.btn.btn-mini.btn-inverse#zoom-out-button + button.btn.btn-mini.btn-inverse#zoom-out-button(title="Zoom Out (or scroll up)") i.icon-zoom-out.icon-white button.btn.btn-mini.btn-inverse.dropdown-toggle(data-toggle="dropdown")#settings-button i.icon-cog.icon-white.big ul.dropdown-menu if me.get('name') == "Nick" - li(title="\\: Toggle debug display").selectable#debug-toggle + li(title="Ctrl/Cmd + \\: Toggle debug display").selectable#debug-toggle i.icon-globe | Debug Mode i.icon-ok.hide - li(title="G: Toggle grid display").selectable#grid-toggle + li(title="Ctrl/Cmd + G: Toggle grid display").selectable#grid-toggle i.icon-th span(data-i18n="play_level.grid") Grid i.icon-ok.hide diff --git a/app/templates/play/level/tome/spell_debug.jade b/app/templates/play/level/tome/spell_debug.jade new file mode 100644 index 000000000..428446e3a --- /dev/null +++ b/app/templates/play/level/tome/spell_debug.jade @@ -0,0 +1,2 @@ +pre + code \ No newline at end of file diff --git a/app/templates/play/level/tome/spell_toolbar.jade b/app/templates/play/level/tome/spell_toolbar.jade new file mode 100644 index 000000000..3eb45cca2 --- /dev/null +++ b/app/templates/play/level/tome/spell_toolbar.jade @@ -0,0 +1,22 @@ +.spell-progress + .progress + .bar + .scrubber-handle + +.btn-group + button.btn.btn-mini.btn-inverse.banner.step-backward(title="Ctrl/Cmd + Alt + [: Step Backward") + i.icon-arrow-left.icon-white + button.btn.btn-mini.btn-inverse.banner.step-forward(title="Ctrl/Cmd + Alt + ]: Step Forward") + i.icon-arrow-right.icon-white + +.metrics + code.statements-metric + span.metric.statement-index + | / + span.metric.statements-executed + span.metric.statements-executed-total + | + code.calls-metric + span.metric.call-index + | / + span.metric.calls-executed diff --git a/app/views/play/level/tome/cast_button_view.coffee b/app/views/play/level/tome/cast_button_view.coffee index 4b17f4288..f8526ba1c 100644 --- a/app/views/play/level/tome/cast_button_view.coffee +++ b/app/views/play/level/tome/cast_button_view.coffee @@ -24,7 +24,6 @@ module.exports = class CastButtonView extends View context.castShortcutVerbose = @castShortcutVerbose context - afterRender: -> super() # TODO: use a User setting instead of localStorage diff --git a/app/views/play/level/tome/spell.coffee b/app/views/play/level/tome/spell.coffee index 19f88bd3a..84f6cd906 100644 --- a/app/views/play/level/tome/spell.coffee +++ b/app/views/play/level/tome/spell.coffee @@ -64,7 +64,11 @@ module.exports = class Spell functionParameters: @parameters yieldConditionally: thang.plan? requiresThis: thang.requiresThis - if @name is 'chooseAction' or not (me.team in @permissions.readwrite) or thang.id is 'Thoktar' # Gridmancer can't handle it + includeFlow: true + #callIndex: 0 + #timelessVariables: ['i'] + #statementIndex: 9001 + if not (me.team in @permissions.readwrite)# or @name is 'chooseAction' or thang.id is 'Thoktar' # Gridmancer can't handle it #console.log "Turning off includeFlow for", @spellKey aetherOptions.includeFlow = false aether = new Aether aetherOptions diff --git a/app/views/play/level/tome/spell_debug_view.coffee b/app/views/play/level/tome/spell_debug_view.coffee new file mode 100644 index 000000000..bc613c2bf --- /dev/null +++ b/app/views/play/level/tome/spell_debug_view.coffee @@ -0,0 +1,63 @@ +View = require 'views/kinds/CocoView' +template = require 'templates/play/level/tome/spell_debug' +Range = ace.require("ace/range").Range + +module.exports = class DebugView extends View + className: 'spell-debug-view' + template: template + subscriptions: {} + events: {} + + constructor: (options) -> + super options + @ace = options.ace + @variableStates = {} + + afterRender: -> + super() + @ace.on "mousemove", @onMouseMove + #@ace.on "click", onClick # same ACE API as mousemove + + setVariableStates: (@variableStates) -> + @update() + + onMouseMove: (e) => + pos = e.getDocumentPosition() + column = pos.column + until column < 0 + if token = e.editor.session.getTokenAt pos.row, column + break if token.type is 'identifier' + column = token.start - 1 + else + --column + if token?.type is 'identifier' and token.value of @variableStates + @variable = token.value + @pos = {left: e.domEvent.offsetX + 50, top: e.domEvent.offsetY + 50} + @markerRange = new Range pos.row, token.start, pos.row, token.start + token.value.length + else + @variable = @markerRange = null + @update() + + onMouseOut: (e) => + @variable = @markerRange = null + @update() + + update: -> + if @variable + value = @variableStates[@variable] + @$el.find("code").text "#{@variable}: #{value}" + @$el.show().css(@pos) + else + @$el.hide() + @updateMarker() + + updateMarker: -> + if @marker + @ace.getSession().removeMarker @marker + @marker = null + if @markerRange + @marker = @ace.getSession().addMarker @markerRange, "ace_bracket", "text" + + destroy: -> + super() + @ace?.removeEventListener "mousemove", @onMouseMove diff --git a/app/views/play/level/tome/spell_toolbar_view.coffee b/app/views/play/level/tome/spell_toolbar_view.coffee new file mode 100644 index 000000000..573689742 --- /dev/null +++ b/app/views/play/level/tome/spell_toolbar_view.coffee @@ -0,0 +1,94 @@ +View = require 'views/kinds/CocoView' +template = require 'templates/play/level/tome/spell_toolbar' + +module.exports = class SpellToolbarView extends View + className: 'spell-toolbar-view' + template: template + + subscriptions: + 'spell-step-backward': 'onStepBackward' + 'spell-step-forward': 'onStepForward' + + events: + 'mousemove .progress': 'onProgressHover' + 'mouseout .progress': 'onProgressMouseOut' + 'click .step-backward': 'onStepBackward' + 'click .step-forward': 'onStepForward' + + constructor: (options) -> + super options + @ace = options.ace + + afterRender: -> + super() + + setStatementIndex: (statementIndex) -> + return unless total = @callState?.statementsExecuted + @statementIndex = Math.min(total - 1, Math.max(0, statementIndex)) + @statementRatio = @statementIndex / (total - 1) + @statementTime = @callState.statements[@statementIndex].userInfo.time + @$el.find('.bar').css('width', 100 * @statementRatio + '%') + Backbone.Mediator.publish 'tome:spell-statement-index-updated', statementIndex: @statementIndex, ace: @ace + @$el.find('.step-backward').prop('disabled', @statementIndex is 0) + @$el.find('.step-forward').prop('disabled', @statementIndex is total - 1) + @updateMetrics() + + updateMetrics: -> + statementsExecuted = @callState.statementsExecuted + $metrics = @$el.find('.metrics') + if @metrics.callsExecuted > 1 + $metrics.find('.call-index').text @callIndex + 1 + $metrics.find('.calls-executed').text @metrics.callsExecuted + $metrics.find('.calls-metric').show().attr('title', "Method call #{@callIndex + 1} of #{@metrics.callsExecuted} calls") + else + $metrics.find('.calls-metric').hide() + if @metrics.statementsExecuted + $metrics.find('.statement-index').text @statementIndex + 1 + $metrics.find('.statements-executed').text statementsExecuted + if @metrics.statementsExecuted > statementsExecuted + $metrics.find('.statements-executed-total').text " (#{@metrics.statementsExecuted})" + titleSuffix = " (#{@metrics.statementsExecuted} statements total)" + else + $metrics.find('.statements-executed-total').text "" + titleSuffix = "" + $metrics.find('.statements-metric').show().attr('title', "Statement #{@statementIndex + 1} of #{statementsExecuted} this call#{titleSuffix}") + else + $metrics.find('.statements-metric').hide() + + setStatementRatio: (ratio) -> + return unless total = @callState?.statementsExecuted + @setStatementIndex Math.floor ratio * total + + onProgressHover: (e) -> + @setStatementRatio e.offsetX / @$el.find('.progress').width() + @updateTime() + @maintainIndexHover = true + + onProgressMouseOut: (e) -> + @maintainIndexHover = false + + onStepBackward: (e) -> @step -1 + onStepForward: (e) -> @step 1 + step: (delta) -> + lastTime = @statementTime + @setStatementIndex @statementIndex + delta + @updateTime() if @statementIndex isnt lastTime + + updateTime: -> + @maintainIndexScrub = true + clearTimeout @maintainIndexScrubTimeout if @maintainIndexScrubTimeout + @maintainIndexScrubTimeout = _.delay (=> @maintainIndexScrub = false), 500 + Backbone.Mediator.publish 'level-set-time', time: @statementTime, scrubDuration: 500 + + setCallState: (callState, statementIndex, @callIndex, @metrics) -> + return if callState is @callState and statementIndex is @statementIndex + return unless @callState = callState + if not @maintainIndexHover and not @maintainIndexScrub and statementIndex? and callState.statements[statementIndex].userInfo.time isnt @statementTime + @setStatementIndex statementIndex + else + @setStatementRatio @statementRatio + # Not sure yet whether it's better to maintain @statementIndex or @statementRatio + #else if @statementRatio is 1 or not @statementIndex? + # @setStatementRatio 1 + #else + # @setStatementIndex @statementIndex diff --git a/app/views/play/level/tome/spell_view.coffee b/app/views/play/level/tome/spell_view.coffee index 33314e2e9..7d319cef4 100644 --- a/app/views/play/level/tome/spell_view.coffee +++ b/app/views/play/level/tome/spell_view.coffee @@ -4,6 +4,8 @@ template = require 'templates/play/level/tome/spell' filters = require 'lib/image_filter' Range = ace.require("ace/range").Range Problem = require './problem' +SpellDebugView = require './spell_debug_view' +SpellToolbarView = require './spell_toolbar_view' module.exports = class SpellView extends View id: 'spell-view' @@ -25,9 +27,10 @@ module.exports = class SpellView extends View 'level:session-will-save': 'onSessionWillSave' 'modal-closed': 'focus' 'focus-editor': 'focus' + 'tome:spell-statement-index-updated': 'onStatementIndexUpdated' events: - 'click .ace': -> console.log 'clicked ace', @ + 'mouseout': 'onMouseOut' constructor: (options) -> super options @@ -48,6 +51,7 @@ module.exports = class SpellView extends View else # needs to happen after the code generating this view is complete setTimeout @onLoaded, 1 + @createDebugView() createACE: -> # Test themes and settings here: http://ace.ajax.org/build/kitchen-sink.html @@ -86,24 +90,30 @@ module.exports = class SpellView extends View name: 'end-all-scripts' bindKey: {win: 'Escape', mac: 'Escape'} exec: -> Backbone.Mediator.publish 'level:escape-pressed' - - # TODO: These don't work on, for example, Danish keyboards. Figure out a more universal solution. -# @ace.commands.addCommand -# name: 'toggle-grid' -# bindKey: {win: 'Alt-G', mac: 'Alt-G'} -# exec: -> Backbone.Mediator.publish 'level-toggle-grid' -# @ace.commands.addCommand -# name: 'toggle-debug' -# bindKey: {win: 'Alt-\\', mac: 'Alt-\\'} -# exec: -> Backbone.Mediator.publish 'level-toggle-debug' -# @ace.commands.addCommand -# name: 'level-scrub-forward' -# bindKey: {win: 'Alt-]', mac: 'Alt-]'} -# exec: -> Backbone.Mediator.publish 'level-scrub-forward' -# @ace.commands.addCommand -# name: 'level-scrub-back' -# bindKey: {win: 'Alt-[', mac: 'Alt-['} -# exec: -> Backbone.Mediator.publish 'level-scrub-back' + @ace.commands.addCommand + name: 'toggle-grid' + bindKey: {win: 'Ctrl-G', mac: 'Command-G|Ctrl-G'} + exec: -> Backbone.Mediator.publish 'level-toggle-grid' + @ace.commands.addCommand + name: 'toggle-debug' + bindKey: {win: 'Ctrl-\\', mac: 'Command-\\|Ctrl-\\'} + exec: -> Backbone.Mediator.publish 'level-toggle-debug' + @ace.commands.addCommand + name: 'level-scrub-forward' + bindKey: {win: 'Ctrl-]', mac: 'Command-]|Ctrl-]'} + exec: -> Backbone.Mediator.publish 'level-scrub-forward' + @ace.commands.addCommand + name: 'level-scrub-back' + bindKey: {win: 'Ctrl-[', mac: 'Command-[|Ctrl-]'} + exec: -> Backbone.Mediator.publish 'level-scrub-back' + @ace.commands.addCommand + name: 'spell-step-forward' + bindKey: {win: 'Ctrl-Alt-]', mac: 'Command-Alt-]|Ctrl-Alt-]'} + exec: -> Backbone.Mediator.publish 'spell-step-forward' + @ace.commands.addCommand + name: 'spell-step-backward' + bindKey: {win: 'Ctrl-Alt-[', mac: 'Command-Alt-[|Ctrl-Alt-]'} + exec: -> Backbone.Mediator.publish 'spell-step-backward' fillACE: -> @ace.setValue @spell.source @@ -145,6 +155,17 @@ module.exports = class SpellView extends View Backbone.Mediator.publish 'tome:spell-loaded', spell: @spell @eventsSuppressed = false # Now that the initial change is in, we can start running any changed code + createDebugView: -> + @debugView = new SpellDebugView ace: @ace + @$el.append @debugView.render().$el.hide() + + createToolbarView: -> + @toolbarView = new SpellToolbarView ace: @ace + @$el.prepend @toolbarView.render().$el + + onMouseOut: (e) -> + @debugView.onMouseOut e + getSource: -> @ace.getValue() # could also do @firepad.getText() @@ -368,22 +389,33 @@ module.exports = class SpellView extends View @thang = e.selectedThang # update our thang to the current version @highlightCurrentLine() + onStatementIndexUpdated: (e) -> + return unless e.ace is @ace + @highlightCurrentLine() + highlightCurrentLine: (flow) => + # TODO: move this whole thing into SpellDebugView or somewhere? flow ?= @spellThang?.castAether?.flow return unless flow executed = [] matched = false - for callState, callNumber in flow.states or [] + states = flow.states ? [] + currentCallIndex = null + for callState, callNumber in states + if not currentCallIndex? and callState.userInfo?.time > @thang.world.age + currentCallIndex = callNumber - 1 if matched executed.pop() break executed.push [] - for state, statementNumber in callState + for state, statementNumber in callState.statements if state.userInfo?.time > @thang.world.age matched = true break _.last(executed).push state #state.executing = true if state.userInfo?.time is @thang.world.age # no work + currentCallIndex ?= callNumber - 1 + #console.log "got call index", currentCallIndex, "for time", @thang.world.age, "out of", states.length # TODO: don't redo the markers if they haven't actually changed text = @aceDoc.getValue() @@ -397,11 +429,20 @@ module.exports = class SpellView extends View markerRange.end.detach() @aceSession.removeMarker markerRange.id @markerRanges = [] + @debugView.setVariableStates {} @aceSession.removeGutterDecoration row, 'executing' for row in [0 ... @aceSession.getLength()] $(@ace.container).find('.ace_gutter-cell.executing').removeClass('executing') - return unless executed.length + unless executed.length + @toolbarView?.$el.hide() + return + unless @toolbarView or (@spell.name is "plan" and @spellThang.castAether.metrics.statementsExecuted < 20) + @createToolbarView() lastExecuted = _.last executed + @toolbarView?.$el.show() + statementIndex = Math.max 0, lastExecuted.length - 1 + @toolbarView?.setCallState states[currentCallIndex], statementIndex, currentCallIndex, @spellThang.castAether.metrics marked = {} + lastExecuted = lastExecuted[0 .. @toolbarView.statementIndex] if @toolbarView?.statementIndex? for state, i in lastExecuted #clazz = if state.executing then 'executing' else 'executed' # doesn't work clazz = if i is lastExecuted.length - 1 then 'executing' else 'executed' @@ -410,6 +451,9 @@ module.exports = class SpellView extends View continue if marked[key] > 2 # don't allow more than three of the same marker marked[key] ?= 0 ++marked[key] + else + @debugView.setVariableStates state.variables + #console.log "at", state.userInfo.time, "vars are now:", state.variables [start, end] = [offsetToPos(state.range[0]), offsetToPos(state.range[1])] markerRange = new Range(start.row, start.column, end.row, end.column) markerRange.start = @aceDoc.createAnchor markerRange.start @@ -454,3 +498,4 @@ module.exports = class SpellView extends View super() @firepad?.dispose() @ace.destroy() + @debugView.destroy() diff --git a/app/views/play/level/tome/tome_view.coffee b/app/views/play/level/tome/tome_view.coffee index 6b43cd3e0..e87fc3949 100644 --- a/app/views/play/level/tome/tome_view.coffee +++ b/app/views/play/level/tome/tome_view.coffee @@ -114,6 +114,7 @@ module.exports = class TomeView extends View @spellTabView?.$el.after('
').detach() @spellTabView = null @removeSubView @spellPaletteView if @spellPaletteView + @castButton?.$el.hide() @thangList?.$el.show() onSpriteSelected: (e) -> @@ -137,6 +138,7 @@ module.exports = class TomeView extends View @$el.find('#' + @spellTabView.id).after(@spellTabView.el).remove() @spellView.setThang thang @spellTabView.setThang thang + @castButton.$el.show() @thangList.$el.hide() @spellPaletteView = @insertSubView new SpellPaletteView thang: thang @spellPaletteView.toggleControls {}, @spellView.controlsEnabled # TODO: know when palette should have been disabled but didn't exist