WebKit Bugzilla
Attachment 369695 Details for
Bug 197829
: Web Inspector: Formatter: pretty-print CSS using a Worker
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-197829-20190512225303.patch (text/plain), 12.02 KB, created by
Devin Rousso
on 2019-05-12 22:53:03 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Devin Rousso
Created:
2019-05-12 22:53:03 PDT
Size:
12.02 KB
patch
obsolete
>diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog >index eafa215585124fc48807022fe0541ed3c2d3ad7e..28e91e1e5c185af515e3d1ca79f6e88be78f4043 100644 >--- a/Source/WebInspectorUI/ChangeLog >+++ b/Source/WebInspectorUI/ChangeLog >@@ -1,3 +1,28 @@ >+2019-05-12 Devin Rousso <drousso@apple.com> >+ >+ Web Inspector: Formatter: pretty-print CSS using a Worker >+ https://bugs.webkit.org/show_bug.cgi?id=197829 >+ <rdar://problem/36891532> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * UserInterface/Proxies/FormatterWorkerProxy.js: >+ (WI.FormatterWorkerProxy.prototype.formatCSS): Added. >+ * UserInterface/Workers/Formatter/FormatterWorker.js: >+ (FormatterWorker.prototype.formatCSS): Added. >+ * UserInterface/Workers/Formatter/CSSFormatter.js: Added. >+ (CSSFormatter): >+ (CSSFormatter.prototype.get success): >+ (CSSFormatter.prototype.get formattedText): >+ (CSSFormatter.prototype.get sourceMapData): >+ (CSSFormatter.prototype._format): >+ >+ * UserInterface/Views/TextEditor.js: >+ (WI.TextEditor.prototype._canUseFormatterWorker): >+ (WI.TextEditor.prototype._startWorkerPrettyPrint): >+ >+ * .eslintrc: >+ > 2019-05-09 Devin Rousso <drousso@apple.com> > > Web Inspector: Uncaught Exception: null is not an object (evaluating 'resource.parentFrame.securityOrigin') >diff --git a/Source/WebInspectorUI/.eslintrc b/Source/WebInspectorUI/.eslintrc >index e503f7c75d968a74b7542550895aadff62552669..fc6d0eaa251eec221a95e1035ec49fd00e54b205 100644 >--- a/Source/WebInspectorUI/.eslintrc >+++ b/Source/WebInspectorUI/.eslintrc >@@ -90,6 +90,7 @@ > "esprima": true, > > // Formatters >+ "CSSFormatter": true, > "ESTreeWalker": true, > "EsprimaFormatter": true, > "FormatterWorker": true, >diff --git a/Source/WebInspectorUI/UserInterface/Proxies/FormatterWorkerProxy.js b/Source/WebInspectorUI/UserInterface/Proxies/FormatterWorkerProxy.js >index fca1005d0a5f5012d58eaa4d8f2e0b9dc9fded9b..bdbe112c8035d38293f3b052d7098a4fb9558473 100644 >--- a/Source/WebInspectorUI/UserInterface/Proxies/FormatterWorkerProxy.js >+++ b/Source/WebInspectorUI/UserInterface/Proxies/FormatterWorkerProxy.js >@@ -50,6 +50,11 @@ WI.FormatterWorkerProxy = class FormatterWorkerProxy > this.performAction("formatJavaScript", ...arguments); > } > >+ formatCSS(sourceText, indentString, state, includeSourceMapData) >+ { >+ this.performAction("formatCSS", ...arguments); >+ } >+ > // Public > > performAction(actionName) >diff --git a/Source/WebInspectorUI/UserInterface/Views/TextEditor.js b/Source/WebInspectorUI/UserInterface/Views/TextEditor.js >index 814f24b7e08c068f0dc36f541a12ab3cd204eb71..f16ee734fadfe0cfc40779118d88b67d0ce7735c 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/TextEditor.js >+++ b/Source/WebInspectorUI/UserInterface/Views/TextEditor.js >@@ -896,7 +896,8 @@ WI.TextEditor = class TextEditor extends WI.View > > _canUseFormatterWorker() > { >- return this._codeMirror.getMode().name === "javascript"; >+ let mode = this._codeMirror.getMode().name; >+ return mode === "javascript" || mode === "css"; > } > > _attemptToDetermineMIMEType() >@@ -919,22 +920,27 @@ WI.TextEditor = class TextEditor extends WI.View > > _startWorkerPrettyPrint(beforePrettyPrintState, callback) > { >+ let workerProxy = WI.FormatterWorkerProxy.singleton(); > let sourceText = this._codeMirror.getValue(); > let indentString = WI.indentString(); > const includeSourceMapData = true; > >- let sourceType = this._delegate ? this._delegate.textEditorScriptSourceType(this) : WI.Script.SourceType.Program; >- const isModule = sourceType === WI.Script.SourceType.Module; >- >- let workerProxy = WI.FormatterWorkerProxy.singleton(); >- workerProxy.formatJavaScript(sourceText, isModule, indentString, includeSourceMapData, ({formattedText, sourceMapData}) => { >+ let formatCallback = ({formattedText, sourceMapData}) => { > // Handle if formatting failed, which is possible for invalid programs. > if (formattedText === null) { > callback(); > return; > } > this._finishPrettyPrint(beforePrettyPrintState, formattedText, sourceMapData, callback); >- }); >+ }; >+ >+ let mode = this._codeMirror.getMode().name; >+ if (mode === "javascript") { >+ let sourceType = this._delegate ? this._delegate.textEditorScriptSourceType(this) : WI.Script.SourceType.Program; >+ const isModule = sourceType === WI.Script.SourceType.Module; >+ workerProxy.formatJavaScript(sourceText, isModule, indentString, includeSourceMapData, formatCallback); >+ } else if (mode === "css") >+ workerProxy.formatCSS(sourceText, indentString, includeSourceMapData, formatCallback); > } > > _startCodeMirrorPrettyPrint(beforePrettyPrintState, callback) >diff --git a/Source/WebInspectorUI/UserInterface/Workers/Formatter/CSSFormatter.js b/Source/WebInspectorUI/UserInterface/Workers/Formatter/CSSFormatter.js >new file mode 100644 >index 0000000000000000000000000000000000000000..e4e7cf50b5971c7704ac45532baf45fa6b1b0bc8 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Workers/Formatter/CSSFormatter.js >@@ -0,0 +1,160 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+CSSFormatter = class CSSFormatter >+{ >+ constructor(sourceText, indentString = " ") >+ { >+ this._success = false; >+ >+ this._sourceText = sourceText; >+ >+ this._builder = new FormatterContentBuilder(indentString); >+ this._builder.setOriginalLineEndings(this._sourceText.lineEndings()); >+ >+ this._format(); >+ >+ this._success = true; >+ } >+ >+ // Public >+ >+ get success() { return this._success; } >+ >+ get formattedText() >+ { >+ if (!this._success) >+ return null; >+ return this._builder.formattedContent; >+ } >+ >+ get sourceMapData() >+ { >+ if (!this._success) >+ return null; >+ return this._builder.sourceMapData; >+ } >+ >+ // Private >+ >+ _format() >+ { >+ const quoteTypes = new Set([`"`, `'`]); >+ >+ const dedentBefore = new Set([`}`]); >+ >+ const newlineBefore = new Set([`}`]); >+ const newlineAfter = new Set([`;`, `{`, `}`]); >+ >+ const indentAfter = new Set([`{`]); >+ >+ const addSpaceBefore = new Set([`+`, `*`, `~`, `>`, `{`]); >+ const addSpaceAfter = new Set([`+`, `*`, `~`, `>`, `:`, `,`, `)`]); >+ >+ const removeSpaceBefore = new Set([`,`, `:`, `;`]); >+ >+ for (let i = 0; i < this._sourceText.length; ++i) { >+ let c = this._sourceText[i]; >+ >+ let inQuote = quoteTypes.has(c); >+ let inComment = c === `/` && this._sourceText[i + 1] === `*`; >+ >+ if (inQuote || inComment) { >+ let endIndex = i; >+ do { >+ endIndex = this._sourceText.indexOf(inComment ? `*/` : c, endIndex + 1); >+ } while (endIndex !== -1 && this._sourceText[endIndex - 1] === `\\`); >+ >+ if (endIndex === -1) >+ endIndex = this._sourceText.length; >+ >+ this._builder.appendToken(this._sourceText.substring(i, endIndex + 1), i); >+ i = endIndex; >+ continue; >+ } >+ >+ if (/\s/.test(c)) { >+ if (!this._builder.lastTokenWasWhitespace) { >+ if (c === `\n`) >+ this._builder.appendNewline(); >+ else >+ this._builder.appendSpace(); >+ } >+ continue; >+ } >+ >+ if (c === `}` && this._builder.lastNewlineAppendWasMultiple) >+ this._builder.removeLastNewline(); >+ >+ if (dedentBefore.has(c)) >+ this._builder.dedent(); >+ >+ if (newlineBefore.has(c) && !this._builder.lastNewlineAppendWasMultiple) >+ this._builder.appendNewline(); >+ >+ if (addSpaceBefore.has(c) && !this._builder.lastTokenWasWhitespace) >+ this._builder.appendSpace(); >+ else if (removeSpaceBefore.has(c) && this._builder.lastTokenWasWhitespace) { >+ if (c !== `:`) >+ this._builder.removeLastWhitespace(); >+ } >+ >+ this._builder.appendToken(c, i); >+ >+ if (addSpaceAfter.has(c) && !this._builder.lastTokenWasWhitespace) { >+ let inSelector = false; >+ >+ if (c === `:`) { >+ let nextOpenBrace = this._sourceText.indexOf(`{`, i); >+ let nextSemicolon = this._sourceText.indexOf(`;`, i); >+ let nextQuote = Infinity; >+ for (let quoteType of quoteTypes) { >+ let quoteIndex = this._sourceText.indexOf(quoteType, i); >+ if (quoteIndex !== -1 && quoteIndex < nextQuote) >+ nextQuote = quoteIndex; >+ } >+ >+ if (nextOpenBrace !== -1 && nextOpenBrace < nextSemicolon && nextOpenBrace < nextQuote) >+ inSelector = true; >+ } >+ >+ if (!inSelector) >+ this._builder.appendSpace(); >+ } >+ >+ if (indentAfter.has(c)) >+ this._builder.indent(); >+ >+ if (newlineAfter.has(c)) { >+ if (c === `}`) >+ this._builder.appendMultipleNewlines(2); >+ else >+ this._builder.appendNewline(); >+ } >+ } >+ >+ this._builder.finish(); >+ } >+}; >diff --git a/Source/WebInspectorUI/UserInterface/Workers/Formatter/FormatterWorker.js b/Source/WebInspectorUI/UserInterface/Workers/Formatter/FormatterWorker.js >index 0f5c8450d283e7b55bf54b92a97ae67c5d2cc5b2..bccd10fc39327c3b27163a072ad17607bd7573d3 100644 >--- a/Source/WebInspectorUI/UserInterface/Workers/Formatter/FormatterWorker.js >+++ b/Source/WebInspectorUI/UserInterface/Workers/Formatter/FormatterWorker.js >@@ -29,6 +29,7 @@ importScripts(...[ > "FormatterContentBuilder.js", > "ESTreeWalker.js", > "EsprimaFormatter.js", >+ "CSSFormatter.js", > ]); > > FormatterWorker = class FormatterWorker >@@ -88,6 +89,18 @@ FormatterWorker = class FormatterWorker > return {formattedText: null}; > } > >+ formatCSS(sourceText, indentString, includeSourceMapData) >+ { >+ let result = {formattedText: null}; >+ let formatter = new CSSFormatter(sourceText, indentString); >+ if (formatter.success) { >+ result.formattedText = formatter.formattedText; >+ if (includeSourceMapData) >+ result.sourceMapData = formatter.sourceMapData; >+ } >+ return result; >+ } >+ > // Private > > _handleMessage(event)
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 197829
:
369695
|
369736
|
369944