diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index ed6dc1a71f7..2e94e39e71d 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1661,9 +1661,9 @@ module FourSlash { } var actualMatchPosition = -1; - if (bracePosition >= actual[0].start() && bracePosition <= actual[0].end()) { + if (bracePosition === actual[0].start()) { actualMatchPosition = actual[1].start(); - } else if (bracePosition >= actual[1].start() && bracePosition <= actual[1].end()) { + } else if (bracePosition === actual[1].start()) { actualMatchPosition = actual[0].start(); } else { throw new Error('verifyMatchingBracePosition failed - could not find the brace position: ' + bracePosition + ' in the returned list: (' + actual[0].start() + ',' + actual[0].end() + ') and (' + actual[1].start() + ',' + actual[1].end() + ')'); diff --git a/src/services/braceMatcher.ts b/src/services/braceMatcher.ts deleted file mode 100644 index 3615f677024..00000000000 --- a/src/services/braceMatcher.ts +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -/// - -module TypeScript.Services { - export class BraceMatcher { - - // Given a script name and position in the script, return a pair of text range if the - // position corresponds to a "brace matchin" characters (e.g. "{" or "(", etc.) - // If the position is not on any range, return an empty set. - public static getMatchSpans(syntaxTree: TypeScript.SyntaxTree, position: number): TypeScript.TextSpan[] { - var result: TypeScript.TextSpan[] = []; - - var token = findToken(syntaxTree.sourceUnit(), position); - - if (start(token) === position) { - var matchKind = BraceMatcher.getMatchingTokenKind(token); - - if (matchKind !== null) { - var parentElement = token.parent; - - for (var i = 0, n = childCount(parentElement); i < n; i++) { - var current = childAt(parentElement, i); - - if (current !== null && fullWidth(current) > 0) { - if (current.kind() === matchKind) { - var range1 = new TypeScript.TextSpan(start(token), width(token)); - var range2 = new TypeScript.TextSpan(start(current), width(current)); - if (range1.start() < range2.start()) { - result.push(range1, range2); - } - else { - result.push(range2, range1); - } - break; - } - } - } - } - } - - return result; - } - - private static getMatchingTokenKind(token: TypeScript.ISyntaxToken): TypeScript.SyntaxKind { - switch (token.kind()) { - case TypeScript.SyntaxKind.OpenBraceToken: return TypeScript.SyntaxKind.CloseBraceToken - case TypeScript.SyntaxKind.OpenParenToken: return TypeScript.SyntaxKind.CloseParenToken; - case TypeScript.SyntaxKind.OpenBracketToken: return TypeScript.SyntaxKind.CloseBracketToken; - case TypeScript.SyntaxKind.LessThanToken: return TypeScript.SyntaxKind.GreaterThanToken; - case TypeScript.SyntaxKind.CloseBraceToken: return TypeScript.SyntaxKind.OpenBraceToken - case TypeScript.SyntaxKind.CloseParenToken: return TypeScript.SyntaxKind.OpenParenToken; - case TypeScript.SyntaxKind.CloseBracketToken: return TypeScript.SyntaxKind.OpenBracketToken; - case TypeScript.SyntaxKind.GreaterThanToken: return TypeScript.SyntaxKind.LessThanToken; - } - - return null; - } - } -} \ No newline at end of file diff --git a/src/services/services.ts b/src/services/services.ts index 04e63f6dbe1..819dcc8d825 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -7,7 +7,6 @@ /// /// /// -/// /// /// /// @@ -2111,7 +2110,7 @@ module ts { if (child.getFullStart() <= position && position < child.getEnd()) { current = child; continue outer; - } + } } return current; } @@ -3759,14 +3758,61 @@ module ts { } function getBraceMatchingAtPosition(filename: string, position: number) { - filename = TypeScript.switchToForwardSlashes(filename); - var syntaxTree = getSyntaxTree(filename); - return TypeScript.Services.BraceMatcher.getMatchSpans(syntaxTree, position); + var sourceFile = getCurrentSourceFile(filename); + var result: TypeScript.TextSpan[] = []; + + var token = getTokenAtPosition(sourceFile, position); + + if (token.getStart(sourceFile) === position) { + var matchKind = getMatchingTokenKind(token); + + // Ensure that there is a corresponding token to match ours. + if (matchKind) { + var parentElement = token.parent; + + var childNodes = parentElement.getChildren(sourceFile); + for (var i = 0, n = childNodes.length; i < n; i++) { + var current = childNodes[i]; + + if (current.kind === matchKind) { + var range1 = new TypeScript.TextSpan(token.getStart(sourceFile), token.getWidth(sourceFile)); + var range2 = new TypeScript.TextSpan(current.getStart(sourceFile), current.getWidth(sourceFile)); + + // We want to order the braces when we return the result. + if (range1.start() < range2.start()) { + result.push(range1, range2); + } + else { + result.push(range2, range1); + } + + break; + } + } + } + } + + return result; + + function getMatchingTokenKind(token: Node): ts.SyntaxKind { + switch (token.kind) { + case ts.SyntaxKind.OpenBraceToken: return ts.SyntaxKind.CloseBraceToken + case ts.SyntaxKind.OpenParenToken: return ts.SyntaxKind.CloseParenToken; + case ts.SyntaxKind.OpenBracketToken: return ts.SyntaxKind.CloseBracketToken; + case ts.SyntaxKind.LessThanToken: return ts.SyntaxKind.GreaterThanToken; + case ts.SyntaxKind.CloseBraceToken: return ts.SyntaxKind.OpenBraceToken + case ts.SyntaxKind.CloseParenToken: return ts.SyntaxKind.OpenParenToken; + case ts.SyntaxKind.CloseBracketToken: return ts.SyntaxKind.OpenBracketToken; + case ts.SyntaxKind.GreaterThanToken: return ts.SyntaxKind.LessThanToken; + } + + return undefined; + } } function getIndentationAtPosition(filename: string, position: number, editorOptions: EditorOptions) { filename = TypeScript.switchToForwardSlashes(filename); - + var sourceFile = getCurrentSourceFile(filename); var options = new TypeScript.FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter) diff --git a/tests/cases/fourslash_old/getMatchingBraces.ts b/tests/cases/fourslash/getMatchingBraces.ts similarity index 79% rename from tests/cases/fourslash_old/getMatchingBraces.ts rename to tests/cases/fourslash/getMatchingBraces.ts index 13d5effa15f..fc8a71197db 100644 --- a/tests/cases/fourslash_old/getMatchingBraces.ts +++ b/tests/cases/fourslash/getMatchingBraces.ts @@ -38,6 +38,6 @@ ////} test.ranges().forEach((range) => { - verify.matchingBracePositionInCurrentFile(range.start, range.end - 1); - verify.matchingBracePositionInCurrentFile(range.end - 1, range.start); - }); \ No newline at end of file + verify.matchingBracePositionInCurrentFile(range.start, range.end - 1); + verify.matchingBracePositionInCurrentFile(range.end - 1, range.start); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getMatchingBracesAdjacentBraces.ts b/tests/cases/fourslash/getMatchingBracesAdjacentBraces.ts new file mode 100644 index 00000000000..8dd997ebe73 --- /dev/null +++ b/tests/cases/fourslash/getMatchingBracesAdjacentBraces.ts @@ -0,0 +1,9 @@ +////function f[||][|(x: T)|][|{ +//// return x; +////}|] + +// If there is an adjacent opening and closing brace, +// then only the opening brace should get highlighted. +test.ranges().forEach(range => { + verify.matchingBracePositionInCurrentFile(range.start, range.end - 1); +}); \ No newline at end of file