Web Inspector: Styles: close unbalanced quotes and parenthesis when editing values
authornvasilyev@apple.com <nvasilyev@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Feb 2019 22:17:56 +0000 (22:17 +0000)
committernvasilyev@apple.com <nvasilyev@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Feb 2019 22:17:56 +0000 (22:17 +0000)
https://bugs.webkit.org/show_bug.cgi?id=182523
<rdar://problem/37260209>

Reviewed by Devin Rousso.

Source/WebInspectorUI:

Close CSS comments, append missing closed quotes and right parenthesis.

* UserInterface/Models/CSSCompletions.js:
(WI.CSSCompletions.completeUnbalancedValue):
* UserInterface/Models/CSSProperty.js:
(WI.CSSProperty.prototype.set rawValue):

LayoutTests:

Test common cases of unmatched quotes, parenthesis, comments, and trailing backslashes.

* inspector/unit-tests/css-completions-expected.txt: Added.
* inspector/unit-tests/css-completions.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@241209 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/inspector/unit-tests/css-completions-expected.txt [new file with mode: 0644]
LayoutTests/inspector/unit-tests/css-completions.html [new file with mode: 0644]
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Models/CSSCompletions.js
Source/WebInspectorUI/UserInterface/Models/CSSProperty.js

index a528a96..c7af54c 100644 (file)
@@ -1,3 +1,16 @@
+2019-02-08  Nikita Vasilyev  <nvasilyev@apple.com>
+
+        Web Inspector: Styles: close unbalanced quotes and parenthesis when editing values
+        https://bugs.webkit.org/show_bug.cgi?id=182523
+        <rdar://problem/37260209>
+
+        Reviewed by Devin Rousso.
+
+        Test common cases of unmatched quotes, parenthesis, comments, and trailing backslashes.
+
+        * inspector/unit-tests/css-completions-expected.txt: Added.
+        * inspector/unit-tests/css-completions.html: Added.
+
 2019-02-08  Per Arne Vollan  <pvollan@apple.com>
 
         Layout Test accessibility/set-value-not-work-for-disabled-sliders.html is failing
diff --git a/LayoutTests/inspector/unit-tests/css-completions-expected.txt b/LayoutTests/inspector/unit-tests/css-completions-expected.txt
new file mode 100644 (file)
index 0000000..bd776ff
--- /dev/null
@@ -0,0 +1,41 @@
+Testing CSS completion.
+
+
+== Running test suite: CSSCompletions
+-- Running test case: CSSCompletions.completeUnbalancedValue
+url(|)
+url()|
+rgb(1|)
+rgb(1,2,3)|
+calc(var(--foo|))
+'|'
+''|
+'foo|'
+'foo'|
+"|"
+""|
+"bar|"
+"bar"|
+/*|*/
+/**/|
+/* "foo */|
+/* 'foo */|
+/* (foo */|
+('foo"|')
+('foo")|')
+("bar"')|')
+("bar")|
+'(|'
+'(foo|'
+"(|"
+"(bar|"
+\|\
+\\|
+\\\|\
+"\"|"
+'\'|'
+(\)|)
+/*\*/|*/
+radial-gradient(ellipse closest-corner at var(--v) var(--h), hsl(198, 100%, 20%) 0%, hsla(204, 100%, 20%, 0) 100%)|
+"Helvetica Neue", 'Source Code Pro', "Comic Sans", 'PT Mono'|
+
diff --git a/LayoutTests/inspector/unit-tests/css-completions.html b/LayoutTests/inspector/unit-tests/css-completions.html
new file mode 100644 (file)
index 0000000..5313e59
--- /dev/null
@@ -0,0 +1,73 @@
+<!doctype html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script>
+function test()
+{
+    let suite = InspectorTest.createSyncSuite("CSSCompletions");
+
+    suite.addTestCase({
+        name: "CSSCompletions.completeUnbalancedValue",
+        test() {
+            function log(cssValue) {
+                let suffix = WI.CSSCompletions.completeUnbalancedValue(cssValue);
+                InspectorTest.log(cssValue + "|" + suffix);
+            }
+
+            log(`url(`);
+            log(`url()`);
+            log(`rgb(1`);
+            log(`rgb(1,2,3)`);
+            log(`calc(var(--foo`);
+
+            log(`'`);
+            log(`''`);
+            log(`'foo`);
+            log(`'foo'`);
+
+            log(`"`);
+            log(`""`);
+            log(`"bar`);
+            log(`"bar"`);
+
+            log(`/*`);
+            log(`/**/`);
+            log(`/* "foo */`);
+            log(`/* 'foo */`);
+            log(`/* (foo */`);
+
+            log(`('foo"`);
+            log(`('foo")`);
+            log(`("bar"')`);
+            log(`("bar")`);
+
+            log(`'(`);
+            log(`'(foo`);
+            log(`"(`);
+            log(`"(bar`);
+
+            log(`\\`);
+            log(`\\\\`);
+            log(`\\\\\\`);
+
+            log(`"\\"`);
+            log(`'\\'`);
+            log(`(\\)`);
+            log(`/*\\*/`);
+
+            log(`radial-gradient(ellipse closest-corner at var(--v) var(--h), hsl(198, 100%, 20%) 0%, hsla(204, 100%, 20%, 0) 100%)`);
+            log(`"Helvetica Neue", 'Source Code Pro', "Comic Sans", 'PT Mono'`);
+
+            return true;
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Testing CSS completion.</p>
+</body>
+</html>
index 8169e2a..aae175a 100644 (file)
@@ -1,3 +1,18 @@
+2019-02-08  Nikita Vasilyev  <nvasilyev@apple.com>
+
+        Web Inspector: Styles: close unbalanced quotes and parenthesis when editing values
+        https://bugs.webkit.org/show_bug.cgi?id=182523
+        <rdar://problem/37260209>
+
+        Reviewed by Devin Rousso.
+
+        Close CSS comments, append missing closed quotes and right parenthesis.
+
+        * UserInterface/Models/CSSCompletions.js:
+        (WI.CSSCompletions.completeUnbalancedValue):
+        * UserInterface/Models/CSSProperty.js:
+        (WI.CSSProperty.prototype.set rawValue):
+
 2019-02-07  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Make Timeline markers light gray instead of black in dark mode
index 09d6104..bb40d39 100644 (file)
@@ -171,6 +171,91 @@ WI.CSSCompletions = class CSSCompletions
             target.CSSAgent.getSupportedSystemFontFamilyNames(fontFamilyNamesCallback);
     }
 
+    static completeUnbalancedValue(value)
+    {
+        const State = {
+            Data: 0,
+            SingleQuoteString: 1,
+            DoubleQuoteString: 2,
+            Comment: 3
+        };
+
+        let state = State.Data;
+        let unclosedParenthesisCount = 0;
+        let trailingBackslash = false;
+        let length = value.length;
+
+        for (let i = 0; i < length; ++i) {
+            switch (value[i]) {
+            case "'":
+                if (state === State.Data)
+                    state = State.SingleQuoteString;
+                else if (state === State.SingleQuoteString)
+                    state = State.Data;
+                break;
+
+            case "\"":
+                if (state === State.Data)
+                    state = State.DoubleQuoteString;
+                else if (state === State.DoubleQuoteString)
+                    state = State.Data;
+                break;
+
+            case "(":
+                if (state === State.Data)
+                    ++unclosedParenthesisCount;
+                break;
+
+            case ")":
+                if (state === State.Data && unclosedParenthesisCount)
+                    --unclosedParenthesisCount;
+                break;
+
+            case "/":
+                if (state === State.Data) {
+                    if (value[i + 1] === "*")
+                        state = State.Comment;
+                }
+                break;
+
+            case "\\":
+                if (i === length - 1)
+                    trailingBackslash = true;
+                else
+                    ++i; // Skip next character.
+                break;
+
+            case "*":
+                if (state === State.Comment) {
+                    if (value[i + 1] === "/")
+                        state = State.Data;
+                }
+                break;
+            }
+        }
+
+        let suffix = "";
+
+        if (trailingBackslash)
+            suffix += "\\";
+
+        switch (state) {
+        case State.SingleQuoteString:
+            suffix += "'";
+            break;
+        case State.DoubleQuoteString:
+            suffix += "\"";
+            break;
+        case State.Comment:
+            suffix += "*/";
+            break;
+        }
+
+        suffix += ")".repeat(unclosedParenthesisCount);
+
+        return suffix;
+    }
+
     // Public
 
     get values()
index 6696783..7410b0a 100644 (file)
@@ -230,6 +230,10 @@ WI.CSSProperty = class CSSProperty extends WI.Object
 
         this._markModified();
 
+        let suffix = WI.CSSCompletions.completeUnbalancedValue(value);
+        if (suffix)
+            value += suffix;
+
         this._rawValue = value;
         this._value = undefined;
         this._updateStyleText();