Changeset 142091 in webkit
- Timestamp:
- Feb 7, 2013 3:51:08 AM (11 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r142084 r142091 1 2013-02-07 Andrey Lushnikov <lushnikov@chromium.org> 2 3 Web Inspector: highlight matching braces in DTE. 4 https://bugs.webkit.org/show_bug.cgi?id=108697 5 6 Reviewed by Pavel Feldman. 7 8 New layout test to verify brace matching functionality. Fix some 9 layout test expectations as the patch removes braces from highlight 10 ranges. 11 12 * inspector/editor/brace-matcher-expected.txt: Added. 13 * inspector/editor/brace-matcher.html: Added. 14 * inspector/editor/highlighter-basics-expected.txt: 15 * inspector/editor/text-editor-long-line-expected.txt: 16 1 17 2013-02-07 Matt Falkenhagen <falken@chromium.org> 2 18 -
trunk/LayoutTests/inspector/editor/highlighter-basics-expected.txt
r141987 r142091 92 92 16 : * line #7 : whitespace[0-1] whitespace[2-3] javascript-ident[3-7] whitespace[7-8] javascript-number[9-10] 93 93 17 : * line #8 : whitespace[0-1] whitespace[2-3] javascript-ident[3-7] whitespace[7-8] javascript-number[9-10] 94 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]94 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] 95 95 19 : some text : javascript-ident[0-4] whitespace[4-5] javascript-ident[5-9] 96 96 20 : : … … 114 114 16 : * line #7 : whitespace[0-1] whitespace[2-3] javascript-ident[3-7] whitespace[7-8] javascript-number[9-10] 115 115 17 : * line #8 : whitespace[0-1] whitespace[2-3] javascript-ident[3-7] whitespace[7-8] javascript-number[9-10] 116 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]116 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] 117 117 19 : some text : javascript-ident[0-4] whitespace[4-5] javascript-ident[5-9] 118 118 20 : : -
trunk/LayoutTests/inspector/editor/text-editor-long-line-expected.txt
r141987 r142091 3 3 4 4 <div class="inner-container" tabindex="0"> 5 <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>5 <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> 6 6 -
trunk/Source/WebCore/ChangeLog
r142087 r142091 1 2013-02-07 Andrey Lushnikov <lushnikov@chromium.org> 2 3 Web Inspector: highlight matching braces in DTE. 4 https://bugs.webkit.org/show_bug.cgi?id=108697 5 6 Reviewed by Pavel Feldman. 7 8 Implement BraceMatcher class which for given position in textModel 9 will respond with enclosing brace pair for that position. 10 Make use of this class in DefaultTextEditor by handling 11 selectionChange event. Make use of this class in "_closingBlockOffset" 12 method of TextEditorMainPanel as this method implements similar 13 functionality. 14 15 New test: inspector/editor/brace-matcher.html 16 17 * inspector/front-end/DefaultTextEditor.js: 18 (WebInspector.TextEditorMainPanel): 19 (WebInspector.TextEditorMainPanel.prototype._applyDomUpdates): 20 (WebInspector.TextEditorMainPanel.prototype._closingBlockOffset): 21 (WebInspector.TextEditorMainPanel.prototype._handleSelectionChange): 22 (WebInspector.TextEditorMainPanel.BraceHighlightController): 23 (WebInspector.TextEditorMainPanel.BraceHighlightController.prototype.handleSelectionChange): 24 * inspector/front-end/TextEditorHighlighter.js: 25 (WebInspector.TextEditorHighlighter.prototype._highlightLines): 26 * inspector/front-end/TextEditorModel.js: 27 (WebInspector.TextEditorModel.endsWithBracketRegex): 28 (WebInspector.TextEditorModel.endsWithBracketRegex.): 29 * inspector/front-end/textEditor.css: 30 (.text-editor-brace-match): 31 1 32 2013-02-05 Eunmi Lee <eunmi15.lee@samsung.com> and Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com> 2 33 -
trunk/Source/WebCore/inspector/front-end/DefaultTextEditor.js
r141986 r142091 1370 1370 1371 1371 this._tokenHighlighter = new WebInspector.TextEditorMainPanel.TokenHighlighter(this, textModel); 1372 this._braceMatcher = new WebInspector.TextEditorModel.BraceMatcher(textModel); 1373 this._braceHighlighter = new WebInspector.TextEditorMainPanel.BraceHighlightController(this, textModel, this._braceMatcher); 1372 1374 1373 1375 this._freeCachedElements(); … … 2402 2404 // Unindent after block 2403 2405 if (editInfo.text === "}" && editInfo.range.isEmpty() && selection.isEmpty() && !this._textModel.line(editInfo.range.endLine).trim()) { 2404 var offset = this._closingBlockOffset(editInfo.range , selection);2406 var offset = this._closingBlockOffset(editInfo.range); 2405 2407 if (offset >= 0) { 2406 2408 editInfo.range.startColumn = offset; … … 2492 2494 /** 2493 2495 * @param {WebInspector.TextRange} oldRange 2494 * @param {WebInspector.TextRange} selection2495 2496 * @return {number} 2496 2497 */ 2497 _closingBlockOffset: function(oldRange, selection) 2498 { 2499 var nestingLevel = 1; 2500 for (var i = oldRange.endLine; i >= 0; --i) { 2501 var attribute = this._textModel.getAttribute(i, "highlight"); 2502 if (!attribute) 2503 continue; 2504 var ranges = attribute.ranges; 2505 for (var j = ranges.length - 1; j >= 0; j--) { 2506 var token = ranges[j].token; 2507 if (token === "block-start") { 2508 if (!(--nestingLevel)) { 2509 var lineContent = this._textModel.line(i); 2510 return lineContent.length - lineContent.trimLeft().length; 2511 } 2512 } 2513 if (token === "block-end") 2514 ++nestingLevel; 2515 } 2516 } 2517 return -1; 2498 _closingBlockOffset: function(oldRange) 2499 { 2500 var leftBrace = this._braceMatcher.findLeftCandidate(oldRange.startLine, oldRange.startColumn); 2501 if (!leftBrace || leftBrace.token !== "block-start") 2502 return -1; 2503 var lineContent = this._textModel.line(leftBrace.lineNumber); 2504 return lineContent.length - lineContent.trimLeft().length; 2518 2505 }, 2519 2506 … … 2681 2668 2682 2669 this._tokenHighlighter.handleSelectionChange(textRange); 2670 this._braceHighlighter.handleSelectionChange(textRange); 2683 2671 this._delegate.selectionChanged(textRange); 2684 2672 }, … … 3360 3348 } 3361 3349 3350 /** 3351 * @constructor 3352 * @param {WebInspector.TextEditorMainPanel} textEditor 3353 * @param {WebInspector.TextEditorModel} textModel 3354 * @param {WebInspector.TextEditorModel.BraceMatcher} braceMatcher 3355 */ 3356 WebInspector.TextEditorMainPanel.BraceHighlightController = function(textEditor, textModel, braceMatcher) 3357 { 3358 this._textEditor = textEditor; 3359 this._textModel = textModel; 3360 this._braceMatcher = braceMatcher; 3361 this._highlightDescriptors = []; 3362 } 3363 3364 WebInspector.TextEditorMainPanel.BraceHighlightController.prototype = { 3365 /** 3366 * @param {WebInspector.TextRange} selectionRange 3367 */ 3368 handleSelectionChange: function(selectionRange) 3369 { 3370 if (!selectionRange || !selectionRange.isEmpty()) { 3371 this._removeHighlight(); 3372 return; 3373 } 3374 3375 if (this._highlightedRange && this._highlightedRange.compareTo(selectionRange) === 0) 3376 return; 3377 3378 this._removeHighlight(); 3379 var lineNumber = selectionRange.startLine; 3380 var column = selectionRange.startColumn; 3381 var line = this._textModel.line(lineNumber); 3382 if (column > 0 && /[)}]/.test(line.charAt(column - 1))) 3383 --column; 3384 3385 var enclosingBraces = this._braceMatcher.enclosingBraces(lineNumber, column); 3386 if (!enclosingBraces) 3387 return; 3388 3389 this._highlightedRange = selectionRange; 3390 this._highlightDescriptors.push(this._textEditor.highlightRange(WebInspector.TextRange.createFromLocation(enclosingBraces.leftBrace.lineNumber, enclosingBraces.leftBrace.column), "text-editor-brace-match")); 3391 this._highlightDescriptors.push(this._textEditor.highlightRange(WebInspector.TextRange.createFromLocation(enclosingBraces.rightBrace.lineNumber, enclosingBraces.rightBrace.column), "text-editor-brace-match")); 3392 }, 3393 3394 _removeHighlight: function() 3395 { 3396 if (!this._highlightDescriptors.length) 3397 return; 3398 3399 for(var i = 0; i < this._highlightDescriptors.length; ++i) 3400 this._textEditor.removeHighlight(this._highlightDescriptors[i]); 3401 3402 this._highlightDescriptors = []; 3403 delete this._highlightedRange; 3404 } 3405 } 3406 3362 3407 WebInspector.debugDefaultTextEditor = false; -
trunk/Source/WebCore/inspector/front-end/TextEditorHighlighter.js
r140421 r142091 186 186 // Highlight line. 187 187 state.ranges = state.ranges || []; 188 state.braces = state.braces || []; 188 189 do { 189 190 var newColumn = this._tokenizer.nextToken(lastHighlightedColumn); 190 191 var tokenType = this._tokenizer.tokenType; 191 if (tokenType && lastHighlightedColumn < this._highlightLineLimit) 192 state.ranges.push({ 193 startColumn: lastHighlightedColumn, 194 endColumn: newColumn - 1, 195 token: tokenType 196 }); 192 if (tokenType && lastHighlightedColumn < this._highlightLineLimit) { 193 if (tokenType === "brace-start" || tokenType === "brace-end" || tokenType === "block-start" || tokenType === "block-end") { 194 state.braces.push({ 195 startColumn: lastHighlightedColumn, 196 endColumn: newColumn - 1, 197 token: tokenType 198 }); 199 } else { 200 state.ranges.push({ 201 startColumn: lastHighlightedColumn, 202 endColumn: newColumn - 1, 203 token: tokenType 204 }); 205 } 206 } 197 207 lastHighlightedColumn = newColumn; 198 208 if (++tokensCount > this._highlightChunkLimit) -
trunk/Source/WebCore/inspector/front-end/TextEditorModel.js
r135574 r142091 657 657 __proto__: WebInspector.Object.prototype 658 658 } 659 660 /** 661 * @constructor 662 * @param {WebInspector.TextEditorModel} textModel 663 */ 664 WebInspector.TextEditorModel.BraceMatcher = function(textModel) 665 { 666 this._textModel = textModel; 667 } 668 669 WebInspector.TextEditorModel.BraceMatcher.prototype = { 670 /** 671 * @param {number} lineNumber 672 * @return {Array.<{startColumn: number, endColumn: number, token: string}>} 673 */ 674 _braceRanges: function(lineNumber) 675 { 676 if (lineNumber >= this._textModel.linesCount || lineNumber < 0) 677 return null; 678 679 var attribute = this._textModel.getAttribute(lineNumber, "highlight"); 680 if (!attribute) 681 return null; 682 else 683 return attribute.braces; 684 }, 685 686 /** 687 * @param {string} braceTokenLeft 688 * @param {string} braceTokenRight 689 * @return {boolean} 690 */ 691 _matches: function(braceTokenLeft, braceTokenRight) 692 { 693 return ((braceTokenLeft === "brace-start" && braceTokenRight === "brace-end") || (braceTokenLeft === "block-start" && braceTokenRight === "block-end")); 694 }, 695 696 /** 697 * @param {number} lineNumber 698 * @param {number} column 699 * @param {number=} maxBraceIteration 700 * @return {?{lineNumber: number, column: number, token: string}} 701 */ 702 findLeftCandidate: function(lineNumber, column, maxBraceIteration) 703 { 704 var braces = this._braceRanges(lineNumber); 705 if (!braces) 706 return null; 707 708 var braceIndex = braces.length - 1; 709 while (braceIndex >= 0 && braces[braceIndex].startColumn > column) 710 --braceIndex; 711 712 var brace = braceIndex >= 0 ? braces[braceIndex] : null; 713 if (brace && brace.startColumn === column && (brace.token === "block-end" || brace.token === "brace-end")) 714 --braceIndex; 715 716 var stack = []; 717 maxBraceIteration = maxBraceIteration || Number.MAX_VALUE; 718 while (--maxBraceIteration) { 719 if (braceIndex < 0) { 720 while ((braces = this._braceRanges(--lineNumber)) && !braces.length) {}; 721 if (!braces) 722 return null; 723 braceIndex = braces.length - 1; 724 } 725 brace = braces[braceIndex]; 726 if (brace.token === "block-end" || brace.token === "brace-end") 727 stack.push(brace.token); 728 else if (stack.length === 0) 729 return { 730 lineNumber: lineNumber, 731 column: brace.startColumn, 732 token: brace.token 733 }; 734 else if (!this._matches(brace.token, stack.pop())) 735 return null; 736 737 --braceIndex; 738 } 739 return null; 740 }, 741 742 /** 743 * @param {number} lineNumber 744 * @param {number} column 745 * @param {number=} maxBraceIteration 746 * @return {?{lineNumber: number, column: number, token: string}} 747 */ 748 findRightCandidate: function(lineNumber, column, maxBraceIteration) 749 { 750 var braces = this._braceRanges(lineNumber); 751 if (!braces) 752 return null; 753 754 var braceIndex = 0; 755 while (braceIndex < braces.length && braces[braceIndex].startColumn < column) 756 ++braceIndex; 757 758 var brace = braceIndex < braces.length ? braces[braceIndex] : null; 759 if (brace && brace.startColumn === column && (brace.token === "block-start" || brace.token === "brace-start")) 760 ++braceIndex; 761 762 var stack = []; 763 maxBraceIteration = maxBraceIteration || Number.MAX_VALUE; 764 while (--maxBraceIteration) { 765 if (braceIndex >= braces.length) { 766 while ((braces = this._braceRanges(++lineNumber)) && !braces.length) {}; 767 if (!braces) 768 return null; 769 braceIndex = 0; 770 } 771 brace = braces[braceIndex]; 772 if (brace.token === "block-start" || brace.token === "brace-start") 773 stack.push(brace.token); 774 else if (stack.length === 0) 775 return { 776 lineNumber: lineNumber, 777 column: brace.startColumn, 778 token: brace.token 779 }; 780 else if (!this._matches(stack.pop(), brace.token)) 781 return null; 782 ++braceIndex; 783 } 784 return null; 785 }, 786 787 /** 788 * @param {number} lineNumber 789 * @param {number} column 790 * @param {number=} maxBraceIteration 791 * @return {?{leftBrace: {lineNumber: number, column: number, token: string}, rightBrace: {lineNumber: number, column: number, token: string}}} 792 */ 793 enclosingBraces: function(lineNumber, column, maxBraceIteration) 794 { 795 var leftBraceLocation = this.findLeftCandidate(lineNumber, column, maxBraceIteration); 796 if (!leftBraceLocation) 797 return null; 798 799 var rightBraceLocation = this.findRightCandidate(lineNumber, column, maxBraceIteration); 800 if (!rightBraceLocation) 801 return null; 802 803 if (!this._matches(leftBraceLocation.token, rightBraceLocation.token)) 804 return null; 805 806 return { 807 leftBrace: leftBraceLocation, 808 rightBrace: rightBraceLocation 809 }; 810 }, 811 } -
trunk/Source/WebCore/inspector/front-end/textEditor.css
r141414 r142091 41 41 border: 1px solid gray; 42 42 border-radius: 3px; 43 } 44 45 .text-editor-brace-match { 46 border-bottom: 1px solid black; 43 47 } 44 48
Note: See TracChangeset
for help on using the changeset viewer.