Add functional error banners (with poor messages)

This commit is contained in:
Phoenix Eliot 2016-08-24 17:09:04 -07:00
parent f93c70a56c
commit 0a2875c880
5 changed files with 94 additions and 43 deletions

View file

@ -89,7 +89,7 @@ module.exports =
'tome:problems-updated': c.object {title: 'Problems Updated', description: 'Published when problems have been updated', required: ['spell', 'problems', 'isCast']},
spell: {type: 'object'}
problems: {type: 'array'}
isCast: {type: 'boolean'}
isCast: {type: 'boolean'} # Whether the code has been Run yet. Sometimes determines if error displays as just annotation or as full banner.
'tome:change-language': c.object {title: 'Tome Change Language', description: 'Published when the Tome should update its programming language', required: ['language']},
language: {type: 'string'}

View file

@ -1,43 +1,82 @@
Range = ace.require('ace/range').Range
# This class can either wrap an AetherProblem,
# or act as a general runtime error container for web-dev iFrame errors.
module.exports = class Problem
annotation: null
markerRange: null
constructor: (@aether, @aetherProblem, @ace, isCast=false, @levelID) ->
@buildAnnotation()
@buildMarkerRange() if isCast
# TODO: Convert calls to constructor to use object
constructor: ({ @aether, @aetherProblem, @ace, isCast=false, @levelID, error }) ->
debugger if arguments.length > 1
if @aetherProblem
@annotation = @buildAnnotationFromAetherProblem(@aetherProblem)
{@lineMarkerRange, @textMarkerRange} = @buildMarkerRangesFromAetherProblem(@aetherProblem) if isCast
@level = @aetherProblem.level
@row = @aetherProblem.range?[0]?.row
@column = @aetherProblem.range?[0]?.col
@range = @aetherProblem.range
@message = @aetherProblem.message
@hint = @aetherProblem.hint
@userInfo = @aetherProblem.userInfo
else
@annotation = @buildAnnotationFromWebDevError(error)
@lineMarkerRange = new Range error.line, 0, error.line, 1
@lineMarkerRange.start = @ace.getSession().getDocument().createAnchor @lineMarkerRange.start
@lineMarkerRange.end = @ace.getSession().getDocument().createAnchor @lineMarkerRange.end
@lineMarkerRange.id = @ace.getSession().addMarker @lineMarkerRange, 'problem-line', 'fullLine'
@level = error?.type or 'error'
@row = error?.line
@column = error?.column
@message = error.text or error.raw or 'Unknown Error'
@hint = undefined
@userInfo = undefined
# TODO: get ACE screen line, too, for positioning, since any multiline "lines" will mess up positioning
Backbone.Mediator.publish("problem:problem-created", line: @annotation.row, text: @annotation.text) if application.isIPadApp
destroy: ->
@removeMarkerRanges()
@userCodeProblem.off() if @userCodeProblem
buildAnnotationFromWebDevError: (error) ->
{
row: error.line
column: error.column
raw: error.error
text: error.message
type: error.type
createdBy: 'web-dev-iframe'
}
buildAnnotation: ->
return unless @aetherProblem.range
text = @aetherProblem.message.replace /^Line \d+: /, ''
start = @aetherProblem.range[0]
@annotation =
buildAnnotationFromAetherProblem: (aetherProblem) ->
return unless aetherProblem.range
text = aetherProblem.message.replace /^Line \d+: /, ''
start = aetherProblem.range[0]
{
row: start.row,
column: start.col,
raw: text,
text: text,
type: @aetherProblem.level ? 'error'
createdBy: 'aether'
}
buildMarkerRange: ->
return unless @aetherProblem.range
[start, end] = @aetherProblem.range
textClazz = "problem-marker-#{@aetherProblem.level}"
@textMarkerRange = new Range start.row, start.col, end.row, end.col
@textMarkerRange.start = @ace.getSession().getDocument().createAnchor @textMarkerRange.start
@textMarkerRange.end = @ace.getSession().getDocument().createAnchor @textMarkerRange.end
@textMarkerRange.id = @ace.getSession().addMarker @textMarkerRange, textClazz, 'text'
buildMarkerRangesFromAetherProblem: (aetherProblem) ->
return unless aetherProblem.range
[start, end] = aetherProblem.range
textClazz = "problem-marker-#{aetherProblem.level}"
textMarkerRange = new Range start.row, start.col, end.row, end.col
textMarkerRange.start = @ace.getSession().getDocument().createAnchor textMarkerRange.start
textMarkerRange.end = @ace.getSession().getDocument().createAnchor textMarkerRange.end
textMarkerRange.id = @ace.getSession().addMarker textMarkerRange, textClazz, 'text'
lineClazz = "problem-line"
@lineMarkerRange = new Range start.row, start.col, end.row, end.col
@lineMarkerRange.start = @ace.getSession().getDocument().createAnchor @lineMarkerRange.start
@lineMarkerRange.end = @ace.getSession().getDocument().createAnchor @lineMarkerRange.end
@lineMarkerRange.id = @ace.getSession().addMarker @lineMarkerRange, lineClazz, 'fullLine'
lineMarkerRange = new Range start.row, start.col, end.row, end.col
lineMarkerRange.start = @ace.getSession().getDocument().createAnchor lineMarkerRange.start
lineMarkerRange.end = @ace.getSession().getDocument().createAnchor lineMarkerRange.end
lineMarkerRange.id = @ace.getSession().addMarker lineMarkerRange, lineClazz, 'fullLine'
{ lineMarkerRange, textMarkerRange }
removeMarkerRanges: ->
if @textMarkerRange

View file

@ -38,31 +38,31 @@ module.exports = class ProblemAlertView extends CocoView
afterRender: ->
super()
if @problem?
@$el.addClass('alert').addClass("alert-#{@problem.aetherProblem.level}").hide().fadeIn('slow')
@$el.addClass('no-hint') unless @problem.aetherProblem.hint
@$el.addClass('alert').addClass("alert-#{@problem.level}").hide().fadeIn('slow')
@$el.addClass('no-hint') unless @problem.hint
@playSound 'error_appear'
setProblemMessage: ->
if @problem?
format = (s) -> marked(s.replace(/</g, '&lt;').replace(/>/g, '&gt;')) if s?
message = @problem.aetherProblem.message
message = @problem.message
# Add time to problem message if hint is for a missing null check
# NOTE: This may need to be updated with Aether error hint changes
if @problem.aetherProblem.hint? and /(?:null|undefined)/.test @problem.aetherProblem.hint
age = @problem.aetherProblem.userInfo?.age
if @problem.hint? and /(?:null|undefined)/.test @problem.hint
age = @problem.userInfo?.age
if age?
if /^Line \d+:/.test message
message = message.replace /^(Line \d+)/, "$1, time #{age.toFixed(1)}"
else
message = "Time #{age.toFixed(1)}: #{message}"
@message = format message
@hint = format @problem.aetherProblem.hint
@hint = format @problem.hint
onShowProblemAlert: (data) ->
return unless $('#code-area').is(":visible")
if @problem?
if @$el.hasClass "alert-#{@problem.aetherProblem.level}"
@$el.removeClass "alert-#{@problem.aetherProblem.level}"
if @$el.hasClass "alert-#{@problem.level}"
@$el.removeClass "alert-#{@problem.level}"
if @$el.hasClass "no-hint"
@$el.removeClass "no-hint"
@problem = data.problem

View file

@ -831,11 +831,11 @@ module.exports = class SpellView extends CocoView
for aetherProblem, problemIndex in aether.getAllProblems()
continue if key = aetherProblem.userInfo?.key and key of seenProblemKeys
seenProblemKeys[key] = true if key
@problems.push problem = new Problem aether, aetherProblem, @ace, isCast, @options.levelID
@problems.push problem = new Problem { aether, aetherProblem, @ace, isCast, levelID: @options.levelID }
if isCast and problemIndex is 0
if problem.aetherProblem.range?
if problem.range?
lineOffsetPx = 0
for i in [0...problem.aetherProblem.range[0].row]
for i in [0...problem.row]
lineOffsetPx += @aceSession.getRowLength(i) * @ace.renderer.lineHeight
lineOffsetPx -= @ace.session.getScrollTop()
Backbone.Mediator.publish 'tome:show-problem-alert', problem: problem, lineOffsetPx: Math.max lineOffsetPx, 0
@ -993,19 +993,32 @@ module.exports = class SpellView extends CocoView
@spell.transpile() # TODO: is there any way we can avoid doing this if it hasn't changed? Causes a slight hang.
@updateAether false, false
onWebDevError: (e) ->
onWebDevError: (error) ->
annotations = @aceSession.getAnnotations()
console.log {spellviewOnWebDevError: arguments}
newAnnotation = {
createdBy: 'web-dev-iframe'
row: e.line + @linesBeforeScript(@getSource())
column: e.column
raw: e.error
text: e.message
type: e.type
}
annotations.push(newAnnotation)
offsetError = _.merge {}, error, { line: error.line + @linesBeforeScript(@getSource()) }
console.log {error, offsetError}
problem = new Problem({ error: offsetError, @ace, levelID: @options.levelID })
@problems.push problem
problemIndex = 0 # TODO: Unstub
if problemIndex is 0
lineOffsetPx = 0
for i in [0...problem.row]
lineOffsetPx += @aceSession.getRowLength(i) * @ace.renderer.lineHeight
lineOffsetPx -= @ace.session.getScrollTop()
Backbone.Mediator.publish 'tome:show-problem-alert', problem: problem, lineOffsetPx: Math.max lineOffsetPx, 0
# @saveUserCodeProblem(aether, aetherProblem)
console.log {annotation: problem.annotation}
annotations.push problem.annotation if problem.annotation
@aceSession.setAnnotations annotations, true
Backbone.Mediator.publish 'tome:problems-updated', spell: @spell, problems: @problems, isCast: true
# TODO: Unset this on rerun
@ace.setStyle 'user-code-problem'
# TODO: When is this unset?
@ace.setStyle 'spell-cast'
linesBeforeScript: (html) ->
# TODO: refactor, make it work with multiple scripts. What to do when error is in level-creator's code?

View file

@ -206,4 +206,3 @@ module.exports =
return false if index is -1
return false if delta.deltaPath[index+1] in ['en', 'en-US', 'en-GB'] # English speakers are most likely just spamming, so always treat those as patches, not saves.
return true