Modified: trunk/Source/WebInspectorUI/ChangeLog (199168 => 199169)
--- trunk/Source/WebInspectorUI/ChangeLog 2016-04-07 19:29:32 UTC (rev 199168)
+++ trunk/Source/WebInspectorUI/ChangeLog 2016-04-07 19:29:38 UTC (rev 199169)
@@ -1,5 +1,117 @@
2016-04-07 Joseph Pecoraro <[email protected]>
+ Web Inspector: Inspector hangs when trying to view a large XHR resource
+ https://bugs.webkit.org/show_bug.cgi?id=144107
+ <rdar://problem/20669463>
+
+ Reviewed by Timothy Hatcher.
+
+ Previously auto formatting (initial pretty print of source code) in TextEditor
+ was done synchronously in this order:
+
+ (1) revealing the Editor as soon as we have content
+ (2) set the CodeMirror value
+ (3) pretty print with the CodeMirror editor
+ (4) set the CodeMirror value
+ => Layout
+
+ At the end, CodeMirror would layout once with the new content. This approach
+ performs very poorly when step (3) is an asynchronous action, because it would
+ mean CodeMirror would layout for both (2) and at the end (4) and the layout
+ itself can be very costly if the content is minified and so has very long
+ lines at the top of the file that need to be syntax highlighted and visible
+ since we do not wrap.
+
+ This patch changes the order of operations to benefit asynchronous formatting.
+ When SourceCodeTextEditor determines that it can autoformat it:
+
+ (1) set the CodeMirror value
+ (2) pretty print to source text
+ (3) reveal the Editor when pretty printing is done
+ (4) set the CodeMirror value
+ => Layout
+
+ This maintains the fact that to undo pretty printing we can just "undo" the
+ editor to get the original text. This also means we only do a single
+ CodeMirror layout, with the pretty printed and therefore more manageable
+ source text for highlighting. It also means we continue to show a loading
+ indicator in the editor while we are pretty printing. If this is truely
+ done asynchronously, which is the case for _javascript_ with FormatterWorker,
+ then the loading indicator will animate smoothly.
+
+ This sequence also works with the traditional synchronous formatters,
+ which we still have for CSS.
+
+ * UserInterface/Views/ContentView.js:
+ (WebInspector.ContentView.contentViewForRepresentedObject):
+ * UserInterface/Views/NavigationSidebarPanel.js:
+ (WebInspector.NavigationSidebarPanel.prototype.showDefaultContentViewForTreeElement):
+ (WebInspector.NavigationSidebarPanel.prototype._checkElementsForPendingViewStateCookie):
+ BreakpointTreeElements can now be restored and reselected when its
+ source code is null. Avoid deleting the pending cookie data if a
+ ContentView was not shown for the resource. When the Breakpoint
+ and SourceCode get hooked up, this code will run again and work.
+
+ * UserInterface/Views/ScriptContentView.js:
+ (WebInspector.ScriptContentView.prototype._togglePrettyPrint):
+ * UserInterface/Views/TextResourceContentView.js:
+ (WebInspector.TextResourceContentView.prototype._togglePrettyPrint):
+ * UserInterface/Views/TextContentView.js:
+ (WebInspector.TextContentView.prototype._togglePrettyPrint):
+ New API for toggling formatting, now that it is an async operation.
+
+ * UserInterface/Views/SourceCodeTextEditor.js:
+ (WebInspector.SourceCodeTextEditor):
+ (WebInspector.SourceCodeTextEditor.prototype.toggleTypeAnnotations):
+ (WebInspector.SourceCodeTextEditor.prototype.prettyPrint):
+ (WebInspector.SourceCodeTextEditor.prototype._populateWithContent):
+ (WebInspector.SourceCodeTextEditor.prototype._proceedPopulateWithContent):
+ (WebInspector.SourceCodeTextEditor.prototype._prepareEditorForInitialContent):
+ (WebInspector.SourceCodeTextEditor.prototype._populateWithInlineScriptContent.scriptContentAvailable):
+ (WebInspector.SourceCodeTextEditor.prototype._populateWithInlineScriptContent):
+ (WebInspector.SourceCodeTextEditor.prototype._populateWithScriptContent):
+ (WebInspector.SourceCodeTextEditor.prototype.textEditorUpdatedFormatting):
+ (WebInspector.SourceCodeTextEditor.prototype._contentWillPopulate): Deleted.
+ Move auto formatting logic into SourceCodeTextEditor, because it
+ determines if content should be auto formatted, and it loads the
+ initial content so it can determine when to show the editor for
+ the first time.
+
+ When we get the initial content and determine we have to autoformat,
+ setup the TextEditor, but don't proceed with WillPopulate/DidPopulate
+ until after we have formatted text.
+
+ * UserInterface/Views/TextEditor.js:
+ (WebInspector.TextEditor):
+ (WebInspector.TextEditor.set string.update):
+ (WebInspector.TextEditor.prototype.set string):
+ (WebInspector.TextEditor.prototype.updateFormattedState):
+ (WebInspector.TextEditor.prototype.hasFormatter):
+ (WebInspector.TextEditor.prototype._format):
+ (WebInspector.TextEditor.prototype.prettyPrint):
+ (WebInspector.TextEditor.prototype._canUseFormatterWorker):
+ (WebInspector.TextEditor.prototype._startWorkerPrettyPrint):
+ (WebInspector.TextEditor.prototype._startCodeMirrorPrettyPrint):
+ (WebInspector.TextEditor.prototype._finishPrettyPrint):
+ (WebInspector.TextEditor.prototype._undoFormatting):
+ (WebInspector.TextEditor.prototype._updateAfterFormatting):
+ Break up the synchronous pretty printing code into multiple steps.
+ One path can be asynchronous formatting via FormatterWorker, another
+ path may be synchronous formatting using the CodeMirror formatters.
+
+ (WebInspector.TextEditor.prototype.set formatted): Deleted.
+ Remove the synchronous `set formatted` setter. Replace with
+ updateFormattedState().
+
+ (WebInspector.TextEditor.prototype.set autoFormat): Deleted.
+ Remove the TextEditor's autoformat. Since formatting can be async, having
+ the TextEditor showing and asynchronously format its initial contents is
+ a recipe for poor performance causing multiple layouts of different content.
+ Instead, autoformatting is handled by SourceCodeTextEditor, and TextEditor
+ can then be shown when it has the right data.
+
+2016-04-07 Joseph Pecoraro <[email protected]>
+
Web Inspector: Improve _javascript_ pretty printing
https://bugs.webkit.org/show_bug.cgi?id=156178
<rdar://problem/25535719>
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js (199168 => 199169)
--- trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js 2016-04-07 19:29:32 UTC (rev 199168)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js 2016-04-07 19:29:38 UTC (rev 199169)
@@ -40,11 +40,13 @@
this._contentPopulated = false;
this._invalidLineNumbers = {0: true};
this._ignoreContentDidChange = 0;
+ this._requestingScriptContent = false;
this._typeTokenScrollHandler = null;
this._typeTokenAnnotator = null;
this._basicBlockAnnotator = null;
+ this._autoFormat = false;
this._isProbablyMinified = false;
// FIXME: Currently this just jumps between resources and related source map resources. It doesn't "jump to symbol" yet.
@@ -260,8 +262,12 @@
return false;
var newActivatedState = !this._typeTokenAnnotator.isActive();
- if (newActivatedState && this._isProbablyMinified && !this.formatted)
- this.formatted = true;
+ if (newActivatedState && this._isProbablyMinified && !this.formatted) {
+ this.updateFormattedState(true).then(() => {
+ this._setTypeTokenAnnotatorEnabledState(newActivatedState);
+ });
+ return;
+ }
this._setTypeTokenAnnotatorEnabledState(newActivatedState);
return newActivatedState;
@@ -298,16 +304,16 @@
if (shouldResumeTypeTokenAnnotator || shouldResumeBasicBlockAnnotator)
this._setTypeTokenAnnotatorEnabledState(false);
- super.prettyPrint(pretty);
-
- if (pretty || !this._isProbablyMinified) {
- if (shouldResumeTypeTokenAnnotator || shouldResumeBasicBlockAnnotator)
- this._setTypeTokenAnnotatorEnabledState(true);
- } else {
- console.assert(!pretty && this._isProbablyMinified);
- if (this._typeTokenAnnotator || this._basicBlockAnnotator)
- this._setTypeTokenAnnotatorEnabledState(false);
- }
+ return super.prettyPrint(pretty).then(() => {
+ if (pretty || !this._isProbablyMinified) {
+ if (shouldResumeTypeTokenAnnotator || shouldResumeBasicBlockAnnotator)
+ this._setTypeTokenAnnotatorEnabledState(true);
+ } else {
+ console.assert(!pretty && this._isProbablyMinified);
+ if (this._typeTokenAnnotator || this._basicBlockAnnotator)
+ this._setTypeTokenAnnotatorEnabledState(false);
+ }
+ });
}
// Private
@@ -358,40 +364,6 @@
delete this._breakpointMap[lineInfo.lineNumber];
}
- _contentWillPopulate(content)
- {
- this.dispatchEventToListeners(WebInspector.SourceCodeTextEditor.Event.ContentWillPopulate);
-
- // We only do the rest of this work before the first populate.
- if (this._contentPopulated)
- return;
-
- if (this._supportsDebugging) {
- this._breakpointMap = {};
-
- var breakpoints = WebInspector.debuggerManager.breakpointsForSourceCode(this._sourceCode);
- for (var i = 0; i < breakpoints.length; ++i) {
- var breakpoint = breakpoints[i];
- console.assert(this._matchesBreakpoint(breakpoint));
- var lineInfo = this._editorLineInfoForSourceCodeLocation(breakpoint.sourceCodeLocation);
- this._addBreakpointWithEditorLineInfo(breakpoint, lineInfo);
- this.setBreakpointInfoForLineAndColumn(lineInfo.lineNumber, lineInfo.columnNumber, this._breakpointInfoForBreakpoint(breakpoint));
- }
- }
-
- if (this._sourceCode instanceof WebInspector.Resource)
- this.mimeType = this._sourceCode.syntheticMIMEType;
- else if (this._sourceCode instanceof WebInspector.Script)
- this.mimeType = "text/_javascript_";
-
- // Automatically format the content if it looks minified and it can be formatted.
- console.assert(!this.formatted);
- if (this.canBeFormatted() && this._isLikelyMinified(content)) {
- this.autoFormat = true;
- this._isProbablyMinified = true;
- }
- }
-
_isLikelyMinified(content)
{
let whiteSpaceCount = 0;
@@ -412,6 +384,43 @@
return ratio < 0.1;
}
+ _populateWithContent(content)
+ {
+ content = content || "";
+
+ this._prepareEditorForInitialContent(content);
+
+ // If we can auto format, format the TextEditor before showing it.
+ if (this._autoFormat) {
+ console.assert(!this.formatted);
+ this._autoFormat = false;
+ this.string = content;
+ this.updateFormattedState(true).then(() => {
+ this._proceedPopulateWithContent(this.string);
+ });
+ return;
+ }
+
+ this._proceedPopulateWithContent(content);
+ }
+
+ _proceedPopulateWithContent(content)
+ {
+ this.dispatchEventToListeners(WebInspector.SourceCodeTextEditor.Event.ContentWillPopulate);
+
+ this.string = content;
+
+ this._makeTypeTokenAnnotator();
+ this._makeBasicBlockAnnotator();
+
+ if (WebInspector.showJavaScriptTypeInformationSetting.value) {
+ if (this._basicBlockAnnotator || this._typeTokenAnnotator)
+ this._setTypeTokenAnnotatorEnabledState(true);
+ }
+
+ this._contentDidPopulate();
+ }
+
_contentDidPopulate()
{
this._contentPopulated = true;
@@ -427,22 +436,36 @@
this._updateEditableMarkers();
}
- _populateWithContent(content)
+ _prepareEditorForInitialContent(content)
{
- content = content || "";
+ // Only do this work before the first populate.
+ if (this._contentPopulated)
+ return;
- this._contentWillPopulate(content);
- this.string = content;
+ if (this._supportsDebugging) {
+ this._breakpointMap = {};
- this._makeTypeTokenAnnotator();
- this._makeBasicBlockAnnotator();
+ var breakpoints = WebInspector.debuggerManager.breakpointsForSourceCode(this._sourceCode);
+ for (var i = 0; i < breakpoints.length; ++i) {
+ var breakpoint = breakpoints[i];
+ console.assert(this._matchesBreakpoint(breakpoint));
+ var lineInfo = this._editorLineInfoForSourceCodeLocation(breakpoint.sourceCodeLocation);
+ this._addBreakpointWithEditorLineInfo(breakpoint, lineInfo);
+ this.setBreakpointInfoForLineAndColumn(lineInfo.lineNumber, lineInfo.columnNumber, this._breakpointInfoForBreakpoint(breakpoint));
+ }
+ }
- if (WebInspector.showJavaScriptTypeInformationSetting.value) {
- if (this._basicBlockAnnotator || this._typeTokenAnnotator)
- this._setTypeTokenAnnotatorEnabledState(true);
+ if (this._sourceCode instanceof WebInspector.Resource)
+ this.mimeType = this._sourceCode.syntheticMIMEType;
+ else if (this._sourceCode instanceof WebInspector.Script)
+ this.mimeType = "text/_javascript_";
+
+ // Decide to automatically format the content if it looks minified and it can be formatted.
+ console.assert(!this.formatted);
+ if (this.canBeFormatted() && this._isLikelyMinified(content)) {
+ this._autoFormat = true;
+ this._isProbablyMinified = true;
}
-
- this._contentDidPopulate();
}
_contentAvailable(parameters)
@@ -662,7 +685,7 @@
if (--pendingRequestCount)
return;
- delete this._requestingScriptContent;
+ this._requestingScriptContent = false;
// Abort if the full content populated while waiting for these async callbacks.
if (this._fullContentPopulated)
@@ -727,7 +750,7 @@
function scriptContentAvailable(parameters)
{
var content = parameters.content;
- delete this._requestingScriptContent;
+ this._requestingScriptContent = false;
// Abort if the full content populated while waiting for this async callback.
if (this._fullContentPopulated)
@@ -1137,7 +1160,7 @@
{
this._ignoreAllBreakpointLocationUpdates = true;
this._sourceCode.formatterSourceMap = this.formatterSourceMap;
- delete this._ignoreAllBreakpointLocationUpdates;
+ this._ignoreAllBreakpointLocationUpdates = false;
// Always put the source map on both the Script and Resource if both exist. For example,
// if this SourceCode is a Resource, then there might also be a Script. In the debugger,
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TextEditor.js (199168 => 199169)
--- trunk/Source/WebInspectorUI/UserInterface/Views/TextEditor.js 2016-04-07 19:29:32 UTC (rev 199168)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TextEditor.js 2016-04-07 19:29:38 UTC (rev 199169)
@@ -64,6 +64,7 @@
this._ignoreCodeMirrorContentDidChangeEvent = 0;
this._formatted = false;
+ this._formattingPromise = null;
this._formatterSourceMap = null;
this._delegate = delegate || null;
@@ -89,22 +90,20 @@
if (this._initialStringNotSet)
this._codeMirror.removeLineClass(0, "wrap");
- this._codeMirror.setValue(newString);
- console.assert(this.string.length === newString.length, "A lot of our code depends on precise text offsets, so the string should remain the same.");
+ if (this._codeMirror.getValue() !== newString) {
+ this._codeMirror.setValue(newString);
+ console.assert(this.string.length === newString.length, "A lot of our code depends on precise text offsets, so the string should remain the same.");
+ } else {
+ // Ensure we at display content even if the value did not change. This often happens when auto formatting.
+ this.layout();
+ }
if (this._initialStringNotSet) {
this._codeMirror.clearHistory();
this._codeMirror.markClean();
- delete this._initialStringNotSet;
+ this._initialStringNotSet = false;
}
- // Automatically format the content.
- if (this._autoFormat) {
- console.assert(!this.formatted);
- this.formatted = true;
- delete this._autoFormat;
- }
-
// Update the execution line now that we might have content for that line.
this._updateExecutionLine();
@@ -137,39 +136,15 @@
return this._formatted;
}
- set formatted(formatted)
+ updateFormattedState(formatted)
{
- if (this._formatted === formatted)
- return;
-
- console.assert(!formatted || this.canBeFormatted());
- if (formatted && !this.canBeFormatted())
- return;
-
- this._ignoreCodeMirrorContentDidChangeEvent++;
- this.prettyPrint(formatted);
- this._ignoreCodeMirrorContentDidChangeEvent--;
- console.assert(this._ignoreCodeMirrorContentDidChangeEvent >= 0);
-
- this._formatted = formatted;
-
- this.dispatchEventToListeners(WebInspector.TextEditor.Event.FormattingDidChange);
+ return this._format(formatted).catch(handlePromiseException);
}
- set autoFormat(auto)
- {
- this._autoFormat = auto;
- }
-
hasFormatter()
{
- var supportedModes = {
- "_javascript_": true,
- "css": true,
- };
-
- var mode = this._codeMirror.getMode();
- return mode.name in supportedModes;
+ let mode = this._codeMirror.getMode().name;
+ return mode === "_javascript_" || mode === "css";
}
canBeFormatted()
@@ -464,8 +439,9 @@
// If we need to unformat, reveal the line after a wait.
// Otherwise the line highlight doesn't work properly.
if (this._formatted && forceUnformatted) {
- this.formatted = false;
- setTimeout(this.revealPosition.bind(this), 0, position, textRangeToSelect);
+ this.updateFormattedState(false).then(() => {
+ setTimeout(this.revealPosition.bind(this), 0, position, textRangeToSelect);
+ });
return;
}
@@ -721,101 +697,186 @@
this._codeMirror.refresh();
}
+ _format(formatted)
+ {
+ if (this._formatted === formatted)
+ return Promise.resolve(this._formatted);
+
+ console.assert(!formatted || this.canBeFormatted());
+ if (formatted && !this.canBeFormatted())
+ return Promise.resolve(this._formatted);
+
+ if (this._formattingPromise)
+ return this._formattingPromise;
+
+ this._ignoreCodeMirrorContentDidChangeEvent++;
+ this._formattingPromise = this.prettyPrint(formatted).then(() => {
+ this._ignoreCodeMirrorContentDidChangeEvent--;
+ console.assert(this._ignoreCodeMirrorContentDidChangeEvent >= 0);
+
+ this._formattingPromise = null;
+
+ let originalFormatted = this._formatted;
+ this._formatted = !!this._formatterSourceMap;
+
+ if (this._formatted !== originalFormatted)
+ this.dispatchEventToListeners(WebInspector.TextEditor.Event.FormattingDidChange);
+
+ return this._formatted;
+ });
+
+ return this._formattingPromise;
+ }
+
prettyPrint(pretty)
{
- function prettyPrintAndUpdateEditor()
- {
- var start = {line: 0, ch: 0};
- var end = {line: this._codeMirror.lineCount() - 1};
+ return new Promise((resolve, reject) => {
+ let beforePrettyPrintState = {
+ selectionAnchor: this._codeMirror.getCursor("anchor"),
+ selectionHead: this._codeMirror.getCursor("head"),
+ };
- var oldSelectionAnchor = this._codeMirror.getCursor("anchor");
- var oldSelectionHead = this._codeMirror.getCursor("head");
- var newSelectionAnchor, newSelectionHead;
- var newExecutionLocation = null;
+ if (!pretty)
+ this._undoFormatting(beforePrettyPrintState, resolve);
+ else if (this._canUseFormatterWorker())
+ this._startWorkerPrettyPrint(beforePrettyPrintState, resolve);
+ else
+ this._startCodeMirrorPrettyPrint(beforePrettyPrintState, resolve);
+ });
+ }
- if (pretty) {
- // <rdar://problem/10593948> Provide a way to change the tab width in the Web Inspector
- var indentString = " ";
- var builder = new FormatterContentBuilder(indentString);
- var formatter = new WebInspector.Formatter(this._codeMirror, builder);
- formatter.format(start, end);
+ _canUseFormatterWorker()
+ {
+ return this._codeMirror.getMode().name === "_javascript_";
+ }
- this._formatterSourceMap = WebInspector.FormatterSourceMap.fromSourceMapData(builder.sourceMapData);
+ _startWorkerPrettyPrint(beforePrettyPrintState, callback)
+ {
+ // <rdar://problem/10593948> Provide a way to change the tab width in the Web Inspector
+ let indentString = " ";
+ let sourceText = this._codeMirror.getValue();
+ let includeSourceMapData = true;
- this._codeMirror.setValue(builder.formattedContent);
+ let workerProxy = WebInspector.FormatterWorkerProxy.singleton();
+ workerProxy.formatJavaScript(sourceText, indentString, includeSourceMapData, ({formattedText, sourceMapData}) => {
+ // Handle if formatting failed, which is possible for invalid programs.
+ if (formattedText === null) {
+ callback();
+ return;
+ }
+ this._finishPrettyPrint(beforePrettyPrintState, formattedText, sourceMapData, callback);
+ });
+ }
- if (this._positionToReveal) {
- var newRevealPosition = this._formatterSourceMap.originalToFormatted(this._positionToReveal.lineNumber, this._positionToReveal.columnNumber);
- this._positionToReveal = new WebInspector.SourceCodePosition(newRevealPosition.lineNumber, newRevealPosition.columnNumber);
- }
+ _startCodeMirrorPrettyPrint(beforePrettyPrintState, callback)
+ {
+ // <rdar://problem/10593948> Provide a way to change the tab width in the Web Inspector
+ let indentString = " ";
+ let start = {line: 0, ch: 0};
+ let end = {line: this._codeMirror.lineCount() - 1};
+ let builder = new FormatterContentBuilder(indentString);
+ let formatter = new WebInspector.Formatter(this._codeMirror, builder);
+ formatter.format(start, end);
- if (this._textRangeToSelect) {
- var mappedRevealSelectionStart = this._formatterSourceMap.originalToFormatted(this._textRangeToSelect.startLine, this._textRangeToSelect.startColumn);
- var mappedRevealSelectionEnd = this._formatterSourceMap.originalToFormatted(this._textRangeToSelect.endLine, this._textRangeToSelect.endColumn);
- this._textRangeToSelect = new WebInspector.TextRange(mappedRevealSelectionStart.lineNumber, mappedRevealSelectionStart.columnNumber, mappedRevealSelectionEnd.lineNumber, mappedRevealSelectionEnd.columnNumber);
- }
+ let formattedText = builder.formattedContent;
+ let sourceMapData = builder.sourceMapData;
+ this._finishPrettyPrint(beforePrettyPrintState, formattedText, sourceMapData, callback);
+ }
- if (!isNaN(this._executionLineNumber)) {
- console.assert(!isNaN(this._executionColumnNumber));
- newExecutionLocation = this._formatterSourceMap.originalToFormatted(this._executionLineNumber, this._executionColumnNumber);
- }
+ _finishPrettyPrint(beforePrettyPrintState, formattedText, sourceMapData, callback)
+ {
+ this._codeMirror.operation(() => {
+ this._formatterSourceMap = WebInspector.FormatterSourceMap.fromSourceMapData(sourceMapData);
+ this._codeMirror.setValue(formattedText);
+ this._updateAfterFormatting(true, beforePrettyPrintState);
+ });
- var mappedAnchorLocation = this._formatterSourceMap.originalToFormatted(oldSelectionAnchor.line, oldSelectionAnchor.ch);
- var mappedHeadLocation = this._formatterSourceMap.originalToFormatted(oldSelectionHead.line, oldSelectionHead.ch);
- newSelectionAnchor = {line: mappedAnchorLocation.lineNumber, ch: mappedAnchorLocation.columnNumber};
- newSelectionHead = {line: mappedHeadLocation.lineNumber, ch: mappedHeadLocation.columnNumber};
- } else {
- this._codeMirror.undo();
+ callback();
+ }
- if (this._positionToReveal) {
- var newRevealPosition = this._formatterSourceMap.formattedToOriginal(this._positionToReveal.lineNumber, this._positionToReveal.columnNumber);
- this._positionToReveal = new WebInspector.SourceCodePosition(newRevealPosition.lineNumber, newRevealPosition.columnNumber);
- }
+ _undoFormatting(beforePrettyPrintState, callback)
+ {
+ this._codeMirror.operation(() => {
+ this._codeMirror.undo();
+ this._updateAfterFormatting(false, beforePrettyPrintState);
+ });
- if (this._textRangeToSelect) {
- var mappedRevealSelectionStart = this._formatterSourceMap.formattedToOriginal(this._textRangeToSelect.startLine, this._textRangeToSelect.startColumn);
- var mappedRevealSelectionEnd = this._formatterSourceMap.formattedToOriginal(this._textRangeToSelect.endLine, this._textRangeToSelect.endColumn);
- this._textRangeToSelect = new WebInspector.TextRange(mappedRevealSelectionStart.lineNumber, mappedRevealSelectionStart.columnNumber, mappedRevealSelectionEnd.lineNumber, mappedRevealSelectionEnd.columnNumber);
- }
+ callback();
+ }
- if (!isNaN(this._executionLineNumber)) {
- console.assert(!isNaN(this._executionColumnNumber));
- newExecutionLocation = this._formatterSourceMap.formattedToOriginal(this._executionLineNumber, this._executionColumnNumber);
- }
+ _updateAfterFormatting(pretty, beforePrettyPrintState)
+ {
+ let oldSelectionAnchor = beforePrettyPrintState.selectionAnchor;
+ let oldSelectionHead = beforePrettyPrintState.selectionHead;
+ let newSelectionAnchor, newSelectionHead;
+ let newExecutionLocation = null;
- var mappedAnchorLocation = this._formatterSourceMap.formattedToOriginal(oldSelectionAnchor.line, oldSelectionAnchor.ch);
- var mappedHeadLocation = this._formatterSourceMap.formattedToOriginal(oldSelectionHead.line, oldSelectionHead.ch);
- newSelectionAnchor = {line: mappedAnchorLocation.lineNumber, ch: mappedAnchorLocation.columnNumber};
- newSelectionHead = {line: mappedHeadLocation.lineNumber, ch: mappedHeadLocation.columnNumber};
+ if (pretty) {
+ if (this._positionToReveal) {
+ let newRevealPosition = this._formatterSourceMap.originalToFormatted(this._positionToReveal.lineNumber, this._positionToReveal.columnNumber);
+ this._positionToReveal = new WebInspector.SourceCodePosition(newRevealPosition.lineNumber, newRevealPosition.columnNumber);
+ }
- this._formatterSourceMap = null;
+ if (this._textRangeToSelect) {
+ let mappedRevealSelectionStart = this._formatterSourceMap.originalToFormatted(this._textRangeToSelect.startLine, this._textRangeToSelect.startColumn);
+ let mappedRevealSelectionEnd = this._formatterSourceMap.originalToFormatted(this._textRangeToSelect.endLine, this._textRangeToSelect.endColumn);
+ this._textRangeToSelect = new WebInspector.TextRange(mappedRevealSelectionStart.lineNumber, mappedRevealSelectionStart.columnNumber, mappedRevealSelectionEnd.lineNumber, mappedRevealSelectionEnd.columnNumber);
}
- this._scrollIntoViewCentered(newSelectionAnchor);
- this._codeMirror.setSelection(newSelectionAnchor, newSelectionHead);
+ if (!isNaN(this._executionLineNumber)) {
+ console.assert(!isNaN(this._executionColumnNumber));
+ newExecutionLocation = this._formatterSourceMap.originalToFormatted(this._executionLineNumber, this._executionColumnNumber);
+ }
- if (newExecutionLocation) {
- delete this._executionLineHandle;
- this.executionColumnNumber = newExecutionLocation.columnNumber;
- this.executionLineNumber = newExecutionLocation.lineNumber;
+ let mappedAnchorLocation = this._formatterSourceMap.originalToFormatted(oldSelectionAnchor.line, oldSelectionAnchor.ch);
+ let mappedHeadLocation = this._formatterSourceMap.originalToFormatted(oldSelectionHead.line, oldSelectionHead.ch);
+ newSelectionAnchor = {line: mappedAnchorLocation.lineNumber, ch: mappedAnchorLocation.columnNumber};
+ newSelectionHead = {line: mappedHeadLocation.lineNumber, ch: mappedHeadLocation.columnNumber};
+ } else {
+ if (this._positionToReveal) {
+ let newRevealPosition = this._formatterSourceMap.formattedToOriginal(this._positionToReveal.lineNumber, this._positionToReveal.columnNumber);
+ this._positionToReveal = new WebInspector.SourceCodePosition(newRevealPosition.lineNumber, newRevealPosition.columnNumber);
}
- // FIXME: <rdar://problem/13129955> FindBanner: New searches should not lose search position (start from current selection/caret)
- if (this.currentSearchQuery) {
- var searchQuery = this.currentSearchQuery;
- this.searchCleared();
- // Set timeout so that this happens after the current CodeMirror operation.
- // The editor has to update for the value and selection changes.
- setTimeout(function(query) {
- this.performSearch(searchQuery);
- }.bind(this), 0);
+ if (this._textRangeToSelect) {
+ let mappedRevealSelectionStart = this._formatterSourceMap.formattedToOriginal(this._textRangeToSelect.startLine, this._textRangeToSelect.startColumn);
+ let mappedRevealSelectionEnd = this._formatterSourceMap.formattedToOriginal(this._textRangeToSelect.endLine, this._textRangeToSelect.endColumn);
+ this._textRangeToSelect = new WebInspector.TextRange(mappedRevealSelectionStart.lineNumber, mappedRevealSelectionStart.columnNumber, mappedRevealSelectionEnd.lineNumber, mappedRevealSelectionEnd.columnNumber);
}
- if (this._delegate && typeof this._delegate.textEditorUpdatedFormatting === "function")
- this._delegate.textEditorUpdatedFormatting(this);
+ if (!isNaN(this._executionLineNumber)) {
+ console.assert(!isNaN(this._executionColumnNumber));
+ newExecutionLocation = this._formatterSourceMap.formattedToOriginal(this._executionLineNumber, this._executionColumnNumber);
+ }
+
+ let mappedAnchorLocation = this._formatterSourceMap.formattedToOriginal(oldSelectionAnchor.line, oldSelectionAnchor.ch);
+ let mappedHeadLocation = this._formatterSourceMap.formattedToOriginal(oldSelectionHead.line, oldSelectionHead.ch);
+ newSelectionAnchor = {line: mappedAnchorLocation.lineNumber, ch: mappedAnchorLocation.columnNumber};
+ newSelectionHead = {line: mappedHeadLocation.lineNumber, ch: mappedHeadLocation.columnNumber};
+
+ this._formatterSourceMap = null;
}
- this._codeMirror.operation(prettyPrintAndUpdateEditor.bind(this));
+ this._scrollIntoViewCentered(newSelectionAnchor);
+ this._codeMirror.setSelection(newSelectionAnchor, newSelectionHead);
+
+ if (newExecutionLocation) {
+ this._executionLineHandle = null;
+ this.executionColumnNumber = newExecutionLocation.columnNumber;
+ this.executionLineNumber = newExecutionLocation.lineNumber;
+ }
+
+ // FIXME: <rdar://problem/13129955> FindBanner: New searches should not lose search position (start from current selection/caret)
+ if (this.currentSearchQuery) {
+ let searchQuery = this.currentSearchQuery;
+ this.searchCleared();
+ // Set timeout so that this happens after the current CodeMirror operation.
+ // The editor has to update for the value and selection changes.
+ setTimeout(() => { this.performSearch(searchQuery) }, 0);
+ }
+
+ if (this._delegate && typeof this._delegate.textEditorUpdatedFormatting === "function")
+ this._delegate.textEditorUpdatedFormatting(this);
}
// Private