+2013-02-07 Andrey Lushnikov <lushnikov@chromium.org>
+
+ 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 <falken@chromium.org>
Rollout r142058 various crashes and timeouts on AppleMac and Chromium
--- /dev/null
+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"}}
+
+
--- /dev/null
+<html>
+<head>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+<script src="editor-test.js"></script>
+<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>
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 : :
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 : :
<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>
+2013-02-07 Andrey Lushnikov <lushnikov@chromium.org>
+
+ 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 <eunmi15.lee@samsung.com> and Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com>
[EFL][WK2] Refactoring initialization and shutdown codes of EFL libraries.
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();
// 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;
/**
* @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;
},
/**
this._lastSelection = textRange;
this._tokenHighlighter.handleSelectionChange(textRange);
+ this._braceHighlighter.handleSelectionChange(textRange);
this._delegate.selectionChanged(textRange);
},
}
}
+/**
+ * @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;
// 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;
__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
+ };
+ },
+}
border-radius: 3px;
}
+.text-editor-brace-match {
+ border-bottom: 1px solid black;
+}
+
.text-editor-contents .inner-container {
position: absolute;
top: 0;