mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-12-19 20:12:43 -05:00
103 lines
4.5 KiB
CoffeeScript
103 lines
4.5 KiB
CoffeeScript
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.
|
||
# TODO: Use subclasses? Might need a factory pattern for that (bleh)
|
||
module.exports = class Problem
|
||
annotation: null
|
||
markerRange: null
|
||
# 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] or {}
|
||
@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?
|
||
|
||
# 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
|
||
|
||
isEqual: (problem) ->
|
||
_.all ['row', 'column', 'level', 'column', 'message', 'hint'], (attr) =>
|
||
@[attr] is problem[attr]
|
||
|
||
destroy: ->
|
||
@removeMarkerRanges()
|
||
@userCodeProblem.off() if @userCodeProblem
|
||
|
||
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]
|
||
{
|
||
row: start.row,
|
||
column: start.col,
|
||
raw: text,
|
||
text: text,
|
||
type: @aetherProblem.level ? 'error'
|
||
createdBy: 'aether'
|
||
}
|
||
|
||
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 }
|
||
|
||
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, textMarkerRange }
|
||
|
||
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()
|