2014-06-30 22:16:26 -04:00
|
|
|
|
Range = ace.require('ace/range').Range
|
2014-01-03 13:32:13 -05:00
|
|
|
|
|
2016-08-23 19:53:54 -04:00
|
|
|
|
# This class can either wrap an AetherProblem,
|
|
|
|
|
# or act as a general runtime error container for web-dev iFrame errors.
|
|
|
|
|
# TODO: Use subclasses? Might need a factory pattern for that (bleh)
|
2014-01-03 13:32:13 -05:00
|
|
|
|
module.exports = class Problem
|
|
|
|
|
annotation: null
|
|
|
|
|
markerRange: null
|
2016-08-23 19:53:54 -04:00
|
|
|
|
# Construction with AetherProblem will include all but `error`
|
|
|
|
|
# Construction with a standard error will have `error`, `isCast`, `levelID`, `ace`
|
|
|
|
|
constructor: ({ @aether, @aetherProblem, @ace, isCast=false, @levelID, error, userCodeHasChangedSinceLastCast }) ->
|
|
|
|
|
if @aetherProblem
|
|
|
|
|
@annotation = @buildAnnotationFromAetherProblem(@aetherProblem)
|
|
|
|
|
{ @lineMarkerRange, @textMarkerRange } = @buildMarkerRangesFromAetherProblem(@aetherProblem) if isCast
|
|
|
|
|
|
|
|
|
|
{ @level, @range, @message, @hint, @userInfo } = @aetherProblem
|
|
|
|
|
{ @row, @column: col } = @aetherProblem.range?[0]
|
|
|
|
|
@createdBy = 'aether'
|
|
|
|
|
else
|
|
|
|
|
unless userCodeHasChangedSinceLastCast
|
|
|
|
|
@annotation = @buildAnnotationFromWebDevError(error)
|
|
|
|
|
{ @lineMarkerRange, @textMarkerRange } = @buildMarkerRangesFromWebDevError(error)
|
|
|
|
|
|
|
|
|
|
@level = 'error'
|
|
|
|
|
@row = error.line
|
|
|
|
|
@column = error.column
|
|
|
|
|
@message = error.message or 'Unknown Error'
|
|
|
|
|
if error.line and not userCodeHasChangedSinceLastCast
|
|
|
|
|
@message = "Line #{error.line + 1}: " + @message # Ace's gutter numbers are 1-indexed but annotation.rows are 0-indexed
|
|
|
|
|
if userCodeHasChangedSinceLastCast
|
|
|
|
|
@hint = "This error was generated by old code — Try running your new code first."
|
|
|
|
|
else
|
|
|
|
|
@hint = undefined
|
|
|
|
|
@userInfo = undefined
|
|
|
|
|
@createdBy = 'web-dev-iframe'
|
|
|
|
|
# TODO: Include runtime/transpile error types depending on something?
|
|
|
|
|
|
2014-11-08 14:59:39 -05:00
|
|
|
|
# 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
|
2014-01-03 13:32:13 -05:00
|
|
|
|
|
2016-08-23 19:53:54 -04:00
|
|
|
|
isEqual: (problem) ->
|
|
|
|
|
_.all ['row', 'column', 'level', 'column', 'message', 'hint'], (attr) =>
|
|
|
|
|
@[attr] is problem[attr]
|
|
|
|
|
|
2014-01-03 13:32:13 -05:00
|
|
|
|
destroy: ->
|
2014-11-18 13:03:02 -05:00
|
|
|
|
@removeMarkerRanges()
|
2014-08-14 14:55:43 -04:00
|
|
|
|
@userCodeProblem.off() if @userCodeProblem
|
2014-01-03 13:32:13 -05:00
|
|
|
|
|
2016-08-23 19:53:54 -04:00
|
|
|
|
buildAnnotationFromWebDevError: (error) ->
|
|
|
|
|
{
|
|
|
|
|
row: error.line
|
|
|
|
|
column: error.column
|
|
|
|
|
raw: error.message
|
|
|
|
|
text: error.message
|
|
|
|
|
type: 'error'
|
|
|
|
|
createdBy: 'web-dev-iframe'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buildAnnotationFromAetherProblem: (aetherProblem) ->
|
|
|
|
|
return unless aetherProblem.range
|
|
|
|
|
text = aetherProblem.message.replace /^Line \d+: /, ''
|
|
|
|
|
start = aetherProblem.range[0]
|
|
|
|
|
{
|
2014-02-03 16:58:25 -05:00
|
|
|
|
row: start.row,
|
|
|
|
|
column: start.col,
|
2014-01-03 13:32:13 -05:00
|
|
|
|
raw: text,
|
|
|
|
|
text: text,
|
2014-06-30 22:16:26 -04:00
|
|
|
|
type: @aetherProblem.level ? 'error'
|
2016-07-19 14:29:57 -04:00
|
|
|
|
createdBy: 'aether'
|
2016-08-23 19:53:54 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buildMarkerRangesFromWebDevError: (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'
|
|
|
|
|
textMarkerRange = undefined # We don't get any per-character info from standard errors
|
|
|
|
|
{ lineMarkerRange, textMarkerRange }
|
2014-01-03 13:32:13 -05:00
|
|
|
|
|
2016-08-23 19:53:54 -04:00
|
|
|
|
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'
|
2014-11-18 13:03:02 -05:00
|
|
|
|
lineClazz = "problem-line"
|
2016-08-23 19:53:54 -04:00
|
|
|
|
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 }
|
2014-01-03 13:32:13 -05:00
|
|
|
|
|
2014-11-18 13:03:02 -05:00
|
|
|
|
removeMarkerRanges: ->
|
|
|
|
|
if @textMarkerRange
|
|
|
|
|
@ace.getSession().removeMarker @textMarkerRange.id
|
|
|
|
|
@textMarkerRange.start.detach()
|
|
|
|
|
@textMarkerRange.end.detach()
|
|
|
|
|
if @lineMarkerRange
|
|
|
|
|
@ace.getSession().removeMarker @lineMarkerRange.id
|
|
|
|
|
@lineMarkerRange.start.detach()
|
|
|
|
|
@lineMarkerRange.end.detach()
|