Web Inspector: Uncaught TDZ Exception with Type Profiler
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / SourceCodeTextEditor.js
1 /*
2  * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WebInspector.SourceCodeTextEditor = class SourceCodeTextEditor extends WebInspector.TextEditor
27 {
28     constructor(sourceCode)
29     {
30         console.assert(sourceCode instanceof WebInspector.SourceCode);
31
32         super();
33
34         this.delegate = this;
35
36         this._sourceCode = sourceCode;
37         this._breakpointMap = {};
38         this._issuesLineNumberMap = new Map;
39         this._widgetMap = new Map;
40         this._contentPopulated = false;
41         this._invalidLineNumbers = {0: true};
42         this._ignoreContentDidChange = 0;
43
44         this._typeTokenScrollHandler = null;
45         this._typeTokenAnnotator = null;
46         this._basicBlockAnnotator = null;
47
48         this._isProbablyMinified = false;
49
50         // FIXME: Currently this just jumps between resources and related source map resources. It doesn't "jump to symbol" yet.
51         this._updateTokenTrackingControllerState();
52
53         this.element.classList.add("source-code");
54
55         if (this._supportsDebugging) {
56             WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.DisabledStateDidChange, this._breakpointStatusDidChange, this);
57             WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.AutoContinueDidChange, this._breakpointStatusDidChange, this);
58             WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.ResolvedStateDidChange, this._breakpointStatusDidChange, this);
59             WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.LocationDidChange, this._updateBreakpointLocation, this);
60
61             WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.BreakpointsEnabledDidChange, this._breakpointsEnabledDidChange, this);
62             WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.BreakpointAdded, this._breakpointAdded, this);
63             WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.BreakpointRemoved, this._breakpointRemoved, this);
64             WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ActiveCallFrameDidChange, this._activeCallFrameDidChange, this);
65
66             WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.Paused, this._debuggerDidPause, this);
67             WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.Resumed, this._debuggerDidResume, this);
68             if (WebInspector.debuggerManager.activeCallFrame)
69                 this._debuggerDidPause();
70
71             this._activeCallFrameDidChange();
72         }
73
74         WebInspector.issueManager.addEventListener(WebInspector.IssueManager.Event.IssueWasAdded, this._issueWasAdded, this);
75
76         if (this._sourceCode instanceof WebInspector.SourceMapResource || this._sourceCode.sourceMaps.length > 0)
77             WebInspector.notifications.addEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._updateTokenTrackingControllerState, this);
78         else
79             this._sourceCode.addEventListener(WebInspector.SourceCode.Event.SourceMapAdded, this._sourceCodeSourceMapAdded, this);
80
81         sourceCode.requestContent().then(this._contentAvailable.bind(this));
82
83         // FIXME: Cmd+L shorcut doesn't actually work.
84         new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.Command, "L", this.showGoToLineDialog.bind(this), this.element);
85         new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.Control, "G", this.showGoToLineDialog.bind(this), this.element);
86     }
87
88     // Public
89
90     get sourceCode()
91     {
92         return this._sourceCode;
93     }
94
95     shown()
96     {
97         WebInspector.TextEditor.prototype.shown.call(this);
98
99         if (WebInspector.showJavaScriptTypeInformationSetting.value) {
100             if (this._typeTokenAnnotator)
101                 this._typeTokenAnnotator.resume();
102             if (this._basicBlockAnnotator)
103                 this._basicBlockAnnotator.resume();
104             if (!this._typeTokenScrollHandler && (this._typeTokenAnnotator || this._basicBlockAnnotator))
105                 this._enableScrollEventsForTypeTokenAnnotator();
106         } else {
107             if (this._typeTokenAnnotator || this._basicBlockAnnotator)
108                 this._setTypeTokenAnnotatorEnabledState(false);
109         }
110     }
111
112     hidden()
113     {
114         WebInspector.TextEditor.prototype.hidden.call(this);
115
116         this.tokenTrackingController.removeHighlightedRange();
117
118         this._dismissPopover();
119         
120         this._dismissEditingController(true);
121
122         if (this._typeTokenAnnotator)
123             this._typeTokenAnnotator.pause();
124         if (this._basicBlockAnnotator)
125             this._basicBlockAnnotator.pause();
126     }
127
128     close()
129     {
130         if (this._supportsDebugging) {
131             WebInspector.Breakpoint.removeEventListener(WebInspector.Breakpoint.Event.DisabledStateDidChange, this._breakpointStatusDidChange, this);
132             WebInspector.Breakpoint.removeEventListener(WebInspector.Breakpoint.Event.AutoContinueDidChange, this._breakpointStatusDidChange, this);
133             WebInspector.Breakpoint.removeEventListener(WebInspector.Breakpoint.Event.ResolvedStateDidChange, this._breakpointStatusDidChange, this);
134             WebInspector.Breakpoint.removeEventListener(WebInspector.Breakpoint.Event.LocationDidChange, this._updateBreakpointLocation, this);
135
136             WebInspector.debuggerManager.removeEventListener(WebInspector.DebuggerManager.Event.BreakpointsEnabledDidChange, this._breakpointsEnabledDidChange, this);
137             WebInspector.debuggerManager.removeEventListener(WebInspector.DebuggerManager.Event.BreakpointAdded, this._breakpointAdded, this);
138             WebInspector.debuggerManager.removeEventListener(WebInspector.DebuggerManager.Event.BreakpointRemoved, this._breakpointRemoved, this);
139             WebInspector.debuggerManager.removeEventListener(WebInspector.DebuggerManager.Event.ActiveCallFrameDidChange, this._activeCallFrameDidChange, this);
140
141             if (this._activeCallFrameSourceCodeLocation) {
142                 this._activeCallFrameSourceCodeLocation.removeEventListener(WebInspector.SourceCodeLocation.Event.LocationChanged, this._activeCallFrameSourceCodeLocationChanged, this);
143                 delete this._activeCallFrameSourceCodeLocation;
144             }
145         }
146
147         WebInspector.issueManager.removeEventListener(WebInspector.IssueManager.Event.IssueWasAdded, this._issueWasAdded, this);
148
149         WebInspector.notifications.removeEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._updateTokenTrackingControllerState, this);
150         this._sourceCode.removeEventListener(WebInspector.SourceCode.Event.SourceMapAdded, this._sourceCodeSourceMapAdded, this);
151     }
152
153     canBeFormatted()
154     {
155         // Currently we assume that source map resources are formatted how the author wants it.
156         // We could allow source map resources to be formatted, we would then need to make
157         // SourceCodeLocation watch listen for mappedResource's formatting changes, and keep
158         // a formatted location alongside the regular mapped location.
159         if (this._sourceCode instanceof WebInspector.SourceMapResource)
160             return false;
161
162         return WebInspector.TextEditor.prototype.canBeFormatted.call(this);
163     }
164
165     canShowTypeAnnotations()
166     {
167         return !!this._typeTokenAnnotator;
168     }
169
170     customPerformSearch(query)
171     {
172         function searchResultCallback(error, matches)
173         {
174             // Bail if the query changed since we started.
175             if (this.currentSearchQuery !== query)
176                 return;
177
178             if (error || !matches || !matches.length) {
179                 // Report zero matches.
180                 this.dispatchEventToListeners(WebInspector.TextEditor.Event.NumberOfSearchResultsDidChange);
181                 return;
182             }
183
184             var queryRegex = new RegExp(query.escapeForRegExp(), "gi");
185             var searchResults = [];
186
187             for (var i = 0; i < matches.length; ++i) {
188                 var matchLineNumber = matches[i].lineNumber;
189                 var line = this.line(matchLineNumber);
190                 if (!line)
191                     return;
192
193                 // Reset the last index to reuse the regex on a new line.
194                 queryRegex.lastIndex = 0;
195
196                 // Search the line and mark the ranges.
197                 var lineMatch = null;
198                 while (queryRegex.lastIndex + query.length <= line.length && (lineMatch = queryRegex.exec(line))) {
199                     var resultTextRange = new WebInspector.TextRange(matchLineNumber, lineMatch.index, matchLineNumber, queryRegex.lastIndex);
200                     searchResults.push(resultTextRange);
201                 }
202             }
203
204             this.addSearchResults(searchResults);
205
206             this.dispatchEventToListeners(WebInspector.TextEditor.Event.NumberOfSearchResultsDidChange);
207         }
208
209         if (this.hasEdits())
210             return false;
211
212         if (this._sourceCode instanceof WebInspector.SourceMapResource)
213             return false;
214
215         if (this._sourceCode instanceof WebInspector.Resource)
216             PageAgent.searchInResource(this._sourceCode.parentFrame.id, this._sourceCode.url, query, false, false, searchResultCallback.bind(this));
217         else if (this._sourceCode instanceof WebInspector.Script)
218             DebuggerAgent.searchInContent(this._sourceCode.id, query, false, false, searchResultCallback.bind(this));
219         return true;
220     }
221
222     showGoToLineDialog()
223     {
224         if (!this._goToLineDialog) {
225             this._goToLineDialog = new WebInspector.GoToLineDialog;
226             this._goToLineDialog.delegate = this;
227         }
228
229         this._goToLineDialog.present(this.element);
230     }
231
232     isGoToLineDialogValueValid(goToLineDialog, lineNumber)
233     {
234         return !isNaN(lineNumber) && lineNumber > 0 && lineNumber <= this.lineCount;
235     }
236
237     goToLineDialogValueWasValidated(goToLineDialog, lineNumber)
238     {
239         var position = new WebInspector.SourceCodePosition(lineNumber - 1, 0);
240         var range = new WebInspector.TextRange(lineNumber - 1, 0, lineNumber, 0);
241         this.revealPosition(position, range, false, true);
242     }
243
244     goToLineDialogWasDismissed()
245     {
246         this.focus();
247     }
248
249     contentDidChange(replacedRanges, newRanges)
250     {
251         super.contentDidChange(replacedRanges, newRanges);
252
253         if (this._ignoreContentDidChange > 0)
254             return;
255
256         for (var range of newRanges)
257             this._updateEditableMarkers(range);
258
259         if (this._typeTokenAnnotator || this._basicBlockAnnotator) {
260             this._setTypeTokenAnnotatorEnabledState(false);
261             this._typeTokenAnnotator = null;
262             this._basicBlockAnnotator = null;
263         }
264     }
265
266     toggleTypeAnnotations()
267     {
268         if (!this._typeTokenAnnotator)
269             return false;
270
271         var newActivatedState = !this._typeTokenAnnotator.isActive();
272         if (newActivatedState && this._isProbablyMinified && !this.formatted)
273             this.formatted = true;
274
275         this._setTypeTokenAnnotatorEnabledState(newActivatedState);
276         return newActivatedState;
277     }
278
279     showPopoverForTypes(types, bounds, title)
280     {
281         var content = document.createElement("div");
282         content.className = "object expandable";
283
284         var titleElement = document.createElement("div");
285         titleElement.className = "title";
286         titleElement.textContent = title;
287         content.appendChild(titleElement);
288
289         var section = new WebInspector.TypePropertiesSection(types);
290         section.expanded = true;
291         section.element.classList.add("body");
292         content.appendChild(section.element);
293
294         this._showPopover(content, bounds);
295     }
296
297     // Protected
298
299     prettyPrint(pretty)
300     {
301         // The annotators must be cleared before pretty printing takes place and resumed 
302         // after so that they clear their annotations in a known state and insert new annotations 
303         // in the new state.
304         var shouldResumeTypeTokenAnnotator = this._typeTokenAnnotator && this._typeTokenAnnotator.isActive();
305         var shouldResumeBasicBlockAnnotator = this._basicBlockAnnotator && this._basicBlockAnnotator.isActive();
306         if (shouldResumeTypeTokenAnnotator || shouldResumeBasicBlockAnnotator)
307             this._setTypeTokenAnnotatorEnabledState(false);
308
309         super.prettyPrint(pretty);
310
311         if (pretty || !this._isProbablyMinified) {
312             if (shouldResumeTypeTokenAnnotator || shouldResumeBasicBlockAnnotator)
313                 this._setTypeTokenAnnotatorEnabledState(true);
314         } else {
315             console.assert(!pretty && this._isProbablyMinified);
316             if (this._typeTokenAnnotator || this._basicBlockAnnotator)
317                 this._setTypeTokenAnnotatorEnabledState(false);
318         }
319     }
320
321     // Private
322
323     _unformattedLineInfoForEditorLineInfo(lineInfo)
324     {
325         if (this.formatterSourceMap)
326             return this.formatterSourceMap.formattedToOriginal(lineInfo.lineNumber, lineInfo.columnNumber);
327         return lineInfo;
328     }
329
330     _sourceCodeLocationForEditorPosition(position)
331     {
332         var lineInfo = {lineNumber: position.line, columnNumber: position.ch};
333         var unformattedLineInfo = this._unformattedLineInfoForEditorLineInfo(lineInfo);
334         return this.sourceCode.createSourceCodeLocation(unformattedLineInfo.lineNumber, unformattedLineInfo.columnNumber);
335     }
336
337     _editorLineInfoForSourceCodeLocation(sourceCodeLocation)
338     {
339         if (this._sourceCode instanceof WebInspector.SourceMapResource)
340             return {lineNumber: sourceCodeLocation.displayLineNumber, columnNumber: sourceCodeLocation.displayColumnNumber};
341         return {lineNumber: sourceCodeLocation.formattedLineNumber, columnNumber: sourceCodeLocation.formattedColumnNumber};
342     }
343
344     _breakpointForEditorLineInfo(lineInfo)
345     {
346         if (!this._breakpointMap[lineInfo.lineNumber])
347             return null;
348         return this._breakpointMap[lineInfo.lineNumber][lineInfo.columnNumber];
349     }
350
351     _addBreakpointWithEditorLineInfo(breakpoint, lineInfo)
352     {
353         if (!this._breakpointMap[lineInfo.lineNumber])
354             this._breakpointMap[lineInfo.lineNumber] = {};
355
356         this._breakpointMap[lineInfo.lineNumber][lineInfo.columnNumber] = breakpoint;
357     }
358
359     _removeBreakpointWithEditorLineInfo(breakpoint, lineInfo)
360     {
361         console.assert(breakpoint === this._breakpointMap[lineInfo.lineNumber][lineInfo.columnNumber]);
362
363         delete this._breakpointMap[lineInfo.lineNumber][lineInfo.columnNumber];
364
365         if (isEmptyObject(this._breakpointMap[lineInfo.lineNumber]))
366             delete this._breakpointMap[lineInfo.lineNumber];
367     }
368
369     _contentWillPopulate(content)
370     {
371         this.dispatchEventToListeners(WebInspector.SourceCodeTextEditor.Event.ContentWillPopulate);
372
373         // We only do the rest of this work before the first populate.
374         if (this._contentPopulated)
375             return;
376
377         if (this._supportsDebugging) {
378             this._breakpointMap = {};
379
380             var breakpoints = WebInspector.debuggerManager.breakpointsForSourceCode(this._sourceCode);
381             for (var i = 0; i < breakpoints.length; ++i) {
382                 var breakpoint = breakpoints[i];
383                 console.assert(this._matchesBreakpoint(breakpoint));
384                 var lineInfo = this._editorLineInfoForSourceCodeLocation(breakpoint.sourceCodeLocation);
385                 this._addBreakpointWithEditorLineInfo(breakpoint, lineInfo);
386                 this.setBreakpointInfoForLineAndColumn(lineInfo.lineNumber, lineInfo.columnNumber, this._breakpointInfoForBreakpoint(breakpoint));
387             }
388         }
389
390         if (this._sourceCode instanceof WebInspector.Resource)
391             this.mimeType = this._sourceCode.syntheticMIMEType;
392         else if (this._sourceCode instanceof WebInspector.Script)
393             this.mimeType = "text/javascript";
394
395         // Automatically format the content if it looks minified and it can be formatted.
396         console.assert(!this.formatted);
397         if (this.canBeFormatted()) {
398             var lastNewlineIndex = 0;
399             while (true) {
400                 var nextNewlineIndex = content.indexOf("\n", lastNewlineIndex);
401                 if (nextNewlineIndex === -1) {
402                     if (content.length - lastNewlineIndex > WebInspector.SourceCodeTextEditor.AutoFormatMinimumLineLength) {
403                         this.autoFormat = true;
404                         this._isProbablyMinified = true;
405                     }
406                     break;
407                 }
408
409                 if (nextNewlineIndex - lastNewlineIndex > WebInspector.SourceCodeTextEditor.AutoFormatMinimumLineLength) {
410                     this.autoFormat = true;
411                     this._isProbablyMinified = true;
412                     break;
413                 }
414
415                 lastNewlineIndex = nextNewlineIndex + 1;
416             }
417         }
418     }
419
420     _contentDidPopulate()
421     {
422         this._contentPopulated = true;
423
424         this.dispatchEventToListeners(WebInspector.SourceCodeTextEditor.Event.ContentDidPopulate);
425
426         // We add the issues each time content is populated. This is needed because lines might not exist
427         // if we tried added them before when the full content wasn't available. (When populating with
428         // partial script content this can be called multiple times.)
429
430         this._reinsertAllIssues();
431
432         this._updateEditableMarkers();
433     }
434
435     _populateWithContent(content)
436     {
437         content = content || "";
438
439         this._contentWillPopulate(content);
440         this.string = content;
441
442         this._makeTypeTokenAnnotator();
443         this._makeBasicBlockAnnotator();
444
445         if (WebInspector.showJavaScriptTypeInformationSetting.value) {
446             if (this._basicBlockAnnotator || this._typeTokenAnnotator)
447                 this._setTypeTokenAnnotatorEnabledState(true);
448         }
449
450         this._contentDidPopulate();
451     }
452
453     _contentAvailable(parameters)
454     {
455         // Return if resource is not available.
456         if (parameters.error)
457             return;
458
459         var sourceCode = parameters.sourceCode;
460         var content = parameters.content;
461         var base64Encoded = parameters.base64Encoded;
462
463         console.assert(sourceCode === this._sourceCode);
464         console.assert(!base64Encoded);
465
466         // Abort if the full content populated while waiting for this async callback.
467         if (this._fullContentPopulated)
468             return;
469
470         this._fullContentPopulated = true;
471         this._invalidLineNumbers = {};
472
473         this._populateWithContent(content);
474     }
475
476     _breakpointStatusDidChange(event)
477     {
478         this._updateBreakpointStatus(event.target);
479     }
480
481     _breakpointsEnabledDidChange()
482     {
483         console.assert(this._supportsDebugging);
484
485         var breakpoints = WebInspector.debuggerManager.breakpointsForSourceCode(this._sourceCode);
486         for (var breakpoint of breakpoints)
487             this._updateBreakpointStatus(breakpoint);
488     }
489
490     _updateBreakpointStatus(breakpoint)
491     {
492         console.assert(this._supportsDebugging);
493
494         if (!this._contentPopulated)
495             return;
496
497         if (!this._matchesBreakpoint(breakpoint))
498             return;
499
500         var lineInfo = this._editorLineInfoForSourceCodeLocation(breakpoint.sourceCodeLocation);
501         this.setBreakpointInfoForLineAndColumn(lineInfo.lineNumber, lineInfo.columnNumber, this._breakpointInfoForBreakpoint(breakpoint));
502     }
503
504     _updateBreakpointLocation(event)
505     {
506         console.assert(this._supportsDebugging);
507
508         if (!this._contentPopulated)
509             return;
510
511         var breakpoint = event.target;
512         if (!this._matchesBreakpoint(breakpoint))
513             return;
514
515         if (this._ignoreAllBreakpointLocationUpdates)
516             return;
517
518         if (breakpoint === this._ignoreLocationUpdateBreakpoint)
519             return;
520
521         var sourceCodeLocation = breakpoint.sourceCodeLocation;
522
523         if (this._sourceCode instanceof WebInspector.SourceMapResource) {
524             // Update our breakpoint location if the display location changed.
525             if (sourceCodeLocation.displaySourceCode !== this._sourceCode)
526                 return;
527             var oldLineInfo = {lineNumber: event.data.oldDisplayLineNumber, columnNumber: event.data.oldDisplayColumnNumber};
528             var newLineInfo = {lineNumber: sourceCodeLocation.displayLineNumber, columnNumber: sourceCodeLocation.displayColumnNumber};
529         } else {
530             // Update our breakpoint location if the original location changed.
531             if (sourceCodeLocation.sourceCode !== this._sourceCode)
532                 return;
533             var oldLineInfo = {lineNumber: event.data.oldFormattedLineNumber, columnNumber: event.data.oldFormattedColumnNumber};
534             var newLineInfo = {lineNumber: sourceCodeLocation.formattedLineNumber, columnNumber: sourceCodeLocation.formattedColumnNumber};
535         }
536
537         var existingBreakpoint = this._breakpointForEditorLineInfo(oldLineInfo);
538         if (!existingBreakpoint)
539             return;
540
541         console.assert(breakpoint === existingBreakpoint);
542
543         this.setBreakpointInfoForLineAndColumn(oldLineInfo.lineNumber, oldLineInfo.columnNumber, null);
544         this.setBreakpointInfoForLineAndColumn(newLineInfo.lineNumber, newLineInfo.columnNumber, this._breakpointInfoForBreakpoint(breakpoint));
545
546         this._removeBreakpointWithEditorLineInfo(breakpoint, oldLineInfo);
547         this._addBreakpointWithEditorLineInfo(breakpoint, newLineInfo);
548     }
549
550     _breakpointAdded(event)
551     {
552         console.assert(this._supportsDebugging);
553
554         if (!this._contentPopulated)
555             return;
556
557         var breakpoint = event.data.breakpoint;
558         if (!this._matchesBreakpoint(breakpoint))
559             return;
560
561         if (breakpoint === this._ignoreBreakpointAddedBreakpoint)
562             return;
563
564         var lineInfo = this._editorLineInfoForSourceCodeLocation(breakpoint.sourceCodeLocation);
565         this._addBreakpointWithEditorLineInfo(breakpoint, lineInfo);
566         this.setBreakpointInfoForLineAndColumn(lineInfo.lineNumber, lineInfo.columnNumber, this._breakpointInfoForBreakpoint(breakpoint));
567     }
568
569     _breakpointRemoved(event)
570     {
571         console.assert(this._supportsDebugging);
572
573         if (!this._contentPopulated)
574             return;
575
576         var breakpoint = event.data.breakpoint;
577         if (!this._matchesBreakpoint(breakpoint))
578             return;
579
580         if (breakpoint === this._ignoreBreakpointRemovedBreakpoint)
581             return;
582
583         var lineInfo = this._editorLineInfoForSourceCodeLocation(breakpoint.sourceCodeLocation);
584         this._removeBreakpointWithEditorLineInfo(breakpoint, lineInfo);
585         this.setBreakpointInfoForLineAndColumn(lineInfo.lineNumber, lineInfo.columnNumber, null);
586     }
587
588     _activeCallFrameDidChange()
589     {
590         console.assert(this._supportsDebugging);
591
592         if (this._activeCallFrameSourceCodeLocation) {
593             this._activeCallFrameSourceCodeLocation.removeEventListener(WebInspector.SourceCodeLocation.Event.LocationChanged, this._activeCallFrameSourceCodeLocationChanged, this);
594             delete this._activeCallFrameSourceCodeLocation;
595         }
596
597         var activeCallFrame = WebInspector.debuggerManager.activeCallFrame;
598         if (!activeCallFrame || !this._matchesSourceCodeLocation(activeCallFrame.sourceCodeLocation)) {
599             this.executionLineNumber = NaN;
600             this.executionColumnNumber = NaN;
601             return;
602         }
603
604         this._dismissPopover();
605
606         this._activeCallFrameSourceCodeLocation = activeCallFrame.sourceCodeLocation;
607         this._activeCallFrameSourceCodeLocation.addEventListener(WebInspector.SourceCodeLocation.Event.LocationChanged, this._activeCallFrameSourceCodeLocationChanged, this);
608
609         // Don't return early if the line number didn't change. The execution state still
610         // could have changed (e.g. continuing in a loop with a breakpoint inside).
611
612         var lineInfo = this._editorLineInfoForSourceCodeLocation(activeCallFrame.sourceCodeLocation);
613         this.executionLineNumber = lineInfo.lineNumber;
614         this.executionColumnNumber = lineInfo.columnNumber;
615
616         // If we have full content or this source code isn't a Resource we can return early.
617         // Script source code populates from the request started in the constructor.
618         if (this._fullContentPopulated || !(this._sourceCode instanceof WebInspector.Resource) || this._requestingScriptContent)
619             return;
620
621         // Since we are paused in the debugger we need to show some content, and since the Resource
622         // content hasn't populated yet we need to populate with content from the Scripts by URL.
623         // Document resources will attempt to populate the scripts as inline (in <script> tags.)
624         // Other resources are assumed to be full scripts (JavaScript resources).
625         if (this._sourceCode.type === WebInspector.Resource.Type.Document)
626             this._populateWithInlineScriptContent();
627         else
628             this._populateWithScriptContent();
629     }
630
631     _activeCallFrameSourceCodeLocationChanged(event)
632     {
633         console.assert(!isNaN(this.executionLineNumber));
634         if (isNaN(this.executionLineNumber))
635             return;
636
637         console.assert(WebInspector.debuggerManager.activeCallFrame);
638         console.assert(this._activeCallFrameSourceCodeLocation === WebInspector.debuggerManager.activeCallFrame.sourceCodeLocation);
639
640         var lineInfo = this._editorLineInfoForSourceCodeLocation(this._activeCallFrameSourceCodeLocation);
641         this.executionLineNumber = lineInfo.lineNumber;
642         this.executionColumnNumber = lineInfo.columnNumber;
643     }
644
645     _populateWithInlineScriptContent()
646     {
647         console.assert(this._sourceCode instanceof WebInspector.Resource);
648         console.assert(!this._fullContentPopulated);
649         console.assert(!this._requestingScriptContent);
650
651         var scripts = this._sourceCode.scripts;
652         console.assert(scripts.length);
653         if (!scripts.length)
654             return;
655
656         var pendingRequestCount = scripts.length;
657
658         // If the number of scripts hasn't change since the last populate, then there is nothing to do.
659         if (this._inlineScriptContentPopulated === pendingRequestCount)
660             return;
661
662         this._inlineScriptContentPopulated = pendingRequestCount;
663
664         function scriptContentAvailable(parameters)
665         {
666             // Return early if we are still waiting for content from other scripts.
667             if (--pendingRequestCount)
668                 return;
669
670             delete this._requestingScriptContent;
671
672             // Abort if the full content populated while waiting for these async callbacks.
673             if (this._fullContentPopulated)
674                 return;
675
676             var scriptOpenTag = "<script>";
677             var scriptCloseTag = "</script>";
678
679             var content = "";
680             var lineNumber = 0;
681             var columnNumber = 0;
682
683             this._invalidLineNumbers = {};
684
685             for (var i = 0; i < scripts.length; ++i) {
686                 // Fill the line gap with newline characters.
687                 for (var newLinesCount = scripts[i].range.startLine - lineNumber; newLinesCount > 0; --newLinesCount) {
688                     if (!columnNumber)
689                         this._invalidLineNumbers[scripts[i].range.startLine - newLinesCount] = true;
690                     columnNumber = 0;
691                     content += "\n";
692                 }
693
694                 // Fill the column gap with space characters.
695                 for (var spacesCount = scripts[i].range.startColumn - columnNumber - scriptOpenTag.length; spacesCount > 0; --spacesCount)
696                     content += " ";
697
698                 // Add script tags and content.
699                 content += scriptOpenTag;
700                 content += scripts[i].content;
701                 content += scriptCloseTag;
702
703                 lineNumber = scripts[i].range.endLine;
704                 columnNumber = scripts[i].range.endColumn + scriptCloseTag.length;
705             }
706
707             this._populateWithContent(content);
708         }
709
710         this._requestingScriptContent = true;
711
712         var boundScriptContentAvailable = scriptContentAvailable.bind(this);
713         for (var i = 0; i < scripts.length; ++i)
714             scripts[i].requestContent().then(boundScriptContentAvailable);
715     }
716
717     _populateWithScriptContent()
718     {
719         console.assert(this._sourceCode instanceof WebInspector.Resource);
720         console.assert(!this._fullContentPopulated);
721         console.assert(!this._requestingScriptContent);
722
723         // We can assume this resource only has one script that starts at line/column 0.
724         var scripts = this._sourceCode.scripts;
725         console.assert(scripts.length === 1);
726         if (!scripts.length)
727             return;
728
729         console.assert(scripts[0].range.startLine === 0);
730         console.assert(scripts[0].range.startColumn === 0);
731
732         function scriptContentAvailable(parameters)
733         {
734             var content = parameters.content;
735             delete this._requestingScriptContent;
736
737             // Abort if the full content populated while waiting for this async callback.
738             if (this._fullContentPopulated)
739                 return;
740
741             // This is the full content.
742             this._fullContentPopulated = true;
743
744             this._populateWithContent(content);
745         }
746
747         this._requestingScriptContent = true;
748
749         scripts[0].requestContent().then(scriptContentAvailable.bind(this));
750     }
751
752     _matchesSourceCodeLocation(sourceCodeLocation)
753     {
754         if (this._sourceCode instanceof WebInspector.SourceMapResource)
755             return sourceCodeLocation.displaySourceCode === this._sourceCode;
756         if (this._sourceCode instanceof WebInspector.Resource)
757             return sourceCodeLocation.sourceCode.url === this._sourceCode.url;
758         if (this._sourceCode instanceof WebInspector.Script)
759             return sourceCodeLocation.sourceCode === this._sourceCode;
760         return false;
761     }
762
763     _matchesBreakpoint(breakpoint)
764     {
765         console.assert(this._supportsDebugging);
766         if (this._sourceCode instanceof WebInspector.SourceMapResource)
767             return breakpoint.sourceCodeLocation.displaySourceCode === this._sourceCode;
768         if (this._sourceCode instanceof WebInspector.Resource)
769             return breakpoint.url === this._sourceCode.url;
770         if (this._sourceCode instanceof WebInspector.Script)
771             return breakpoint.url === this._sourceCode.url || breakpoint.scriptIdentifier === this._sourceCode.id;
772         return false;
773     }
774
775     _matchesIssue(issue)
776     {
777         if (this._sourceCode instanceof WebInspector.Resource)
778             return issue.url === this._sourceCode.url;
779         // FIXME: Support issues for Scripts based on id, not only by URL.
780         if (this._sourceCode instanceof WebInspector.Script)
781             return issue.url === this._sourceCode.url;
782         return false;
783     }
784
785     _issueWasAdded(event)
786     {
787         var issue = event.data.issue;
788         if (!this._matchesIssue(issue))
789             return;
790
791         this._addIssue(issue);
792     }
793
794     _addIssue(issue)
795     {
796         // FIXME: Issue should have a SourceCodeLocation.
797         var sourceCodeLocation = this._sourceCode.createSourceCodeLocation(issue.lineNumber, issue.columnNumber);
798         var lineNumber = sourceCodeLocation.formattedLineNumber;
799
800         var lineNumberIssues = this._issuesLineNumberMap.get(lineNumber);
801         if (!lineNumberIssues) {
802             lineNumberIssues = [];
803             this._issuesLineNumberMap.set(lineNumber, lineNumberIssues);
804         }
805
806         // Avoid displaying duplicate issues on the same line.
807         for (var existingIssue of lineNumberIssues) {
808             if (existingIssue.columnNumber === issue.columnNumber && existingIssue.text === issue.text)
809                 return;
810         }
811
812         lineNumberIssues.push(issue);
813
814         if (issue.level === WebInspector.IssueMessage.Level.Error)
815             this.addStyleClassToLine(lineNumber, WebInspector.SourceCodeTextEditor.LineErrorStyleClassName);
816         else if (issue.level === WebInspector.IssueMessage.Level.Warning)
817             this.addStyleClassToLine(lineNumber, WebInspector.SourceCodeTextEditor.LineWarningStyleClassName);
818         else
819             console.error("Unknown issue level");
820
821         var widget = this._issueWidgetForLine(lineNumber);
822         if (widget) {
823             if (issue.level === WebInspector.IssueMessage.Level.Error)
824                 widget.widgetElement.classList.add(WebInspector.SourceCodeTextEditor.LineErrorStyleClassName);
825             else if (issue.level === WebInspector.IssueMessage.Level.Warning)
826                 widget.widgetElement.classList.add(WebInspector.SourceCodeTextEditor.LineWarningStyleClassName);
827
828             this._updateIssueWidgetForIssues(widget, lineNumberIssues);
829         }
830     }
831
832     _issueWidgetForLine(lineNumber)
833     {
834         var widget = this._widgetMap.get(lineNumber);
835         if (widget)
836             return widget;
837
838         widget = this.createWidgetForLine(lineNumber);
839         if (!widget)
840             return null;
841
842         var widgetElement = widget.widgetElement;
843         widgetElement.classList.add("issue-widget");
844         widgetElement.classList.add("inline");
845         widgetElement.addEventListener("click", this._handleWidgetClick.bind(this, widget, lineNumber));
846
847         this._widgetMap.set(lineNumber, widget);
848
849         return widget;
850     }
851
852     _iconClassNameForIssueLevel(level)
853     {
854         if (level === WebInspector.IssueMessage.Level.Warning)
855             return "icon-warning";
856
857         console.assert(level === WebInspector.IssueMessage.Level.Error);
858         return "icon-error";
859     }
860
861     _updateIssueWidgetForIssues(widget, issues)
862     {
863         var widgetElement = widget.widgetElement;
864         widgetElement.removeChildren();
865
866         if (widgetElement.classList.contains("inline") || issues.length === 1) {
867             var arrowElement = widgetElement.appendChild(document.createElement("span"));
868             arrowElement.className = "arrow";
869
870             var iconElement = widgetElement.appendChild(document.createElement("span"));
871             iconElement.className = "icon";            
872
873             var textElement = widgetElement.appendChild(document.createElement("span"));
874             textElement.className = "text";
875
876             if (issues.length === 1) {
877                 iconElement.classList.add(this._iconClassNameForIssueLevel(issues[0].level));
878                 textElement.textContent = issues[0].text;
879             } else {
880                 var errorsCount = 0;
881                 var warningsCount = 0;
882                 for (var issue of issues) {
883                     if (issue.level === WebInspector.IssueMessage.Level.Error)
884                         ++errorsCount;
885                     else if (issue.level === WebInspector.IssueMessage.Level.Warning)
886                         ++warningsCount;
887                 }
888
889                 if (warningsCount && errorsCount) {
890                     iconElement.classList.add(this._iconClassNameForIssueLevel(issue.level));
891                     textElement.textContent = WebInspector.UIString("%d Errors, %d Warnings").format(errorsCount, warningsCount);
892                 } else if (errorsCount) {
893                     iconElement.classList.add(this._iconClassNameForIssueLevel(issue.level));
894                     textElement.textContent = WebInspector.UIString("%d Errors").format(errorsCount);
895                 } else if (warningsCount) {
896                     iconElement.classList.add(this._iconClassNameForIssueLevel(issue.level));
897                     textElement.textContent = WebInspector.UIString("%d Warnings").format(warningsCount);
898                 }
899
900                 widget[WebInspector.SourceCodeTextEditor.WidgetContainsMultipleIssuesSymbol] = true;
901             }
902         } else {
903             for (var issue of issues) {
904                 var iconElement = widgetElement.appendChild(document.createElement("span"));
905                 iconElement.className = "icon";
906                 iconElement.classList.add(this._iconClassNameForIssueLevel(issue.level));
907
908                 var textElement = widgetElement.appendChild(document.createElement("span"));
909                 textElement.className = "text";
910                 textElement.textContent = issue.text;
911
912                 widgetElement.appendChild(document.createElement("br"));
913             }
914         }
915
916         widget.update();
917     }
918
919     _isWidgetToggleable(widget)
920     {
921         if (widget[WebInspector.SourceCodeTextEditor.WidgetContainsMultipleIssuesSymbol])
922             return true;
923
924         if (!widget.widgetElement.classList.contains("inline"))
925             return true;
926
927         var textElement = widget.widgetElement.lastChild;
928         if (textElement.offsetWidth !== textElement.scrollWidth)
929             return true;
930         
931         return false;
932     }
933
934     _handleWidgetClick(widget, lineNumber, event)
935     {
936         if (!this._isWidgetToggleable(widget))
937             return;
938
939         widget.widgetElement.classList.toggle("inline");
940
941         var lineNumberIssues = this._issuesLineNumberMap.get(lineNumber);
942         this._updateIssueWidgetForIssues(widget, lineNumberIssues);
943     }
944
945     _breakpointInfoForBreakpoint(breakpoint)
946     {
947         return {resolved: breakpoint.resolved, disabled: breakpoint.disabled, autoContinue: breakpoint.autoContinue};
948     }
949
950     get _supportsDebugging()
951     {
952         if (this._sourceCode instanceof WebInspector.Resource)
953             return this._sourceCode.type === WebInspector.Resource.Type.Document || this._sourceCode.type === WebInspector.Resource.Type.Script;
954         if (this._sourceCode instanceof WebInspector.Script)
955             return true;
956         return false;
957     }
958
959     // TextEditor Delegate
960
961     textEditorBaseURL(textEditor)
962     {
963         return this._sourceCode.url;
964     }
965
966     textEditorShouldHideLineNumber(textEditor, lineNumber)
967     {
968         return lineNumber in this._invalidLineNumbers;
969     }
970
971     textEditorGutterContextMenu(textEditor, lineNumber, columnNumber, editorBreakpoints, event)
972     {
973         if (!this._supportsDebugging)
974             return;
975
976         event.preventDefault();
977
978         function continueToLocation()
979         {
980             WebInspector.debuggerManager.continueToLocation(script.id, sourceCodeLocation.lineNumber, sourceCodeLocation.columnNumber);
981         }
982
983         function addBreakpoint()
984         {
985             var data = this.textEditorBreakpointAdded(this, lineNumber, columnNumber);
986             this.setBreakpointInfoForLineAndColumn(data.lineNumber, data.columnNumber, data.breakpointInfo);
987         }
988
989         function revealInSidebar()
990         {
991             WebInspector.debuggerSidebarPanel.show();
992             var treeElement = WebInspector.debuggerSidebarPanel.treeElementForRepresentedObject(breakpoint);
993             if (treeElement)
994                 treeElement.revealAndSelect();
995         }
996
997         var contextMenu = new WebInspector.ContextMenu(event);
998
999         // Paused. Add Continue to Here option only if we have a script identifier for the location.
1000         if (WebInspector.debuggerManager.paused) {
1001             var editorLineInfo = {lineNumber, columnNumber};
1002             var unformattedLineInfo = this._unformattedLineInfoForEditorLineInfo(editorLineInfo);
1003             var sourceCodeLocation = this._sourceCode.createSourceCodeLocation(unformattedLineInfo.lineNumber, unformattedLineInfo.columnNumber);
1004
1005             if (sourceCodeLocation.sourceCode instanceof WebInspector.Script)
1006                 var script = sourceCodeLocation.sourceCode;
1007             else if (sourceCodeLocation.sourceCode instanceof WebInspector.Resource)
1008                 var script = sourceCodeLocation.sourceCode.scriptForLocation(sourceCodeLocation);
1009
1010             if (script) {
1011
1012                 contextMenu.appendItem(WebInspector.UIString("Continue to Here"), continueToLocation);
1013                 contextMenu.appendSeparator();
1014             }
1015         }
1016
1017         var breakpoints = [];
1018         for (var i = 0; i < editorBreakpoints.length; ++i) {
1019             var lineInfo = editorBreakpoints[i];
1020             var breakpoint = this._breakpointForEditorLineInfo(lineInfo);
1021             console.assert(breakpoint);
1022             if (breakpoint)
1023                 breakpoints.push(breakpoint);
1024         }
1025
1026         // No breakpoints.
1027         if (!breakpoints.length) {
1028
1029             contextMenu.appendItem(WebInspector.UIString("Add Breakpoint"), addBreakpoint.bind(this));
1030             contextMenu.show();
1031             return;
1032         }
1033
1034         // Single breakpoint.
1035         if (breakpoints.length === 1) {
1036             var breakpoint = breakpoints[0];
1037
1038             breakpoint.appendContextMenuItems(contextMenu, event.target);
1039             contextMenu.appendSeparator();
1040             contextMenu.appendItem(WebInspector.UIString("Reveal in Debugger Navigation Sidebar"), revealInSidebar);
1041             contextMenu.show();
1042             return;
1043         }
1044
1045         // Multiple breakpoints.
1046         var shouldDisable = false;
1047         for (var i = 0; i < breakpoints.length; ++i) {
1048             if (!breakpoints[i].disabled) {
1049                 shouldDisable = true;
1050                 break;
1051             }
1052         }
1053
1054         function removeBreakpoints()
1055         {
1056             for (var i = 0; i < breakpoints.length; ++i) {
1057                 var breakpoint = breakpoints[i];
1058                 if (WebInspector.debuggerManager.isBreakpointRemovable(breakpoint))
1059                     WebInspector.debuggerManager.removeBreakpoint(breakpoint);
1060             }
1061         }
1062
1063         function toggleBreakpoints()
1064         {
1065             for (var i = 0; i < breakpoints.length; ++i)
1066                 breakpoints[i].disabled = shouldDisable;
1067         }
1068
1069         if (shouldDisable)
1070             contextMenu.appendItem(WebInspector.UIString("Disable Breakpoints"), toggleBreakpoints.bind(this));
1071         else
1072             contextMenu.appendItem(WebInspector.UIString("Enable Breakpoints"), toggleBreakpoints.bind(this));
1073         contextMenu.appendItem(WebInspector.UIString("Delete Breakpoints"), removeBreakpoints.bind(this));
1074         contextMenu.show();
1075     }
1076
1077     textEditorBreakpointAdded(textEditor, lineNumber, columnNumber)
1078     {
1079         if (!this._supportsDebugging)
1080             return null;
1081
1082         var editorLineInfo = {lineNumber, columnNumber};
1083         var unformattedLineInfo = this._unformattedLineInfoForEditorLineInfo(editorLineInfo);
1084         var sourceCodeLocation = this._sourceCode.createSourceCodeLocation(unformattedLineInfo.lineNumber, unformattedLineInfo.columnNumber);
1085         var breakpoint = new WebInspector.Breakpoint(sourceCodeLocation);
1086
1087         var lineInfo = this._editorLineInfoForSourceCodeLocation(breakpoint.sourceCodeLocation);
1088         this._addBreakpointWithEditorLineInfo(breakpoint, lineInfo);
1089
1090         this._ignoreBreakpointAddedBreakpoint = breakpoint;
1091
1092         var shouldSkipEventDispatch = false;
1093         var shouldSpeculativelyResolveBreakpoint = true;
1094         WebInspector.debuggerManager.addBreakpoint(breakpoint, shouldSkipEventDispatch, shouldSpeculativelyResolveBreakpoint);
1095         delete this._ignoreBreakpointAddedBreakpoint;
1096
1097         // Return the more accurate location and breakpoint info.
1098         return {
1099             breakpointInfo: this._breakpointInfoForBreakpoint(breakpoint),
1100             lineNumber: lineInfo.lineNumber,
1101             columnNumber: lineInfo.columnNumber
1102         };
1103     }
1104
1105     textEditorBreakpointRemoved(textEditor, lineNumber, columnNumber)
1106     {
1107         console.assert(this._supportsDebugging);
1108         if (!this._supportsDebugging)
1109             return;
1110
1111         var lineInfo = {lineNumber, columnNumber};
1112         var breakpoint = this._breakpointForEditorLineInfo(lineInfo);
1113         console.assert(breakpoint);
1114         if (!breakpoint)
1115             return;
1116
1117         this._removeBreakpointWithEditorLineInfo(breakpoint, lineInfo);
1118
1119         this._ignoreBreakpointRemovedBreakpoint = breakpoint;
1120         WebInspector.debuggerManager.removeBreakpoint(breakpoint);
1121         delete this._ignoreBreakpointAddedBreakpoint;
1122     }
1123
1124     textEditorBreakpointMoved(textEditor, oldLineNumber, oldColumnNumber, newLineNumber, newColumnNumber)
1125     {
1126         console.assert(this._supportsDebugging);
1127         if (!this._supportsDebugging)
1128             return;
1129
1130         var oldLineInfo = {lineNumber: oldLineNumber, columnNumber: oldColumnNumber};
1131         var breakpoint = this._breakpointForEditorLineInfo(oldLineInfo);
1132         console.assert(breakpoint);
1133         if (!breakpoint)
1134             return;
1135
1136         this._removeBreakpointWithEditorLineInfo(breakpoint, oldLineInfo);
1137
1138         var newLineInfo = {lineNumber: newLineNumber, columnNumber: newColumnNumber};
1139         var unformattedNewLineInfo = this._unformattedLineInfoForEditorLineInfo(newLineInfo);
1140         this._ignoreLocationUpdateBreakpoint = breakpoint;
1141         breakpoint.sourceCodeLocation.update(this._sourceCode, unformattedNewLineInfo.lineNumber, unformattedNewLineInfo.columnNumber);
1142         delete this._ignoreLocationUpdateBreakpoint;
1143
1144         var accurateNewLineInfo = this._editorLineInfoForSourceCodeLocation(breakpoint.sourceCodeLocation);
1145         this._addBreakpointWithEditorLineInfo(breakpoint, accurateNewLineInfo);
1146
1147         if (accurateNewLineInfo.lineNumber !== newLineInfo.lineNumber || accurateNewLineInfo.columnNumber !== newLineInfo.columnNumber)
1148             this.updateBreakpointLineAndColumn(newLineInfo.lineNumber, newLineInfo.columnNumber, accurateNewLineInfo.lineNumber, accurateNewLineInfo.columnNumber);
1149     }
1150
1151     textEditorBreakpointClicked(textEditor, lineNumber, columnNumber)
1152     {
1153         console.assert(this._supportsDebugging);
1154         if (!this._supportsDebugging)
1155             return;
1156
1157         var breakpoint = this._breakpointForEditorLineInfo({lineNumber, columnNumber});
1158         console.assert(breakpoint);
1159         if (!breakpoint)
1160             return;
1161
1162         breakpoint.cycleToNextMode();
1163     }
1164
1165     textEditorUpdatedFormatting(textEditor)
1166     {
1167         this._ignoreAllBreakpointLocationUpdates = true;
1168         this._sourceCode.formatterSourceMap = this.formatterSourceMap;
1169         delete this._ignoreAllBreakpointLocationUpdates;
1170
1171         // Always put the source map on both the Script and Resource if both exist. For example,
1172         // if this SourceCode is a Resource, then there might also be a Script. In the debugger,
1173         // the backend identifies call frames with Script line and column information, and the
1174         // Script needs the formatter source map to produce the proper display line and column.
1175         if (this._sourceCode instanceof WebInspector.Resource && !(this._sourceCode instanceof WebInspector.SourceMapResource)) {
1176             var scripts = this._sourceCode.scripts;
1177             for (var i = 0; i < scripts.length; ++i)
1178                 scripts[i].formatterSourceMap = this.formatterSourceMap;
1179         } else if (this._sourceCode instanceof WebInspector.Script) {
1180             if (this._sourceCode.resource)
1181                 this._sourceCode.resource.formatterSourceMap = this.formatterSourceMap;
1182         }
1183
1184         // Some breakpoints / issues may have moved, some might not have. Just go through
1185         // and remove and reinsert all the breakpoints / issues.
1186
1187         var oldBreakpointMap = this._breakpointMap;
1188         this._breakpointMap = {};
1189
1190         for (var lineNumber in oldBreakpointMap) {
1191             for (var columnNumber in oldBreakpointMap[lineNumber]) {
1192                 var breakpoint = oldBreakpointMap[lineNumber][columnNumber];
1193                 var newLineInfo = this._editorLineInfoForSourceCodeLocation(breakpoint.sourceCodeLocation);
1194                 this._addBreakpointWithEditorLineInfo(breakpoint, newLineInfo);
1195                 this.setBreakpointInfoForLineAndColumn(lineNumber, columnNumber, null);
1196                 this.setBreakpointInfoForLineAndColumn(newLineInfo.lineNumber, newLineInfo.columnNumber, this._breakpointInfoForBreakpoint(breakpoint));
1197             }
1198         }
1199
1200         this._reinsertAllIssues();
1201     }
1202
1203     _clearWidgets()
1204     {
1205         for (var widget of this._widgetMap.values())
1206             widget.clear();
1207
1208         this._widgetMap.clear();
1209     }
1210
1211     _reinsertAllIssues()
1212     {
1213         this._issuesLineNumberMap.clear();
1214         this._clearWidgets();
1215
1216         var issues = WebInspector.issueManager.issuesForSourceCode(this._sourceCode);
1217         for (var issue of issues) {
1218             console.assert(this._matchesIssue(issue));
1219             this._addIssue(issue);
1220         }
1221     }
1222
1223     _debuggerDidPause(event)
1224     {
1225         this._updateTokenTrackingControllerState();
1226         if (this._typeTokenAnnotator && this._typeTokenAnnotator.isActive())
1227             this._typeTokenAnnotator.refresh();
1228         if (this._basicBlockAnnotator && this._basicBlockAnnotator.isActive())
1229             this._basicBlockAnnotator.refresh();
1230     }
1231
1232     _debuggerDidResume(event)
1233     {
1234         this._updateTokenTrackingControllerState();
1235         this._dismissPopover();
1236         if (this._typeTokenAnnotator && this._typeTokenAnnotator.isActive())
1237             this._typeTokenAnnotator.refresh();
1238         if (this._basicBlockAnnotator && this._basicBlockAnnotator.isActive())
1239             this._basicBlockAnnotator.refresh();
1240     }
1241
1242     _sourceCodeSourceMapAdded(event)
1243     {
1244         WebInspector.notifications.addEventListener(WebInspector.Notification.GlobalModifierKeysDidChange, this._updateTokenTrackingControllerState, this);
1245         this._sourceCode.removeEventListener(WebInspector.SourceCode.Event.SourceMapAdded, this._sourceCodeSourceMapAdded, this);
1246
1247         this._updateTokenTrackingControllerState();
1248     }
1249
1250     _updateTokenTrackingControllerState()
1251     {
1252         var mode = WebInspector.CodeMirrorTokenTrackingController.Mode.None;
1253         if (WebInspector.debuggerManager.paused)
1254             mode = WebInspector.CodeMirrorTokenTrackingController.Mode.JavaScriptExpression;
1255         else if (this._typeTokenAnnotator && this._typeTokenAnnotator.isActive())
1256             mode = WebInspector.CodeMirrorTokenTrackingController.Mode.JavaScriptTypeInformation;
1257         else if (this._hasColorMarkers())
1258             mode = WebInspector.CodeMirrorTokenTrackingController.Mode.MarkedTokens;
1259         else if ((this._sourceCode instanceof WebInspector.SourceMapResource || this._sourceCode.sourceMaps.length !== 0) && WebInspector.modifierKeys.metaKey && !WebInspector.modifierKeys.altKey && !WebInspector.modifierKeys.shiftKey)
1260             mode = WebInspector.CodeMirrorTokenTrackingController.Mode.NonSymbolTokens;
1261
1262         this.tokenTrackingController.enabled = mode !== WebInspector.CodeMirrorTokenTrackingController.Mode.None;
1263
1264         if (mode === this.tokenTrackingController.mode)
1265             return;
1266
1267         switch (mode) {
1268         case WebInspector.CodeMirrorTokenTrackingController.Mode.MarkedTokens:
1269             this.tokenTrackingController.mouseOverDelayDuration = 0;
1270             this.tokenTrackingController.mouseOutReleaseDelayDuration = 0;
1271             break;
1272         case WebInspector.CodeMirrorTokenTrackingController.Mode.NonSymbolTokens:
1273             this.tokenTrackingController.mouseOverDelayDuration = 0;
1274             this.tokenTrackingController.mouseOutReleaseDelayDuration = 0;
1275             this.tokenTrackingController.classNameForHighlightedRange = WebInspector.CodeMirrorTokenTrackingController.JumpToSymbolHighlightStyleClassName;
1276             this._dismissPopover();
1277             break;
1278         case WebInspector.CodeMirrorTokenTrackingController.Mode.JavaScriptExpression:
1279         case WebInspector.CodeMirrorTokenTrackingController.Mode.JavaScriptTypeInformation:
1280             this.tokenTrackingController.mouseOverDelayDuration = WebInspector.SourceCodeTextEditor.DurationToMouseOverTokenToMakeHoveredToken;
1281             this.tokenTrackingController.mouseOutReleaseDelayDuration = WebInspector.SourceCodeTextEditor.DurationToMouseOutOfHoveredTokenToRelease;
1282             this.tokenTrackingController.classNameForHighlightedRange = WebInspector.SourceCodeTextEditor.HoveredExpressionHighlightStyleClassName;
1283             break;
1284         }
1285
1286         this.tokenTrackingController.mode = mode;
1287     }
1288
1289     _hasColorMarkers()
1290     {
1291         for (var marker of this.markers) {
1292             if (marker.type === WebInspector.TextMarker.Type.Color)
1293                 return true;
1294         }
1295         return false;
1296     }
1297
1298     // CodeMirrorTokenTrackingController Delegate
1299
1300     tokenTrackingControllerCanReleaseHighlightedRange(tokenTrackingController, element)
1301     {
1302         if (!this._popover)
1303             return true;
1304
1305         if (!window.getSelection().isCollapsed && this._popover.element.contains(window.getSelection().anchorNode))
1306             return false;
1307
1308         return true;
1309     }
1310
1311     tokenTrackingControllerHighlightedRangeReleased(tokenTrackingController)
1312     {
1313         if (!this._mouseIsOverPopover)
1314             this._dismissPopover();
1315     }
1316
1317     tokenTrackingControllerHighlightedRangeWasClicked(tokenTrackingController)
1318     {
1319         if (this.tokenTrackingController.mode !== WebInspector.CodeMirrorTokenTrackingController.Mode.NonSymbolTokens)
1320             return;
1321
1322         // Links are handled by TextEditor.
1323         if (/\blink\b/.test(this.tokenTrackingController.candidate.hoveredToken.type))
1324             return;
1325
1326         var sourceCodeLocation = this._sourceCodeLocationForEditorPosition(this.tokenTrackingController.candidate.hoveredTokenRange.start);
1327         if (this.sourceCode instanceof WebInspector.SourceMapResource)
1328             WebInspector.resourceSidebarPanel.showOriginalOrFormattedSourceCodeLocation(sourceCodeLocation);
1329         else
1330             WebInspector.resourceSidebarPanel.showSourceCodeLocation(sourceCodeLocation);
1331     }
1332
1333     tokenTrackingControllerNewHighlightCandidate(tokenTrackingController, candidate)
1334     {
1335         if (this.tokenTrackingController.mode === WebInspector.CodeMirrorTokenTrackingController.Mode.NonSymbolTokens) {
1336             this.tokenTrackingController.highlightRange(candidate.hoveredTokenRange);
1337             return;
1338         }
1339
1340         if (this.tokenTrackingController.mode === WebInspector.CodeMirrorTokenTrackingController.Mode.JavaScriptExpression) {
1341             this._tokenTrackingControllerHighlightedJavaScriptExpression(candidate);
1342             return;
1343         }
1344
1345         if (this.tokenTrackingController.mode === WebInspector.CodeMirrorTokenTrackingController.Mode.JavaScriptTypeInformation) {
1346             this._tokenTrackingControllerHighlightedJavaScriptTypeInformation(candidate);
1347             return;
1348         }
1349
1350         if (this.tokenTrackingController.mode === WebInspector.CodeMirrorTokenTrackingController.Mode.MarkedTokens) {
1351             var markers = this.markersAtPosition(candidate.hoveredTokenRange.start);
1352             if (markers.length > 0)
1353                 this._tokenTrackingControllerHighlightedMarkedExpression(candidate, markers);
1354             else
1355                 this._dismissEditingController();
1356         }
1357     }
1358
1359     tokenTrackingControllerMouseOutOfHoveredMarker(tokenTrackingController, hoveredMarker)
1360     {
1361         this._dismissEditingController();
1362     }
1363
1364     _tokenTrackingControllerHighlightedJavaScriptExpression(candidate)
1365     {
1366         console.assert(candidate.expression);
1367
1368         function populate(error, result, wasThrown)
1369         {
1370             if (error || wasThrown)
1371                 return;
1372
1373             if (candidate !== this.tokenTrackingController.candidate)
1374                 return;
1375
1376             var data = WebInspector.RemoteObject.fromPayload(result);
1377             switch (data.type) {
1378             case "function":
1379                 this._showPopoverForFunction(data);
1380                 break;
1381             case "object":
1382                 if (data.subtype === "null" || data.subtype === "regexp")
1383                     this._showPopoverWithFormattedValue(data);
1384                 else
1385                     this._showPopoverForObject(data);
1386                 break;
1387             case "string":
1388             case "number":
1389             case "boolean":
1390             case "undefined":
1391             case "symbol":
1392                 this._showPopoverWithFormattedValue(data);
1393                 break;
1394             }
1395         }
1396
1397         if (WebInspector.debuggerManager.activeCallFrame) {
1398             DebuggerAgent.evaluateOnCallFrame.invoke({callFrameId: WebInspector.debuggerManager.activeCallFrame.id, expression: candidate.expression, objectGroup: "popover", doNotPauseOnExceptionsAndMuteConsole: true}, populate.bind(this));
1399             return;
1400         }
1401
1402         // No call frame available. Use the main page's context.
1403         RuntimeAgent.evaluate.invoke({expression: candidate.expression, objectGroup: "popover", doNotPauseOnExceptionsAndMuteConsole: true}, populate.bind(this));
1404     }
1405
1406     _tokenTrackingControllerHighlightedJavaScriptTypeInformation(candidate)
1407     {
1408         console.assert(candidate.expression);
1409
1410         var sourceCode = this._sourceCode;
1411         var sourceID = sourceCode instanceof WebInspector.Script ? sourceCode.id : sourceCode.scripts[0].id;
1412         var range = candidate.hoveredTokenRange;
1413         var offset = this.currentPositionToOriginalOffset({line: range.start.line, ch: range.start.ch});
1414
1415         var allRequests = [{
1416             typeInformationDescriptor: WebInspector.ScriptSyntaxTree.TypeProfilerSearchDescriptor.NormalExpression,
1417             sourceID,
1418             divot: offset
1419         }];
1420
1421         function handler(error, allTypes) {
1422             if (error)
1423                 return;
1424
1425             if (candidate !== this.tokenTrackingController.candidate)
1426                 return;
1427
1428             console.assert(allTypes.length === 1);
1429             if (!allTypes.length)
1430                 return;
1431             var types = allTypes[0];
1432             if (types.isValid) {
1433                 var popoverTitle = WebInspector.TypeTokenView.titleForPopover(WebInspector.TypeTokenView.TitleType.Variable, candidate.expression);
1434                 this.showPopoverForTypes(types, null, popoverTitle);
1435             }
1436         }
1437
1438         RuntimeAgent.getRuntimeTypesForVariablesAtOffsets(allRequests, handler.bind(this));
1439     }
1440
1441     _showPopover(content, bounds)
1442     {
1443         console.assert(this.tokenTrackingController.candidate || bounds);
1444
1445         var shouldHighlightRange = false;
1446         var candidate = this.tokenTrackingController.candidate;
1447         // If bounds is falsey, this is a popover introduced from a hover event.
1448         // Otherwise, this is called from TypeTokenAnnotator.
1449         if (!bounds) {
1450             if (!candidate)
1451                 return;
1452
1453             var rects = this.rectsForRange(candidate.hoveredTokenRange);
1454             bounds = WebInspector.Rect.unionOfRects(rects);
1455
1456             shouldHighlightRange = true;
1457         }
1458
1459         content.classList.add(WebInspector.SourceCodeTextEditor.PopoverDebuggerContentStyleClassName);
1460
1461         this._popover = this._popover || new WebInspector.Popover(this);
1462         this._popover.presentNewContentWithFrame(content, bounds.pad(5), [WebInspector.RectEdge.MIN_Y, WebInspector.RectEdge.MAX_Y, WebInspector.RectEdge.MAX_X]);
1463         if (shouldHighlightRange)
1464             this.tokenTrackingController.highlightRange(candidate.expressionRange);
1465
1466         this._trackPopoverEvents();
1467     }
1468
1469     _showPopoverForFunction(data)
1470     {
1471         var candidate = this.tokenTrackingController.candidate;
1472
1473         function didGetDetails(error, response)
1474         {
1475             if (error) {
1476                 console.error(error);
1477                 this._dismissPopover();
1478                 return;
1479             }
1480
1481             // Nothing to do if the token has changed since the time we
1482             // asked for the function details from the backend.
1483             if (candidate !== this.tokenTrackingController.candidate)
1484                 return;
1485
1486             var wrapper = document.createElement("div");
1487             wrapper.className = "body formatted-function";
1488             wrapper.textContent = data.description;
1489
1490             var content = document.createElement("div");
1491             content.className = "function";
1492
1493             var title = content.appendChild(document.createElement("div"));
1494             title.className = "title";
1495             title.textContent = response.name || response.inferredName || response.displayName || WebInspector.UIString("(anonymous function)");
1496
1497             content.appendChild(wrapper);
1498
1499             this._showPopover(content);
1500         }
1501         DebuggerAgent.getFunctionDetails(data.objectId, didGetDetails.bind(this));
1502     }
1503
1504     _showPopoverForObject(data)
1505     {
1506         var content = document.createElement("div");
1507         content.className = "object expandable";
1508
1509         var titleElement = document.createElement("div");
1510         titleElement.className = "title";
1511         titleElement.textContent = data.description;
1512         content.appendChild(titleElement);
1513
1514         // FIXME: If this is a variable, it would be nice to put the variable name in the PropertyPath.
1515         var objectTree = new WebInspector.ObjectTreeView(data);
1516         objectTree.showOnlyProperties();
1517         objectTree.expand();
1518
1519         var bodyElement = content.appendChild(document.createElement("div"));
1520         bodyElement.className = "body";
1521         bodyElement.appendChild(objectTree.element);
1522
1523         this._showPopover(content);
1524     }
1525
1526     _showPopoverWithFormattedValue(remoteObject)
1527     {
1528         var content = WebInspector.FormattedValue.createElementForRemoteObject(remoteObject);
1529         this._showPopover(content);
1530     }
1531
1532     willDismissPopover(popover)
1533     {
1534         this.tokenTrackingController.removeHighlightedRange();
1535
1536         RuntimeAgent.releaseObjectGroup("popover");
1537     }
1538
1539     _dismissPopover()
1540     {
1541         if (!this._popover)
1542             return;
1543
1544         this._popover.dismiss();
1545
1546         if (this._popoverEventListeners && this._popoverEventListenersAreRegistered) {
1547             this._popoverEventListenersAreRegistered = false;
1548             this._popoverEventListeners.unregister();
1549         }
1550     }
1551
1552     _trackPopoverEvents()
1553     {
1554         if (!this._popoverEventListeners) 
1555             this._popoverEventListeners = new WebInspector.EventListenerSet(this, "Popover listeners");
1556         if (!this._popoverEventListenersAreRegistered) {
1557             this._popoverEventListenersAreRegistered = true;
1558             this._popoverEventListeners.register(this._popover.element, "mouseover", this._popoverMouseover);
1559             this._popoverEventListeners.register(this._popover.element, "mouseout", this._popoverMouseout);
1560             this._popoverEventListeners.install();
1561         }
1562     }
1563
1564     _popoverMouseover(event)
1565     {
1566         this._mouseIsOverPopover = true;
1567     }
1568
1569     _popoverMouseout(event)
1570     {
1571         this._mouseIsOverPopover = this._popover.element.contains(event.relatedTarget);
1572     }
1573
1574     _updateEditableMarkers(range)
1575     {
1576         this.createColorMarkers(range);
1577         this.createGradientMarkers(range);
1578
1579         this._updateTokenTrackingControllerState();
1580     }
1581
1582     _tokenTrackingControllerHighlightedMarkedExpression(candidate, markers)
1583     {
1584         // Look for the outermost editable marker.
1585         var editableMarker;
1586         for (var marker of markers) {
1587             if (!marker.range || (marker.type !== WebInspector.TextMarker.Type.Color && marker.type !== WebInspector.TextMarker.Type.Gradient))
1588                 continue;
1589
1590             if (!editableMarker || (marker.range.startLine < editableMarker.range.startLine || (marker.range.startLine === editableMarker.range.startLine && marker.range.startColumn < editableMarker.range.startColumn)))
1591                 editableMarker = marker;
1592         }
1593
1594         if (!editableMarker) {
1595             this.tokenTrackingController.hoveredMarker = null;
1596             return;
1597         }
1598
1599         if (this.tokenTrackingController.hoveredMarker === editableMarker)
1600             return;
1601
1602         this._dismissEditingController();
1603
1604         this.tokenTrackingController.hoveredMarker = editableMarker;
1605
1606         this._editingController = this.editingControllerForMarker(editableMarker);
1607
1608         if (marker.type === WebInspector.TextMarker.Type.Color) {
1609             var color = this._editingController.value;
1610             if (!color || !color.valid) {
1611                 editableMarker.clear();
1612                 delete this._editingController;
1613                 return;
1614             }
1615         }
1616
1617         this._editingController.delegate = this;
1618         this._editingController.presentHoverMenu();
1619     }
1620
1621     _dismissEditingController(discrete)
1622     {
1623         if (this._editingController)
1624             this._editingController.dismissHoverMenu(discrete);
1625         
1626         this.tokenTrackingController.hoveredMarker = null;
1627         delete this._editingController;
1628     }
1629
1630     // CodeMirrorEditingController Delegate
1631     
1632     editingControllerDidStartEditing(editingController)
1633     {
1634         // We can pause the token tracking controller during editing, it will be reset
1635         // to the expected state by calling _updateEditableMarkers() in the
1636         // editingControllerDidFinishEditing delegate.
1637         this.tokenTrackingController.enabled = false;
1638
1639         // We clear the marker since we'll reset it after editing.
1640         editingController.marker.clear();
1641         
1642         // We ignore content changes made as a result of color editing.
1643         this._ignoreContentDidChange++;
1644     }
1645     
1646     editingControllerDidFinishEditing(editingController)
1647     {
1648         this._updateEditableMarkers(editingController.range);
1649
1650         this._ignoreContentDidChange--;
1651
1652         delete this._editingController;
1653     }
1654
1655     _setTypeTokenAnnotatorEnabledState(shouldActivate)
1656     {
1657         console.assert(this._typeTokenAnnotator);
1658         if (!this._typeTokenAnnotator)
1659             return;
1660
1661         if (shouldActivate) {
1662             RuntimeAgent.enableTypeProfiler();
1663
1664             this._typeTokenAnnotator.reset();
1665             if (this._basicBlockAnnotator) {
1666                 console.assert(!this._basicBlockAnnotator.isActive());
1667                 this._basicBlockAnnotator.reset();
1668             }
1669
1670             if (!this._typeTokenScrollHandler)
1671                 this._enableScrollEventsForTypeTokenAnnotator();
1672         } else {
1673             // Because we disable type profiling when exiting the inspector, there is no need to call 
1674             // RuntimeAgent.disableTypeProfiler() here.  If we were to call it here, JavaScriptCore would 
1675             // compile out all the necessary type profiling information, so if a user were to quickly press then 
1676             // unpress the type profiling button, we wouldn't be able to re-show type information which would 
1677             // provide a confusing user experience.
1678
1679             this._typeTokenAnnotator.clear();
1680             if (this._basicBlockAnnotator)
1681                 this._basicBlockAnnotator.clear();
1682
1683             if (this._typeTokenScrollHandler)
1684                 this._disableScrollEventsForTypeTokenAnnotator();
1685         }
1686
1687         WebInspector.showJavaScriptTypeInformationSetting.value = shouldActivate;
1688
1689         this._updateTokenTrackingControllerState();
1690     }
1691
1692     _getAssociatedScript()
1693     {
1694         var script = null;
1695         // FIXME: This needs to me modified to work with HTML files with inline script tags.
1696         if (this._sourceCode instanceof WebInspector.Script)
1697             script = this._sourceCode;
1698         else if (this._sourceCode instanceof WebInspector.Resource && this._sourceCode.type === WebInspector.Resource.Type.Script && this._sourceCode.scripts.length)
1699             script = this._sourceCode.scripts[0];
1700         return script;
1701     }
1702
1703     _makeTypeTokenAnnotator()
1704     {
1705         if (!RuntimeAgent.getRuntimeTypesForVariablesAtOffsets)
1706             return;
1707
1708         var script = this._getAssociatedScript();
1709         if (!script)
1710             return;
1711
1712         this._typeTokenAnnotator = new WebInspector.TypeTokenAnnotator(this, script);
1713     }
1714
1715     _makeBasicBlockAnnotator()
1716     {
1717         if (!RuntimeAgent.getBasicBlocks)
1718             return;
1719
1720         var script = this._getAssociatedScript();
1721         if (!script)
1722             return;
1723
1724         this._basicBlockAnnotator = new WebInspector.BasicBlockAnnotator(this, script);
1725     }
1726
1727     _enableScrollEventsForTypeTokenAnnotator()
1728     {
1729         // Pause updating type tokens while scrolling to prevent frame loss.
1730         console.assert(!this._typeTokenScrollHandler);
1731         this._typeTokenScrollHandler = this._makeTypeTokenScrollEventHandler();
1732         this.addScrollHandler(this._typeTokenScrollHandler);
1733     }
1734
1735     _disableScrollEventsForTypeTokenAnnotator()
1736     {
1737         console.assert(this._typeTokenScrollHandler);
1738         this.removeScrollHandler(this._typeTokenScrollHandler);
1739         this._typeTokenScrollHandler = null;
1740     }
1741
1742     _makeTypeTokenScrollEventHandler()
1743     {
1744         var timeoutIdentifier = null;
1745         function scrollHandler()
1746         {
1747             if (timeoutIdentifier)
1748                 clearTimeout(timeoutIdentifier);
1749             else {
1750                 if (this._typeTokenAnnotator)
1751                     this._typeTokenAnnotator.pause();
1752                 if (this._basicBlockAnnotator)
1753                     this._basicBlockAnnotator.pause();
1754             }
1755
1756             timeoutIdentifier = setTimeout(function() {
1757                 timeoutIdentifier = null;
1758                 if (this._typeTokenAnnotator)
1759                     this._typeTokenAnnotator.resume();
1760                 if (this._basicBlockAnnotator)
1761                     this._basicBlockAnnotator.resume();
1762             }.bind(this), WebInspector.SourceCodeTextEditor.DurationToUpdateTypeTokensAfterScrolling);
1763         }
1764
1765         return scrollHandler.bind(this);
1766     }
1767 };
1768
1769 WebInspector.SourceCodeTextEditor.LineErrorStyleClassName = "error";
1770 WebInspector.SourceCodeTextEditor.LineWarningStyleClassName = "warning";
1771 WebInspector.SourceCodeTextEditor.PopoverDebuggerContentStyleClassName = "debugger-popover-content";
1772 WebInspector.SourceCodeTextEditor.HoveredExpressionHighlightStyleClassName = "hovered-expression-highlight";
1773 WebInspector.SourceCodeTextEditor.DurationToMouseOverTokenToMakeHoveredToken = 500;
1774 WebInspector.SourceCodeTextEditor.DurationToMouseOutOfHoveredTokenToRelease = 1000;
1775 WebInspector.SourceCodeTextEditor.DurationToUpdateTypeTokensAfterScrolling = 100;
1776 WebInspector.SourceCodeTextEditor.AutoFormatMinimumLineLength = 500;
1777 WebInspector.SourceCodeTextEditor.WidgetContainsMultipleIssuesSymbol = Symbol("source-code-widget-contains-multiple-issues");
1778
1779 WebInspector.SourceCodeTextEditor.Event = {
1780     ContentWillPopulate: "source-code-text-editor-content-will-populate",
1781     ContentDidPopulate: "source-code-text-editor-content-did-populate"
1782 };