Title: [142091] trunk
Revision
142091
Author
[email protected]
Date
2013-02-07 03:51:08 -0800 (Thu, 07 Feb 2013)

Log Message

Web Inspector: highlight matching braces in DTE.
https://bugs.webkit.org/show_bug.cgi?id=108697

Patch by Andrey Lushnikov <[email protected]> on 2013-02-07
Reviewed by Pavel Feldman.

Source/WebCore:

Implement BraceMatcher class which for given position in textModel
will respond with enclosing brace pair for that position.
Make use of this class in DefaultTextEditor by handling
selectionChange event. Make use of this class in "_closingBlockOffset"
method of TextEditorMainPanel as this method implements similar
functionality.

New test: inspector/editor/brace-matcher.html

* inspector/front-end/DefaultTextEditor.js:
(WebInspector.TextEditorMainPanel):
(WebInspector.TextEditorMainPanel.prototype._applyDomUpdates):
(WebInspector.TextEditorMainPanel.prototype._closingBlockOffset):
(WebInspector.TextEditorMainPanel.prototype._handleSelectionChange):
(WebInspector.TextEditorMainPanel.BraceHighlightController):
(WebInspector.TextEditorMainPanel.BraceHighlightController.prototype.handleSelectionChange):
* inspector/front-end/TextEditorHighlighter.js:
(WebInspector.TextEditorHighlighter.prototype._highlightLines):
* inspector/front-end/TextEditorModel.js:
(WebInspector.TextEditorModel.endsWithBracketRegex):
(WebInspector.TextEditorModel.endsWithBracketRegex.):
* inspector/front-end/textEditor.css:
(.text-editor-brace-match):

LayoutTests:

New layout test to verify brace matching functionality. Fix some
layout test expectations as the patch removes braces from highlight
ranges.

* inspector/editor/brace-matcher-expected.txt: Added.
* inspector/editor/brace-matcher.html: Added.
* inspector/editor/highlighter-basics-expected.txt:
* inspector/editor/text-editor-long-line-expected.txt:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (142090 => 142091)


--- trunk/LayoutTests/ChangeLog	2013-02-07 11:46:12 UTC (rev 142090)
+++ trunk/LayoutTests/ChangeLog	2013-02-07 11:51:08 UTC (rev 142091)
@@ -1,3 +1,19 @@
+2013-02-07  Andrey Lushnikov  <[email protected]>
+
+        Web Inspector: highlight matching braces in DTE.
+        https://bugs.webkit.org/show_bug.cgi?id=108697
+
+        Reviewed by Pavel Feldman.
+
+        New layout test to verify brace matching functionality. Fix some
+        layout test expectations as the patch removes braces from highlight
+        ranges.
+
+        * inspector/editor/brace-matcher-expected.txt: Added.
+        * inspector/editor/brace-matcher.html: Added.
+        * inspector/editor/highlighter-basics-expected.txt:
+        * inspector/editor/text-editor-long-line-expected.txt:
+
 2013-02-07  Matt Falkenhagen  <[email protected]>
 
         Rollout r142058 various crashes and timeouts on AppleMac and Chromium

Added: trunk/LayoutTests/inspector/editor/brace-matcher-expected.txt (0 => 142091)


--- trunk/LayoutTests/inspector/editor/brace-matcher-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/editor/brace-matcher-expected.txt	2013-02-07 11:51:08 UTC (rev 142091)
@@ -0,0 +1,81 @@
+This test checks highlighter correctness.
+
+function bar() {
+    // comment here
+    var a, b, c, d;
+    var a = ((1 + 2) * (3 + 4));
+    for(var i = 0; i < 100; ++i) {
+        if (a < b && c > d) {
+        }
+    }
+}
+Cursor at line #0 >>>function bar() {<<< column 0 (char is "f")
+enclosing braces: null
+
+Cursor at line #0 >>>function bar() {<<< column 12 (char is "(")
+enclosing braces: {"leftBrace":{"lineNumber":0,"column":12,"token":"brace-start"},"rightBrace":{"lineNumber":0,"column":13,"token":"brace-end"}}
+
+Cursor at line #0 >>>function bar() {<<< column 13 (char is ")")
+enclosing braces: {"leftBrace":{"lineNumber":0,"column":12,"token":"brace-start"},"rightBrace":{"lineNumber":0,"column":13,"token":"brace-end"}}
+
+Cursor at line #0 >>>function bar() {<<< column 14 (char is " ")
+enclosing braces: null
+
+Cursor at line #0 >>>function bar() {<<< column 15 (char is "{")
+enclosing braces: {"leftBrace":{"lineNumber":0,"column":15,"token":"block-start"},"rightBrace":{"lineNumber":8,"column":0,"token":"block-end"}}
+
+Cursor at line #2 >>>    var a, b, c, d;<<< column 5 (char is "a")
+enclosing braces: {"leftBrace":{"lineNumber":0,"column":15,"token":"block-start"},"rightBrace":{"lineNumber":8,"column":0,"token":"block-end"}}
+
+Cursor at line #3 >>>    var a = ((1 + 2) * (3 + 4));<<< column 12 (char is "(")
+enclosing braces: {"leftBrace":{"lineNumber":3,"column":12,"token":"brace-start"},"rightBrace":{"lineNumber":3,"column":30,"token":"brace-end"}}
+
+Cursor at line #3 >>>    var a = ((1 + 2) * (3 + 4));<<< column 13 (char is "(")
+enclosing braces: {"leftBrace":{"lineNumber":3,"column":13,"token":"brace-start"},"rightBrace":{"lineNumber":3,"column":19,"token":"brace-end"}}
+
+Cursor at line #3 >>>    var a = ((1 + 2) * (3 + 4));<<< column 14 (char is "1")
+enclosing braces: {"leftBrace":{"lineNumber":3,"column":13,"token":"brace-start"},"rightBrace":{"lineNumber":3,"column":19,"token":"brace-end"}}
+
+Cursor at line #3 >>>    var a = ((1 + 2) * (3 + 4));<<< column 15 (char is " ")
+enclosing braces: {"leftBrace":{"lineNumber":3,"column":13,"token":"brace-start"},"rightBrace":{"lineNumber":3,"column":19,"token":"brace-end"}}
+
+Cursor at line #3 >>>    var a = ((1 + 2) * (3 + 4));<<< column 22 (char is " ")
+enclosing braces: {"leftBrace":{"lineNumber":3,"column":12,"token":"brace-start"},"rightBrace":{"lineNumber":3,"column":30,"token":"brace-end"}}
+
+Cursor at line #3 >>>    var a = ((1 + 2) * (3 + 4));<<< column 24 (char is "3")
+enclosing braces: {"leftBrace":{"lineNumber":3,"column":23,"token":"brace-start"},"rightBrace":{"lineNumber":3,"column":29,"token":"brace-end"}}
+
+Cursor at line #3 >>>    var a = ((1 + 2) * (3 + 4));<<< column 29 (char is ")")
+enclosing braces: {"leftBrace":{"lineNumber":3,"column":23,"token":"brace-start"},"rightBrace":{"lineNumber":3,"column":29,"token":"brace-end"}}
+
+Cursor at line #3 >>>    var a = ((1 + 2) * (3 + 4));<<< column 30 (char is ")")
+enclosing braces: {"leftBrace":{"lineNumber":3,"column":12,"token":"brace-start"},"rightBrace":{"lineNumber":3,"column":30,"token":"brace-end"}}
+
+Cursor at line #3 >>>    var a = ((1 + 2) * (3 + 4));<<< column 31 (char is ";")
+enclosing braces: {"leftBrace":{"lineNumber":0,"column":15,"token":"block-start"},"rightBrace":{"lineNumber":8,"column":0,"token":"block-end"}}
+
+Cursor at line #4 >>>    for(var i = 0; i < 100; ++i) {<<< column 19 (char is "i")
+enclosing braces: {"leftBrace":{"lineNumber":4,"column":7,"token":"brace-start"},"rightBrace":{"lineNumber":4,"column":31,"token":"brace-end"}}
+
+Cursor at line #4 >>>    for(var i = 0; i < 100; ++i) {<<< column 32 (char is " ")
+enclosing braces: {"leftBrace":{"lineNumber":0,"column":15,"token":"block-start"},"rightBrace":{"lineNumber":8,"column":0,"token":"block-end"}}
+
+Cursor at line #4 >>>    for(var i = 0; i < 100; ++i) {<<< column 33 (char is "{")
+enclosing braces: {"leftBrace":{"lineNumber":4,"column":33,"token":"block-start"},"rightBrace":{"lineNumber":7,"column":4,"token":"block-end"}}
+
+Cursor at line #5 >>>        if (a < b && c > d) {<<< column 20 (char is " ")
+enclosing braces: {"leftBrace":{"lineNumber":5,"column":11,"token":"brace-start"},"rightBrace":{"lineNumber":5,"column":26,"token":"brace-end"}}
+
+Cursor at line #5 >>>        if (a < b && c > d) {<<< column 28 (char is "{")
+enclosing braces: {"leftBrace":{"lineNumber":5,"column":28,"token":"block-start"},"rightBrace":{"lineNumber":6,"column":8,"token":"block-end"}}
+
+Cursor at line #6 >>>        }<<< column 8 (char is "}")
+enclosing braces: {"leftBrace":{"lineNumber":5,"column":28,"token":"block-start"},"rightBrace":{"lineNumber":6,"column":8,"token":"block-end"}}
+
+Cursor at line #7 >>>    }<<< column 4 (char is "}")
+enclosing braces: {"leftBrace":{"lineNumber":4,"column":33,"token":"block-start"},"rightBrace":{"lineNumber":7,"column":4,"token":"block-end"}}
+
+Cursor at line #8 >>>}<<< column 0 (char is "}")
+enclosing braces: {"leftBrace":{"lineNumber":0,"column":15,"token":"block-start"},"rightBrace":{"lineNumber":8,"column":0,"token":"block-end"}}
+
+

Added: trunk/LayoutTests/inspector/editor/brace-matcher.html (0 => 142091)


--- trunk/LayoutTests/inspector/editor/brace-matcher.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/editor/brace-matcher.html	2013-02-07 11:51:08 UTC (rev 142091)
@@ -0,0 +1,73 @@
+<html>
+<head>
+<script src=""
+<script src=""
+<script>
+
+function test()
+{
+function bar() {
+    // comment here
+    var a, b, c, d;
+    var a = ((1 + 2) * (3 + 4));
+    for(var i = 0; i < 100; ++i) {
+        if (a < b && c > d) {
+        }
+    }
+}
+
+
+    var textEditor = InspectorTest.createTestEditor();
+    textEditor.overrideViewportForTest(0, undefined, 3);
+    textEditor.mimeType = "text/_javascript_";
+    textEditor.setReadOnly(false);
+    textEditor.setText(bar.toString());
+    InspectorTest.addResult(textEditor.text());
+
+    var braceHighlighter = new WebInspector.TextEditorModel.BraceMatcher(textEditor._textModel);
+    function testAndDump(lineNumber, column)
+    {
+        var line = textEditor._textModel.line(lineNumber);
+        var text = "Cursor at line #" + (lineNumber) + " >>>" + line + "<<< column " + column + " (char is \"" + line.charAt(column) + "\")";
+        text += "\nenclosing braces: " + JSON.stringify(braceHighlighter.enclosingBraces(lineNumber, column));
+        text += "\n";
+        InspectorTest.addResult(text);
+    }
+
+    testAndDump(0, 0);
+    testAndDump(0, 12);
+    testAndDump(0, 13);
+    testAndDump(0, 14);
+    testAndDump(0, 15);
+    testAndDump(2, 5);
+    testAndDump(3, 12);
+    testAndDump(3, 13);
+    testAndDump(3, 14);
+    testAndDump(3, 15);
+    testAndDump(3, 22);
+    testAndDump(3, 24);
+    testAndDump(3, 29);
+    testAndDump(3, 30);
+    testAndDump(3, 31);
+    testAndDump(4, 19);
+    testAndDump(4, 32);
+    testAndDump(4, 33);
+    testAndDump(5, 20);
+    testAndDump(5, 28);
+    testAndDump(6, 8);
+    testAndDump(7, 4);
+    testAndDump(8, 0);
+
+    InspectorTest.completeTest();
+}
+
+</script>
+</head>
+
+<body _onload_="runTest()">
+<p>
+This test checks highlighter correctness.
+</p>
+
+</body>
+</html>

Modified: trunk/LayoutTests/inspector/editor/highlighter-basics-expected.txt (142090 => 142091)


--- trunk/LayoutTests/inspector/editor/highlighter-basics-expected.txt	2013-02-07 11:46:12 UTC (rev 142090)
+++ trunk/LayoutTests/inspector/editor/highlighter-basics-expected.txt	2013-02-07 11:51:08 UTC (rev 142091)
@@ -91,7 +91,7 @@
 15 :  * line #6 : whitespace[0-1] whitespace[2-3] _javascript_-ident[3-7] whitespace[7-8] _javascript_-number[9-10]
 16 :  * line #7 : whitespace[0-1] whitespace[2-3] _javascript_-ident[3-7] whitespace[7-8] _javascript_-number[9-10]
 17 :  * line #8 : whitespace[0-1] whitespace[2-3] _javascript_-ident[3-7] whitespace[7-8] _javascript_-number[9-10]
-18 :  * var a = new A(); //*/ : whitespace[0-1] whitespace[2-3] _javascript_-keyword[3-6] whitespace[6-7] _javascript_-ident[7-8] whitespace[8-9] whitespace[10-11] _javascript_-keyword[11-14] whitespace[14-15] _javascript_-ident[15-16] brace-start[16-17] brace-end[17-18] whitespace[19-20] _javascript_-comment[20-24]
+18 :  * var a = new A(); //*/ : whitespace[0-1] whitespace[2-3] _javascript_-keyword[3-6] whitespace[6-7] _javascript_-ident[7-8] whitespace[8-9] whitespace[10-11] _javascript_-keyword[11-14] whitespace[14-15] _javascript_-ident[15-16] whitespace[19-20] _javascript_-comment[20-24]
 19 : some text : _javascript_-ident[0-4] whitespace[4-5] _javascript_-ident[5-9]
 20 :  :
 
@@ -113,7 +113,7 @@
 15 :  * line #6 : whitespace[0-1] whitespace[2-3] _javascript_-ident[3-7] whitespace[7-8] _javascript_-number[9-10]
 16 :  * line #7 : whitespace[0-1] whitespace[2-3] _javascript_-ident[3-7] whitespace[7-8] _javascript_-number[9-10]
 17 :  * line #8 : whitespace[0-1] whitespace[2-3] _javascript_-ident[3-7] whitespace[7-8] _javascript_-number[9-10]
-18 :  * var a = new A(); //*/ : whitespace[0-1] whitespace[2-3] _javascript_-keyword[3-6] whitespace[6-7] _javascript_-ident[7-8] whitespace[8-9] whitespace[10-11] _javascript_-keyword[11-14] whitespace[14-15] _javascript_-ident[15-16] brace-start[16-17] brace-end[17-18] whitespace[19-20] _javascript_-comment[20-24]
+18 :  * var a = new A(); //*/ : whitespace[0-1] whitespace[2-3] _javascript_-keyword[3-6] whitespace[6-7] _javascript_-ident[7-8] whitespace[8-9] whitespace[10-11] _javascript_-keyword[11-14] whitespace[14-15] _javascript_-ident[15-16] whitespace[19-20] _javascript_-comment[20-24]
 19 : some text : _javascript_-ident[0-4] whitespace[4-5] _javascript_-ident[5-9]
 20 :  :
 

Modified: trunk/LayoutTests/inspector/editor/text-editor-long-line-expected.txt (142090 => 142091)


--- trunk/LayoutTests/inspector/editor/text-editor-long-line-expected.txt	2013-02-07 11:46:12 UTC (rev 142090)
+++ trunk/LayoutTests/inspector/editor/text-editor-long-line-expected.txt	2013-02-07 11:51:08 UTC (rev 142091)
@@ -2,5 +2,5 @@
 
 
 <div class="inner-container" tabindex="0">
-<div class="webkit-line-content"><span class="webkit-_javascript_-comment">/* START */</span><span class="webkit-whitespace"> </span><span class="webkit-_javascript_-keyword">this</span>.<span class="webkit-_javascript_-ident">field</span><span class="webkit-whitespace"> </span>=<span class="webkit-whitespace"> </span><span class="webkit-_javascript_-string">"foo"</span>;<span class="webkit-whitespace"> </span><span class="webkit-_javascript_-comment">/* comment */</span><span class="webkit-whitespace"> </span><span class="webkit-_javascript_-keyword">function</span><span class="webkit-whitespace"> </span><span class="webkit-_javascript_-ident">bar</span><span class="webkit-brace-start">(</span><span class="webkit-brace-end">)</span><span class="webkit-whitespace"> </span><span class="webkit-block-start">{</span><span class="webkit-whitespace"> </span><span class="webkit-_javascript_-keyword">return</span><span class="webkit-whitespace"> </span><span class="webkit-_javascript_-keyword">null</span>;<span class="webkit-whitespace"> </span><span class="webkit-block-end">}</span><span class="webkit-_javascript_-keyword">this</span>.<span class="webkit-_javascript_-ident">field</span><span class="webkit-whitespace"> </span>=<span class="webkit-whitespace"> </span><span class="webkit-_javascript_-string">"foo"</span>;<span class="webkit-whitespace"> </span><span class="webkit-_javascript_-comment">/* comment */</span> function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }/* FINISH */</div></div>
+<div class="webkit-line-content"><span class="webkit-_javascript_-comment">/* START */</span><span class="webkit-whitespace"> </span><span class="webkit-_javascript_-keyword">this</span>.<span class="webkit-_javascript_-ident">field</span><span class="webkit-whitespace"> </span>=<span class="webkit-whitespace"> </span><span class="webkit-_javascript_-string">"foo"</span>;<span class="webkit-whitespace"> </span><span class="webkit-_javascript_-comment">/* comment */</span><span class="webkit-whitespace"> </span><span class="webkit-_javascript_-keyword">function</span><span class="webkit-whitespace"> </span><span class="webkit-_javascript_-ident">bar</span>()<span class="webkit-whitespace"> </span>{<span class="webkit-whitespace"> </span><span class="webkit-_javascript_-keyword">return</span><span class="webkit-whitespace"> </span><span class="webkit-_javascript_-keyword">null</span>;<span class="webkit-whitespace"> </span>}<span class="webkit-_javascript_-keyword">this</span>.<span class="webkit-_javascript_-ident">field</span><span class="webkit-whitespace"> </span>=<span class="webkit-whitespace"> </span><span class="webkit-_javascript_-string">"foo"</span>;<span class="webkit-whitespace"> </span><span class="webkit-_javascript_-comment">/* comment */</span> function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }this.field = "foo"; /* comment */ function bar() { return null; }/* FINISH */</div></div>
 

Modified: trunk/Source/WebCore/ChangeLog (142090 => 142091)


--- trunk/Source/WebCore/ChangeLog	2013-02-07 11:46:12 UTC (rev 142090)
+++ trunk/Source/WebCore/ChangeLog	2013-02-07 11:51:08 UTC (rev 142091)
@@ -1,3 +1,34 @@
+2013-02-07  Andrey Lushnikov  <[email protected]>
+
+        Web Inspector: highlight matching braces in DTE.
+        https://bugs.webkit.org/show_bug.cgi?id=108697
+
+        Reviewed by Pavel Feldman.
+
+        Implement BraceMatcher class which for given position in textModel
+        will respond with enclosing brace pair for that position.
+        Make use of this class in DefaultTextEditor by handling
+        selectionChange event. Make use of this class in "_closingBlockOffset"
+        method of TextEditorMainPanel as this method implements similar
+        functionality.
+
+        New test: inspector/editor/brace-matcher.html
+
+        * inspector/front-end/DefaultTextEditor.js:
+        (WebInspector.TextEditorMainPanel):
+        (WebInspector.TextEditorMainPanel.prototype._applyDomUpdates):
+        (WebInspector.TextEditorMainPanel.prototype._closingBlockOffset):
+        (WebInspector.TextEditorMainPanel.prototype._handleSelectionChange):
+        (WebInspector.TextEditorMainPanel.BraceHighlightController):
+        (WebInspector.TextEditorMainPanel.BraceHighlightController.prototype.handleSelectionChange):
+        * inspector/front-end/TextEditorHighlighter.js:
+        (WebInspector.TextEditorHighlighter.prototype._highlightLines):
+        * inspector/front-end/TextEditorModel.js:
+        (WebInspector.TextEditorModel.endsWithBracketRegex):
+        (WebInspector.TextEditorModel.endsWithBracketRegex.):
+        * inspector/front-end/textEditor.css:
+        (.text-editor-brace-match):
+
 2013-02-05  Eunmi Lee  <[email protected]> and Raphael Kubo da Costa  <[email protected]>
 
         [EFL][WK2] Refactoring initialization and shutdown codes of EFL libraries.

Modified: trunk/Source/WebCore/inspector/front-end/DefaultTextEditor.js (142090 => 142091)


--- trunk/Source/WebCore/inspector/front-end/DefaultTextEditor.js	2013-02-07 11:46:12 UTC (rev 142090)
+++ trunk/Source/WebCore/inspector/front-end/DefaultTextEditor.js	2013-02-07 11:51:08 UTC (rev 142091)
@@ -1369,6 +1369,8 @@
     this._highlightDescriptors = [];
 
     this._tokenHighlighter = new WebInspector.TextEditorMainPanel.TokenHighlighter(this, textModel);
+    this._braceMatcher = new WebInspector.TextEditorModel.BraceMatcher(textModel);
+    this._braceHighlighter = new WebInspector.TextEditorMainPanel.BraceHighlightController(this, textModel, this._braceMatcher);
 
     this._freeCachedElements();
     this.buildChunks();
@@ -2401,7 +2403,7 @@
 
         // Unindent after block
         if (editInfo.text === "}" && editInfo.range.isEmpty() && selection.isEmpty() && !this._textModel.line(editInfo.range.endLine).trim()) {
-            var offset = this._closingBlockOffset(editInfo.range, selection);
+            var offset = this._closingBlockOffset(editInfo.range);
             if (offset >= 0) {
                 editInfo.range.startColumn = offset;
                 selection.startColumn = offset + 1;
@@ -2491,30 +2493,15 @@
 
     /**
      * @param {WebInspector.TextRange} oldRange
-     * @param {WebInspector.TextRange} selection
      * @return {number}
      */
-    _closingBlockOffset: function(oldRange, selection)
+    _closingBlockOffset: function(oldRange)
     {
-        var nestingLevel = 1;
-        for (var i = oldRange.endLine; i >= 0; --i) {
-            var attribute = this._textModel.getAttribute(i, "highlight");
-            if (!attribute)
-                continue;
-            var ranges = attribute.ranges;
-            for (var j = ranges.length - 1; j >= 0; j--) {
-                var token = ranges[j].token;
-                if (token === "block-start") {
-                    if (!(--nestingLevel)) {
-                        var lineContent = this._textModel.line(i);
-                        return lineContent.length - lineContent.trimLeft().length;
-                    }
-                }
-                if (token === "block-end")
-                    ++nestingLevel;
-            }
-        }
-        return -1;
+        var leftBrace = this._braceMatcher.findLeftCandidate(oldRange.startLine, oldRange.startColumn);
+        if (!leftBrace || leftBrace.token !== "block-start")
+            return -1;
+        var lineContent = this._textModel.line(leftBrace.lineNumber);
+        return lineContent.length - lineContent.trimLeft().length;
     },
 
     /**
@@ -2680,6 +2667,7 @@
             this._lastSelection = textRange;
 
         this._tokenHighlighter.handleSelectionChange(textRange);
+        this._braceHighlighter.handleSelectionChange(textRange);
         this._delegate.selectionChanged(textRange);
     },
 
@@ -3359,4 +3347,61 @@
     }
 }
 
+/**
+ * @constructor
+ * @param {WebInspector.TextEditorMainPanel} textEditor
+ * @param {WebInspector.TextEditorModel} textModel
+ * @param {WebInspector.TextEditorModel.BraceMatcher} braceMatcher
+ */
+WebInspector.TextEditorMainPanel.BraceHighlightController = function(textEditor, textModel, braceMatcher)
+{
+    this._textEditor = textEditor;
+    this._textModel = textModel;
+    this._braceMatcher = braceMatcher;
+    this._highlightDescriptors = [];
+}
+
+WebInspector.TextEditorMainPanel.BraceHighlightController.prototype = {
+    /**
+     * @param {WebInspector.TextRange} selectionRange
+     */
+    handleSelectionChange: function(selectionRange)
+    {
+        if (!selectionRange || !selectionRange.isEmpty()) {
+            this._removeHighlight();
+            return;
+        }
+
+        if (this._highlightedRange && this._highlightedRange.compareTo(selectionRange) === 0)
+            return;
+
+        this._removeHighlight();
+        var lineNumber = selectionRange.startLine;
+        var column = selectionRange.startColumn;
+        var line = this._textModel.line(lineNumber);
+        if (column > 0 && /[)}]/.test(line.charAt(column - 1)))
+            --column;
+
+        var enclosingBraces = this._braceMatcher.enclosingBraces(lineNumber, column);
+        if (!enclosingBraces)
+            return;
+
+        this._highlightedRange = selectionRange;
+        this._highlightDescriptors.push(this._textEditor.highlightRange(WebInspector.TextRange.createFromLocation(enclosingBraces.leftBrace.lineNumber, enclosingBraces.leftBrace.column), "text-editor-brace-match"));
+        this._highlightDescriptors.push(this._textEditor.highlightRange(WebInspector.TextRange.createFromLocation(enclosingBraces.rightBrace.lineNumber, enclosingBraces.rightBrace.column), "text-editor-brace-match"));
+    },
+
+    _removeHighlight: function()
+    {
+        if (!this._highlightDescriptors.length)
+            return;
+
+        for(var i = 0; i < this._highlightDescriptors.length; ++i)
+            this._textEditor.removeHighlight(this._highlightDescriptors[i]);
+
+        this._highlightDescriptors = [];
+        delete this._highlightedRange;
+    }
+}
+
 WebInspector.debugDefaultTextEditor = false;

Modified: trunk/Source/WebCore/inspector/front-end/TextEditorHighlighter.js (142090 => 142091)


--- trunk/Source/WebCore/inspector/front-end/TextEditorHighlighter.js	2013-02-07 11:46:12 UTC (rev 142090)
+++ trunk/Source/WebCore/inspector/front-end/TextEditorHighlighter.js	2013-02-07 11:51:08 UTC (rev 142091)
@@ -185,15 +185,25 @@
 
                 // Highlight line.
                 state.ranges = state.ranges || [];
+                state.braces = state.braces || [];
                 do {
                     var newColumn = this._tokenizer.nextToken(lastHighlightedColumn);
                     var tokenType = this._tokenizer.tokenType;
-                    if (tokenType && lastHighlightedColumn < this._highlightLineLimit)
-                        state.ranges.push({
-                            startColumn: lastHighlightedColumn,
-                            endColumn: newColumn - 1,
-                            token: tokenType
-                        });
+                    if (tokenType && lastHighlightedColumn < this._highlightLineLimit) {
+                        if (tokenType === "brace-start" || tokenType === "brace-end" || tokenType === "block-start" || tokenType === "block-end") {
+                            state.braces.push({
+                                startColumn: lastHighlightedColumn,
+                                endColumn: newColumn - 1,
+                                token: tokenType
+                            });
+                        } else {
+                            state.ranges.push({
+                                startColumn: lastHighlightedColumn,
+                                endColumn: newColumn - 1,
+                                token: tokenType
+                            });
+                        }
+                    }
                     lastHighlightedColumn = newColumn;
                     if (++tokensCount > this._highlightChunkLimit)
                         break;

Modified: trunk/Source/WebCore/inspector/front-end/TextEditorModel.js (142090 => 142091)


--- trunk/Source/WebCore/inspector/front-end/TextEditorModel.js	2013-02-07 11:46:12 UTC (rev 142090)
+++ trunk/Source/WebCore/inspector/front-end/TextEditorModel.js	2013-02-07 11:51:08 UTC (rev 142091)
@@ -656,3 +656,156 @@
 
     __proto__: WebInspector.Object.prototype
 }
+
+/**
+ * @constructor
+ * @param {WebInspector.TextEditorModel} textModel
+ */
+WebInspector.TextEditorModel.BraceMatcher = function(textModel)
+{
+    this._textModel = textModel;
+}
+
+WebInspector.TextEditorModel.BraceMatcher.prototype = {
+    /**
+     * @param {number} lineNumber
+     * @return {Array.<{startColumn: number, endColumn: number, token: string}>}
+     */
+    _braceRanges: function(lineNumber)
+    {
+        if (lineNumber >= this._textModel.linesCount || lineNumber < 0)
+            return null;
+
+        var attribute = this._textModel.getAttribute(lineNumber, "highlight");
+        if (!attribute)
+            return null;
+        else
+            return attribute.braces;
+    },
+
+    /**
+     * @param {string} braceTokenLeft
+     * @param {string} braceTokenRight
+     * @return {boolean}
+     */
+    _matches: function(braceTokenLeft, braceTokenRight)
+    {
+        return ((braceTokenLeft === "brace-start" && braceTokenRight === "brace-end") || (braceTokenLeft === "block-start" && braceTokenRight === "block-end"));
+    },
+
+    /**
+     * @param {number} lineNumber
+     * @param {number} column
+     * @param {number=} maxBraceIteration
+     * @return {?{lineNumber: number, column: number, token: string}}
+     */
+    findLeftCandidate: function(lineNumber, column, maxBraceIteration)
+    {
+        var braces = this._braceRanges(lineNumber);
+        if (!braces)
+            return null;
+
+        var braceIndex = braces.length - 1;
+        while (braceIndex >= 0 && braces[braceIndex].startColumn > column)
+            --braceIndex;
+
+        var brace = braceIndex >= 0 ? braces[braceIndex] : null;
+        if (brace && brace.startColumn === column && (brace.token === "block-end" || brace.token === "brace-end"))
+            --braceIndex;
+
+        var stack = [];
+        maxBraceIteration = maxBraceIteration || Number.MAX_VALUE;
+        while (--maxBraceIteration) {
+            if (braceIndex < 0) {
+                while ((braces = this._braceRanges(--lineNumber)) && !braces.length) {};
+                if (!braces)
+                    return null;
+                braceIndex = braces.length - 1;
+            }
+            brace = braces[braceIndex];
+            if (brace.token === "block-end" || brace.token === "brace-end")
+                stack.push(brace.token);
+            else if (stack.length === 0)
+                return {
+                    lineNumber: lineNumber,
+                    column: brace.startColumn,
+                    token: brace.token
+                };
+            else if (!this._matches(brace.token, stack.pop()))
+                return null;
+
+            --braceIndex;
+        }
+        return null;
+    },
+
+    /**
+     * @param {number} lineNumber
+     * @param {number} column
+     * @param {number=} maxBraceIteration
+     * @return {?{lineNumber: number, column: number, token: string}}
+     */
+    findRightCandidate: function(lineNumber, column, maxBraceIteration)
+    {
+        var braces = this._braceRanges(lineNumber);
+        if (!braces)
+            return null;
+
+        var braceIndex = 0;
+        while (braceIndex < braces.length && braces[braceIndex].startColumn < column)
+            ++braceIndex;
+
+        var brace = braceIndex < braces.length ? braces[braceIndex] : null;
+        if (brace && brace.startColumn === column && (brace.token === "block-start" || brace.token === "brace-start"))
+            ++braceIndex;
+
+        var stack = [];
+        maxBraceIteration = maxBraceIteration || Number.MAX_VALUE;
+        while (--maxBraceIteration) {
+            if (braceIndex >= braces.length) {
+                while ((braces = this._braceRanges(++lineNumber)) && !braces.length) {};
+                if (!braces)
+                    return null;
+                braceIndex = 0;
+            }
+            brace = braces[braceIndex];
+            if (brace.token === "block-start" || brace.token === "brace-start")
+                stack.push(brace.token);
+            else if (stack.length === 0)
+                return {
+                    lineNumber: lineNumber,
+                    column: brace.startColumn,
+                    token: brace.token
+                };
+            else if (!this._matches(stack.pop(), brace.token))
+                return null;
+            ++braceIndex;
+        }
+        return null;
+    },
+
+    /**
+     * @param {number} lineNumber
+     * @param {number} column
+     * @param {number=} maxBraceIteration
+     * @return {?{leftBrace: {lineNumber: number, column: number, token: string}, rightBrace: {lineNumber: number, column: number, token: string}}}
+     */
+    enclosingBraces: function(lineNumber, column, maxBraceIteration)
+    {
+        var leftBraceLocation = this.findLeftCandidate(lineNumber, column, maxBraceIteration);
+        if (!leftBraceLocation)
+            return null;
+
+        var rightBraceLocation = this.findRightCandidate(lineNumber, column, maxBraceIteration);
+        if (!rightBraceLocation)
+            return null;
+
+        if (!this._matches(leftBraceLocation.token, rightBraceLocation.token))
+            return null;
+
+        return {
+            leftBrace: leftBraceLocation,
+            rightBrace: rightBraceLocation
+        };
+    },
+}

Modified: trunk/Source/WebCore/inspector/front-end/textEditor.css (142090 => 142091)


--- trunk/Source/WebCore/inspector/front-end/textEditor.css	2013-02-07 11:46:12 UTC (rev 142090)
+++ trunk/Source/WebCore/inspector/front-end/textEditor.css	2013-02-07 11:51:08 UTC (rev 142091)
@@ -42,6 +42,10 @@
     border-radius: 3px;
 }
 
+.text-editor-brace-match {
+    border-bottom: 1px solid black;
+}
+
 .text-editor-contents .inner-container {
     position: absolute;
     top: 0;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to