diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 3b68b44063e62..5a9948cd35f72 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -439,20 +439,21 @@ namespace ts.formatting { } if (previousRange! && formattingScanner.getStartPos() >= originalRange.end) { - const token = + const tokenInfo = formattingScanner.isOnEOF() ? formattingScanner.readEOFTokenRange() : formattingScanner.isOnToken() ? formattingScanner.readTokenInfo(enclosingNode).token : undefined; - if (token) { + if (tokenInfo) { + const parent = findPrecedingToken(tokenInfo.end, sourceFile, enclosingNode)?.parent || previousParent!; processPair( - token, - sourceFile.getLineAndCharacterOfPosition(token.pos).line, - enclosingNode, + tokenInfo, + sourceFile.getLineAndCharacterOfPosition(tokenInfo.pos).line, + parent, previousRange, previousRangeStartLine!, previousParent!, - enclosingNode, + parent, /*dynamicIndentation*/ undefined); } } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 016eb35227eda..e0465bce94eef 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1256,8 +1256,10 @@ namespace ts { * Finds the rightmost token satisfying `token.end <= position`, * excluding `JsxText` tokens containing only whitespace. */ - export function findPrecedingToken(position: number, sourceFile: SourceFile, startNode?: Node, excludeJsdoc?: boolean): Node | undefined { - const result = find(startNode || sourceFile); + export function findPrecedingToken(position: number, sourceFile: SourceFileLike, startNode: Node, excludeJsdoc?: boolean): Node | undefined; + export function findPrecedingToken(position: number, sourceFile: SourceFile, startNode?: Node, excludeJsdoc?: boolean): Node | undefined; + export function findPrecedingToken(position: number, sourceFile: SourceFileLike, startNode?: Node, excludeJsdoc?: boolean): Node | undefined { + const result = find((startNode || sourceFile) as Node); Debug.assert(!(result && isWhiteSpaceOnlyJsxText(result))); return result; @@ -1322,7 +1324,7 @@ namespace ts { return isToken(n) && !isWhiteSpaceOnlyJsxText(n); } - function findRightmostToken(n: Node, sourceFile: SourceFile): Node | undefined { + function findRightmostToken(n: Node, sourceFile: SourceFileLike): Node | undefined { if (isNonWhitespaceToken(n)) { return n; } @@ -1339,7 +1341,7 @@ namespace ts { /** * Finds the rightmost child to the left of `children[exclusiveStartPosition]` which is a non-all-whitespace token or has constituent tokens. */ - function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number, sourceFile: SourceFile, parentKind: SyntaxKind): Node | undefined { + function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number, sourceFile: SourceFileLike, parentKind: SyntaxKind): Node | undefined { for (let i = exclusiveStartPosition - 1; i >= 0; i--) { const child = children[i]; diff --git a/tests/cases/fourslash/formatOnTypeOpenCurlyWithBraceCompletion.ts b/tests/cases/fourslash/formatOnTypeOpenCurlyWithBraceCompletion.ts new file mode 100644 index 0000000000000..b303b1ea62d6d --- /dev/null +++ b/tests/cases/fourslash/formatOnTypeOpenCurlyWithBraceCompletion.ts @@ -0,0 +1,12 @@ +/// + +//// if (foo) { +//// if (bar) {/**/} +//// } + +goTo.marker(""); +format.onType("", "{"); +verify.currentFileContentIs( +`if (foo) { + if (bar) { } +}`);